繁体   English   中英

使用SO_BINDTODEVICE的接口上没有流量绑定

[英]No traffic bind on interface using SO_BINDTODEVICE

我正在尝试使用SO_BINDTODEVICE将套接字绑定到eth0。 我正在将eth0传递给变量opt 我的套接字名称是socketfd

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0) {
        perror("socket(): error ");
        return 0;
    }
    struct ifreq ifr;

    memset(&ifr, 0, sizeof(struct ifreq));
    fprintf(stderr,ifr.ifr_name, sizeof(ifr.ifr_name), opt);
    ioctl(sockfd, SIOCGIFINDEX, &ifr);
    setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, opt, strlen(opt));
    fprintf(stderr, "The bind is done on interface %s \n", opt);
    fprintf(stderr, "opt length is %zu \n", strlen(opt));

为了进行一些调试,我将opt和strlen(opt)的值重定向到日志文件,它们正确获取了值。

猫/home/cayman/log.txt
绑定在接口eth0上完成
选择长度为4

我还通过捕获eth0上的数据包来进行验证,但看不到通过eth0的流量。 所看到的是其他与网络相关的流量,如下所示:

tshark -i eth0
  1   0.000000 Cisco_51:fd:09 -> Spanning-tree-(for-bridges)_00 STP 62 Conf. Root = 32768/78/00:24:50:51:fd:00  Cost = 0  Port = 0x8009
  2   0.326720 192.168.78.1 -> 224.0.0.13   PIMv2 70 Hello
  3   1.030538 Cisco_51:fd:09 -> Cisco_51:fd:09 LOOP 62 Reply
  4   2.004544 Cisco_51:fd:09 -> Spanning-tree-(for-bridges)_00 STP 62 Conf. Root = 32768/78/00:24:50:51:fd:00  Cost = 0  Port = 0x8009
  5   3.254223 192.168.78.1 -> 224.0.0.10   EIGRP 76 Hello
  6   4.010168 Cisco_51:fd:09 -> Spanning-tree-(for-bridges)_00 STP 62 Conf. Root = 32768/78/00:24:50:51:fd:00  Cost = 0  Port = 0x8009
  7   6.014839 Cisco_51:fd:09 -> Spanning-tree-(for-bridges)_00 STP 62 Conf. Root = 32768/78/00:24:50:51:fd:00  Cost = 0  Port = 0x8009
  8   7.896252 192.168.78.1 -> 224.0.0.10   EIGRP 76 Hello
  9   8.023003 Cisco_51:fd:09 -> Spanning-tree-(for-bridges)_00 STP 62 Conf. Root = 32768/78/00:24:50:51:fd:00  Cost = 0  Port = 0x8009

我还查看了该线程,并确保以超级用户身份运行代码。 我也查看了SO_BINDTODEVICE的手册页 ,但不确定可能缺少什么。 有什么建议吗?

您无需检查大部分正在拨打的电话的返回码。 它们中的一个或多个可能以显示其他信息的方式失败。 您应该(总是)检查返回值是否有错误。

编辑:我添加了错误处理到您的代码:

#include <sys/socket.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>

int main() {
  const char* opt = "wlp4s0";
  int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  if(sockfd < 0) {
    perror("socket(): error ");
    return 1;
  }
  struct ifreq ifr;

  memset(&ifr, 0, sizeof(struct ifreq));
  fprintf(stderr,ifr.ifr_name, sizeof(ifr.ifr_name), opt);
  if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) {
    perror("ioctl(): error ");
    return 2;
  }
  if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, opt, strlen(opt)) > 0) {
    perror("setsockopt(): error ");
    return 3;
  }
  fprintf(stderr, "The bind is done on interface %s \n", opt);
  fprintf(stderr, "opt length is %zu \n", strlen(opt));
}

并发现ioctl()失败了。 然后,我注意到您没有初始化ifr.ifr_name 如果将opt复制到ifr.ifr_name ,您的问题会消失吗?

您的第一个fprintf()语句是错误的。 您没有将opt值正确输出到stderr ,并且也没有在调用SIOCGIFINDEX之前将opt复制到ifr.ifr_name中。

尝试类似这样的方法:

if (strlen(opt) >= sizeof(ifr.ifr_name)) {
    fprintf(stderr, "%s", "interface name is too long \n");
    return 0;
}

...

struct ifreq ifr;
memset(&ifr, 0, sizeof(struct ifreq));
strncpy(ifr.ifr_name, opt, sizeof(ifr.ifr_name));

if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) {
    perror("ioctl(): error ");
    close(sockfd);
    return 0;
}

请参阅使用SIOCGIFINDEX获取C中Linux网络接口的索引号

话虽如此,如果您要绑定到接口名称,则SIOCGIFINDEX在调用SO_BINDTODEVICE之前使用SIOCGIFINDEX 只需自己调用SO_BINDTODEVICE

sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
    perror("socket(): error ");
    return 0;
}

if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, opt, strlen(opt)) < 0) {
    perror("setsockopt(): error ");
    close(sockfd);
    return 0;
}

在这种情况下,使用SIOCGIFINDEX没有意义。 有意义的是,如果您使用SIOCGIFADDR来检索接口的IP地址(请参阅使用SIOCGIFADDR在C中获取网络接口的IP地址 ),然后将该IP传递给bind()而不是将接口名称传递给SO_BINDTODEVICE

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM