Friday, February 19, 2010

Howto get a list of network interfaces in Linux, part 2

Welcome back, networkers !

Now, we are able to loop over all network interfaces within a shell script. How about we do it in C ? Let's make a first attempt using syscalls, shall we ? The alert reader already guessed that like all major things, there will be three parts (talking about major things, Google suggests me that there are three little pigs, stooges, musketeers. But Rs beat them all with 3 billion hits, what an ignorant fool I was, to not even know about RRR).

So, whenever it comes to system and kernel stuff, system calls are your friends, and thus we naturally turn to ioctl and friends, in order to find out more about the network interfaces. A quick "man ioctl"  reveals that there is a manual page that knows them all ioctls. So, let's summon it right away by doing "man ioctl_list".  Now that you have it in front of your eyes in it's full glory, you will just trust me and use SIOCGIFCONF to know about network interfaces. Because that manual page was rather obscure, wasn't it ?

So basically that's how it works : you prepare an ifconf structure to issue the ioctl itself, and add within another pointer to a few ifreq structures that will hold the answer to your request. It's that simple. Got it ? Let's proceed to the source code then :
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/ioctl.h>#include <linux/if.h>intmain(int argc, char **argv){  int devices, n, i;  struct ifconf config;  struct ifreq ifreq[128];  int ret;  /* Initialize the structure to 0s */  memset(&config, 0, sizeof(struct ifconf));  /* Open a socket to issue the ioctl */  devices = socket(AF_INET, SOCK_STREAM, 0);  if (devices < 0)    {      perror("cannot open socket");      return 1;    }  /* fill-in the config request structure, including a buffer to hold the answer */  config.ifc_buf = (char *) ifreq;  config.ifc_len = 128 * sizeof(struct ifreq);  /* issue the system call */  ret = ioctl(devices, SIOCGIFCONF, (char *) &config);  if (ret < 0)    {      perror("ioctl failed\n");      close(devices);      return 2;    }  /* and parse the results, the length of the answer hints at the number of interfaces */  n = config.ifc_len / (sizeof(struct ifreq));  for (i = 0; i < n; i++)     {      printf("Interface : %s\n", ifreq[i].ifr_name);    }    close(devices);}

And now let's try it :
$ ./iflist Interface : loInterface : eth1

Assuming I ran it on the same hardware, there seems to be some inconsistency. Because there are missing interfaces, and these are the ones that had no traffic in the stats. Which leads us to believe that SIOCGIFCONF does not return information about non running interfaces.

By digging a little bit further, we will realise, doing "man netdevice", that SIOCGIFCONF belongs to IP layer and thus only returns information about up interfaces that have an IP address. So, let's discuss next week about another solution using netlink sockets. To be continued...

PS: of course you can use that code if you need, although it is not that great. Well it depends on what you need ;-)

No comments: