无法使用SO_BINDTODEVICE在两个NIC之间通过NAT执行TCP握手 [英] Can't perform TCP-handshake through a NAT between two NICs with SO_BINDTODEVICE

查看:256
本文介绍了无法使用SO_BINDTODEVICE在两个NIC之间通过NAT执行TCP握手的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将计算机连接到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:

  1. wlan0将TCP SYN数据包发送到129.104.0.1
  2. 该数据包已由路由器正确地NAT,并由eth0从129.104.0.198接收到
  3. eth0答复一个SYN,ACK数据包,该数据包已正确地NAT回到wlan0
  4. 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 ...)充当路由器并丢弃可疑源地址的数据包,以防止欺骗(在

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_filternet.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