2017-05-16 83 views
2

自从我打孔打孔几天后,为了有一种可靠的行为,但我现在处于死路一条。TCP打孔(旁路监听插座)

UDP打孔的伟大工程只需先发送一个数据包到远端,并获得远程发送一个数据包的otherway,因为它会通过源NAT降落。它相当可靠从我尝试

但现在来TCP ...我不明白。

现在,我可以建立通过NAT的,但的连接只连接插座

A.connect(B) -> Crash agains't B's NAT, but open a hole in A's NAT. 
B.connect(A) -> Get in A's NAT hole, reach A's connecting socket. 

但现在,这sended连接的SYN数据包的两个插座连接。

你会认为我会做到这一点,通过2 NAT的连接,万岁。

但问题是,这不是一个正常的行为,并给予本文:http://www.brynosaurus.com/pub/net/p2pnat/,我应该可以有一个监听插座并联到连接插座。

所以我确实绑定了一个监听套接字,它可以接受入站连接。

但入站连接总是由一个倾听的连接插座,而不是陷入...

如:

#!/usr/bin/env python3 
from socket import * 
from threading import Thread 
Socket = socket 

# The used endpoints: 
LOCAL = '0.0.0.0', 7000 
REMOTE = 'remote', 7000 

# Create the listening socket, bind it and make it listen: 
Listening = Socket(AF_INET, SOCK_STREAM) 
Listening.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 
Listening.bind(LOCAL) 
Listening.listen(5) 

# Just start in another thread some kind of debug: 
# Print the addr of any connecting client: 
def handle(): 
    while not Listening._closed: 
     client, addr = Listening.accept() 
     print('ACCEPTED', addr) 
Thread(target=handle).start() 

# Now creating the connecting socket: 
Connecting = Socket(AF_INET, SOCK_STREAM) 
Connecting.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) 
Connecting.bind(LOCAL) 

# Now we can attempt a connection: 
try: 
    Connecting.connect(REMOTE) 
    print('CONNECTED', Connecting.getpeername()) 
except Exception as e: 
    print('TRIED', type(e), e) 

现在有了这个脚本,只是同意在端口上一个朋友或其他任何人,并执行它的一端,Connecting.connect(...)应运行一点点(等待超时,因为SYN数据包坠毁到远处的NAT,但幸运的是在他自己的NAT中打开了一个洞),同时执行脚本另一端,现在Connecting.connect(...)会返回因为它会连接。

最奇怪的部分是:Listening插座从未触发

为什么?如何让侦听套接字通过连接套接字捕获入站连接?

注意:关闭连接插座确实会在网络上发送一些立即关闭该孔的东西,至少它会在我的网络上发生。

2nd-Note:我在窗户上。

编辑:主要的问题是,在任何情况下,该脚本输出CONNECTED [...]而不是CLIENT [...],其中给出了一些讲座不应该发生。

+0

您是否试图在侦听端获取数据包捕获?你看到远程端的SYN请求吗? –

+0

是的,正如我所说,每个双方插座(远程/本地)做建立连接,但不是在'Listening'插座... – WKnight02

回答

1

于是,经过更多的测试和阅读,这里就是我来:

事实上,它是可能绑定侦听套接字和套接字在同一地址(ip,端口)上建立出站连接。

但插槽的行为在很大程度上取决于系统/ TCP协议栈的实现,在4.3节http://www.brynosaurus.com/pub/net/p2pnat/作为mentionned:在TCP打洞什么客户端应用程序与观察他们的插座发生

取决于所涉及的时间安排和TCP实施。假设一个的第一个外出的SYN包到的公共端点由NAT 下降,但的第一个后续SYN包到一个的公共端点获得通过,以一个之前A的TCP重新传输其SYN。根据所涉及的操作系统上,两件事情之一可能会发生:

,对于进入的SYN匹配的会话端点的出站会话的 一个试图发起
  • 一个的TCP实施公告。 A的TCP堆栈因此将此新会话与本地应用程序连接()到B的公共端点的套接字相关联。应用程序的异步connect()调用成功,并且应用程序的侦听套接字没有任何反应。
    由于所接收的SYN数据包不包括用于的ACK的早先出站SYN,的TCP回复的带有SYN-ACK分组公共端点,则SYN部分为仅一个重播A的原始出站SYN,使用相同的序列号。一旦B的TCP接收到A的SYN-ACK,它以其自己的ACK作出响应,并且TCP会话在两端都进入连接状态。

  • 另外,一个的TCP实现可能,而不是发现一个有一个活跃的监听套接字端口等待传入的连接尝试上。由于的SYN看起来像传入的连接尝试,一个的TCP创建与新的TCP会话关联的新流套接字和手这个新的socket通过应用程序的下一个接受()调用的应用程序在它的听筒上。 的TCP然后响应用SYN-ACK如上,和TCP连接建立进行照常为客户机/服务器式的连接。
    由于的现有的出站连接()尝试使用)的源和目的地端点的组合,现在是使用由其他插座,即只是返回到应用程序通过接受(一个,的异步连接()尝试必须在某个时候失败,通常会出现“正在使用中的地址”错误。尽管如此,该应用程序仍需要与B进行通信所需的工作对等流套接字,因此它忽略了此故障。

第一行为以上似乎是通常的基于BSD的操作系统,而第二行为Linux和Windows下显示更常见。

所以我实际上是在第一种情况。在我的Windows 10上。

这意味着为了为TCP打孔提供可靠的方法,我需要将侦听套接字同时作为连接套接字绑定,但后来我需要检测哪一个触发了(监听或连接)并将其传递给应用程序的流程。

+0

困扰我的唯一情况是我只看到两种行为中的一种,但我想我会保留这段内容,并将采取相应行动。 – WKnight02

1

为什么监听套接字不会被触发

我想答案是这里的某个地方。TCP连接是由四个元素的元组定义:

  • 本地地址
  • 本地端口
  • 远程地址
  • 远程端口

当你建立TCP连接您从这个多元组绑定到本地主机上的连接套接字。

当SYN经由NAT发送它创建绑定: - 本地地址/端口 - >公共地址/端口

当远程侧发送它的SYN到公共地址/端口这个地址被转换为本地地址/端口并交付给本地机器。在这台机器上,该连接与初始连接无法区分,并且已成功建立(使用SYN/ACK)。

这意味着在本地没有收到INITIAL SYN。

如何让监听套接字通过连接套接字来接收入站连接?

对于源NAT来说这是不可能的。要接受NAT后面新的连接,你需要的目的地NAT一些公共IP /端口映射到你的私有IP /端口

+0

再次感谢您对您的回答,它真是其乐融融单独不是在这个问题上:) 现在,如果我得到你的权利,你说,我不能接受连接,因为我的NAT还没有任何重定向? 因为它是我试图解决冲孔的问题。 现在,在此基础上,那么我可以运行给出的例子用'REMOTE =“localhost”的剧本,7000'它应该工作打算的呢? 没有更多的NAT,数据包在本地发送。 那么,它实际上是做同样的事情:连接套接字捕获连接,监听套接字不。 – WKnight02

+0

(顺便说一句,我首先绑定哪个套接字无关紧要,连接套接字总是优先于收听/接受套接字,叹息) – WKnight02

+0

(可能我没完全理解你) – WKnight02