小明的学习笔记

03 — NAT 与端口映射

4 分钟阅读

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 包时:

  1. 路由器执行 NAT,随机挑选一个空闲端口,比如 10056
  2. 在内存里建立带协议状态和超时的 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 打洞或中继;不同工具的直连/中继机制并不相同