03 — NAT 与端口映射
03 — NAT 与端口映射
这是 NAT 问答专题。完整机制与 Linux hook 见 NAT、conntrack 与防火墙。
端口属于哪一层?(概念纠偏)
| 层 | 名称 | 核心概念 | 例子 |
|---|---|---|---|
| L7 | 应用层 | 信件内容 | HTTP, SSH, DHCP |
| L4 | 传输层 | 端口 (Port) | TCP 80, UDP 53 |
| L3 | 网络层 | IP 地址 | 192.168.1.1 |
| L2 | 数据链路层 | MAC 地址 | AA:BB:CC:DD:EE:FF |
端口是传输层(L4)的专属概念。 它的作用是区分同一台电脑上不同的进程——浏览器用端口 A 访问网页,微信用端口 B 发消息。
为什么 NAT 要改端口?(NAPT 的诞生)
基础 NAT 的困境
纯粹的 NAT 只改 IP 地址。但你家只有一个公网 IP。如果手机(192.168.1.10)和电脑(192.168.1.20)同时访问百度的 80 端口:
- 只改源 IP → 两个包的源 IP 都变成同一个公网 IP
- 百度回包到公网 IP 时,路由器就懵了:"这个包是给手机还是给电脑的?"
NAPT(网络地址端口转换)
现代路由器用的都是 NAPT (Network Address Port Translation),也叫 PAT (Port Address Translation),俗称端口复用。
端口发生冲突或转换策略要求时,路由器可在改源 IP 的同时分配一个外部源端口(如 45000)。NAT 不保证每条 flow 都改端口,也不保证只依据端口识别回包:
手机: 192.168.1.10:30000 → 公网IP:45000
电脑: 192.168.1.20:40000 → 公网IP:45001
回包时,路由器看端口号就知道该还给谁。
每个包端口都变吗?(连接跟踪 Conntrack)
绝对不是!如果每个包端口都变,TCP 连接当场就断了。
TCP 是面向连接的协议,靠四元组(源IP、源端口、目标IP、目标端口)维持状态。
Connection Tracking(连接跟踪)机制
当手机(端口 54321)对百度发起 TCP 三次握手的第一个 SYN 包时:
- 路由器执行 NAT,随机挑选一个空闲端口,比如
10056 - 在内存里建立带协议状态和超时的 conntrack/NAT 映射
协议: TCP
内网: 192.168.1.100:54321
外网: 203.0.113.5:10056
目标: 198.51.100.20:443(文档示例地址)
状态: ESTABLISHED
超时: 由协议状态和实现配置决定
在这条 TCP 连接结束(四次挥手断开)之前,这台手机发往百度的成千上万个数据包,全都会固定使用 10056 端口。
连接结束并从 conntrack 超时/删除后,相关绑定才可回收;异常断连也依赖超时清理。
端口号范围
NAT 的外部端口分配范围和算法由实现决定。IANA 的动态/私有端口分类、主机的 ephemeral port 配置和 NAT 设备的可用端口池是三个相关但不同的概念。
入站困境:为什么 NAT 让内网服务不可达
从内往外发(出站),一切完美——NAT 表会自动创建条目。
但从外往内连(入站),NAT 表里根本没有对应条目:
朋友想连你的
203.0.113.8:25565,若没有已有映射或静态 DNAT,网关无法确定内部目标;状态防火墙通常也会丢弃。严格说,丢弃是转发/防火墙策略结果,不是 NAT 这三个字天然规定的动作。
这就是为什么:
- 传统的**端口映射(Port Forwarding)**需要在路由器上手动配置
- 在 CGNAT 环境下,端口映射也失效(你根本没有公网 IP)
- 可使用端口映射能力、内向外隧道、NAT 打洞或中继;不同工具的直连/中继机制并不相同