I have been looking into this for a while after seeing conflicting answers to how SO_BINDTODEVICE is actually used. Some sources claim that the correct usage is to pass in a struct ifreq
pointer, which has the device name and index obtained via an ioctl. For example:
struct ifreq ifr;
memset(&ifr, 0, sizeof(struct ifreq));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth0");
ioctl(fd, SIOCGIFINDEX, &ifr);
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void*)&ifr, sizeof(struct ifreq));
Where as Beej’s networking tutorial says to pass the device name as a char pointer. For example:
char *devname = "eth0";
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, devname, strlen(devname));
I have tried both of these methods and they both do what is required, but I wanted to note that the device index obtained in the first method is superfluous. If you look at the kernel code in net/core/sock.c, sock_bindtodevice
just copies the device name string, calls dev_get_by_name_rcu
to get the device and binds to it.
The reason that the first approach works is that the device name is the first element in the ifreq
structure, see http://linux.die.net/man/7/netdevice.
NOTE: SO_BINDTODEVICE requires elevated permissions:
- run the executable with full root permission
- after building the executable you can use
sudo setcap
to grant the executable permission to use this specific socket option then you can run the executable without root permission and the executable has permission to use theSO_BINDTODEVICE
feature (via earlier call tosetcap
).