无法使用SO_BINDTODEVICE在两个NIC之间通过NAT执行TCP握手 [英] Can't perform TCP-handshake through a NAT between two NICs with SO_BINDTODEVICE
问题描述
我正在尝试将计算机连接到NAT的两面(由OpenWRT运行),并通过NAT建立TCP连接:
I'm trying to connect my computer to both sides of a NAT (run by OpenWRT) and to establish a TCP connection through the NAT:
- 我在第一个NIC(eth0,IP地址129.104.0.1)上运行DHCP服务器,并将其连接到路由器的WAN端口(IP地址129.104.0.198)
- 我将wifi(wlan0,IP地址192.168.1.119)连接到NAT后面的路由器的SSID
我正在使用python和SO_BINDTODEVICE选项通过NAT在服务器(在eth0上)和客户端(在wlan0上)之间发送数据包:
I'm using python and the SO_BINDTODEVICE option to send packet between a server (on eth0) and a client (on wlan0) through the NAT:
对于服务器:
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind((str(self.local_ip_addr),self.handler.port))
self.server.setsockopt(socket.SOL_SOCKET,25,self.iface.name+"\0")
self.server.listen(10)
while self.stopped() is False:
connect = self.server.accept()[0]
connect.settimeout(1)
connect.close()
self.server.close()
对于客户:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, 25, self.iface.name + "\0")
sock.settimeout(1)
try:
sock.connect((self.dest,self.handler.port))
sock.close()
expect socket.timeout, socket.error as e:
return -1
我的问题是连接之前超时.我对两个接口进行了布线,看来问题出在客户端方面:
My problem is that the connection times out before. I wiresharked both my interfaces and it seems the problem resides on the client's side:
- wlan0将TCP SYN数据包发送到129.104.0.1
- 该数据包已由路由器正确地NAT,并由eth0从129.104.0.198接收到
- eth0答复一个SYN,ACK数据包,该数据包已正确地NAT回到wlan0
- wlan0无法理解此SYN,ACK,并尝试重新传输第一个SYN数据包
我认为这可能与linux内核拒绝接收来自属于该机器的地址的数据包有关,但是如果有人有线索的话,那将很有帮助!
I'm thinking it might have something to do with the linux-kernel refusing to receive a packet from an address that belongs to the machine but if anyone has a clue it would be of great help!
我缩小了范围:这确实是一个内核问题,从eth0发送的数据包被内核视为火星人",因为它们具有本地ip地址作为源.设置net.ipv4.conf.all.accept_local=1
没有帮助,也没有停用net.ipv4.conf.all.rp_filter=0
.
I narrowed it down: it is indeed a kernel issue, the packets sent from eth0 are perceived as "martians" by the kernel because they have a local ip address as source. Setting net.ipv4.conf.all.accept_local=1
did not help, neither did deactivating net.ipv4.conf.all.rp_filter=0
.
推荐答案
浏览内核源代码并添加了许多KERNEL_WARNING之后,我们发现它来自哪里:linux内核是在某些主流发行版上配置的(Ubuntu ...)充当路由器并丢弃可疑源地址的数据包,以防止欺骗(在 https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt 和
After browsing the kernel sources and adding a lot of KERNEL_WARNING we found where it came from: the linux kernel is configured on certain mainstream distributions (Ubuntu...) to act as a router and drop packets where the source address is suspect in order to prevent spoofing (search "rp_filter" on https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt and RFC3704).
要允许此类流量,您必须在计算机上(以root用户身份)设置一些变量:
To allow such traffic you have to set some variables on your machine (as 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
,否则它将无法正常工作(内核默认为限制性最强的设置).
where your_nic
is the network interface receiving the packet. Beware to change both net.ipv4.conf.all.rp_filter
and net.ipv4.conf.your_nic.rp_filter
, it will not work otherwise (the kernel defaults to the most restrictive setting).
这篇关于无法使用SO_BINDTODEVICE在两个NIC之间通过NAT执行TCP握手的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!