基于STUN服务器探测VMware的NAT模式下P2P穿透性(NAT类型),RFC 5780和RFC 3489协议情况

Zou, Ning 发布于 10 小时前 技术实践 2275 字 89 次阅读


前言

一直很想了解VMware的NAT模式使用的是哪一种类型的NAT,对于P2P应用的穿透难度如何。但是网上一直很少有测试。为此设计了一个实验,使用Stunserver+VMware来测试。先说结论VMware NAT 类型为 端口受限锥形(Port Restricted Cone),详细结论请看完文章。

前期准备

本次实验需要两台虚拟机,一台当做服务器,一台作为客户端:

在本地的VMware上部署一台Linux服务器,例如Rocky-Linux8.x,网络类型选择桥接模式,网络需要两张网卡,桥接到宿主机的网络。

{2BB33AD7 7508 4711 A926 C69CABBDCECE}

另外部署一台Windows server2016,关闭Windows防火墙,使用NatTypeTester32在宿主机上当做客户端进行测试,选择NAT网络模式,确保能够访问到宿主机的网络。

{FC8D929B 4CDF 4D4B 90DD 32F2F6BEC0D5}

具体配置如下:

组件配置
Linux 服务器(STUN 服务端)Rocky Linux / OpenCloudOS,桥接网络模式,双 IP
Windows 客户端(NatTypeTester)Windows 10/11,NAT 网络模式(VMnet8)
STUN 服务软件stunserver(源码编译)
测试工具NatTypeTester(Windows)

服务器部署

Linux 端:部署 stunserver

1、安装编译依赖

sudo dnf install -y gcc-c++ make boost-devel openssl-devel git

2、下载并编译 stunserver

sudo dnf install coturn -y

编译成功后,当前目录下会生成可执行文件 stunserver雷点:若 make 报错,检查是否缺少 boost 或 openssl 开发包。OpenCloudOS 9 需确保 EPEL 源配置正确。

配置 Linux 双 IP(关键步骤)

ip addr show

添加辅助 IP(别名 IP)

若当前仅有一个 IP(如 192.168.101.127),需要为同一网卡添加第二个 IP:

sudo ip addr add 192.168.101.128/24 dev ens160
ip addr show ens160
# 应同时看到 inet 192.168.101.127/24 和 inet 192.168.101.128/24

雷点

  • 两个 IP 必须在同一子网(如 /24)。
  • 辅助 IP 不能与其他设备冲突,先用 ping 确认该 IP 未被占用。
  • 该命令为临时生效,重启后失效。如需永久生效,需修改网卡配置文件(如 /etc/sysconfig/network-scripts/ifcfg-ens160)。

确认两个 IP 均能被客户端路由访问

ping 192.168.101.127
ping 192.168.101.128
{24579915 76F1 4A8E 817D EF882DB2A36B}

启动 stunserver

参数名是 --altinterface 和 --altadvertised

nohup ./stunserver --mode full \
  --primaryinterface 192.168.101.127 \
  --altinterface 192.168.101.128 \
  --primaryadvertised 192.168.101.127 \
  --altadvertised 192.168.101.128 &

参数说明

参数含义
--mode full启用 Change-Request 支持(RFC 5780)
--primaryinterface主 IP(监听 3478 端口)
--altinterface辅助 IP(监听 3479 端口)
--primaryadvertised通告给客户端的主 IP
--altadvertised通告给客户端的辅助 IP

验证服务状态

# 查看进程
ps aux | grep stunserver | grep -v grep

# 查看端口监听(应同时看到 3478 和 3479)
netstat -ulnp | grep -E "3478|3479"
{8F28F139 B913 405D BE42 864314A02A91}

防火墙放行

sudo firewall-cmd --permanent --add-port=3478/udp
sudo firewall-cmd --permanent --add-port=3479/udp
sudo firewall-cmd --reload
{4D7330B6 9D51 411E 998A 43A5B57811EA}

Windows 端:使用 NatTypeTester 测试

  • STUN Server:填入 Linux 主 IP + 端口,如 192.168.101.127:3478(默认端口可以不填)
  • 勾选RFC 5780 和 RFC 3489
{54A2EDA1 F3A7 4F78 B2B2 75B63C0621AD}

测试结果RFC 5780协议下:

结果项含义
Binding test: Success基础通信正常
Mapping behavior: EndpointIndependent端点独立映射(锥形 NAT)
Filtering behavior: AddressAndPortDependent地址和端口依赖过滤
结论端口受限锥形 NAT(Port Restricted Cone)

总结:VMware NAT 类型为 端口受限锥形(Port Restricted Cone)

详细行为解析(基于 RFC 3489 / 5780 分类测试):

测试维度结果含义
映射行为(Mapping behavior)Endpoint Independent端点独立映射:从同一内部 IP 和端口发出的数据包,无论发往哪个外部目标,都会被 NAT 网关映射为同一个公网 IP 和端口。这属于锥形(Cone) NAT 的核心特征。
过滤行为(Filtering behavior)AddressAndPortDependent地址和端口依赖过滤:外部主机只有在其 IP 地址和端口号 都与内部主机先前通信过的外部目标精确匹配时,才能向内网发送数据包。

综合判定(基于 RFC 5780 整合算法)为:PortRestrictedCone(端口受限型)

  • 映射:采用锥形映射(同一个内网端口映射到同一个公网端口)。
  • 过滤:采用端口受限过滤(即外部主机必须同时匹配 目标 IP + 目标端口 才能向内网发包)。

