Files
cs-note/hhs/NETWORK/03-网络层/08-NAT原理与应用.md
T
2026-05-24 11:42:38 +08:00

7.7 KiB
Raw Blame History

tags, create time
tags create time
计算机网络
NAT
SNAT
DNAT
PAT
STUN
TURN
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

关联笔记