不同网络模型下建立 P2P 连接

不同网络模型下建立 P2P 连接

一、公网 - 公网

image-20230425171056854

在当前网络模型中,客户端 A 和客户端 B 都位于公网。客户端 A 和 客户端 B 通过以下步骤即可建立 P2P 连接:

  1. 客户端 A 向中心服务器上报自身信息,并获取客户端 B 信息;客户端 B 向中心服务器上报自身信息,并获取客户端 A 信息;(PS: 忽略两端获取对端信息时的时间差)
  2. 客户端 A 根据从中心服务器获取的信息发现 B 具有公网地址,于是 A 直接向 B 发起连接;(PS: 可以互换连接顺序)
  3. 客户端 B 根据从中心服务器获取的信息发现 A 具有公网地址,因此 B 等待 A 进行连接;

二、NAT - 公网

image-20230425163422662

在当前网络模型中,客户端 B 位于公网,有公网 IP,客户端 A 位于任意 NAT 后。客户端 A 和 客户端 B 通过以下步骤即可建立 P2P 连接:

  1. 客户端 A 向中心服务器上报自身信息,并获取客户端 B 信息;客户端 B 向中心服务器上报自身信息,并获取客户端 A 信息;(PS: 忽略两端获取对端信息时的时间差)
  2. 客户端 B 根据从中心服务器获取的信息发现 A 位于 NAT 后,因此 B 等待 A 进行连接;
  3. 客户端 A 根据从中心服务器获取的信息发现 B 位于公网,于是 A 直接向 B 发起连接;

三、客户端位于同一NAT后

image-20230425174627374

在当前网络模型中,客户端 A 和客户端 B 位于同一任意 NAT 后。客户端 A 和 客户端 B 通过以下步骤即可建立 P2P 连接:

  1. 客户端 A 向中心服务器上报自身信息,并获取客户端 B 信息;客户端 B 向中心服务器上报自身信息,并获取客户端 A 信息;(PS: 忽略两端获取对端信息时的时间差)
  2. 客户端 A 根据从中心服务器获取的信息发现 B 的公网地址和自身相同,猜测 B 可能与自己位于同一内网中,于是 A 尝试直接向 B 发起连接;(PS: 可以互换连接顺序)
  3. 客户端 B 根据从中心服务器获取的信息发现 A 的公网地址和自身相同,猜测 A 可能与自己位于同一内网中,因此 B 等待 A 进行连接;

四、客户端分属与不同NAT下

image-20230425180929671

在当前网络模型中,客户端 A 和客户端 B 都位于 NAT 后。客户端 A 和 客户端 B 能否建立 P2P 连接和各自所属 NAT 类型有关。

1. 任意 NAT - (Full Cone NAT或Restricted Cone NAT)

image-20230425183759867

Full Cone NAT、Restricted Cone NAT和Port Restricted Cone NAT都有同样的映射规则:本地地址和端口不变时,映射到 NAT 上的端口不变

当一端位于 Full Cone NAT或Restricted Cone NAT 下,另一端为任意 NAT 时,通过以下方式可以建立 P2P 连接:

  1. 客户端 A 向中心服务器上报自身信息,并获取客户端 B 信息;客户端 B 向中心服务器上报自身信息,并获取客户端 A 信息;(PS: 忽略两端获取对端信息时的时间差)
  2. 客户端 A 持续向客户端 B 在 NAT 网关2 上映射的公网地址和端口发送数据。对于 Restricted Cone NAT,由于NAT 网关2上还没有放开相应的过滤规则,因此前面客户端A发向客户端B的部分数据包会被丢失;
  3. 客户端 B 向客户端 A 的公网地址和端口发送数据,用以更新 NAT 网关2的过滤规则;
  4. 当NAT 网关2的过滤规则被刷新后,客户端 A 发向客户端B的数据便会被 NAT 网关2 接收,并转发给客户端 B;
  5. 接收数据时,客户端 B 就会知道客户端在 NAT 网关1上映射的端口和地址,此时客户端 B向NAT 网关1上映射的端口和地址发包,客户端A即可收到。此时客户端 A 和客户端 B 成功建立 P2P连接。

2. Easy NAT - Easy NAT

