Get the index number of a Linux network interface in C using SIOCGIFINDEX
Content |
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:
- Create an
ifreq
structure for passing data in and out ofioctl
. - Provide an open socket descriptor.
- 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
- netdevice(7) (Linux manpage)
Tags: c