绑定 vs SO_BINDTODEVICE 套接字

12

我正在Linux(Ubuntu 13.10)上运行一个项目,该项目使用原始套接字连接到设备。

以下是我的代码:

/* 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;
}

但是我的计算机上有2个网卡,我希望只监听其中一个,比如eth0。我发现两个选项:bind和SO_BINDTODEVICE:

/* 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;
}

只有bind起作用。所以我的问题是这两者之间有什么区别?


1
你尝试过使用strlen(ifName)而不是IFNAMSIZ-1吗?只是猜测... - Per Johansson
1
@PerJohansson:那将是个糟糕的主意。手册中写道:“传递的选项是一个变长的,以 null 结尾的接口名称字符串,最大大小为 IFNAMSIZ”,但 strlen 不会计算空值。 - Ben Voigt
2个回答

15

来自Linux man页man 7 socket的SO_BINDTODEVICE套接字选项:

请注意,该选项仅适用于某些套接字类型,特别是AF_INET套接字。它不支持数据包套接字(在那里使用普通bind(2))。


1
这是工作版本。
{
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) {
        }
}

1
ifName.c_str()复制到if_bind.ifr_name中,使用strcpy()函数。如果不确定是否有足够的空间进行复制,请使用if (ifName.size() >= IFNAMESIZ)进行预防。使用strncpy函数只会导致截断设备名称并显示误导性信息。 - Ethouris
SO_BINDTODEVICE 需要一个字符串,而不是一个 ifreq 结构体。只需使用 ifName.c_str()ifName.length() 即可。 - Alexis Wilke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接