iPhone WiFi Subnet Mask and Router Address - iphone

I have code that allows me to determine the MAC address and the IP address of the WiFi connection on the iPhone, but I can't figure out how to get the Subnet Mask and Router address for the connection. Can anyone point me in the right direction here?

You can get that information by calling getifaddrs. (I use this function in an app of mine to figure out the iPhone's IP address.)
struct ifaddrs *ifa = NULL, *ifList;
getifaddrs(&ifList); // should check for errors
for (ifa = ifList; ifa != NULL; ifa = ifa->ifa_next) {
ifa->ifa_addr // interface address
ifa->ifa_netmask // subnet mask
ifa->ifa_dstaddr // broadcast address, NOT router address
}
freeifaddrs(ifList); // clean up after yourself
This gets you the subnet mask; for the router address, see this question.
This is all old-school UNIX networking stuff, you'll have to pick out which of the interfaces is the WiFi connection (other stuff like a loopback interface will be in there too). Then you might have to use functions like inet_ntoa() depending on what format you want to read the IP addresses. It's not bad, just tedious and ugly. Have fun!

NSString *address = #"error";
NSString *netmask = #"error";
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success = 0;
// retrieve the current interfaces - returns 0 on success
success = getifaddrs(&interfaces);
if (success == 0)
{
// Loop through linked list of interfaces
temp_addr = interfaces;
while(temp_addr != NULL)
{
if(temp_addr->ifa_addr->sa_family == AF_INET)
{
// Check if interface is en0 which is the wifi connection on the iPhone
if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:#"en0"])
{
// Get NSString from C String
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
netmask = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr)];
}
}
temp_addr = temp_addr->ifa_next;
}
}
// Free memory
freeifaddrs(interfaces);
NSLog(#"address %#", address);
NSLog(#"netmask %#", netmask);

Related

Error with sendto() function: Invalid Argument Error

I am working on writing a ping CLI program for linux and I have been getting errno 22: invalid argument in the sendto() function. I don't understand why, all the arguments seem to be correct.
Here is where I call the function:
// send echo request
bytesSent = sendto(socketFD, // socket file descriptor
(char*)&packet, PacketSize, // packet and size
0, // flags
(sockaddr*)DestinationAddr, (socklen_t)sizeof(DestinationAddr)); // destination address and size
'packet' looks like this:
(I call initializePacket() in the function where I call sendto())
struct PacketData {
icmphdr header;
char message[PacketSize - sizeof(header)]; // want total size to be 64 bytes
};
PacketData initializePacket(int &transmitted) {
PacketData packet = {};
packet.header.type = ICMP_ECHO; // set ICMP type to Echo
packet.header.un.echo.id = getpid() & 0xFFFF; // set id (ICMP field is 16 bits)
packet.header.checksum = 0; // fixed checksum because data is unchanging
packet.header.un.echo.sequence = transmitted++;
// fill up message
memset(&packet.message, '0', sizeof(packet.message));
packet.message[PacketSize - sizeof(packet.header) - 1] = '\0';
return packet;
}
'DestinationAddr' is this:
// variables needed to store IP Address
addrinfo* result;
sockaddr_in* DestinationAddr;
char ipString[INET_ADDRSTRLEN];
// get IP Address and store in result (passed by reference)
if (getIPAddress(argv[1], result) != 0) {
std::cout << "Invalid IP Address. Terminating ...\n";
exit(EXIT_FAILURE);
}
else {
DestinationAddr = (sockaddr_in*)result->ai_addr; // get struct from resulting linked list
void* address;
address = &DestinationAddr->sin_addr; // store IP Address
inet_ntop(result->ai_family, address, ipString, sizeof(ipString)); // convert binary IP to string
std::cout << "IP: " << ipString << std::endl;
}
And the getIPAddress() function is:
int getIPAddress(char* hostName, addrinfo* &result) {
addrinfo tempStruct = {0};
tempStruct.ai_family = AF_INET; // want IPv4
tempStruct.ai_socktype = SOCK_DGRAM; // set socket type to datagram
tempStruct.ai_flags = AI_PASSIVE; // fill in IP automatically
// get and validate IP address
return (getaddrinfo(hostName, &PortNo, &tempStruct, &result));
}
PortNo is defined as: const char PortNo = '0';
According to documentation icmp:
A user protocol may receive ICMP packets for all local sockets by opening a raw socket with the protocol IPPROTO_ICMP.
So, try creating your socket like that:
socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)
And, if you encounter EPERM error, then run your program as root.

NetService getting proper Inet type while debugging but not working from archived IPA

I am working with netsevices and using below function to Get IPV4 and IPV6 address.Getting Proper addresses while debugging or simple IPA file. But AFTER ARCHIVING I do not get proper INET Type.
This is strange issue.
func netServiceDidResolveAddress(_ sender: NetService) {
        if let addresses = sender.addresses, addresses.count > 0 {
            for address in addresses {
                let data = address as NSData
                
                let inetAddress: sockaddr_in = data.castToCPointer()
                if inetAddress.sin_family == __uint8_t(AF_INET) {
                    if let ip = String(cString: inet_ntoa(inetAddress.sin_addr), encoding: .ascii) {
                        // IPv4
                        bonjourIP = ip
                    }
                } else if inetAddress.sin_family == __uint8_t(AF_INET6) {
                    let inetAddress6: sockaddr_in6 = data.castToCPointer()
                    let ipStringBuffer = UnsafeMutablePointer<Int8>.allocate(capacity: Int(INET6_ADDRSTRLEN))
                    var addr = inetAddress6.sin6_addr
                    
                    if let ipString = inet_ntop(Int32(inetAddress6.sin6_family), &addr, ipStringBuffer, __uint32_t(INET6_ADDRSTRLEN)) {
                        if let ip = String(cString: ipString, encoding: .ascii) {
                            // IPv6
                            bonjourIP = ip
                        }
                    }
                    
                    ipStringBuffer.deallocate(capacity: Int(INET6_ADDRSTRLEN))
                }
            }
        }
    }

How to resolve an internet address?

I have a problem: How can I convert (resolve) an ip address (like www.google.com) into ip address (array of byte)? I tried different code but every time the code crash if the address don't exist. There is a way to check also this?
+ (void) resolveIPAddress: (NSString*) dnsAddress {
struct hostent hostentry;
const char str = [ dnsAddress UTF8String ];
hostentry = gethostbyname(str);
char ipbuf[4];
char *ipbuf_ptr = &ipbuf[0];
ipbuf_ptr = inet_ntoa(*((struct in_addr *)hostentry->h_addr_list[0]));
printf("%s",ipbuf_ptr);
}
The problem is that your method tries using the results of gethostbyname without checking h_errno. When h_errno is non-zero, the results in hostentry are invalid. Dereferencing them in inet_ntoa causes the crash.
+ (void) resolveIPAddress: (NSString*) dnsAddress {
struct hostent hostentry;
const char str = [ dnsAddress UTF8String ];
hostentry = gethostbyname(str);
if (h_errno) {
NSLog(#"Error resolving host: %d", h_errno);
return;
}
char ipbuf[4];
char *ipbuf_ptr = &ipbuf[0];
ipbuf_ptr = inet_ntoa(*((struct in_addr *)hostentry->h_addr_list[0]));
printf("%s",ipbuf_ptr);
}

Dispatch source is only called when I do a NSLog() first

I am trying to use grand central dispatch in conjunction with bsd sockets to send an icmp ping. I add DISPATCH_SOURCE_TYPE_WRITE and DISPATCH_SOURCE_TYPE_READ as dispatch sources to read and write async.
So this is the method were I create the bsd socket and install the dispatch sources:
- (void)start
{
int err;
const struct sockaddr * addrPtr;
assert(self.hostAddress != nil);
// Open the socket.
addrPtr = (const struct sockaddr *) [self.hostAddress bytes];
fd = -1;
err = 0;
switch (addrPtr->sa_family) {
case AF_INET: {
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (fd < 0) {
err = errno;
}
} break;
case AF_INET6:
assert(NO);
// fall through
default: {
err = EPROTONOSUPPORT;
} break;
}
if (err != 0) {
[self didFailWithError:[NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:nil]];
} else {
dispatch_source_t writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_event_handler(writeSource, ^{
abort(); // testing
// call call method here to send a ping
});
dispatch_resume(writeSource);
//NSLog(#"testout");
dispatch_source_t readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_event_handler(readSource, ^{
unsigned long bytesAvail = dispatch_source_get_data(readSource);
NSLog(#"bytes available: %lu", bytesAvail);
});
dispatch_resume(readSource);
}
}
You see the //NSLog(#"testout");? The funny thing is that the write block is only called when the //NSLog(#"testout"); is NOT commented out. This is very odd. I didn't test the read callback. The sending needs to be working first.
So what is going on here?
There are kind of a bunch of things missing here. I'm not sure exactly which one is causing the weird behavior, but when I do all of the missing things, it seems to work "as expected" and my write event handler is called reliably and repeatedly. In general, there are a bunch of things you need to do when setting up a socket like this before passing it off to GCD. They are:
Create the socket
Bind it to a local address (missing in your code)
Set it to non-blocking (missing in your code)
Here is a little example I was able to put together in which the write handler gets called repeatedly, as expected:
int DoStuff()
{
int fd = -1;
// Create
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("cannot create socket");
return 0;
}
// Bind
struct sockaddr_in *localAddressPtr = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
memset((char *)localAddressPtr, 0, sizeof(*localAddressPtr));
localAddressPtr->sin_family = AF_INET;
localAddressPtr->sin_addr.s_addr = htonl(INADDR_ANY);
localAddressPtr->sin_port = htons(0);
if (bind(fd, (struct sockaddr *)localAddressPtr, sizeof(*localAddressPtr)) < 0) {
perror("bind failed");
return 0;
}
// Set non-blocking
int flags;
if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
flags = 0;
if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK))
{
perror("Couldnt set non-blocking");
return 0;
}
// Do a DNS lookup...
struct hostent *hp;
struct sockaddr_in *remoteAddressPtr = malloc(sizeof(struct sockaddr_in));
// Fill in the server's address and data
memset((char*)remoteAddressPtr, 0, sizeof(*remoteAddressPtr));
remoteAddressPtr->sin_family = AF_INET;
remoteAddressPtr->sin_port = htons(12345);
// Look up the address of the server by name
const char* host = "www.google.com";
hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "could not obtain address of %s\n", host);
return 0;
}
// Copy the host's address into the remote address structure
memcpy((void *)&remoteAddressPtr->sin_addr, hp->h_addr_list[0], hp->h_length);
dispatch_source_t writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_event_handler(writeSource, ^{
// Send message
const char* my_message = "the only thing we have to fear is fear itself.";
unsigned long len = strlen(my_message);
if (sendto(fd, my_message, len, 0, (struct sockaddr *)remoteAddressPtr, sizeof(*remoteAddressPtr)) != len) {
perror("sendto failed");
dispatch_source_cancel(writeSource);
}
});
dispatch_source_set_cancel_handler(writeSource, ^{
close(fd);
free(localAddressPtr);
free(remoteAddressPtr);
});
dispatch_resume(writeSource);
return 1;
}
NB: There's no way to dispose of the writeSource in my example without there being an error in a send operation. It's a trivial example...
My general theory on why NSLog triggers the handler to fire in your case, is that it keeps execution at or below that stack frame long enough for the background thread to come around and call the handler, but without that NSLog, your function returns, and something has a chance to die before the handler can get called. In fact, if you're using ARC it's probably the writeSource itself that is getting deallocated, since I don't see you making a strong reference to it anywhere outside the scope of this function. (My example captures a strong reference to it in the block, thus keeping it alive.) You could test this in your code by stashing a strong reference to writeSource.
I found the error:
In newer SDKs dispatch sources are subject to automatic reference counting despite the fact that they are no Objective-C objects.
So when the start method is over ARC disposes the dispatch source and they never get called.
NSLog delays the end of the start method in a way that the dispatch source triggers before the source gets disposed.

