无法使用SO_BINDTODEVICE通过两个NIC之间的NAT执行TCP握手

时间:2014-06-03 09:09:22

标签: python linux tcp network-programming nat

我尝试将计算机连接到NAT的两端(由OpenWRT运行)并通过NAT建立TCP连接:

  • 我在第一个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上)之间发送数据包:

对于服务器:

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

我的问题是连接超时了。我将两个接口都连接起来,似乎问题出在客户端:

  1. wlan0发送TCP SYN数据包到129.104.0.1
  2. 路由器正确NAT数据包,并由eth0
  3. 从129.104.0.198接收
  4. eth0使用SYN,ACK数据包回复,该数据包已正确NAT回到wlan0
  5. wlan0不理解此SYN,ACK并尝试重新传输第一个SYN数据包
  6. 我认为它可能与linux-kernel有关,拒绝从属于该机器的地址接收数据包但如果有人有线索那将会有很大的帮助!

    编辑:我缩小了它:它确实是一个内核问题,从eth0发送的数据包被视为" martians"由内核,因为他们有一个本地IP地址作为源。设置net.ipv4.conf.all.accept_local=1没有帮助,也没有停用net.ipv4.conf.all.rp_filter=0

1 个答案:

答案 0 :(得分:1)

在浏览内核源代码并添加大量KERNEL_WARNING后,我们发现它来自哪里:linux内核在某些主流发行版(Ubuntu ...)上配置充当路由器并丢弃源地址可疑的数据包为了防止欺骗(在https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txtRFC3704上搜索" rp_filter")

要允许此类流量,您必须在您的计算机上设置一些变量(以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,否则它将无效(内核默认为限制性最强的设置)。