Easy NAT 代指 RFC3489 所定义的 Full Cone NAT、Restricted Cone NAT、Port Restricted Cone NAT。

image-20230425185223983

当两端都位于 Easy NAT 下时,通过以下方式可以建立 P2P 连接(任意 NAT - (Full Cone NAT或Restricted Cone NAT) 流程类似):

  1. 客户端 A 向中心服务器上报自身信息,并获取客户端 B 信息;客户端 B 向中心服务器上报自身信息,并获取客户端 A 信息;(PS: 忽略两端获取对端信息时的时间差)
  2. 客户端 A 持续向客户端 B 在 NAT 网关2 上映射的公网地址和端口发送数据,由于NAT 网关2上还没有放开相应的过滤规则,因此前面客户端A发向客户端B的部分数据包会被丢失;
  3. 客户端 B 向客户端 A 的公网地址和端口发送数据,用以更新 NAT 网关2的过滤规则;
  4. 当NAT 网关2的过滤规则被刷新后,客户端 A 发向客户端B的数据便会被 NAT 网关2 接收,并转发给客户端 B;
  5. 接收数据时,客户端 B 就会知道客户端在 NAT 网关1上映射的端口和地址,此时客户端 B向NAT 网关1上映射的端口和地址发包,客户端A即可收到。此时客户端 A 和客户端 B 成功建立 P2P连接。

3. Symmetric NAT - Port Restricted Cone NAT

image-20230425190545112

当客户端 A 位于 Symmetric NAT 下,客户端 B 位于 Port Restricted Cone NAT 时,通过以下方式可以建立 P2P 连接:

  1. 客户端 A 向中心服务器上报自身信息,并获取客户端 B 信息;客户端 B 向中心服务器上报自身信息,并获取客户端 A 信息;(PS: 忽略两端获取对端信息时的时间差)
  2. 客户端 A 持续向客户端 B 在 NAT 网关2 上映射的公网地址和端口发送数据。由于 NAT 网关2 没有放开相应的过滤规则,因此客户端 A 发往客户端 B 的数据包会被 NAT 网关2拦截,无法到达客户端 B;;
  3. 由于客户端 A 在NAT 网关1上映射的端点(IP:Port 中 Port 未知),因此客户端 B 无法向一个明确的端点发送数据包来更新 NAT 网关2 过滤规则。

此时就需要通过以下几种方案来让碰撞,让客户端 A 发向客户端 B 的包顺利通过 NAT 网关2。

全端口开放

虽然我们不知道客户端 A 在映射NAT 网关1上映射的端口是多少,但是我们知道,他映射的端口一定是 1024 - 65535 内其中一个,并且一定不是 A 连接中心服务器时使用的端口。

我们可以顺序构造目的端口为 1024 - 65535 的短 TTL 包(短 TTL 包可以让包不走到公网,仅仅用于打开防火墙规则,以免被识别为 Dos 攻击),让 NAT 网关2 开放所有可能端口(相当于将 Port Restricted Cone NAT 变为 Restricted Cone NAT)。

但是经过实际测试发现该方法效果不佳,主要有以下原因:

  • 需要构造大量数据包:平均需要发包 32256 个包 才能碰撞到 客户端 A 在 NAT 网关1上映射的端口。假设客户端 B 的发包速率为 100 p/s,那么就需要五分半才能碰撞到端口;
  • 容易触发运营商 QoS 限制:经过实际测试,发现一定时间内无效数据包过多时,运营商会对客户端 B 的包进行大量丢弃,导致丢包率上升。严重情况下运营商会直接全部丢弃客户端 B 的数据包。

端口预测

在部分 NAT 上,端口映射具有一定规律 。

比如发往目的 IP 1 时,映射的端口为 22001;发往目的 IP 2 时,映射的端口为 22002;那么我们可以猜测,发往目的 IP 3时使用的端口可能为 22003。

使用此种方案,需要客户端 A 向多个服务器请求来确认自身映射端口,从这些映射的端口中找到可能存在的端口变化规律。

此种方法具有一定可行性,但和 NAT 行为有关,不是一个通用解决方案。

生日攻击

在前面的“全端口开放”方法中,客户端 A 只在 NAT 网关1 上映射了一个端口。但是实际情况下,客户端 A 可以在 NAT 网关1 上映射多个端口。

