3

Background of the question:

On our machine we have multiple network interfaces which lead to different networks. There are possible overlapping IP addresses (e.g. two different machines in two different networks with the same IP address). So when we want to connect with specific peer then we need to specify not only it's IP address but also our network interface which lead to the proper network. We want to write application in C/C++ able to connect with specific peers via TCP.

Question:

I'm trying to make a TCP connection using socket with SO_BINDTODEVICE set. Here is a simplified snippet:

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));

(I know about struct ifreq, but it seems that only the first field in it (ifr_name field is in use). So I can pass only name of the interface.)

  • If forced interface is the same as interface according to the routing table, then everything works correctly.
  • If forced interface is different, then (tested with Wireshark):
    1. SYN is sent from forced interface to desired peer.
    2. SYN,ACK from desired peer is received on forced interface.
    3. ACK is not sent from forced interface and connection is not established. (And goto step 2.)

How to check where SYN,ACK or ACK is rejected by our system? And how correctly force TCP socket to make connection using specific interface (against routing table)?

Maybe there are some other, more convenient ways to create TCP connection on desired interface?

Thanks!

4

3 回答 3

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 = 真;

于 2013-04-11T08:05:16.043 回答
0

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

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

IE,

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));

然后调用连接。

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

于 2012-10-01T19:50:18.780 回答
0

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

我在另一个类似问题的答案中找到了解决这个问题的方法:

要允许这样的流量,你必须在你的机器上设置一些变量(作为 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_filternet.ipv4.conf.your_nic.rp_filter,否则它将不起作用(内核默认为最严格的设置)。

于 2017-01-17T14:31:45.070 回答