使用STUN进行NAT下的UDP洞穿以实现服务器/客户端通信

3

问题

我正在开发一个通信系统,其中:

AB是NAT下的计算机,A是服务器,B是客户端。 S是STUN服务器。

S运行在一个可以通过互联网访问的机器上。

流程如下:

A hits S with an opcode saying he's the server
S registers A as server

B hits S with an opcode saying he's the client
S sends to A B's external infos (IP, PORT)
S sends to B A's external infos (IP, PORT)

A starts sending B an opcode saying he's the server every 500ms
and meanwhile listens for packets saying he's got a client

B starts sending A an opcode saying he's the client every 500ms
and meanwhile listen for packets saying he's got the server

问题

问题出现在这里,STUN服务器完成了它的工作,因为双方都收到了有关对方的正确信息。

但是我从未收到过另一端的消息,因此双方都在等待握手操作码或任何其他内容而没有接收到。

NAT的行为

我已经检查了这个NAT的行为,似乎是这样的:

A位于192.168.X.X的4444端口上连接到外部暴露的N.N.N.N:4444端口,所以只要端口空闲,端口号就保持不变,如果不可用则会获得一个新的(随机的?)端口号。

测试

我运行的测试看到A和B两端都托管在同一台机器上,并绑定到机器的内部IP,尝试绑定到127.0.0.1、0.0.0.0,但什么也没改变。

如果在等待握手时使用nclocalhost发送echo,则可以接收并显示该消息(作为未识别的消息),没有任何问题。然而通过NAT路由的连接不起作用,每个数据包都被丢弃。

还尝试过将A托管在计算机上,将B托管在移动数据下的Android手机上,使用特别编写的应用程序。仍然等待某些东西,就像nodejs测试一样。


更新: 我尝试做的另一件事是用nc打开一个洞。

我在同一个NAT下的两台不同机器上运行了以下命令:

echo "GREET UNKOWN PEER" | nc -u <NAT IP> 4567 -p 4568

echo "GREET UNKOWN PEER" | nc -u <NAT IP> 4568 -p 4567

每台机器都运行了多次。据我所知,这应该会在第一个数据包被丢弃并且随后转发之后在NAT中打洞。但是没有任何反应,没有一端收到了消息。

我还尝试了:

从本地机器 echo "GREET UNKOWN PEER" | nc -u <PUBLIC IP> 4567 -p 4568

从公共机器 echo "GREET UNKOWN PEER" | nc -u <NAT IP> 4568 -p 4567

这个可以工作,位于NAT下的本地机器联系公共机器,并在第一个丢弃的数据包之后能够在分配的端口上接收和发送。我想知道为什么这不能在同一NAT下的两台机器上工作(???)


代码

我没有展示任何代码,因为我认为其中存在某种逻辑缺陷,然而这是该GitHub项目的链接。 index.js包含STUN服务器,tests文件夹包含测试用例: test.js启动stun服务器,PeerClientTest.jsPeerServerTest.js是客户端和服务器的模拟。
在公共计算机上运行node tests/test.js以启动服务器(更改config.jstests/config.js中的IP)
然后运行node tests/PeerServerTest.js以启动服务器("A"),再运行node tests/PeerClientTest.js以启动客户端("B")。两者都通过STUN识别对方,然后监听另一端的握手操作码同时发送自己的握手操作码。这从未发生过,因此它们会永远发送/监听。
Node不是必需的,所以如果有其他语言的更好解决方案,请告诉我,将不胜感激。
1个回答

1
B的NAT正在过滤A的数据包,不允许它们通过。NAT会过滤发送给它的未知数据包。您的服务器A正在向客户端B发送数据包。但是客户端B以前从未通过NAT向A发送数据包。因此,对于B的NAT来说,A的数据包是未知的并被丢弃。
您需要在B的NAT中打一个洞,使NAT允许传入的数据包通过。从B到A NAT的IP:Port发送一个数据包。之后,当您从A向B发送数据包时,B的NAT将不会丢弃A的数据包。
如果A和B的NAT具有对称和对称/PRC NAT这样的组合,则此方法无效。在这种情况下,您将需要使用TURN中继服务器。

实际上我就是这么做的... A和B联系S后,他们会收到对方的地址(NAT IP,PORT),然后开始相互发送数据包并等待响应。如果有响应,就意味着打洞成功了。但事实上,这种情况从未发生过,他们一直卡在发送/等待响应的状态。 - vinzdef
B的NAT类型是什么?你写道:“A位于192.168.X.X,端口4444连接到外部暴露N.N.N.N:4444,因此只要端口号空闲,它就会保持不变”。你能验证一下B是否也是这样吗?你需要知道当B向A发送数据包时,从服务器S获得的公共端口是否保持不变。 - Tahlil
看看这是否符合您的情况... https://dev59.com/143da4cB1Zd3GeqP1Ijn - Tahlil
在我的测试中,A和B都托管在同一台机器上,因此具有相同的NAT、相同的外部和内部IP,只是不同的端口。我尝试了在两个不同的网络下使用这个配置,使用不同的路由器和ISP。我还尝试了将A放在我的机器上,将B放在Android手机的移动数据下。结果相同。 - vinzdef
对于同一网络,您不需要进行NAT。但是对于不同的NAT,您需要知道两端的NAT类型。每个NAT具有不同的行为,对于NAT遍历,这些信息是必不可少的。如果不知道这一点,我们无法确定任何事情。 - Tahlil
我知道如果我在同一网络中,我不必经过NAT,这只是一个测试。 - vinzdef

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