ADAM'S WEB PRESENCE

5 September 2006

Enumerating Network Interfaces on Linux

Filed under: Nerd Notes — adam @ 1:34 pm

Here is some C code which will list the network interfaces on your Linux box and also the IP and MAC address associated with each interface. I put it together because I couldn’t find an example on the net of exactly what I wanted to do - so now here it is.

/*
  Example code to obtain IP and MAC for all available interfaces on Linux.
  by Adam Pierce <adam@doctort.org>
  http://www.doctort.org/adam/
*/

#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>

int main(void)
{
	char          buf[1024];
	struct ifconf ifc;
	struct ifreq *ifr;
	int           sck;
	int           nInterfaces;
	int           i;

/* Get a socket handle. */
	sck = socket(AF_INET, SOCK_DGRAM, 0);
	if(sck < 0)
	{
		perror("socket");
		return 1;
	}

/* Query available interfaces. */
	ifc.ifc_len = sizeof(buf);
	ifc.ifc_buf = buf;
	if(ioctl(sck, SIOCGIFCONF, &ifc) < 0)
	{
		perror("ioctl(SIOCGIFCONF)");
		return 1;
	}

/* Iterate through the list of interfaces. */
	ifr         = ifc.ifc_req;
	nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
	for(i = 0; i < nInterfaces; i++)
	{
		struct ifreq *item = &ifr[i];

	/* Show the device name and IP address */
		printf("%s: IP %s",
		       item->ifr_name,
		       inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr));

	/* Get the MAC address */
		if(ioctl(sck, SIOCGIFHWADDR, item) < 0)
		{
			perror("ioctl(SIOCGIFHWADDR)");
			return 1;
		}

		printf(", MAC %s\\n", ether_ntoa((struct ether_addr *)item->ifr_hwaddr.sa_data));
	}

	return 0;
}

