7.7 KiB
7.7 KiB
tags, create time
| tags | 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(源地址转换)— 内网上网的钥匙
工作流程
sequenceDiagram
participant PC as 内网主机<br/>192.168.1.100:45678
participant NAT as 路由器/NAT网关<br/>eth0: 203.0.113.5<br/>eth1: 192.168.1.1
participant Server as 外部 Web 服务器<br/>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:<br/>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<br/>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
# 内网接口 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
# 查看 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 服务器
sequenceDiagram
participant Client as 外部客户端<br/>x.x.x.x:12345
participant FW as 防火墙/NAT<br/>公网: 203.0.113.5:80
participant Web as 内网 Web<br/>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<br/>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
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
# docker run -p 8080:80 nginx
# = DNAT: host:8080 → container_ip:80
# + SNAT: container reply 时把源 IP 改回 host IP
iptables -t nat -A PREROUTING \
-d <host_ip> -p tcp --dport 8080 -j DNAT --to-destination <container_ip>: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 | 不同目的地获得不同映射端口 | ⭐⭐ 最难穿透 |
常用穿透方案
flowchart TD
P1["STUN<br/>Session Traversal Utilities for NAT"] -->|"1. 告诉对方我的公网 IP:Port"| P2["TURN<br/>Traversal Using Relays around NAT"]
P2 -->|"2. 中继服务器转发电文"| P3["ICE<br/>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 转换 → 返回客户端
# 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 记录