2011年7月17日 星期日

getting both IPv4 and IPv6 addresses of all local network interfaces via "getifaddrs"

In the old days, we often use ioctl to get the IPv4 address  of our local interfaces via :
ioctl(socketfd, SIOCGIFCONF, (struct ifconf)&buffer);
if we are interested in the IPv6 local addresses, we can always check them out via "/proc", for example, this is what we might do:

[sauron@icomserver ~]$ cat /proc/net/if_inet6
fe8000000000000002d0c9fffebb030b      03 40 20 80       eth1
00000000000000000000000000000001 01 80 10 80       lo
  1. IPv6 address displayed in 32 hexadecimal chars without colons as separator
  2. Netlink device number (interface index) in hexadecimal (see “ip addr” , too)
  3. Prefix length in hexadecimal
  4. Scope value (see kernel source “ include/net/ipv6.h” and “net/ipv6/addrconf.c” for more)
  5. Interface flags (see “include/linux/rtnetlink.h” and “net/ipv6/addrconf.c” for more)
  6. Device name
Quite easy, right? But what should we do to get both IPv4 and IPv6 addresses via the same API?
if you are seeking for a IPv4 and IPv6 total solution, then "getifaddrs"  is the answer that satisfies all your needs.

reference:
man 3 getifaddrs, man  3 getaddrinfo, man 3 getnameinfo




#include <arpa/inet.h>
#include <sys/socket.h>

#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int

main(int argc, char *argv[])
{
   struct ifaddrs *ifaddr, *ifa;

   int family, s;
   char host[NI_MAXHOST];

   if (getifaddrs(&ifaddr) == -1) {
       perror("getifaddrs");

       exit(EXIT_FAILURE);
   }

/* Walk through linked list, maintaining head pointer so we
*               can free list later */

   for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {

       family = ifa->ifa_addr->sa_family;

/*   Display interface name and family (including symbolic
*               form of the latter for the common families) */

       printf("%s  address family: %d%s\n",

        ifa->ifa_name, family,
        (family == AF_PACKET) ? " (AF_PACKET)" :
        (family == AF_INET) ?   " (AF_INET)" :
        (family == AF_INET6) ?  " (AF_INET6)" : "");

       /* For an AF_INET* interface address, display the address */

       if (family == AF_INET || family == AF_INET6) {

    s = getnameinfo(ifa->ifa_addr,
     (family == AF_INET) ? sizeof(struct sockaddr_in) :

      sizeof(struct sockaddr_in6),
     host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);

    if (s != 0) {
        printf("getnameinfo() failed: %s\n", gai_strerror(s));

        exit(EXIT_FAILURE);
    }
    printf("\taddress: <%s>\n", host);
       }
   }

   freeifaddrs(ifaddr);
   exit(EXIT_SUCCESS);
}

沒有留言: