无法使用 STUN 执行 TCP 打孔

Posted

技术标签:

【中文标题】无法使用 STUN 执行 TCP 打孔【英文标题】:Failing to perform TCP hole punching using STUN 【发布时间】:2022-01-18 03:47:37 【问题描述】:

我有两台主机 A 和 B。它们位于不同的网络中,位于不同的 NAT 和 ISP 后面。我正在尝试通过使用打孔在它们之间建立 p2p 连接。我使用 STUN 服务器来获取 A 和 B 的映射 IP 地址和端口。它是这样进行的:

对于 A:

.\stunclient.exe --mode behavior stun.stunprotocol.org 3478
Binding test: success
Local address: 192.168.0.110:54709
Mapped address: 186.233.160.141:28769
Behavior test: success
Nat behavior: Endpoint Independent Mapping

对于乙:

.\stunclient.exe --mode behavior stun.stunprotocol.org 3478
Binding test: success
Local address: 192.168.3.1:57015
Mapped address: 45.70.35.52:12870
Behavior test: success
Nat behavior: Endpoint Independent Mapping

然后我尝试通过在 A 和 B 上同时多次执行这两行来执行 TCP 打孔技术(使用 netcat):

在 A 上:

ncat -p 54709 45.70.35.52 12870
Ncat: TIMEOUT.

在 B 上:

ncat -p 57015 186.233.160.141 28769
Ncat: TIMEOUT.

我总是得到“Ncat: Timeout”作为输出(不是立即,这需要一些时间),但是,我可以通过运行以下命令 3 次通过 UDP 打孔在 A 和 B 之间建立直接连接:

在 A 上:

ncat -u -p 54709 45.70.35.52 12870

在 B 上:

ncat -u -p 57015 186.233.160.141 28769

所以问题是 TCP 打孔不起作用。任何想法为什么?

【问题讨论】:

同网流量不经过路由器,无需打孔。路由器在网络之间路由流量,而不是从一个网络返回到同一个网络。桥接同一网络上的流量。 【参考方案1】:

许多问题可能使这成为一个挑战。

首先,stunclient 默认为 UDP,而ncat 默认为 TCP。因此,您的第一个问题是您没有传递标志(在大多数系统上为-u)来告诉ncat 作为UDP 运行。或者,您可以尝试在 tcp 模式下运行 stunclient。 (例如stunclient --protocol tcp stun.stunclient.org),但 TCP NAT 遍历远不如 UDP 可靠——尤其是使用基本的命令行工具)

我不明白你上面的输出如何让主机 A 和主机 B 在同一个 NAT 后面,但两台机器似乎都有相同的本地 IP 地址,使用相同的本地端口,但打印相同的本地 IP 地址@ 987654327@。这是怎么回事?这只是一个错字吗?还是一台机器是另一台机器的 VM 主机并且它们共享一个 IP?

您试图实现的行为,即同一 NAT 后面的两台主机通过 public ip 地址连接称为hairpinning。这依赖于 NAT 足够聪明,可以看到出站数据包确实是发往路由器本身后面的主机,并通过自己的路由表将其环回,而不是在 WAN 适配器上发出。 并非所有 NAT 都支持发夹。所以你要做的就是尝试连接到本地和远程 IP 地址。

另外,尽量避免选择像 20000 这样的硬编码端口。让 stunclient.exe 为您选择一个随机可用的端口。 (即不指定--localport 参数)。然后当您发出ncat 命令时,使用它选择的本地端口连接到另一个IP 地址的远程映射端口。

假设用法:

主机A

stunclient.exe stun.stunprotocol.org
Binding test: success
Local address: 192.168.1.2:1111
Mapped address: 45.70.35.52:2222

主机B

stunclient.exe stun.stunprotocol.org
Binding test: success
Local address: 192.168.1.3:3333
Mapped address: 45.70.35.52:4444

地址从 A 传递到 B 的候选地址:45.70.35.52:2222, 192.168.1.2:1111

地址从 B 传递到 A 的候选地址:45.70.35.52:4444, 192.168.1.3:3333

主机 A 然后并行运行这些命令。但是糟糕,ncat 可能不允许在两个正在运行的程序之间共享套接字端口。查看文档以查看 SO_REUSEADDR 标志是否作为命令行参数隐式公开。它可能会隐式执行此操作。

ncat -u -p 1111 45.70.35.52 4444
ncat -u -p 1111 192.168.1.3:3333

主机 B 然后在两个单独的控制台中执行此操作:

ncat -u -p 3333 45.70.35.52 2222
ncat -u -p 3333 192.168.1.2:1111

换句话说,尝试 A 到 B 和 B 到 A 的所有 4 种组合。

我正要提到通过运行行为测试来确保您没有地址相关映射。 (即“对称 NAT”)。对称 NAT 使 p2p 连接很难“直接”连接。但是你有独立于端点的,这很好。

【讨论】:

同一个本地ip地址确实是笔误。对于 B,本地 ip 是“192.168.3.1”。我更改了主机 A 网络,因此 A 和 B 位于不同的 NAT 和 ISP 后面,在这种情况下,我可以通过 UDP 打孔(即使用带有 -u 选项的 ncat)成功地在它们之间建立直接连接,但我无法设置通过 TCP 打孔直接连接。任何想法为什么? 也感谢您的热心回答! c: IIRC,TCP 打孔需要在两个远程套接字之间同时连接并定期重试。如果您同步某些 NAT 的 SEQ 编号(通常为 0),它会有所帮助。如果 NAT 阻止任何没有 ACK 位的传入 TCP 数据包,那就更难了。另外,关闭 Windows 防火墙,看看这是否有助于您的测试。 再次感谢。我还将问题修改为我所处的新环境。

以上是关于无法使用 STUN 执行 TCP 打孔的主要内容,如果未能解决你的问题,请参考以下文章

使用 STUN 打孔

Java UDP STUN 打孔与 DatagramSocket

TCP打孔(NAT穿越)库还是啥?

移动提供商无法进行 UDP 打孔

UDP打孔无法外接

UDP 打孔 - 无法到达目的地