【问题标题】:TCP Hole PunchingTCP 打孔
【发布时间】:2012-02-07 19:11:50
【问题描述】:

我正在尝试使用 mingw 工具链通过 Windows 套接字实现 TCP 打孔。我认为这个过程是正确的,但 hole 似乎没有采取。我使用this 作为参考。

  1. AB 连接到服务器 S
  2. S 发送到 AB 的路由器 IP + 它用来连接 S 的端口
  3. SB 执行相同的操作
  4. A 启动 2 个线程:
    • 一个线程尝试使用 S 发送的信息连接到 B 的路由器
    • 另一个线程在连接到 S 时,正在等待连接到其路由器的同一端口上的传入连接
  5. B 也是如此

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

  • AB 确实可以让对方使用 ip 和端口
  • 他们在联系服务器时都在监听用于连接路由器的端口
  • 它们都连接到正确的 ip 和端口,但超时(代码错误 10060

我错过了什么?

编辑:在流程浏览器的帮助下,我看到其中一个客户端设法建立了与对等方的连接。但是对端似乎没有考虑要建立的连接。

这是我使用 Wireshark 捕获的内容。举例来说,服务器 S 和客户端 A 在同一台 PC 上。服务器 S 侦听重定向到该 PC 的特定端口 (8060)。 B 仍然尝试连接正确的 IP,因为它看到 S 发送的 A 的公共地址是 localhost,因此使用S 的公共 IP。 (我已经用占位符替换了公共 IP)

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

SO_REUSEADDR 套接字选项允许套接字强制绑定到 另一个套接字正在使用的端口。第二个套接字调用 setsockopt 与 optname 参数设置为SO_REUSEADDR 和 optval 参数设置 到布尔值TRUE,然后在与 原装插座。 一旦第二个套接字成功绑定, 绑定到该端口的所有套接字的行为是不确定的。

但是 TCP 打孔技术需要在同一个端口上进行通信才能打开漏洞

【问题讨论】:

  • 那么您的 TCP 打孔解决方案是什么?我对此很感兴趣。
  • 你能解决这个问题并进行 TCP 打孔吗?
  • @pkrish 我只设法启动了同时 TCP 打开(请参阅所选答案的评论)
  • @Ginn 你有任何代码来说明你的工作吗?我试过用 Python 写一些,但我不知道是我的代码不起作用还是我试图通过的防火墙不喜欢所需的 SYN/SYN/ACK/ACK 序列。
  • @Ginn 啊,真丢人。我wrote one,它似乎工作得很好。

标签: windows tcp network-protocols winsock2 hole-punching


【解决方案1】:

一开始 2 个线程:
一个线程尝试使用 S 发送的信息连接到 B 的路由器
另一个线程在连接到 S 时正在等待用于连接到其路由器的同一端口上的传入连接

你不能用两个线程来做这件事,因为它只是一个操作。每个建立出站连接的 TCP 连接也在等待传入连接。您只需调用“连接”,就可以同时发送出站 SYN 以建立连接并等待入站 SYN 建立连接。

但是,您可能需要关闭与服务器的连接。当您已经从同一端口建立连接时,您的平台可能不允许您从该端口建立 TCP 连接。因此,正如您开始 TCP 打孔一样,关闭与服务器的连接。将新的 TCP 套接字绑定到同一端口,然后调用 connect

【讨论】:

  • 这行得通,但前提是SYN 在它们都通过各自的 NAT/路由器之前都没有到达任何对等点。所以有一点时间问题。那是同时 TCP 打开。但是bford.info/pub/net/p2pnat/index.html 谈到了一个连接请求失败时的同时侦听套接字。我从来没有见过这样的作品。
  • 如果失败,您可能(交叉手指)能够立即重试并且仍然可以工作。但是你不能依赖 TCP 打孔工作。
  • 你知道另一种在不同 NAT/路由器后面建立对等连接的可靠方法吗?
  • 不幸的是 TCP 对我来说是必需的。
  • @Giann 然后使用 TCP 连接到您的 UDP 漏洞的端点。TCP <-> UDP <-> NAT <-> Internet <-> NAT <-> UDP <-> TCP
【解决方案2】:

遍历 NAT 路由器的一个简单解决方案是让您的流量遵循您的 NAT 已经具有转发算法的协议,例如 FTP。

【讨论】:

    【解决方案3】:
    1. 使用 Wireshark 检查 tcp 连接请求(3-way Handhsake 过程)是否正常。

    2. 确保您的侦听器线程使用 select() 来解复用描述符。

    3. sockPeerConect(socket used to connect Other peer) is FD_SET() in Listener Thread.

    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.在连接到服务器和对等体之前启动你的监听线程,并有一个监听线程来接收服务器和客户端。

    【讨论】:

    • 我不明白为什么我必须为套接字使用集合。它有什么变化?
    • 它会通知该套接字上是否有可用的东西。我们必须反复检查特定套接字上是否有可用的东西。
    • WSAETIMEDOUT ....确保所有端口都允许在 NAT 设置中输出 TCP 流量。
    【解决方案4】:

    不是每个路由器都支持tcp打孔,请查看下面的论文详细解释:

    Peer-to-Peer Communication Across Network Address Translators

    【讨论】:

    • 您能否为您的 S、A 和 B 以及路由器添加网络布局,我怀疑由于您在同一台机器上有 S 和 A,所以您的 NAT 路由器甚至没有 NAT 转换B 到达 A 的路由器,因为 A 没有通过路由器与 S 建立连接(它们在同一台机器上!)。为了进行正确的测试,您应该将您的 S 与 A 或 B 放在不同的 LAN 中。
    猜你喜欢
    • 2016-12-05
    • 2011-09-19
    • 2015-02-10
    • 2014-03-08
    • 2017-01-25
    • 2014-06-08
    • 2014-12-28
    • 1970-01-01
    • 2015-05-25
    相关资源
    最近更新 更多