NAT穿越技术详解
约 1868 字大约 6 分钟
nattraversal
2025-07-08
概述
NAT(Network Address Translation)解决了IPv4地址耗尽的问题,但也破坏了端到端通信模型。NAT穿越(NAT Traversal)是一系列允许NAT后面的设备建立直接连接的技术。本文深入解析各种NAT类型及对应的穿越方案。
NAT类型分类
Full Cone NAT(完全锥型)
一旦内部地址(iAddr:iPort)映射到外部地址(eAddr:ePort),所有发到(eAddr:ePort)的包都会被转发到(iAddr:iPort),无论来源。
内部主机 192.168.1.10:5000
↕ NAT映射
外部地址 203.0.113.1:8000
任何外部主机都可以发送数据到 203.0.113.1:8000
数据会被转发到 192.168.1.10:5000Restricted Cone NAT(受限锥型)
只有内部主机曾经发送过数据包的外部IP,才能通过映射端口发送数据到内部主机。
内部主机 → 发送到 Server_A (1.2.3.4)
NAT映射: 192.168.1.10:5000 → 203.0.113.1:8000
只有 1.2.3.4 可以通过 203.0.113.1:8000 到达内部主机
其他IP被丢弃(即使知道端口8000)Port Restricted Cone NAT(端口受限锥型)
在受限锥型的基础上,进一步限制外部端口。只有内部主机曾经发送到的精确IP:Port组合,才能回复。
内部主机 → 发送到 1.2.3.4:9999
NAT映射: 192.168.1.10:5000 → 203.0.113.1:8000
只有 1.2.3.4:9999 可以通过 203.0.113.1:8000 到达内部主机
1.2.3.4:8888(不同端口)会被丢弃Symmetric NAT(对称型)
对于每个不同的目标地址:端口,NAT都会创建不同的映射。这是最严格的NAT类型,直接穿越最困难。
内部主机 → Server_A (1.2.3.4:80) → 映射为 203.0.113.1:8000
内部主机 → Server_B (5.6.7.8:80) → 映射为 203.0.113.1:9000
↑ 不同的外部端口!NAT类型检测
STUN协议
STUN(Session Traversal Utilities for NAT)允许NAT后的设备发现其公网地址和端口,以及NAT类型。
# 使用stunclient测试
stunclient stun.l.google.com:19302
# Python STUN检测
import stun
nat_type, external_ip, external_port = stun.get_ip_info(
stun_host='stun.l.google.com',
stun_port=19302
)
print(f"NAT Type: {nat_type}")
print(f"External IP: {external_ip}")
print(f"External Port: {external_port}")STUN报文格式:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0 0| STUN Message Type | Message Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Magic Cookie (0x2112A442) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
| Transaction ID (96 bits) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+TURN中继
TURN(Traversal Using Relays around NAT)在STUN和打洞都失败时(通常是Symmetric NAT对Symmetric NAT),通过中继服务器转发流量。
# coturn TURN服务器配置 (/etc/turnserver.conf)
listening-port=3478
tls-listening-port=5349
relay-device=eth0
listening-ip=0.0.0.0
external-ip=203.0.113.1
realm=turn.example.com
server-name=turn.example.com
# 认证
lt-cred-mech
user=username:password
# 或使用数据库
# userdb=/var/lib/turn/turndb
# 安全设置
no-multicast-peers
no-cli
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=172.16.0.0-172.31.255.255ICE框架
ICE(Interactive Connectivity Establishment)是一个综合框架,整合了STUN和TURN,用于找到两个端点之间的最佳通信路径。
ICE候选地址优先级:
优先级(从高到低):
1. Host candidate(直连,延迟最低)
2. Server reflexive candidate(STUN穿越)
3. Relay candidate(TURN中继,延迟最高但最可靠)
优先级公式:
priority = (2^24) × type_preference + (2^8) × local_preference + component_idICE交互流程:
UDP打洞(Hole Punching)
UDP打洞是NAT穿越的核心技术,利用NAT设备会在出站时创建映射的特性。
打洞成功率与NAT类型关系:
| Peer A ↓ / Peer B → | Full Cone | Restricted | Port Restricted | Symmetric |
|---|---|---|---|---|
| Full Cone | 100% | 100% | 100% | 100% |
| Restricted | 100% | 100% | 100% | ~90% |
| Port Restricted | 100% | 100% | 100% | ~50% |
| Symmetric | 100% | ~90% | ~50% | ~10% |
UPnP / NAT-PMP / PCP
这些协议允许应用程序请求NAT设备创建端口映射:
# UPnP端口映射(使用miniupnpc)
# 查看外部IP
upnpc -s
# 添加端口映射
upnpc -a 192.168.1.10 8080 8080 TCP
# 删除端口映射
upnpc -d 8080 TCP
# 列出现有映射
upnpc -l# Python UPnP端口映射
import miniupnpc
upnp = miniupnpc.UPnP()
upnp.discoverdelay = 200
upnp.discover()
upnp.selectigd()
# 获取外部IP
external_ip = upnp.externalipaddress()
print(f"External IP: {external_ip}")
# 添加端口映射
upnp.addportmapping(
8080, # 外部端口
'TCP', # 协议
'192.168.1.10', # 内部IP
8080, # 内部端口
'My App', # 描述
'' # 远程主机(空=所有)
)WebRTC中的NAT穿越
WebRTC内置了完整的ICE框架:
const config = {
iceServers: [
// STUN服务器
{ urls: 'stun:stun.l.google.com:19302' },
// TURN服务器(备用)
{
urls: 'turn:turn.example.com:3478',
username: 'user',
credential: 'pass'
}
],
iceCandidatePoolSize: 10,
iceTransportPolicy: 'all' // 'all' 或 'relay'(仅TURN)
};
const pc = new RTCPeerConnection(config);
// 收集ICE候选地址
pc.onicecandidate = (event) => {
if (event.candidate) {
// 通过信令服务器发送给对端
signalingChannel.send({
type: 'candidate',
candidate: event.candidate
});
}
};
// ICE连接状态监控
pc.oniceconnectionstatechange = () => {
console.log('ICE state:', pc.iceConnectionState);
// new → checking → connected → completed
// 或 → failed → disconnected → closed
};总结
NAT穿越是P2P通信的核心挑战。从简单的STUN发现到复杂的ICE框架,每种技术适用于不同的NAT场景。在实际应用中,推荐使用ICE框架(整合STUN+TURN),保证在各种NAT组合下都能建立连接:优先直连,必要时回退到中继。WebRTC已将这些技术封装为标准API,大幅降低了P2P应用的开发门槛。
贡献者
更新日志
9f6c2-feat: organize wiki content and refresh site setup于