Retrieving network address information
Many programs will need to know the network information about the available interfaces on the device they are running on. This recipe will show you how to retrieve the network information for all the active network interfaces on your device. The information that we will be retrieving is the interface name, IP version, IP address, netmask, and default gateway.
We will start off by creating a
NetworkAddressStore
class that can be used to store the information for a given network interface. We will then get a list of active network interfaces and create an instance of the NetworkAddressStore
class for each interface. These objects will then be stored in NSMutableArray
.
This recipe will also introduce several new functions and two new structures, including the very important sockaddr
family of structures. We will discuss these new functions and structures as we describe the code.
Getting ready
This recipe is compatible with both iOS and OS X. No extra frameworks or libraries are required.
How to do it…
Let's retrieve the network address information for our device as follows:
To retrieve the network address information, we will use the
getifaddrs()
function. This function will store a reference to a linked list ofifaddrs
structures. Eachifaddrs
structure will represent a physical or virtual network interface. Thegetifaddrs()
function will return0
if it was successful, or-1
if there was a problem.The
getifaddrs(struct ifaddrs **ifad)
function is not a part of the POSIX standard, but it is a part of most BSD systems; therefore, it is on both OS X and iOS. Refer to the following code:struct ifaddrs *interfaces = NULL; int success = 0; success = getifaddrs(&interfaces);
Once we have the linked list of
ifaddrs
, we will need to loop through the list and retrieve the information about each network interface as shown in the following code:struct ifaddrs *temp_addr = interfaces; for (temp_addr = interfaces; temp_addr != NULL; temp_addr = temp_addr->ifa_next) { int ipversion; NSLog(@"************************"); if(temp_addr->ifa_addr->sa_family == AF_INET) { NSLog(@"IPv4"); ipversion = AF_INET; } else if(temp_addr->ifa_addr->sa_family == AF_INET6) { NSLog(@"IPv6"); ipversion = AF_INET6; } else { NSLog(@"Unknown IP version"); ipversion = 0; }
The
temp_addr ifaddrs
structure is a temporary structure that will be used as we loop through the linked list. We will need to keep a pointer pointing to the firstifaddrs
structure so we can properly release the structure using thefreeifaddrs()
function when we are done with it.We then create a
for
loop to loop through ourifaddrs
linked list.We check the IP address version being used by checking
sa_family
; if it is IPv4, we setipversion
toAF_INET
; if it is IPv6, we setipversion
toAF_INET6
. We will use this variable later in ourinet_ntop()
functions.If the IP address version is neither IPv4 nor IPv6, we set
ipversion
to0
.We need to define three character arrays to hold our network address, netmask, and gateway information for the network interfaces. In the following code snippet, three character arrays are defined:
char naddr[INET6_ADDRSTRLEN]; char nmask[INET6_ADDRSTRLEN]; char ngate[INET6_ADDRSTRLEN];
We set the size of the array to
INET6_ADDRSTRLEN
because it is larger thanINET_ADDRSTRLEN
, so it will hold either IPv4 or IPv6 addresses.INET6_ADDRSTRLEN
is defined as46
, andINET_ADDRSTRLEN
as16
.Now we need to show the result, for which we will use the following code:
NSLog(@"Name: %@",[NSString stringWithUTF8String:temp_addr->ifa_name]); inet_ntop(ipversion,&((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr,naddr,INET_ADDRSTRLEN); NSLog(@"Address: %@",[NSString stringWithUTF8String:naddr]); if ((struct sockaddr_in6 *)temp_addr->ifa_netmask != NULL) { inet_ntop(ipversion,&((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr,nmask,INET_ADDRSTRLEN); NSLog(@"Netmask: %@", [NSString stringWithUTF8String:nmask]); } if ((struct sockaddr_in6 *)temp_addr->ifa_dstaddr != NULL) { inet_ntop(ipversion,&((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr,ngate,INET_ADDRSTRLEN); NSLog(@"Gateway: ", [NSString stringWithUTF8String:ngate]); } } freeifaddrs(interfaces);
The
ifa_name
character array of theifaddr
structure contains the name of the interface; therefore, we convertifa_name
toNSString
and log it.We then use the
inet_ntop
function to populate thenaddr
,nmask
, andngate
character arrays, convert them toNSStrings
, and log them.The data returned from the
getifaddrs()
function is dynamically allocated and should be released using thefreeifaddrs()
function when it is no longer needed to avoid any memory leaks.
How it works…
The getifaddrs()
function will store a reference to a linked list of ifaddrs
structures. The ifaddrs
structure looks like the following:
struct ifaddrs { *ifa_next; /* Pointer to next struct */ char *ifa_name; /*Interface name */ u_int ifa_flags; /*Interface flags */ struct sockaddr *ifa_addr; /*Interface address */ struct sockaddr *ifa_netmask; /*Interface netmask */ struct sockaddr *ifa_dstaddr; /*P2P interface destination or Broadcast address */ void *ifa_data; /*Address specific data */ }
We use ifa_next
in our for
loop because it points to the next element in our linked list. If ifa_next
equals NULL
, we have reached the end of our linked list.
If you look closely, you will notice that the ifaddrs
structure contains three sockaddr
structures. The sockaddr
structure is a generic structure that pointers are cast to. The sockaddr
structure looks like the following code snippet:
struct sockaddr { uint8_t sa_len; sa_family_t sa_family; char sa_data[14]; }
Depending on the value of sa_family
, we can cast the sockaddr
structure as sockaddr_in
(for IPv4 addresses) or sockaddr_in6
(for IPv6 addresses) before retrieving the address information. We use sa_family
to determine the IP address version of the structure. The sa_family
values contain one of the following listed values:
AF_UNIX
: Local to host (pipes)AF_INET
: The IPv4 address familyAF_INET6
: The IPv6 address familyAF_NS
: Xerox NS protocolsAF_CCITT
: CCITT protocols, X.25AF_HYLINK
: NSC HyperchannelAF_ISO
: ISO protocols
We use ifa_name
of the ifaddrs
structure to determine the name of the interface.
We used the inet_ntop
function to convert the binary representation of the network address that is stored in the sockaddr
structure to a character array. If you look at the ntop
part of the function name, n
stands for network and p
stands for the presentation, so you can read the function name as the "inet network to presentation" function. There is a corresponding inet_pton
function that converts an ASCII string to binary, which you can think of as inet presentation to network.
The downloadable code contains projects for both the Mac OS X and iOS devices. Sample projects use a NetworkAddressStore
class to store the information returned by the getifaddrs()
functions. This will make it easier to integrate this recipe with your project.