如何在 NAT 后面的两个节点之间进行通信?

Posted

技术标签:

【中文标题】如何在 NAT 后面的两个节点之间进行通信?【英文标题】:How to communicate between two Nodes behind NAT? 【发布时间】:2018-12-02 21:31:32 【问题描述】:

我有一些节点。每个节点都属于其他网络。每个节点都有像 192.168.0.2 这样的私有 IP,并保持在 NAT 后面。

节点之间是否有可能进行通信?实际上,我需要在这些独立节点之间传输文件。

我尝试使用这个项目 - https://github.com/libp2p/go-libp2p。但是 libp2p 有一些限制:

    两个节点都有私有 IP 地址(同一网络) 其中至少有一个具有公共 IP 地址。

但是我有私有IP地址的节点,它们属于不同的网络。


更新。

有这样的解决方案:

https://en.wikipedia.org/wiki/Hole_punching_(networking) https://en.wikipedia.org/wiki/Universal_Plug_and_Play https://***.com/a/8524609/1756750 UDP/TCP hole punching vs UPnP vs STUN vs? https://***.com/a/31623109/1756750 Behind NAT to behind NAT connection http://www.brynosaurus.com/pub/net/p2pnat/

【问题讨论】:

这不是围棋题,而是网络题。 Go 不能覆盖计算机所在的网络环境设置的限制。 @BertVerhees 我同意你的看法。但是我使用 go 标签只是为了解释,如果有人想给我一些 github 库。 没有可以解决由网络设置创建的限制的 go-library。当没有到 IP 地址的路由时,没有 go-library 可以让您到达该计算机。是TCPIP/路由问题,需要找网管解​​决。 @BertVerhees 我的意思是,也许有一些方法可以解决我的问题。像动态 dns 或某种服务网格。 您需要另一台服务器,您知道该服务器的 IP/端口,以便您可以在 NAT 框中交换端口和 IP,从而建立 P2P 连接。 【参考方案1】:

这个想法是你有一个集合点服务器,节点 1 和 2 连接到它。为此,他们必须知道集合点服务器的 IP。

如下: 1) 1 和 2 都向 RS 发送 UDP 数据包。 N1(节点 1 的 NAT 框)和 N2 在转换表中创建一个条目,将节点的 IP 映射到 RS 的 IP/端口。 2) RS 将 (EIP1,EP1) 传递给节点 2。这是包含 NAT 框的公共 IP 和公共端口的 Tulpe。 RS 将 (EIP2,EP2) 发送到节点 1。 3) 节点 1 在转换表中创建一个映射:(IP1,EP1,EIP2,EP2)。 4) 节点 2 执行相同操作,但使用 (IP2,EP2,EIP1,EP1)。

注意:第 3 步和第 4 步会发生,因为每个节点都会向刚刚收到的元组 (IP,Port) 发送一个 UDP 数据包,因此 NAT 框会添加一个新条目。 在最坏的情况下,这些消息必须发送多次。

这个技巧可以让两个节点都获得公共 IP 并拥有正确的端口。

这提供了一种建立点对点连接的好方法,例如Skype。

我希望这会有所帮助。

【讨论】:

同样对于 Skype,内部的计算机发起 TCP/IP 联系。如果路由器 fo 诀窍是 NAT 内部的计算机被触发以启动与 NAT 外部的会话。这里解释一下。theregister.co.uk/2003/10/08/how_does_skype_get_through 但必须在路由器和防火墙上保留特殊设置以允许 UDP Jbuchel,Max 也想知道用哪个 go 库可以解决这个问题。我认为这是不可能的,但也许你还有其他信息。 我不知道有哪个库可以做到这一点,但自己实现听起来并不难。但也许有一段时间...... 这是一个棘手的问题。我对此感到抱歉。您不需要库,Skype 处理它的方式可以在标准网络功能中完成。问题在于所需的外部供应。【参考方案2】:

Libp2p 没有这样的限制。

您引用的聊天示例的编程方式使其无法支持 NAT 后面的私有 IP 但是 Libp2p 支持 NAT 遍历技术,例如打孔、STUN、TURN 等协议和使用集合点的引导现在使用 DHT。这就是你需要的。

以下示例可能对您有用:

    与集合点聊天:https://github.com/libp2p/go-libp2p-examples/tree/master/chat-with-rendezvous 与托尔聊天:https://github.com/libp2p/go-libp2p-examples/pull/1

【讨论】:

【参考方案3】:

Max,我把它作为你问题的答案。

在网络上配置或无法访问的计算机不能被计算机上的软件覆盖。这将是安全漏洞,并且可能是地址冲突的原因,因为在不同的 NAT 区域中可以使用相同的 IP 地址。

因此,如果路由器使用 NAT,您将看不到路由器后面的计算机。 路由器不会通告这些地址。

NAT 的目的是拥有一个特殊的 IP 地址岛,在 NAT 部分之外没有人可以看到。通过这种方式,公司可以使用更少的唯一 IP 地址来拥有一个运行良好的网络。另一个目的是安全。路由器还会隐藏 NAT 区域内计算机的 MAC 地址。路由器可以隐藏很多东西。

NAT 区域内的计算机可以发起与 NAT 外的计算机的联系((如果允许)路由器会记住该计算机并为其保留地址转换),但 NAT 外的计算机无法寻址NAT 内的计算机。它只能从内部回复计算机。它通过回复路由器来做到这一点,路由器将知道将回复转发到 NAT 区域中的哪台计算机。

Go 不提供可以解决这些外部限制的库。忍受它。你无能为力。

正如 JBuchel 解释的那样,如果有一些额外的规定,例如开放的 UDP 端口和额外的服务器/计算机等,Skype 模型就可以工作。这实际上是网络配置的重新安排,如果没有系统/网络管理员。

但如果在该级别上有支持,解决方案就简单多了,只需将计算机从 NAT 中移除,并为其提供一个对其他计算机可见的 IP 地址。

【讨论】:

以上是关于如何在 NAT 后面的两个节点之间进行通信?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Websocket 的两个设备之间的双向通信

在 NAT 后面工作 - 一种设备通信方案

如何让两个android设备通过TCP进行通信

NAT 后面到 NAT 连接后面

在 NAT 后的两台计算机之间建立连接

如何在两个动画画布元素之间进行通信?