【问题标题】:How to make a TCP socket work with SO_BINDTODEVICE (against routing table)如何使 TCP 套接字与 SO_BINDTODEVICE 一起工作(针对路由表)
【发布时间】:2012-09-18 03:49:57
【问题描述】:

问题背景:

在我们的机器上,我们有多个网络接口,它们通向不同的网络。可能存在重叠的 IP 地址(例如,两个不同网络中的两台不同机器具有相同的 IP 地址)。因此,当我们想与特定的对等方连接时,我们不仅需要指定它的 IP 地址,还需要指定我们的网络接口,它可以连接到正确的网络。 我们想用 C/C++ 编写能够通过 TCP 与特定对等点连接的应用程序。

问题:

我正在尝试使用设置了 SO_BINDTODEVICE 的套接字建立 TCP 连接。这是一个简化的 sn-p:

sockfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, interface_name,
    strlen(interface_name));
connect(sockfd, (sockaddr *) &serv_addr, sizeof(serv_addr));

(我知道struct ifreq,但似乎只有第一个字段(ifr_name字段正在使用)。所以我只能传递接口的名称。)

  • 如果强制接口与路由表中的接口相同,则一切正常。
  • 如果强制接口不同,则(使用 Wireshark 测试):
    1. SYN 从强制接口发送到所需的对等体。
    2. 在强制接口上收到来自所需对等方的 SYN、ACK。
    3. 未从强制接口发送 ACK 且未建立连接。 (然后转到第 2 步。)

如何检查我们的系统在哪里拒绝 SYN、ACK 或 ACK?以及如何正确强制 TCP 套接字使用特定接口(针对路由表)建立连接?

也许还有其他更方便的方法可以在所需接口上创建 TCP 连接?

谢谢!

【问题讨论】:

    标签: c++ c sockets tcp network-programming


    【解决方案1】:

    我知道这不是您的答案,但是您可以禁用其他接口并仅启用您想要的网络,在您的情况下,您似乎需要所有接口,但我认为这种方法可以帮助其他人。您可以使用以下方式启用/禁用网络接口:

    启用

    ifr.ifr_flags = true; 
    strcpy(ifr.ifr_name, "eth0"); //you could put any interface name beside "eth0" 
    res = ioctl(sockfd, SIOCSIFFLAGS, &ifr);
    

    对于禁用,您只需将标志设置为 false,其余代码相同:

    ifr.ifr_flags = true;

    【讨论】:

      【解决方案2】:

      不要使用 SO_BINDTODEVICE。它并非在所有平台上都受支持,并且有一种更简单的方法。

      而是将套接字绑定到您要用于连接到远程端的正确网络上的本地 IP 地址。

      即,

      sockfd = socket(AF_INET, SOCK_STREAM, 0);
      
      struct sockaddr_in sin;
      memset(&sin, 0, sizeof(sin));
      sin.sin_family = AF_INET;
      sin.sin_port = 0; //Auto-determine port.
      sin.sin_addr.s_addr = inet_addr("192.168.1.123"); //Your IP address on same network as peer you want to connect to
      
      bind(sockfd, (sockaddr*)&sin, sizeof(sin));
      

      然后调用connect。

      对于服务器端,除了指定一个端口而不是 0 之外,你会做同样的事情,然后调用监听而不是连接。

      【讨论】:

      • 谢谢。这将是一个很好的解决方案,但我忘了提到我们的机器在每个网络中都有相同的地址。对不起。
      • 我什至讨厌这样说,因为我讨厌人们质疑您的问题而不是回答它,但是为什么您在多个网络上拥有相同的 IP?这听起来像是一个令人困惑的调试噩梦。
      • 抱歉耽搁了。由于可扩展性,我们希望拥有许多相同的网络。有很多接口的机器就是调度器。
      • 在 Windows 上 bind() 只影响传入的数据包。
      • @JorgeFuentesGonzález,实际上这是不正确的。根据 MSDN,“如果应用程序想要在具有多个网络接口和本地 IP 地址的本地计算机上选择特定的本地 IP 地址,请在发送前使用绑定 [...]。” msdn.microsoft.com/en-us/library/windows/desktop/…
      【解决方案3】:

      这是内核配置的一个问题 - 在许多发行版上,默认情况下它被配置为在这种特定情况下拒绝传入的数据包。

      我在this answer to another similar question找到了这个问题的解决方案:

      要允许这样的流量,你必须在你的机器上设置一些变量(作为 root):

      sysctl -w net.ipv4.conf.all.accept_local=1
      sysctl -w net.ipv4.conf.all.rp_filter=0
      sysctl -w net.ipv4.conf.your_nic.rp_filter=0
      

      其中your_nic 是接收数据包的网络接口。注意同时更改net.ipv4.conf.all.rp_filter 和net.ipv4.conf.your_nic.rp_filter,否则将无法正常工作(内核默认为最严格的设置)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-13
        • 2013-11-05
        • 2021-10-01
        • 2020-07-10
        • 2014-01-11
        • 1970-01-01
        相关资源
        最近更新 更多