无法使用 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 打孔的主要内容,如果未能解决你的问题,请参考以下文章