TCP穿透技术

19

我正在使用mingw工具链和windows socket尝试实现TCP打洞。我认为过程是正确的,但洞似乎没有打通。我参考了这个

  1. AB 连接到服务器 S
  2. SA 发送 B 的路由器 IP + 它用于连接到S的端口
  3. SB 也做同样的事情
  4. A 开始了两个线程:
    • 一个线程尝试使用由 S 发送的信息连接到 B 的路由器
    • 另一个线程在连接到S时使用相同的端口等待传入连接
  5. B 做同样的事情

我认为代码没有问题,因为:

  • AB 都获得了对方的 IP 和要使用的端口
  • 当他们联系服务器时,他们都在监听连接到它们的路由器的端口
  • 他们都连接到正确的 IP 和端口,但会超时 (错误代码 10060)

我是否有遗漏的东西?

编辑:使用Process Explorer的帮助,我看到其中一个客户端设法与对等方建立了连接。但是,对等方似乎没有考虑到这个连接已经建立。

以下是我用 Wireshark 抓取的内容。为了举例说明,服务器 S 和客户端 A 在同一台PC上。服务器 S 监听一个特定端口(8060)并重定向到该PC。由于S发送的A的公共地址是localhost,因此B仍然尝试在正确的IP上连接,并因此使用S的公共IP。(我已经用占位符替换了公共IP)

wireshark

编辑2:我认为混淆的原因是传入和传出的连接请求数据都传输在同一端口上。这似乎搞乱了连接状态,因为我们不知道哪个套接字会从端口获取数据。如果我引用 MSDN:

SO_REUSEADDR 套接字选项允许套接字强制绑定到另一个套接字使用的端口。第二个套接字在在调用与原始套接字相同端口上的 bind之前,将 setsockopt 的 optname 参数设置为 SO_REUSEADDR,optval 参数设置为布尔值 TRUE一旦第二个套接字成功绑定,所有绑定到该端口的套接字的行为都是不确定的。

但在 TCP 穿洞技术中需要通过同一端口交流以“打开洞口”!


那么你对TCP打洞有什么解决方案?我对此很感兴趣。 - petersaints
你能解决这个问题并进行TCP打洞吗? - pkrish
@pkrish 我只成功启动了同时TCP打开(请参见所选答案的评论)。 - Giann
@Giann,你有没有任何能够说明你所做的工作的代码?我尝试用Python编写了一些代码,但我无法确定是我的代码不起作用还是我要穿过的防火墙不喜欢所需的SYN/SYN/ACK/ACK序列。 - George Hilliard
@thirtythreeforty 很抱歉,我无法分享任何东西(这不是开源代码)。 - Giann
1
@Giann 哎呀可惜。我写了一个,看起来运行得相当不错。 - George Hilliard
4个回答

16
启动两个线程:
一个线程尝试使用S发送的信息连接到B的路由器
另一个线程在与S连接时使用的相同端口上等待传入连接
这不能用两个线程来实现,因为它只是一个操作。每个正在进行出站连接的TCP连接也在等待入站连接。您只需调用“connect”,即可同时发送出站SYN以建立连接并等待传入SYN以建立连接。
但是,您可能需要关闭与服务器的连接。您的平台可能不允许您从已经建立连接的端口进行TCP连接。因此,在开始TCP打洞之前,请关闭与服务器的连接。将新的TCP套接字绑定到该端口,并调用connect

1
如果失败了,你可能(祈祷)可以立即重试并使其正常工作。但是你不能依赖于TCP打洞的工作。 - David Schwartz
你知道其他可靠的方法来在不同的NAT /路由器后建立点对点连接吗? - Giann
@Giann 然后使用TCP连接到您的UDP洞的端点。TCP <-> UDP <-> NAT <-> 互联网 <-> NAT <-> UDP <-> TCP - David Schwartz
我对TCP打洞这个话题还很陌生,目前不是很清楚“当你开始进行TCP打洞时,关闭与服务器的连接。将一个新的TCP套接字绑定到同一端口”。我是否必须将一个新的TCP套接字绑定到连接服务器的端口?未绑定的套接字会分配另一个NAT地址吗?所以我认为没有必要绑定用于连接服务器B的套接字。我是正确的还是有什么误解?谢谢。 - Summer_More_More_Tea
如果套接字获得另一个NAT地址,它将无法利用您打开的洞。 - David Schwartz
显示剩余2条评论

2

一种简单的方法是使用已经有端口映射算法的协议来穿越NAT路由器,例如FTP。


0
  1. 使用Wireshark检查TCP连接请求(3次握手过程)是否正常进行。

  2. 确保您的监听线程具有select()以对描述符进行多路复用。

  3. sockPeerConect(用于连接其他对等方的套接字)在监听线程中被FD_SET()。

  4. 确保您正在检查

     int Listener Thread()
     {
       while(true)
       {
           FD_SET(sockPeerConn);
           FD_SET(sockServerConn);
           FD_SET(nConnectedSock );
          if (FD_ISSET(sockPeerConect)
          {
            /// and calling accept() in side the
            nConnectedSock = accept( ....);
    
           }
           if (FD_ISSET(sockServerConn)
           {
            /// receive data from Server
            recv(sockServerConn );
    
           }
           if (FD_ISSET(nConnectedSock )
           {
            /// Receive data from Other Peer
             recv(nConnectedSock );
    
           }
    
       }
      }
    

5.确保同时启动对等连接A到B和B到A。
6.在连接到服务器和对等体之前启动您的监听器线程,并为接收服务器和客户端设置单个监听器线程。


我不明白为什么我必须使用集合来处理套接字。这会有什么改变吗? - Giann
它会通知我们该套接字上是否有可用内容。我们必须反复检查特定套接字上是否有可用内容。 - Vikram Ranabhatt
WSAETIMEDOUT……请确保您的NAT设置允许所有端口的出站TCP流量。 - Vikram Ranabhatt

-3

你能否为你的S、A和B以及路由器添加网络布局,我怀疑因为你将S和A放在同一台机器上,所以你的NAT路由器甚至没有在路由器中为B到达A做NAT转换,因为A没有通过路由器与S连接(它们在同一台机器上!)。为了进行适当的测试,你应该将你的S放置在与A或B不在同一局域网的位置。 - Allen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接