Rate this page

Flattr this

Get the index number of a Linux network interface in C using SIOCGIFINDEX

Tested on

Debian (Lenny, Squeeze)
Ubuntu (Lucid, Precise, Trusty)

Objective

To get the index number of a Linux network interface in C using the ioctl command SIOCGIFINDEX

Background

Network interfaces are usually identified by name in user-facing contexts, but for some APIs a number is used instead. A notable example is the sin6_scope_id field of an IPv6 socket address with link scope. Indices are also used in some types of netlink message (particularly those concerned with routing) and in socket addresses for AF_PACKET sockets.

The interface index is typically not the same as the suffix which may form part of the interface name. For example, on one of the machines tested by the author, eth0 had an index of 2. You should not assume that they will be the same on other machines, or that they will necessarily remain the same following a reboot.

Scenario

Suppose you wish to send a raw Ethernet frame using an AF_PACKET socket. To do this you need to know the index number of the network interface from which the frame is to be sent.

The variable if_name points to a null-terminated string containing the name of the interface.

Method

Overview

On Linux-based systems the index number of a network interface can be obtained using the ioctl command SIOCGIFINDEX. The method described here has five steps:

  1. Create an ifreq structure for passing data in and out of ioctl.
  2. Provide an open socket descriptor.
  3. Invoke ioctl.

The following header files will be needed:

#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <net/if.h>

Create an ifreq structure for passing data in and out of ioctl

The ifreq structure should initially contain the name of the interface to be queried, which should be copied into the ifr_name field. Since this is a fixed-length buffer you should take care to ensure that the name does not cause an overrun:

struct ifreq ifr;
size_t if_name_len=strlen(if_name);
if (if_name_len<sizeof(ifr.ifr_name)) {
    memcpy(ifr.ifr_name,if_name,if_name_len);
    ifr.ifr_name[if_name_len]=0;
} else {
    die("interface name is too long");
}

Provide an open socket descriptor

The socket descriptor is merely an artefact of the way in which ioctl commands are invoked generally, and is not used for any particular purpose by SIOCGIFINDEX. It must be open and must refer to a socket (as opposed to, for example, a regular file).

In many of the circumstances were you would use SIOCGIFINDEX there will already be an open socket that you can use. For example, in the particular scenario described above you could open the AF_PACKET socket first and use that. Otherwise, you will need to open one specifically for the purpose of being an argument to ioctl. Any type of socket would suffice, but it should preferably not be one that requires any obscure kernel modules to be loaded:

int fd=socket(AF_UNIX,SOCK_DGRAM,0);
if (fd==-1) {
    die("%s",strerror(errno));
}

Invoke ioctl

Once you have the ifreq structure and socket descriptor then you are ready to invoke ioctl:

if (ioctl(fd,SIOCGIFINDEX,&ifr)==-1) {
    die("%s",strerror(errno));
}

If this completes without error then the interface index should have been returned in ifr.ifr_ifindex.

Further reading

Tags: c