--- tags: [计算机网络, NAT, SNAT, DNAT, PAT, STUN, TURN] create time: 2026-05-18 01:20 --- # NAT 原理与应用 ## 概述 NAT(Network Address Translation,网络地址转换)是 IPv4 时代最重要的"续命"技术之一——它让大量私有 IP 主机通过少数几个公网 IP 访问互联网。理解 NAT 的工作原理对于排查连接问题、设计分布式系统和部署 VPN 至关重要。 > [!QUESTION] NAT 为什么能工作? > NAT 的本质是一个中间人:它在修改经过的数据包的源或目的地址/端口。因为 TCP/IP 协议的端到端原则要求只有通信两端才应看到完整地址,而 NAT 在中间偷偷改了——这破坏了理论模型的"纯洁性",但解决了现实中的地址短缺问题。 ## NAT 分类速览 | 类型 | 全称 | 方向 | 修改字段 | 用途 | |------|------|------|---------|------| | **SNAT** | Source NAT | 出向 | 源 IP | 内网 → 外网 | | **DNAT** | Destination NAT | 入向 | 目的 IP+Port | 外网 → 内网服务器 | | **PAT** | Port Address Translation | 双向 | 同时改 IP+Port | 多主机共享单公网 IP | | **静态 NAT** | Static NAT | 双向一对一 | 固定映射 | 内网服务器暴露到公网 | ## SNAT(源地址转换)— 内网上网的钥匙 ### 工作流程 ```mermaid sequenceDiagram participant PC as 内网主机
192.168.1.100:45678 participant NAT as 路由器/NAT网关
eth0: 203.0.113.5
eth1: 192.168.1.1 participant Server as 外部 Web 服务器
93.184.216.34:80 PC->>NAT: SYN src=192.168.1.100:45678 dst=93.184.216.34:80 Note over NAT: NAT Table Entry:
192.168.1.100:45678 ↔ 203.0.113.5:50001 NAT->>Server: SYN src=203.0.113.5:50001 dst=93.184.216.34:80 Server-->>NAT: SYN-ACK dst=203.0.113.5:50001 Note over NAT: 反向查找 NAT Table
203.0.113.5:50001 → 192.168.1.100:45678 NAT-->>PC: SYN-ACK PC->>NAT: ACK src=192.168.1.100:45678 NAT->>Server: ACK src=203.0.113.5:50001 Note over PC,Server: ← 双方都不知道 NAT 的存在 → ``` ### iptables 实现 SNAT ```bash # 内网接口 eth1, 外网接口 eth0 sudo iptables -t nat -A POSTROUTING \ -s 192.168.1.0/24 -o eth0 -j MASQUERADE # MASQUERADE vs SNAT: # MASQUERADE: 自动获取 eth0 的当前 IP(适合动态 IP,如 DHCP/拨号) # SNAT: 指定固定 IP (适合静态 IP,性能略高) # 等价写法: sudo iptables -t nat -A POSTROUTING \ -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 203.0.113.5 ``` ```bash # 查看 NAT 表条目 $ sudo conntrack -L | head -10 tcp 6 119 SYN_SENT ... src=192.168.1.100 dst=93.184.216.34 src=203.0.113.5 dst=93.184.216.34 ``` ## DNAT(目的地址转换)— 反向代理 ### 典型场景:将公网 IP 的 80 端口转发到内网 Web 服务器 ```mermaid sequenceDiagram participant Client as 外部客户端
x.x.x.x:12345 participant FW as 防火墙/NAT
公网: 203.0.113.5:80 participant Web as 内网 Web
192.168.1.10:80 Client->>FW: SYN src=x.x.x.x:12345 dst=203.0.113.5:80 Note over FW: PREROUTING 链: DNAT
203.0.113.5:80 → 192.168.1.10:80 FW->>Web: SYN src=x.x.x.x:12345 dst=192.168.1.10:80 Note over Web: ← 注意: 源IP仍然是客户端真实IP (Full Cone) Web-->>FW: SYN-ACK dst=x.x.x.x:12345 FW->>Client: SYN-ACK Note over FW,Web: 回程路由需要配置: ip route add x.x.x.x via ... ``` ### iptables 实现 DNAT ```bash sudo iptables -t nat -A PREROUTING \ -d 203.0.113.5 -p tcp --dport 80 -j DNAT \ --to-destination 192.168.1.10:80 # 还需允许转发 sudo iptables -A FORWARD -p tcp -d 192.168.1.10 --dport 80 -j ACCEPT # 如果希望 Web 能看到客户端真实 IP(不启用 SNAT) sudo sysctl net.ipv4.conf.all.accept_local=1 ``` ### Docker 的端口映射本质就是 DNAT + SNAT ```bash # docker run -p 8080:80 nginx # = DNAT: host:8080 → container_ip:80 # + SNAT: container reply 时把源 IP 改回 host IP iptables -t nat -A PREROUTING \ -d -p tcp --dport 8080 -j DNAT --to-destination :80 ``` ## PAT / NAPT(端口级 NAT)— 解决地址枯竭的关键 ### 核心机制 ``` 内网主机 NAT设备 公网IP:Port池 ───────── ─────── ───────────── 192.168.1.10:45678 ──→ 203.0.113.5:50001 203.0.113.5 192.168.1.11:45678 ──→ 203.0.113.5:50002 ← 多个内网IP 192.168.1.12:45678 ──→ 203.0.113.5:50003 ← 复用同一个公网IP 192.168.1.10:45679 ──→ 203.0.113.5:50004 ``` 一个公网 IP 最多可提供 **65535 个端口**,理论上支持约 6.5 万并发内网用户。实际受限于内核文件描述符限制(通常 ~6.5 万)。 ## NAT 对 TCP 的影响 ### TIME_WAIT 放大效应 由于所有内网主机的连接都映射到同一个公网 IP,NAT 设备的 TIME_WAIT 连接数会远超单机。当 NAT 重启时,所有半关闭的连接都会丢失。 ### FTP 的问题 FTP 使用**独立的控制连接和数据连接**,且在 HTTP body 中嵌入 IP 和端口信息: ``` FTP 控制通道: PORT 192,168,1,100,180,13 ← "数据连接请发到这个IP和端口" ``` NAT 后的内网 IP 对公网不可达!解决方案: | 方案 | 说明 | |------|------| | **FTP ALG** | NAT 设备深度解析 FTP 控制流,改写 PORT 命令中的 IP | | **被动模式 PASV** | 服务器提供监听端口,由客户端发起数据连接 | | **SFTP over SSH** | 完全绕过 FTP,用加密隧道传输文件 | > [!warning] NAT ALG 的隐患 > ALG (Application Layer Gateway) 需要深度解析应用层协议内容,容易出错且增加安全风险。现代实践中更倾向于 SFTP/SCP 替代 FTP。 ## NAT 穿透技术 ### NAT 类型分类 | 类型 | 行为 | 连通性 | |------|------|--------| | Full Cone | 任何外部地址都能发送 UDP 到你的映射端口 | ⭐⭐⭐⭐⭐ 最佳 | | Restricted Cone | 仅已知 IP 能发 | ⭐⭐⭐⭐ | | Port Restricted Cone | 仅已知 IP+Port 能发 | ⭐⭐⭐⭐ | | Symmetric | 不同目的地获得不同映射端口 | ⭐⭐ 最难穿透 | ### 常用穿透方案 ```mermaid flowchart TD P1["STUN
Session Traversal Utilities for NAT"] -->|"1. 告诉对方我的公网 IP:Port"| P2["TURN
Traversal Using Relays around NAT"] P2 -->|"2. 中继服务器转发电文"| P3["ICE
Interactive Connectivity Establishment"] P3 -->|"3. 尝试直连 → 失败则 fallback 到 TURN"| Final["WebSocket/WebRTC ✅"] style P1 fill:#DDA0DD,color:#000 style P2 fill:#FFD700,color:#000 style P3 fill:#98FB98,color:#000 ``` ### ICE 流程 ``` Step 1: Host Candidate — 本机直接 IP(局域网内直连最快) Step 2: SRFLX Candidate — STUN 探测得到的公网映射地址 Step 3: Relay Candidate — TURN 服务器分配的 relay 地址 排序优先级: Host > SRFLX > Relay 尝试顺序: 先试直连,超时后走中继 ``` ## NAT64 / DNS64 IPv6 过渡的重要机制:IPv6-only 客户端访问 IPv4-only 服务器 ``` 客户端 (IPv6): 2001:db8::1 DNS64: 将 A 记录 93.184.216.34 → AAAA 记录 ::ffff:93.184.216.34 NAT64 网关: 拦截 IPv6 包 → 转换为 IPv4 包 → 发送到 Internet 回包: IPv4 → IPv6 转换 → 返回客户端 ``` ```bash # Linux NAT64 内核模块 modprobe nf_nat_ipv6 sysctl -w net.ipv6.conf.all.forwarding=1 ip6tables -t nat -A POSTROUTING -s fd00::/64 -j SNAT --to-source 2001:db8:64::1 ``` ## 关联笔记 - [[hhs/NETWORK/CIDR与子网划分]] — NAT 使用 RFC1918 私有地址空间 - [[hhs/NETWORK/TCP状态机详解]] — NAT 影响 TCP 连接生命周期 - [[hhs/NETWORK/DNS原理与优化]] — DNS64 将 A 记录转为 AAAA 记录