如何使TCP套接字使用SO_BINDTODEVICE(针对路由表)

时间:2012-09-26 13:40:45

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

问题背景:

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

问题:

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

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连接?

谢谢!

3 个答案:

答案 0 :(得分:1)

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

启用

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

对于禁用,您只需要将flag设置为false,其余代码都是相同的:

  

ifr.ifr_flags = true;

答案 1 :(得分:0)

不要使用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,然后调用listen而不是connect。

答案 2 :(得分:0)

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

我在this answer to another similar question中找到了解决此问题的方法:

  

要允许此类流量,您必须在您的计算机上设置一些变量(以root身份):

your_nic
     

其中net.ipv4.conf.all.rp_filter是接收数据包的网络接口。请注意同时更改net.ipv4.conf.your_nic.rp_filterplot(c(1:3)),否则它将无效(内核默认为限制性最强的设置)。