how to bind raw socket to specific interface
const char *opt;opt = "eth0";const len = strnlen(opt, IFNAMSIZ);if (len == IFNAMSIZ) { fprintf(stderr, "Too long iface name"); return 1;}setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, opt, len);
First line: set up your variable
Second line: tell the program which interface to bind to
Lines 3-5: get length of interface name and check if it's size not too big.
Six line: set the socket options for socket sd
, binding to the device opt
.
setsockopt prototype:
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
Also, make sure you include the if.h
, socket.h
and string.h
header files
As mentioned earlier, the correct thing to do is use the struct ifreq
to specify the interface name. Here is my code sample.
#define SERVERPORT 5555...struct ifreq ifr;/* Create the socket */sd = socket(AF_INET, SOCK_STREAM, 0);if (sd < 0) { printf("Error in socket() creation - %s", strerror(errno));}/* Bind to eth1 interface only - this is a private VLAN */memset(&ifr, 0, sizeof(ifr));snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth1");if ((rc = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr))) < 0){ perror("Server-setsockopt() error for SO_BINDTODEVICE"); printf("%s\n", strerror(errno)); close(sd); exit(-1);}/* bind to an address */memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(SERVERPORT);serveraddr.sin_addr.s_addr = inet_addr("9.1.2.3");int rc = bind(sd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
I would also like to add that from a security perspective, while it is good to bind the socket to an interface, it does not make sense to use INADDR_ANY
as the listening IP address. Doing so would make the port appear open in netstat on all network interfaces.
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program nametcp 0 0 0.0.0.0:5555 0.0.0.0:* LISTEN 0 210898 26996/myserver
Instead, I specified an IP address specific to the interface being used (a private VLAN). This fixed the netstat output too:
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program nametcp 0 0 9.1.2.3:5555 0.0.0.0:* LISTEN 0 210898 26996/myserver
Bind socket to specific interface IP address
int bind_using_iface_ip(int fd, char *ipaddr, uint16_t port){ struct sockaddr_in localaddr = {0}; localaddr.sin_family = AF_INET; localaddr.sin_port = htons(port); localaddr.sin_addr.s_addr = inet_addr(ipaddr); return bind(fd, (struct sockaddr*) &localaddr, sizeof(struct sockaddr_in));}
Bind socket to specific interface name
int bind_using_iface_name(int fd, char *iface_name){ return setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface_name, strlen(iface_name))}
In bind_using_iface_ip
, to bind to any port 0
should be passed. And also if the fd
is raw socket then need to pass port as 0
. This bind mechanism is common for all kind of sockets like raw, dgram and stream.