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