12

I'm running a project on linux (ubuntu 13.10) which uses raw socket connecting to a device.

Here is my code:

/* builed socket */
if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
  perror("listener: socket");
  return -1;
}

/* Set interface to promiscuous mode */
strncpy(ifopts.ifr_name, ifName, IFNAMSIZ-1);
ioctl(sockfd, SIOCGIFFLAGS, &ifopts);
ifopts.ifr_flags |= IFF_PROMISC;
ioctl(sockfd, SIOCSIFFLAGS, &ifopts);

/* Allow the socket to be reused - incase connection is closed prematurely */
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
  perror("setsockopt");
  close(sockfd);
  return -2;
}

However I have 2 NIC cards on my computer and I would like to listen only to one of them. lets say etho. I found two options bind and SO_BINDTODEVICE as follows:

/* option 1. Bind to device */
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ-1) == -1)  {
  perror("SO_BINDTODEVICE");
  close(sockfd);
  return -4;
}


/* option 2. Bind to device */
memset(&sock_address, 0, sizeof(sock_address));
sock_address.sll_family = PF_PACKET;
sock_address.sll_protocol = htons(ETH_P_ALL);
sock_address.sll_ifindex = if_nametoindex(ifName);
if (bind(sockfd, (struct sockaddr*) &sock_address, sizeof(sock_address)) < 0) {
  perror("bind failed\n");
  close(sockfd);
  return -4;
}

Only bind works. So my question is what is the difference between the two ?

Ami DATA
  • 521
  • 2
  • 9
  • 14
  • 1
    Have you tried `strlen(ifName)` instead of `IFNAMSIZ-1` ? Just a guess... – Per Johansson Nov 27 '13 at 11:50
  • 1
    @PerJohansson: That would be a bad idea. The man page says " The passed option is a variable-length **null-terminated** interface name string with the maximum size of `IFNAMSIZ`", but `strlen` won't could the null. – Ben Voigt Aug 01 '14 at 01:38

2 Answers2

15

From the Linux man-page man 7 socket for socket option SO_BINDTODEVICE:

Note that this works only for some socket types, particularly AF_INET sockets. It is not supported for packet sockets (use normal bind(2) there).

thuovila
  • 1,960
  • 13
  • 21
1

here is the work version.

{
struct ifreq if_bind;
strncpy(if_bind.ifr_name, ifName.c_str(), IFNAMSIZ);

if(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&if_bind,  sizeof(if_bind)) < 0) {
        }
}
snake_xy
  • 41
  • 2
  • 1
    `strcpy(if_bind.ifr_name, ifName.c_str())`. If you are unsure if there's enough space to copy, prevent it by `if (ifName.size() >= IFNAMESIZ)`. The use of `strncpy` will simply lead to looking for a cut-off device name and fail with a misleading message. – Ethouris Mar 24 '20 at 10:42
  • `SO_BINDTODEVICE` expects a string, not an `ifreq` structure. Just use `ifName.c_str()` and `ifName.length()`. – Alexis Wilke Mar 19 '22 at 19:09