Enumerating Network Interfaces on Linux

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>



#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>
#include <arpa/inet.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)
		return 1;

/* Query available interfaces. */
	ifc.ifc_len = sizeof(buf);
	ifc.ifc_buf = buf;
	if(ioctl(sck, SIOCGIFCONF, &ifc) < 0)
		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",
		       inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr));

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

	/* Get the broadcast address (added by Eric) */
		if(ioctl(sck, SIOCGIFBRDADDR, item) >= 0)
			printf(", BROADCAST %s", inet_ntoa(((struct sockaddr_in *)&item->ifr_broadaddr)->sin_addr));

        return 0;

UPDATE: Adam Risi has been kind enough to publish an updated version to handle IPv6 on his website.

UPDATE: Eric supplied some extra code to also list the broadcast address for each interface

29 thoughts on “Enumerating Network Interfaces on Linux

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


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

  3. 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. 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. 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. 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

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

  8. 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. :)

  9. 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.

  10. 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>
    	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 */
    		colon = strchr (ame, ':');
    			*colon = 0;
    			printf("%s:\n", name);
    	return 0;
  11. the above example has a typo:
    colon = strchr (ame, ‘:’);
    should be:
    colon = strchr (name, ‘:’);

    It will compile.

  12. 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

  13. 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?

  14. 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”,
    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.


  15. Hi all,
    I have written a fix for this code to allow it to use IPv6 interfaces, and to eliminate the segfault bug some users were experiencing. The new source can be found at my website.

    Adam Risi

  16. Hi,

    Is there a quick way, with these or similar methods to obtain the subnet mask of these interfaces ?


  17. Hi,
    Great sample, thanks! Thought some of you might be interested in how to get broadcast address:
    if (ioctl(sock, SIOCGIFBRDADDR, &ifr[nInterface]) >= 0) // rectify with ‘item’ as above, as this chunk of code comes from my application
    strcpy(szBroadcast, inet_ntoa(((struct sockaddr_in *)&ifr[nInterface].ifr_broadaddr)->sin_addr));
    So, to reply the previous question: to get the subnet mask, I guess you’d use the same ioctl call, passing SIOCGIFNETMASK as 2nd argument.
    One note: some data returned by ioctl in the buffer (3rd argument) are part of a union, so one ioctl call might overwrite data of a previous call. So, make sure you retrieve the data you need, straight after each ioctl call

  18. Thanks Eric, it just so happens I was thinking about broadcast addresses today. I’ve added your code to the example in the article.

  19. Very cool :)

    Is there a possibility to combine comment #11 and your code so that we can get all interfaces and their associated addresses if they exist?

  20. Hi Eric,

    Great example!

    To get your program to print the MAC address, add the following after the if(ioctl(sck, SIOCGIFHWADDR, item) ifr_hwaddr.sa_data)[0],
    (int)((unsigned char *)item->ifr_hwaddr.sa_data)[1],
    (int)((unsigned char *)item->ifr_hwaddr.sa_data)[2],
    (int)((unsigned char *)item->ifr_hwaddr.sa_data)[3],
    (int)((unsigned char *)item->ifr_hwaddr.sa_data)[4],
    (int)((unsigned char *)item->ifr_hwaddr.sa_data)[5]);

  21. Looks like there were characters your blog doesn’t like in my last comment:

    After the if(ioctl(sck, SIOCGIFHWADDR, item) < 0) { … } block

    printf(“, MAC %02x:%02x:%02x:%02x:%02x:%02x”,
    (int)((unsigned char *)item->ifr_hwaddr.sa_data)[0],
    (int)((unsigned char *)item->ifr_hwaddr.sa_data)[1],
    (int)((unsigned char *)item->ifr_hwaddr.sa_data)[2],
    (int)((unsigned char *)item->ifr_hwaddr.sa_data)[3],
    (int)((unsigned char *)item->ifr_hwaddr.sa_data)[4],
    (int)((unsigned char *)item->ifr_hwaddr.sa_data)[5]);

  22. Hello
    Thank you for giving this example, it may be useful to be.
    Thank you people for improvements.

    If I may, I’d like to give another way to get such kind of info: beside “ifconfig -a” , “/proc/net/dev” and ioctl, there are NETLINK sockets.
    I don’t know how different it is from ioctl, but it seems interesting, many information can be gathered using that kind of IPC, and it seems to work either on request/response or async “events”/msg schemes.
    A overview can be found here : http://www.linuxjournal.com/article/7356.
    Some example at the end of the man page : http://linux.die.net/man/7/netlink

  23. Hello,

    Just a quick thread bump as I encountered this site while trying to do similar thing. The glibc function getifaddrs() seems to be the ideal solution to use. It’s not POSIX but it originated from BSD and seems to be implemented on Linux, hence reasonably cross-platform. Good luck!

  24. Hi,
    Is it possible to get additional info like name, description and vendor of an ethernet adapter?


Comments are closed.