A 需要联系 B,A 不在 NAT 后面,B 是。
我们必须假设 B 位于隐藏 NAT 之后(过载,根据 RFC 2663 NAPT)并且没有创建静态 NAT 的选项,否则 A 可以使用静态 NAT 打开到 B 的连接,在这种情况下不需要C。
问题是由于 NAT 类型,B 无法接受入站连接。NAPT 没有开放的入站端口。连接是从 B 通过 NAT 发起的,并且 B 的 IP 被转换为为 NAT 配置的 IP。如果 B 的端口号在 NAT 上不是空闲的,也可能会被转换。
B 当然可以发起到 A 的连接,但是如果 B 是服务器,它就不会知道 A 正在尝试联系它,或者使用什么地址来到达 A。
如果您了解用于允许 A 连接到 B 的 NAT 遍历方法,那么这将有所帮助,然后您在任何时候都看不到任何连接入站到 B 的方法,这符合 NAT 对 B 入站连接的限制:
实现连接的一种简单方法是中继:
- B可以联系A,但是不知道A的IP地址
- A 和 B 都知道中间设备的 IP 地址 - C(不在 NAT 后面)
- A 和 B 都与 C 建立出站连接
- C 将两个连接缝合在一起,并将消息从 A 中继到 B,反之亦然。
另一种方法是连接反转:
- B可以联系A,但是不知道A的IP地址
- A 和 B 都知道中间设备的 IP 地址 - C
- A 和 B 都与 C 建立出站连接
- B 现在可以获知 A 的 IP 地址和端口
- B 现在可以与 A 建立直接出站连接
通过中继,C 上的开销很大,因为它位于 A 和 B 之间所有流量的数据路径中。在连接反转的情况下,C 仅用于了解 A 的 IP 地址。建立连接后,A 和 B 之间的流量将直接路由,绕过 C。
我认为您的主要困惑在于这些方法中的每一个的第一步。是的,在您的具体示例中,如果 B 知道要连接到哪个 IP:port,B 可以直接联系 A,但事实并非如此,因此要么需要通过中继服务器代理整个连接,要么使用中间服务器来了解 IP :port 然后使该连接本身出站。
RFC 5128 - State of Peer-to-Peer(P2P) Communication Across Network Address Translators(NATs) 中有更多细节
https://www.rfc-editor.org/rfc/rfc5128#page-8
解释了很多方法,这可能是 3.1 Relaying 的变体
3.1. 接力
在存在 NAT 设备的情况下实现对等通信的最可靠但效率最低的方法是使对等通信看起来像通过中继的客户端/服务器通信一样的网络。考虑图 1 中的场景。两台客户端主机 A 和 B 各自发起了到知名集合服务器 S 的 TCP 或 UDP 连接。集合服务器 S 具有可公开寻址的 IP 地址,用于注册目的,发现和中继。NAT 后面的主机向服务器注册。对等主机可以发现 NAT 后面的主机并使用服务器中继所有端到端消息。客户端驻留在单独的专用网络上,它们各自的 NAT 设备阻止任一客户端直接启动与另一个的连接。
Registry, Discovery
Combined with Relay
Server S
192.0.2.128:20001
|
+----------------------------+----------------------------+
| ^ Registry/ ^ ^ Registry/ ^ |
| | Relay-Req Session(A-S) | | Relay-Req Session(B-S) | |
| | 192.0.2.128:20001 | | 192.0.2.128:20001 | |
| | 192.0.2.1:62000 | | 192.0.2.254:31000 | |
| |
+--------------+ +--------------+
| 192.0.2.1 | | 192.0.2.254 |
| | | |
| NAT A | | NAT B |
+--------------+ +--------------+
| |
| ^ Registry/ ^ ^ Registry/ ^ |
| | Relay-Req Session(A-S) | | Relay-Req Session(B-S) | |
| | 192.0.2.128:20001 | | 192.0.2.128:20001 | |
| | 10.0.0.1:1234 | | 10.1.1.3:1234 | |
| |
Client A Client B
10.0.0.1:1234 10.1.1.3:1234
Figure 1: Use of a Relay Server to communicate with peers
两个客户端可以简单地使用服务器 S 在它们之间中继消息,而不是尝试直接连接。例如,要向客户端 B 发送消息,客户端 A 只需将消息沿其已建立的客户端/服务器连接发送到服务器 S,然后服务器 S 使用其与 B 的现有客户端/服务器连接将消息发送到客户端 B。
这种方法的优点是只要
两个客户端都连接到服务器,它就始终有效。航路 NAT 设备不需要是 EIM-NAT。中继的明显缺点是它会消耗服务器的处理能力和网络
带宽,
即使服务器有足够的 I/O
带宽并且在拓扑上正确定位,对等客户端之间的通信延迟也可能会增加。TURN 协议
[TURN] 定义了一种
以相对安全的方式实现与应用程序无关、面向会话的数据包中继的方法。
您还可以使用 3.2 - Connection Reversal 更具体地适用于您的情况:
3.2. 连接反转
以下用于直接
通信的连接反转技术仅在其中一个对等方位于 NAT 设备后面而另一个不在该设备后面时才有效。例如,考虑图 2 中的场景。客户端 A 位于 NAT 之后,但客户端 B 具有可公开寻址的 IP 地址。Rendezvous Server S 有一个可公开寻址的 IP 地址,用于注册和发现的目的。NAT 后面的主机向服务器注册它们的端点。对等主机使用服务器发现 NAT 后主机的端点。
Registry and Discovery
Server S
192.0.2.128:20001
|
+----------------------------+----------------------------+
| ^ Registry Session(A-S) ^ ^ Registry Session(B-S) ^ |
| | 192.0.2.128:20001 | | 192.0.2.128:20001 | |
| | 192.0.2.1:62000 | | 192.0.2.254:1234 | |
| |
| ^ P2P Session (A-B) ^ | P2P Session (B-A) | |
| | 192.0.2.254:1234 | | 192.0.2.1:62000 | |
| | 192.0.2.1:62000 | v 192.0.2.254:1234 v |
| |
+--------------+ |
| 192.0.2.1 | |
| | |
| NAT A | |
+--------------+ |
| |
| ^ Registry Session(A-S) ^ |
| | 192.0.2.128:20001 | |
| | 10.0.0.1:1234 | |
| |
| ^ P2P Session (A-B) ^ |
| | 192.0.2.254:1234 | |
| | 10.0.0.1:1234 | |
| |
Private Client A Public Client B
10.0.0.1:1234 192.0.2.254:1234
Figure 2: Connection reversal using Rendezvous server
客户端 A 的私有 IP 地址为 10.0.0.1,应用程序
使用 TCP 端口 1234。此客户端已
在公共 IP 地址 192.0.2.128 和端口 20001 上与服务器 S建立连接。NAT A 已
分配 TCP 端口 62000,为自己公共IP地址192.0.2.1,
作为A与
S会话的临时公共端点地址;因此,服务器 S 认为客户端 A 使用端口 62000 位于 IP 地址 192.0.2.1。然而,客户端 B 拥有自己的永久 IP 地址 192.0.2.254,并且 B 上的应用程序正在接受端口 1234 上的 TCP 连接。
现在假设客户端 B 希望
与客户端 A建立直接通信会话。 B 可能首先尝试在客户
端 A 认为自己拥有的地址(即 10.0.0.1:1234)或观察到的 A 地址联系客户端 A通过服务器 S,即 192.0.2.1:62000。无论哪种情况,连接都会失败。
在第一种情况下,指向 IP 地址 10.0.0.1 的流量将
被网络丢弃,因为 10.0.0.1 不是可公开
路由的 IP 地址。在第二种情况下,来自 B 的 TCP SYN 请求
将到达定向到端口 62000 的 NAT A,但 NAT A 将拒绝
连接请求,因为只允许传出连接。
在尝试与 A 建立直接连接并失败后,客户端 B 可以使用服务器 S 将请求中继到客户端 A,以启动
与客户端 B 的“反向”连接。客户端 A 在
通过 S接收到此中继请求后,打开一个 TCP通过 B 的
公共 IP 地址和端口号连接到客户端 B。NAT A 允许连接
继续进行,因为它源自防火墙内部,而客户端 B
可以接收连接,因为它不在 NAT 设备后面。
多种当前的对等应用程序实现了这种
技术。当然,它的主要限制是它只有
在只有一个通信对等点位于 NAT 设备后面时才能工作。
如果 NAT 设备是 EIM-NAT,则公共客户端可以联系外部
服务器 S 以确定
预期客户端 A 发起连接的特定公共端点,并仅允许来自这些端点的连接。如果 NAT 设备是 EIM-NAT,则公共客户端可以联系外部服务器 S 以确定
预期来自客户端 A 的连接的特定公共端点,并仅允许来自该端点的连接。如果NAT设备不是
EIM-NAT,公共客户端无法知道具体的公共端点
期望来自客户端 A 的连接。在
越来越普遍的情况下,两个对等方都可以位于 NAT 之后,
连接反转方法失败。Connection Reversal 不是
点对点连接问题的通用解决方案。如果既不能
建立“正向”也不能建立“反向”连接,
应用程序通常会回退到另一种机制,例如中继。