根据概率论的 生日悖论,可以写发现客户端 A 映射的端口、客户端 B 发包数量与成功概率之间的关系,公式如下所示:

$$ \begin{array}{c} P_{success} = 1 - \frac{C_{64,512}^{ports} \times C_{64,512-ports}^{packets }}{C_{64,512}^{ports} \times C_{64,512}^{packets}} \end{array} $$

根据上面的公式绘制出三维图如图所示:

psuccess

根据函数图我们可以发现,当客户端 A 映射在公网上的端口越多时,建立连接所需的发包数越少,下表中列举了部分数据:

使用端口数\发包数50%80%90%99%
10432095901326823807
50888204329035675
100446103014682902
2002235177381467
300149345493981

根据表中数据可以发现:假设客户端 A 占用100个端口,客户端 B 以 100 p/s 的速度进行探测,那么要达到50%的概率仅需 6s,达到 99% 也只需 29s!

根据上面的数据分析可以发现生日攻击是在 Symmetric NAT - Port Restricted Cone NAT 进行 P2P 打洞时一个较为优秀的方案。

4. Symmetric NAT - Symmetric NAT

当两端都是 Symmetric NAT 时,复杂度比 Symmetric NAT - Port Restricted Cone NAT 有了成倍的增长。

假设使用上面的“全端口开发”方案,那么就需要发包 4,161,798,144 次,耗费时间需要一年以上;

即使是使用“生日攻击”方案,一端打开 256 个端口,要达到 50% 的概率需要 54,000 次发包,按照 100 p/s 的发包速率需要9分钟;达到 99% 的成功率需要 170,000 次发包,时间上需要30分钟左右。

即使时间上可以忍受,但 NAT 网关却无法忍受这么多次的发包行为。因为每发一次包,就需要在 NAT 的 session 表上记录一条,想创建一条成功的连接,大部分情况下都会打爆 NAT 的session 表。

因此对于 Symmetric NAT - Symmetric NAT 网络类型,连接建立方案只能选择中继服务器模式

五、客户端位于同一大 NAT 下,但不属于同一内网

image-20230425175617453

在当前网络模型中,客户端 A 和客户端 B 位于同一任意大 NAT 后,但是分属于大 NAT 下的两个小子网中。客户端 A 和 客户端 B 需要通过以下步骤建立连接:

  1. 客户端 A 向中心服务器上报自身信息,并获取客户端 B 信息;客户端 B 向中心服务器上报自身信息,并获取客户端 A 信息;(PS: 忽略两端获取对端信息时的时间差)
  2. 客户端 A 根据从中心服务器获取的信息发现 B 的公网地址和自身相同,猜测 B 可能与自己位于同一内网中,于是 A 尝试直接向 B 发起连接。但是由于 A 和 B不在同一内网中,因此连接建立失败。客户端 A 通过中心服务器通知 B 连接建立失败,需要进行下一步尝试;
  3. 客户端 A 向 B 暴露的公网 IP 和端口直接发送请求。如果NAT 网关不支持 Hairpin 模式,那么这个数据包会被直接丢弃,导致数据包无法到达 NAT 网关2;如果 NAT 网关开启了 Hairpin 模式,A 发向 B 的流量会被 NAT 网关转发给 NAT 网关2,流程进入下一步;
  4. 当数据包到达 NAT 网关2后,下面的流程就和 “客户端分属与不同NAT下”时的打洞行为一致了。

六、多层 NAT

image-20230426151647292

在网络中,存在设备在多层NAT后的情况。

对于这种多层NAT而言,真正有影响的是最靠近公网的那一个 NAT 网关,其余的 NAT 对于客户端和服务端来说都是不可见的,连接不会关心到底经过了多少层NAT。

但是多层 NAT 并非完全没有影响,准确来说,多层NAT 影响的是客户端的端口映射行为。客户端发出的端口映射请求,只有最靠近客户端的那层 NAT 设备会做出响应。其他的NAT设备不会收到客户端的端口映射请求。但是端口映射要产生作用的话,需要的是最靠近公网的 NAT 网关执行端口映射才行。

Licensed under CC BY-NC-SA 4.0
最后更新于 May 16, 2024 11:09 +0800
使用 Hugo 构建
主题 StackJimmy 设计