19 Comments »

  1. Comment by Salman Ahmed — 31 August 2007 @ 5:11 am

    A code snippet that actually does what it advertises and compiles and works in one attempt!
    Thanks - this is very useful.

    Cheers,

  2. Comment by Yiannis Tsiouris — 26 November 2007 @ 8:19 am

    My friend when i try to compile it i get a segmentation fault. Nothing else.. What do you think?

  3. Comment by adam — 26 November 2007 @ 10:01 am

    Here’s how I compile it:

    1. Cut & paste the code into a text file called ifenum.c
    2. gcc -o ifenum ifenum.c
    3. ./ifenum

    That works for me, I just tried it now. I am on Debian Linux with gcc version 4.1.2. What compiler and OS are you using ?

  4. Comment by Yiannis Tsiouris — 27 November 2007 @ 1:15 am

    I have Arch Linux and the compiler i use is gcc 4.2.2. And this is the output:

    [yiannis@main Programs]$ gcc -o interface interface.c
    [yiannis@main Programs]$ ./interface
    Segmentation fault

    A straight segmentation fault! (btw, a very ignoring error don’t u think? :P)
    Thank u for the quick answer! You have done an excellent work here! ;)

  5. Comment by adam — 27 November 2007 @ 8:16 am

    Can’t tell much from a segmentation fault. At least now I know it is failing when you run the utility. I kind of assumed from your last post that it was segfaulting during compilation. So here are some suggestions:

    1. Segfaults are usually caused by a bad pointer or a buffer overflow. There is only one buffer in this code, so try changing buf[1024] to a much larger number (eg. buf[16384]) and see if that helps.

    2. Compile the code with the debug option (gcc -g -o ifenum ifenum.c) and then step through it with a debugger such as kdbg. Then you can see what line is causing the problem.

  6. Comment by Gautam — 5 February 2008 @ 3:32 pm

    Thanks !!! it is very useful.

  7. Comment by Gautam Raut — 5 February 2008 @ 3:39 pm

    Can we fetch routing table from a router?
    If yes then how to do it using C. How would u detect router in a subnet?
    I have a code that detects router if that router has any virtual interface or a proxy ARP.
    My email id is gautam.raut.here@gmail.com

  8. Comment by adam — 5 February 2008 @ 7:43 pm

    Sorry Gautam, that’s not really my area of expertise. Try doing a little research into routing information protocols such as RIP and OSPF.

  9. Comment by marc — 1 March 2008 @ 9:58 am

    Thanks Adam! Worked right out of the box, unlike some of the other i tried.
    Be proud that your code is a part of our firmware. :)

  10. Comment by Michel Onoff — 31 March 2008 @ 6:39 pm

    This code shows only the *running* interfaces.

    To get infos about *all* interfaces, I know of no other way than to read the file /proc/net/dev which, unfortunately, is not quite parse-friendly.

  11. Comment by adam — 31 March 2008 @ 9:29 pm

    Yes it does only list the interfaces that are up.

    Unfortunately, I don’t think you can find every interface via the ioctl method so /proc/net/dev is probably your best bet for what you want.

    /proc/net/dev is not so hard to parse. Here’s some code which can do it - at least on Debian. I don’t know if the format of the file is different on other distros:

    /* listif.c - List all known interfaces on a Linux System */
    
    #include <stdio.h>
    #include <string.h>
    
    main()
    {
    	char line[512];
    	char *colon;
    	char *name;
    	FILE *fp;
    
    	if(0 == (fp = fopen("/proc/net/dev", "r")))
    		return 1;
    
    	while(0 != (name = fgets(line, 512, fp)))
    	{
    		while(isspace(name[0])) /* Trim leading whitespace */
    			name++;
    
    		colon = strchr (ame, ':');
    		if(colon)
    		{
    			*colon = 0;
    			printf("%s:\n", name);
    		}
    	}
    
    	fclose(fp);
    	return 0;
    }
    
  12. Comment by ccspro — 29 June 2008 @ 3:44 pm

    the above example has a typo:
    colon = strchr (ame, ‘:’);
    should be:
    colon = strchr (name, ‘:’);

    It will compile.

  13. Comment by adam — 29 June 2008 @ 9:43 pm

    Thanks for spotting that ccspro!

  14. Comment by Elessedil — 26 July 2008 @ 1:49 am

    Hello Adam,

    i tried your code but unfortunately only the loopback interface is found, though the other two are up.
    If you got an idea what could be the problem, please let me know.

    thank you

  15. Comment by Elessedil — 26 July 2008 @ 1:56 am

    just figured that out. if no ip is assigned the interfaces are not found.
    is there a possibility to get the list of interfaces even if they are not connected?

  16. Comment by adam — 26 July 2008 @ 10:08 pm

    Try the code mentioned in comment #11 above.

  17. Comment by Erb — 28 August 2008 @ 2:54 am

    to fix the seg fault, try #include

    also, that first printf should have a \n

  18. Comment by Erb — 28 August 2008 @ 2:55 am

    Hmm that comment got messed up. Should be
    #include <arpa/inet.h>

  19. Comment by Prameeth Sreesha — 5 November 2008 @ 4:42 pm

    In response to:
    ===========================================
    Comment by Yiannis Tsiouris — 27 November 2007 @ 1:15 am

    I have Arch Linux and the compiler i use is gcc 4.2.2. And this is the output:

    [yiannis@main Programs]$ gcc -o interface interface.c
    [yiannis@main Programs]$ ./interface
    Segmentation fault
    ============================================

    I came across the same problem too.. In my case, it was the query for the MAC Address field for a loopback device, that was the culprit. In the code, the lines below:

    printf(”%s: IP %s\n”,
    item->ifr_name,
    inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr));

    printf(”, MAC %s\\n”, ether_ntoa((struct ether_addr *)item->ifr_hwaddr.sa_data));

    were the culprits in causing the segfaults. Since loopback device does not have a MAC value associated, it might have led to ifr_hwaddr being NULL. So the access to the sa_data might have led to the Segfault. I still need to go through the 2 structures though.

    Commenting the above 2 printf’s and just printing item->ifr_name works fine.

    Regards,
    Prameeth

RSS feed for comments on this post. TrackBack URI

Leave a comment


Powered by WordPress