How to create UUID type 1 in objective C (iOS)

I created UUID (don't know which type) with the following code:
// Create universally unique identifier (object)
CFUUIDRef uuidObject = CFUUIDCreate(kCFAllocatorDefault);
// Get the string representation of CFUUID object.
NSString *uuidStr = (__bridge NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidObject);
CFRelease(uuidObject);
But my API that is send data to says that is not type 1 that it needs http://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_.28MAC_address.29.
How to create this type1 UUID in objC (iphone)?
I have problems making this in obj C, is it an option to use C code to generate this?
I've been searching for the same thing. Here it is:
uuid_generate_time
https://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man3/uuid_generate_time.3.html
Also there's Apple source code for this function:
http://www.opensource.apple.com/source/xnu/xnu-792.13.8/libkern/uuid/uuid.c
NSString* uuidString = nil;
// Get UUID type 1
uuid_t dateUUID;
uuid_generate_time(dateUUID);
// Convert it to string
uuid_string_t unparsedUUID;
uuid_unparse_lower(dateUUID, unparsedUUID);
uuidString = [[NSString alloc] initWithUTF8String:unparsedUUID];
Get the MAC address first: (from developertips)
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
...
- (NSString *)getMacAddress
{
int mgmtInfoBase[6];
char *msgBuffer = NULL;
size_t length;
unsigned char macAddress[6];
struct if_msghdr *interfaceMsgStruct;
struct sockaddr_dl *socketStruct;
NSString *errorFlag = NULL;
// Setup the management Information Base (mib)
mgmtInfoBase[0] = CTL_NET; // Request network subsystem
mgmtInfoBase[1] = AF_ROUTE; // Routing table info
mgmtInfoBase[2] = 0;
mgmtInfoBase[3] = AF_LINK; // Request link layer information
mgmtInfoBase[4] = NET_RT_IFLIST; // Request all configured interfaces
// With all configured interfaces requested, get handle index
if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0)
errorFlag = #"if_nametoindex failure";
else
{
// Get the size of the data available (store in len)
if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0)
errorFlag = #"sysctl mgmtInfoBase failure";
else
{
// Alloc memory based on above call
if ((msgBuffer = malloc(length)) == NULL)
errorFlag = #"buffer allocation failure";
else
{
// Get system information, store in buffer
if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
errorFlag = #"sysctl msgBuffer failure";
}
}
}
// Befor going any further...
if (errorFlag != NULL)
{
NSLog(#"Error: %#", errorFlag);
return errorFlag;
}
// Map msgbuffer to interface message structure
interfaceMsgStruct = (struct if_msghdr *) msgBuffer;
// Map to link-level socket structure
socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);
// Copy link layer address data in socket structure to an array
memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6);
// Read from char array into a string object, into traditional Mac address format
NSString *macAddressString = [NSString stringWithFormat:#"%02X:%02X:%02X:%02X:%02X:%02X",
macAddress[0], macAddress[1], macAddress[2],
macAddress[3], macAddress[4], macAddress[5]];
NSLog(#"Mac Address: %#", macAddressString);
// Release the buffer memory
free(msgBuffer);
return macAddressString;
}
Then generate the UUIDv1 with the rfc4122 spec, if the spec is too long to read, you may port the code from other language, here's one that I found: https://github.com/fredriklindberg/class.uuid.php/blob/master/class.uuid.php
Using following function you can create dynamic UUID.
-(NSString*)getDynamicUUID
{
CFUUIDRef uuidObj = CFUUIDCreate(nil);//create a new UUID
NSString *uuidString = (NSString*)CFUUIDCreateString(nil, uuidObj);
CFRelease(uuidObj);
return uuidString;
}
Hope this helps..