下面分析P2P难易程度

首先,P2P应用需要进行打洞,不同的NAT类型对其打洞难易程度不同。根据测试结果,这是一种“中等偏难”的 NAT 类型。P2P 打洞(UDP 穿透)可行,但条件苛刻、容错率低,远不如全锥形顺畅,但比对称型要好得多。下面是难易程度评价:

NAT 类型打洞成功率难度等级
Full Cone (全锥形)接近 100%⭐ (极简)
Address Restricted Cone (地址受限锥形)~90%⭐⭐ (简单)
Port Restricted Cone (端口受限锥形)~60% ~ 80%⭐⭐⭐⭐ (较难)
Symmetric (对称型)< 10% (通常需要中继)⭐⭐⭐⭐⭐ (地狱级)

为什么“端口受限锥形”打洞是可行的(优点):

  • 端口稳定性:无论 Windows 虚拟机发往哪个外部目标(如 Peer A 或 Peer B),VMware NAT 网关都会将其映射为同一个公网端口(如 192.168.101.91:63552)。
  • 这意味着:在进行 UDP 打洞时,双方不需要去猜测对方 NAT 分配的端口号,因为端口是固定的。这避免了对称型 NAT 中“端口预测”的噩梦。

为什么实际穿透非常艰难(缺点):

Filtering behavior: AddressAndPortDependent 是导致困难的根本原因。

  • 严格的“白名单”机制:NAT 网关只会接受来自 “你之前恰好主动联系过的那台主机的那个特定端口” 的数据包。
  • 现实场景困境
    1. 假设 Peer A(外部公网 IP 1.2.3.4,端口 12345)想给你发数据。
    2. 你的 NAT 网关之前只给 Peer B 发过数据,所以当 Peer A 发来数据时,即便 IP 是对的,只要 Peer A 的源端口 12345 不是你之前联系过的那个端口,数据包就会被 直接丢弃(NAT 不会转发给 Windows 虚拟机)。
    3. 时间差问题:UDP 打洞要求双方几乎同时向对方的公网 IP 和端口发送数据包(并发打洞)。如果一方先发,另一方后发,先发的那一方由于还没收到对方的包,NAT 过滤表里没有对方记录,后发来的包就会被无情丢弃。

在真实的 P2P 网络(如 BitTorrent、WebRTC 音视频通话、游戏联机)中:

  • 成功率(约 60%-70%):如果两台主机都是端口受限锥形,且双方都使用了标准的 并发打洞(Concurrent Connect) 算法,同时在几毫秒内向对方发送数据包,大概率能成功建立直连。
  • 失败场景(约 30%-40%)
    • 双方网络延迟差异过大(一方数据包先到达,另一方的 NAT 表还没生成,导致包被丢弃)。
    • 其中一方使用的 P2P 库不支持并发打洞,只做单向穿刺。
    • 端口复用冲突(主机内部多个程序占用了相同端口映射)。

技术架构上的妥协(ICE 策略)

在现代 P2P 架构(如 WebRTC)中,ICE(交互式连接建立)框架对你这类型 NAT 的处理策略是:

  1. 优先直连(srflx 候选):它会尝试让两端通过 STUN 获取的 192.168.101.91:63552 进行双向 UDP 并发打洞。如果网络状况良好,这里会成功。
  2. 保底中继(Relay 候选):由于端口受限锥形的打洞存在不确定性,ICE 协议通常不会等待太长时间(通常只试几秒钟)。一旦打洞超时,流量就会立即切换到 TURN 服务器(中继转发)

VMware NAT 的端口受限锥形,P2P 能通但全看“运气”和“算法”。 它需要两端严格的时间同步打洞,成功率约七成;失败时,就必须依赖 TURN 服务器中转,此时 P2P 的优势(低延迟、节省带宽)将荡然无存。这也是为什么主流 P2P 应用都会耗费巨资部署 TURN 服务器来兜底的原因。

建议

如果有P2P的需求建议优先选择桥接模式,比如qbit、彗星、PCDN等需求。

故障排查

stunserver 启动失败(退出码 255)

原因:参数错误、IP 不存在、端口被占用。

# 前台运行查看详细错误
./stunserver --mode full \
  --primaryinterface 192.168.101.127 \
  --altinterface 192.168.101.128 \
  --primaryadvertised 192.168.101.127 \
  --altadvertised 192.168.101.128

端口被占用

netstat -ulnp | grep -E "3478|3479"
# 如果被占用,杀掉占用进程
sudo pkill -f turnserver   # 如果是 Coturn
sudo pkill -f stunserver   # 如果是旧实例

辅助 IP 无法绑定

确认 IP 存在:

ip addr show | grep 192.168.101

若不存在,添加别名 IP:

sudo ip addr add 192.168.101.128/24 dev ens160

Windows 无法 ping 通 Linux

  • 检查 VMware 网络模式:Windows 为 NAT,Linux 为桥接。
  • 检查 Linux 防火墙:sudo systemctl stop firewalld 临时关闭测试。
  • 检查 VMware 虚拟网络编辑器是否启用了 NAT 路由。

欢迎来到XiaoZou123,这里是一个电脑极客、数码爱好者网站。我平时喜欢关注数码新闻,研究计算机技术。如果你看我头像觉得我是二次元,那我其实还算不上!
最后更新于 2026-08-01