NAT 内网穿透详解:揭秘网络连接背后的奥秘
NAT 内网穿透详解:揭秘网络连接背后的奥秘
dong4j前言
NAT (网络地址转换, Network Address Translation) 的由来与互联网的发展历史密切相关, 主要是为了解决 IPv4 地址资源紧张问题, 同时增强网络安全性和管理灵活性.
相关文章:
- 先导篇:我的 HomeLab 概要;
- 硬件篇:介绍我所拥有的硬件设备;
- 网络篇:包括网络环境、异地组网与网络安全;
- 服务篇:使用 Docker 搭建的各类服务;
- 数据篇:包括数据存储方案、备份方案和数据恢复方案;
- HomeLab数据同步:构建高效的数据同步网络
- HomeLab数据备份:打造坚实的数据安全防线
- HomeLab 网络续集:升级 10G 网络-再战 10 年
- NAT 内网穿透详解:揭秘网络连接背后的奥秘
背景与由来
1. IPv4 地址枯竭问题
IPv4 使用 32 位地址空间, 最多可以提供约 43 亿个唯一地址. 随着互联网的普及, 联网设备数量迅速增长, 特别是 1990 年代后期, 地址分配紧张的问题愈发明显.
早期解决方案如子网划分和无类别域间路由 (CIDR) 延缓了地址耗尽, 但并不能彻底解决问题.
2. 私有网络需求
- 很多组织和企业需要将大量内部设备联网, 但没有足够的公有 IPv4 地址.
- RFC 1918 在 1996 年提出了私有地址标准, 为内部网络预留了一些专用地址段:
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
- 私有地址无法直接通过互联网通信, 需要一个机制将其转换为公有地址.
3. NAT 的诞生
- NAT 概念最早在 1994 年由 IETF 提出, 记录在 RFC 1631 中, 作为一种解决 IPv4 地址短缺问题的方法.
- NAT 允许多个设备通过一个或少量的公有 IP 地址访问互联网. 它通过在路由器或防火墙上修改 IP 数据包的源地址或目标地址, 实现地址的映射.
NAT 的作用
- 缓解地址枯竭: 内部设备使用私有地址, 多个设备可以共享一个公有地址访问互联网.
- 提高安全性: 外部无法直接访问内部设备, 形成一定的网络隔离.
- 网络管理灵活性: 组织内部地址可以自行规划, 避免更改 ISP 时需调整内部网络结构.
NAT 的类型
- 静态 NAT: 一个私有地址映射到一个固定的公有地址, 常用于需要外部访问的设备.
- 动态 NAT: 一组私有地址动态映射到一组公有地址, 基于需求分配.
- 端口地址转换 (PAT/NAT Overload): 使用单个公有 IP 地址, 通过端口号区分多个内部设备的连接, 是最常见的 NAT 类型.
后续发展
- 随着 IPv6 的推出, NAT 的角色开始被重新审视. IPv6 提供了 128 位地址空间, 几乎可以为每台设备分配一个唯一地址.
- 然而, 由于 IPv6 的部署进展缓慢, NAT 仍然广泛应用于 IPv4 网络, 并在双栈环境下继续扮演重要角色.
总结
NAT 的诞生充分体现了互联网早期技术对现实问题的灵活应对. 即使未来 IPv6 普及, NAT 的概念在某些场景 (如隐私保护) 中仍可能保留其价值.
接下来, 我将详细介绍 NAT 的实现细节, 包括 NAT 表的构建、地址转换过程, 以及如何通过 NAT 实现内网穿透.
概述
在我们家中的局域网内部, 网络设备通常都使用所谓的私有 IP 地址, 例如192.168.xx.xx
. 当我们在网络上发送数据包时, 如果填写的是这样的私有 IP 地址, 那么在网络收到回复的数据包时可能会遇到一个难题:因为成千上万的用户都可能在使用同样的私有 IP 地址——比如192.168.31.2
. 网络无法仅凭这些内部地址来判断究竟应该将数据包转发给哪一个设备.
因此, 为了使局域网内的私有 IP 能够向外部公有 IP 发送和接收信息, 我们需要进行一种称为网络地址转换 (NAT)的机制. 简单来说就是将内部的私有 IP 地址转换为外部的公有 IP 地址的过程.
在局域网与互联网之间, 通常会有一个专门的设备或服务来执行这一转换, 它确保了即使多个内部设备共享相同的私有 IP 地址, 也能正确地接收和发送数据. 这个转换过程可以在路由器、防火墙或者 NAT 设备中完成.
NAT 的工作原理
在你的家庭网络中, 你拥有了一个独立的公网 IP 地址 20.20.20.20
, 并且这个 IP 地址已经配置在你家内置了 NAT 功能的路由器上. 你的手机、电脑以及其他需要连接到互联网的设备都组成了一个局域网, 每个设备都有一个私有 IP 地址.
发送流程
当你想在电脑上访问公网上的一个特定服务, 比如 IP 地址为 30.30.30.30
的服务时, 你需要通过 NAT 路由器来完成这个请求. 当你使用命令行工具 (如 ifconfig) 在你的电脑上查看网络配置时, 你会看到你的电脑的私有 IP 地址 192.168.31.2
:
在准备发送数据包的过程中, 你的电脑内核协议栈会构建一个包含源 IP 地址 192.168.31.2
和目标 IP 地址 30.30.30.30
的 IP 数据包. 这个 IP 数据包的报头包含了关于如何将数据包从源点传输到终点的全部信息.
当这个 IP 数据包被发送到 NAT 路由器时, 路由器的网络地址转换 (SNAT) 功能会介入: 将原始数据包中的私有 IP 地址 192.168.31.2
替换为分配给你的公网 IP 地址 20.20.20.20
, 这个过程称为源地址转换 (Source Network Address Translation) .
同时, NAT 路由器会记住这个映射关系, 即在内部维护一张映射表, 记录着私有 IP 地址和公网 IP 地址之间的对应关系. 这条映射信息对于后续将响应数据包正确地转发回原始设备至关重要.
修改后的数据包现在包含源 IP 地址 20.20.20.20
和目标 IP 地址 30.30.30.30
, 并经过互联网上的多个路由器进行传输和转发. 这些路由器根据数据包中的目标 IP 地址来决定如何将数据包发送到下一个目的地. 到这里发送流程结束.
响应流程
当接收端处理完你的请求并发送响应时, 它会在其构造的数据包中填写自己的 IP 地址作为源地址, 即 30.30.30.30
, 并将目标地址设置为你的公网 IP 地址, 即 20.20.20.20
. 这个修改后的数据包会被发送回 NAT 路由器.
NAT 路由器接收到来自公网的响应后, 会检查其内部维护的映射记录表. 在这个表中, 它会找到一个与公网 IP 地址 20.20.20.20
相关联的私有 IP 地址, 即之前留下的映射记录 192.168.31.2 -> 20.20.20.20
.
NAT 路由器根据这条映射信息知道原始数据包是从你的电脑发送出去的. 因此, 它会执行目的地址转换 (Destination Network Address Translation, DNAT) 功能, 将数据包的目标 IP 地址从公网 IP 地址 20.20.20.20
修改为内部网络的私有 IP 地址 192.168.31.2
.
随后, NAT 路由器会将这个修改后的数据包转发回局域网内的你的电脑. 你的电脑收到数据包后, 会根据其目标 IP 地址识别出这是一个针对它的响应.
NAT (网络地址转换) 在用户毫不知情的情况下, 隐秘地改变了 IP 数据包中的源地址和目标地址. 对于原始的发送者和接收者而言, 这种更改是完全看不见的. 这正是 NAT 运作的核心机制:**它确保了即使是使用私有 IP 地址的设备也能够安全、有效地与互联网上的任何公网 IP 进行通信, 而无需每个设备都有一个唯一的公网 IP 地址. **
NAPT 的工作原理
概述
在了解了 NAT 的工作原理后, 你可能会产生一个疑问:局域网中不仅有你的电脑, 还有其他设备如手机、平板等, 它们各自的映射记录也将是 192.168.xx.xx -> 20.20.20.20
. 这看起来没问题, 但当我们需要接收响应时, NAT 路由器将如何知道哪个响应应该发送给哪一个内部的设备呢?
这个问题确实很重要, 因为如果 NAT 无法区分内部网络的多个连接, 那么它就无法正确地将外部的响应数据包转发回特定的内部设备. 为了解决这个问题, 我们需要引入额外的信息来标识局域网内的每个网络连接.
一个简单而有效的解决方案是使用端口. 每个内部设备在发起网络请求时, 都会分配一个唯一的端口号, 这通常是通过传输控制协议 (TCP) 或用户数据报协议 (UDP) 的源端口实现的. 这样, NAT 路由器就可以根据这些端口号来区分不同的内部设备, 即使它们的私有 IP 地址相同.
NAPT 原理解析
IP 数据包 (在网络层的协议) 不包含端口号信息. 端口号信息是存储在传输层 (如 TCP 或 UDP) 的数据报头中的. 当计算机发送一个 IP 数据包时, 它会在网络层包含源 IP 地址和目标 IP 地址. 但在传输层, TCP 或 UDP 协议会添加额外的头部, 其中包括源端口号和目标端口号.
于是流程就变成了下面这样子. 当你准备发送数据包的时候, 你的电脑内核协议栈就会先构造一个 TCP 或者 UDP 数据报头, 里面写入端口号, 比如发送端口是5000
, 接收端口是3000
, 然后在这个基础上, 加入 IP 数据报头, 填入发送端和接收端的 IP 地址. 那数据包长这样.
数据包传输流程
假设, 发送端IP 地址填的就是192.168.31.2
, 接收端IP 地址就是30.30.30.30
. 将数据包发到 NAT 路由器中. 此时 NAT 路由器会将 IP 数据包里的源 IP 地址和端口号修改一下, 从192.168.31.2:5000
改写成20.20.20.20:6000
. 并且还会在 NAT 路由器内部留下一条 192.168.31.2:5000 -> 20.20.20.20:6000
的映射记录. 之后数据包经过公网里各个路由器的转发, 发到了接收端30.30.30.30:3000
, 到这里发送流程结束.
当接收端准备发送响应时, 它会在数据包中写入原始请求源的 IP 地址 (即你的公网 IP 20.20.20.20
) 作为源地址, 以及目标 IP 地址 (即 NAT 路由器的内部端口 6000
) , 因为这是它接收到数据的来源. 然后, 这个修改后的数据包会被发送回 NAT 路由器.
NAT 路由器在处理这个响应时, 会查找到之前留下的映射记录:192.168.31.2:5000 -> 20.20.20.20:6000
. 基于这个记录, NAT 会将数据包的目的 IP 地址和端口从 20.20.20.20:6000
修改回你的私有网络内的 IP 地址 192.168.31.2
以及对应的端口号 5000
, 之后将其转发给你的电脑上.
如果局域网内有多个设备, 他们就会映射到不同的公网端口上, 毕竟端口最大可达 65535, 完全够用. 这样大家都可以相安无事. 像这种同时转换 IP 和端口的技术, 就是NAPT (Network Address Port Transfer , 网络地址端口转换 ) .
Ping 命令
这里出现了一个疑问. 通常我们认为只有那些包含端口信息的网络协议才能被 NAT (网络地址转换) 识别并进行转发. 然而, 这如何解释 ping 命令的工作原理呢?ping 命令是基于 ICMP 协议的, 而 ICMP 协议的报文中并不包含端口信息. 尽管如此, 我们仍然能够正常地使用 ping 命令与公网上的机器通信, 并接收到回应包. 这是怎么回事呢?
实上针对 ICMP 协议, NAT 路由器做了特殊处理. ping 报文头里有个Identifier
的信息, 它其实指的是放出 ping 命令的进程 id. 对 NAT 路由器来说, 这个Identifier
的作用就跟端口
一样.
另外, 当我们去抓包的时候, 就会发现有两个
Identifier
, 一个后面带个BE (Big Endian)
, 另一个带个LE (Little Endian)
. 其实他们都是同一个数值, 只不过大小端不同, 读出来的值不一样. 就好像同样的数字 345, 反着读就成了 543. 这是为了兼容不同操作系统 (比如 linux 和 Windows) 下大小端不同的情况.
内网穿透
概述
当使用 NAT (网络地址转换) 上网时, 一个基本的前提是内网机器必须主动向公网 IP 发起请求, 这样 NAT 才能将内网的 IP 地址和端口映射到外网的 IP 地址和端口上. 然而, 如果公网上的机器试图主动连接到内网机器, 这个请求将会在 NAT 路由器处受阻.
由于 NAT 路由器上没有相应的 IP 地址和端口映射记录, 因此它不会将数据转发到内网的任何机器.
例如, 假设你在家里电脑上启动了一个 HTTP 服务, 地址是192.168.31.2:5000
, 但你在公司办公室试图通过手机访问这个服务时, 会发现无法连接. 这就引出了一个问题:有没有办法让外网机器访问内网的服务呢?答案是肯定的. 有一句话说得好, 任何问题都可以通过增加一个中间层来解决, 如果不行, 那就再加一层. 在这个情况下, 这个原则同样适用.
归根结底, 由于 NAT (网络地址转换) 的存在, 我们通常只能从内网向外网主动发起连接. 如果内网机器没有首先建立连接, NAT 设备就不会创建相应的映射关系, 而没有这个映射关系, 外网的数据就无法被转发到内网.
为了解决这个问题, 我们可以在公网上部署一台服务器 x, 并为其分配一个可访问的域名. 然后, 让内网的服务主动连接到这台服务器 x, 这样 NAT 路由器就会建立相应的映射关系. 之后, 任何外网的访问请求都可以发送到服务器 x, 服务器 x 再将这些请求转发到内网机器, 并将内网机器的响应返回给请求者, 从而实现数据的双向通信. 这个过程就是我们所说的内网穿透.
至于服务器 x, 你并不需要自己搭建, 市面上已经有许多现成的内网穿透服务. 比如使用某壳提供的内网穿透解决方案, 或者开源的内网穿透服务:
到这里, 我们就可以回答这个问题:为什么我在公司里访问不了家里的电脑?
那是因为家里的电脑在局域网内, 局域网和广域网之间有个 NAT 路由器. 由于 NAT 路由器的存在, 外网服务无法主动连通局域网内的电脑.
即时通讯软件的网络通信机制
我家电脑位于我们小区的局域网中, 而老婆闺蜜家的电脑则位于她们小区的局域网内. 既然两台电脑都处于各自的局域网中, 且 NAT 只允许内网设备主动连接到外网, 那我电脑上登录的 QQ 是如何与老婆闺蜜电脑上的 QQ 建立连接的呢?
这种提问方式隐含了一个错误的假设, 即认为两个 QQ 客户端应用能够直接建立点对点的连接. 但实际情况并非如此, 两个 QQ 客户端之间的通信是间接的, 它们之间还有一个中间环节, 那就是通讯软件服务器:
换言之, 当两个位于内网的 QQ 客户端登录时, 它们都会主动与公网上的通讯服务器建立连接, 此时各自的 NAT 路由器会记录下相应的映射条目. 当一个客户端通过 QQ 发送消息时, 这些数据首先会传输到服务器, 然后由服务器将其转发到另一个客户端. 反之亦然, 通过这种机制, 两台处于内网的计算机得以实现数据的交换.
点对点 (P2P) 网络通信
在 P2P 下载等双向通信场景中, 通常会涉及到 NAT 穿越的问题. 假设还是 A 和 B 两个局域网内的机子, A 内网对应的 NAT 设备叫NAT_A
, B 内网里的 NAT 设备叫NAT_B
, 和一个第三方服务器Server
.
通过第三方服务器帮助两台位于不同局域网的机器 A 和 B 建立连接的简化流程如下:
- Step1 + Step2: A 机器首先主动连接第三方服务器, 其 NAT 设备 (NAT_A) 记录下 A 的内网和外网地址的映射关系. 同时,
Server
记下了 A 的外网 IP 和端口. - Step3 + Step4: B 机器也进行同样的操作, 主动连接服务器, NAT_B 记录下 B 的内网和外网地址映射,
Server
同样获取了 B 的外网 IP 和端口. - Step5 + Step6 + Step7: 关键步骤来了,
Server
通知 A, 让 A 主动向 B 的外网 IP 和端口发送 UDP 消息. 此时 NAT_B 收到这个 A 的 UDP 数据包时, 这时候根据 NAT_B 的设置不同 可能存在 2 种情况:- NAT_B 上没有关于 A 的映射关系导致直接丢包, 不过丢包没关系, 这个操作的 目的是 给 NAT_A 上留下 有关 B 的映射关系;
- 有可能因为延迟或消息达到的顺序问题, NAT_B 已经有了关于 A 的映射关系, 此时 A 和 B 就能正常通信了;
- Step8 + Step9 + Step10: 跟 5,6,7 步骤一样,
Server
通知 B, 让 B 向 A 的外网 IP 和端口发送 UDP 消息. NAT_B 上也留下了关于 A 的映射关系, 这时候由于之前 NAT_A 上有过关于 B 的映射关系, 此时 NAT_A 就能正常接受 B 的数据包, 并将其转发给 A. 到这里 A 和 B 就能正常进行数据通信了. 这就是所谓的 NAT 打洞. - Step11: 注意, 之前我们都是用的 UDP 数据包, 目的只是为了在两个局域网的 NAT 上打个洞出来, 实际上大部分应用用的都是 TCP 连接, 所以, 这时候我们还需要 A 主动向 B 发起 TCP 连接(比如我们熟知的 WireGuard). 到此, 我们就完成了两端之间的通信.
可能会有这样的疑问:既然 UDP 已经使用了一个端口, 那么 TCP 再使用相同的端口, 会不会出现端口重复占用的错误?
实际上, 这种情况并不会发生. 端口重复占用的错误通常出现在两个 TCP 连接没有使用 SO_REUSEADDR 选项, 并且尝试在同一个 IP 地址上使用相同的端口. 然而, UDP 和 TCP 之间并不会引发这样的错误.
原因在于, 在 Linux 内核中, 网络数据包是根据五元组 (传输协议、源 IP、目的 IP、源端口、目的端口) 来唯一确定接收者的. 当两个连接的五元组完全相同时, 内核就无法判断数据应该发送给哪个连接. 但由于 UDP 和 TCP 的 传输协议 不同, 即使它们使用了相同的 IP 地址和端口, 五元组也是不同的.
因此, UDP 和 TCP 可以共享相同的端口而不会发生冲突.
UDP 打洞的局限性
从 2019 年开始, 一些传统的网络穿透技术 (如 pwnat) 不再有效. pwnat 是一种创新的网络穿透方法, 它允许设备在没有代理服务器、第三方服务器、UPnP、DMZ 设置、源端口欺骗或 DNS 转换的情况下, 实现 NAT 环境下的点对点通信.
工作原理
1. 服务端的操作
模拟发送请求: 服务端启动后, 会不断向一个固定的、无法访问的 IP 地址 (比如 3.3.3.3) 发送 ICMP 回显请求包 (ICMP echo request) .
- 注意:3.3.3.3 只是一个占位符, 服务端不是真的期待从这个地址收到任何回应.
- 这些请求包会被服务端的 NAT 记录为 “有一个数据包正在发往 3.3.3.3, 等待返回数据”:
服务端内网 IP:端口 → NAT 公网 IP:端口 → 3.3.3.3
核心目标:
服务端的 NAT 设备在等待这些 ICMP 回显请求包的响应, 但由于 3.3.3.3 并不存在, 响应包自然不会到达.
2. 客户端的操作
- 伪装成一个跳跃点: 当客户端希望连接服务端时, 客户端需要知道 服务端的 IP 地址. 然后, 客户端发送一个 ICMP 超时包 (ICMP Time Exceeded) 到服务端.
- 这个超时包伪装成某个网络节点的响应, 告诉服务端:“你发往 3.3.3.3 的 ICMP 回显请求包超时了, 无法到达目的地. ”
- 关键点在于, 客户端发送的超时包中, 包含了服务端原始发送的 ICMP 回显请求包的完整信息 (原始数据包的内容) .
3. NAT 的行为
识别匹配的请求: 当客户端发送的 ICMP 超时包到达服务端的 NAT 时, NAT 会检查包的内容, 发现里面嵌套了服务端最初发往 3.3.3.3 的 ICMP 请求包.
智能转发: NAT 认为这个 ICMP 超时包是和服务端最初的 ICMP 请求包相关联的回应, 于是将包转发给 NAT 后面的服务端.
4. 服务端获取客户端的 IP 地址
提取 IP 信息: 服务端收到客户端伪装的 ICMP 超时包后, 从中提取出客户端的真实 IP 地址和端口.
完成连接: 服务端和客户端此时可以通过提取的地址建立点对点连接.
服务端(
192.168.1.2
) 启动后它会开始向固定地址 3.3.3.3 发送 固定的 ICMP 请求数据包, 同时会创建一个 NAT 记录:ICMP: 192.168.1.2:Identifier -> 40.40.40.40:xxx -> 3.3.3.3
, 这个请求数据包在经过 NAT 转换后的内容为:1
2
3
4
5
6
7
8
9
10
11IP Header
------------------------
源 IP: 40.40.40.40
目标 IP: 3.3.3.3
ICMP Header
-------------------
Type: 8 (Echo Request)
Code: 0
Identifier: 1111 (用于区分会话, pwnat 使用的固定值, 方便与客户端发送的 ICMP 超时包匹配)
Sequence Number: 2222 (用于追踪包的顺序, pwnat 使用的固定值, 方便与客户端发送的 ICMP 超时包匹配)客户端(
192.168.31.2
) 在只知道服务端对应的公网 IP (40.40.40.40
) 的情况下发送 伪造的超时包, 经过 NAT 转换后的内容为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21IP Header (伪造的超时包)
------------------------
源 IP: 20.20.20.20
目标 IP: 40.40.40.40
ICMP Header (超时包)
-------------------
Type: 11 (Time Exceeded)
Code: 0
Data: (服务端原始发出的 ICMP 回显请求的 IP 和 ICMP 头)
IP Header
------------------------
源 IP: 40.40.40.40
目标 IP: 3.3.3.3
ICMP Header
-------------------
Type: 8 (Echo Request)
Code: 0
Identifier: 1111 (用于区分会话, pwnat 使用的固定值, 方便与客户端发送的 ICMP 超时包匹配)
Sequence Number: 2222 (用于追踪包的顺序, pwnat 使用的固定值, 方便与客户端发送的 ICMP 超时包匹配)因为 ICMP 的请求和响应包匹配依赖于 IP 层的源 IP 和目标 IP 以及 ICMP 数据包头中的字段:Type、Code、Identifier 和 Sequence Number. 最主要的是构建 Identifier 和 Sequence Number, 因为前面服务器端发送的都是固定的 ICMP 请求数据包, 所以这里就非常容易伪造超时包.
伪造的数据包首先达到服务器前面的 NAT 设备, 在检查内后发现与服务端之前发往
3.3.3.3
的请求相关联, 认为这是一个合法的响应.因为 NAT 设备 已经有相关的 NAT 记录了(
ICMP: 2.168.1.2:Identifier -> 40.40.40.40:xxx -> 3.3.3.3
), 就会把目标 IP 为40.40.40.40
的数据包转发给192.168.1.2
.
NAT 类型
简介
NAT 分为两大类, 基本的 NAT 和 NAPT (即 端口 NAT, 英文全称为 Network Address/Port Translator) .
基本 NAT 与 NAPT
基本 NAT
这种类型的 NAT (Basic NAT) 主要是进行 IP 地址的转换, 它将私有网络中的 IP 地址映射到公网上的一个或多个公网 IP 地址. 它的可以分为:
- 静态 NAT (Static NAT): 静态 NAT 是一种将内部网络的私有 IP 地址映射到一个固定的公有 IP 地址的方法. 这种映射关系是由网络管理员手动配置的, 并且在映射建立后不会改变.特点为:
- 一对一映射:每个私有 IP 地址都对应一个唯一的公有 IP 地址.
- 永久性:映射关系是永久性的, 除非管理员手动更改配置.
- 动态 NAT (Dynamic NAT): 动态 NAT 是一种将内部网络的私有 IP 地址动态地映射到公有 IP 地址池中的地址的方法. 映射关系不是永久固定的, 而是根据需要动态分配和释放. 特点为:
- 多对多映射:私有 IP 地址可以映射到公有 IP 地址池中的任何一个地址.
- 临时性:映射关系在会话结束时释放, IP 地址可以重新分配给其他内部主机.
NAPT
也称为端口 NAT (Network Address/Port Translator) , 是一种更高级的 NAT 形式. 它不仅转换 IP 地址, 还转换传输层协议的端口号. NAPT 允许多个内部私有 IP 地址共享同一个公网 IP 地址, 通过不同的端口号来区分不同的数据流. 这是最常见的 NAT 类型, 广泛用于家庭和小型企业网络中, 因为它可以有效地解决公网 IP 地址不足的问题.
NAPT 又分为**锥型 (Cone) 和对称型 (Symmetric)**:
锥型 NAT (Cone NAT): 它在 NAT 转换时, 内部主机的私有 IP 地址和端口号与公网 IP 地址和端口号之间的映射关系是一致的, 不依赖于通信的目的地址.
- 特点:映射一致性, 一旦内部主机的私有端口映射到公网的一个端口, 无论目的地址是什么, 这个映射关系都保持不变.
如果 client A 使用内网端口 123 与 server A 通信, 并且 NAT 将公网端口 456 分配给 client A 的端口 123, 那么当 client A 使用同一个端口 123 向任何其他服务器 (如 server B) 发起通信时, NAT 仍然会将公网端口 456 分配给 client A 的端口 123.
对称型 NAT (Symmetric NAT): 是一种更严格的 NAPT, 它在进行 NAT 转换时, 不仅考虑内部主机的私有 IP 地址和端口号, 还考虑通信的目的地址. 对于每个新的目的地, NAT 可能会分配一个新的公网端口.
- 特点:映射依赖性, 映射关系依赖于目的地址. 即使内部主机的源端口相同, 如果目的地址不同, NAT 也会分配不同的公网端口.
如果 client A 已经使用内网端口 123 与 server A 通信, 并且 NAT 将公网端口 456 分配给这个通信, 那么当 client A 想要与 server B 通信时, NAT 可能会分配一个新的公网端口 (如 789) 给同一个内网端口 123.
锥型 NAT 与 对称型 NAT 的区别:
- **锥型 NAT (Cone NAT)**:映射关系与目的地址无关, 只要源地址 (内部主机的 IP 和端口) 相同, 映射关系就相同.
- 对称型 NAT:映射关系不仅与源地址有关, 还与目的地址有关. 即使是同一个源地址, 如果目的地址不同, 映射关系也可能不同.
锥型 NAT 分类
锥形 NAT 又可分为:完全圆锥体 (Full Cone NAT)、受限制的圆锥体 (Restricted Cone NAT)、端口受限制的圆锥体 NAT (Port Restricted Cone NAT) 三种.
完全圆锥体 NAT
Full Cone NAT
特性
- 最宽松的限制;
- 内网客户端与外部设备通信时, NAT 会创建一个映射 (内部 IP 和端口到外部 IP 和端口的映射) ;
- 任何外部设备, 只要知道这个映射的外部 IP 和端口, 都可以通过该端口直接与内网客户端通信;
规则
内网客户端主动发起连接时, NAT 创建的映射是固定的:内部 IP:端口 → 外部 IP(路由器公网 IP):端口;
外部设备只需知道外部的 IP 和端口, 就能发包到内网客户端, 无需内网客户端与之通信过;
内部服务 192.168.31.2:123
主动访问 30.30.30.30:789
时. 创建的 NAT 记录为:
1 | 内部IP:端口 (192.168.31.2:123) → 外址IP:端口 (20.20.20.20:456) |
此时 任何外部服务 都可以通过 20.20.20.20:456
访问到内部的 192.168.31.2:123
. 因为 NAT 设备并不关心报文的源 IP 和源端口号 (即报文来自谁) , 只要收到 匹配 NAT 记录的报文, 都能发送到内网设备.
此时内部服务 192.168.31.2:123
访问其他的服务比如 40.40.40.40:1234
, 因为源地址相同(192.168.31.2:123
) 的缘故, NAT 则不会再创建映射: NAT 不会为同一个内网地址和端口 (192.168.1.10:12345) 针对不同目标服务器创建多个映射.
受限制的圆锥体 NAT
Restricted Cone NAT
特性
- 中等限制;
- 内网客户端发起连接时, NAT 会创建一个映射;
- 只有客户端主动通信过的外部设备, 才能通过该映射访问内网客户端(记录允许的 IP).
规则
- 内网客户端发起连接时, NAT 创建映射:内部 IP:端口 → 外部 IP(路由器公网 IP):端口 → 允许目标 IP
- 只有客户端通信过的外部设备 (即目标 IP 在 NAT 映射记录中且通讯过的外部设备, 记还要匹配允许的 IP) , 才能通过映射访问客户端.
- 外部设备发来的数据包, 必须与客户端通信的外部 IP 和端口 一致.
内部服务 192.168.31.2:123
主动访问 30.30.30.30:789
时. 创建的 NAT 记录为:
1 | 内网IP:端口 (192.168.31.2:123) → 外部IP:端口 (20.20.20.20:456) → 允许目标IP (30.30.30.30) |
此时只有来自 30.30.30.30
任意端口的请求才能通过 20.20.20.20:456
访问到内部的 192.168.31.2:123
.
比如来自 40.40.40.40
的请求则不能访问内部服务, 因为它没有在允许目标地址中(内网设备正在与哪些外部设备通信) 此时必须由内部服务先发起请求(40.40.40.40:xxx
) 以增加新的允许的目标 IP 记录才能让 Server C 访问:
1 | 内网IP:端口 (192.168.31.2:123) → 外部IP:端口 (20.20.20.20:456) → 允许目标IP (30.30.30.30 & 40.40.40.40) |
这样的 NAT 安全性有一定的提高, 但是也提高了打洞难度. 两台内网设备需要互相给对方发送一个报文, 才能打洞成功.
端口受限制的圆锥体 NAT
Port Restricted Cone NAT
特性
- 最严格的限制;
- 内网客户端发起连接时, NAT 会创建一个映射;
- 只有客户端主动通信过的外部设备, 才能通过该映射访问内网客户端(记录允许的 IP + Port).
规则
内网客户端发起连接时, NAT 创建映射:内部 IP:端口 → 外部 IP(路由器公网 IP):端口 → 允许的目标 IP+端口
外部设备发来的数据包, 必须与客户端通信的外部 IP 和端口 一致.
比受限制的圆锥体 NAT 增加了一层对 端口 的限制.
内部服务 192.168.31.2:123
主动访问 30.30.30.30:789
时. 创建的 NAT 记录为:
1 | 内网IP:端口 (192.168.31.2:123) → 外部IP:端口 (20.20.20.20:456) → 允许的目标IP:端口 (30.30.30.30:789) |
此时来自 30.30.30.30
且端口是 789
的请求才能通过 20.20.20.20:456
访问到内部的 192.168.31.2:123
.
同理如果想让 30.30.30.30:987
也能访问 192.168.31.2.123
, 则必须 由内部服务先发起请求以新增允许的目标 IP+端口记录:
1 | 内网IP:端口 (192.168.31.2:123) → 外部IP:端口 (20.20.20.20:456) → 允许的目标IP:端口 (30.30.30.30:789 & 30.30.30.30:987) |
总结
与完全圆锥形 NAT 相比, 受限圆锥形 NAT 在内网设备向外发送报文时, 路由器除了生成 NAT 记录, 还会根据报文的目的 IP, 记录下内网设备正在与哪些外部设备通信.
这样, 只有内网设备先发送报文给外部设备, 外部设备回应的报文, 才会被转发到内网设备. 而其他外部设备发送过来的报文, 即使匹配 NAT 记录, 也无法发送到内网设备.
而 受限制的圆锥体 NAT 与 端口受限制的圆锥体 NAT 最显著的区别是受限制的范围不一样: 后者相对于前者添加了 端口 的限制.
我们回顾一下 圆锥形 NAT 的定义: 一旦内部主机的私有端口映射到公网的一个端口, 无论目的地址是什么, 这个映射关系都保持不变.
而上述三种 圆锥形 NAT 的示例中自始至终都只有 1 条 NAT 记录, 不同的是 是否需要通过允许的地址来放行请求(与谁通信过的记录).
而 对称型 NAT 会同时根据内网设备出方向报文的 源 IP、源端口号、目的 IP、目的端口号 四个信息来建立 NAT 记录. 如果报文的目的 IP、目的端口号发生了变化, 映射到的外部端口号也会发生改变.
内网设备首先和 ServerA 通信, 内网 IP 和内网端口号会被映射为一个外部 IP 和外部端口号:
1 | 内网IP:端口 (192.168.31.2:123) → 外部IP:端口 (20.20.20.20:456) |
接下来, 内网设备和另一台设备 (Server B)通信, 相同的内网 IP 和内网端口号, 又会被映射为另外一个外部端口号:
1 | 内网IP:端口 (192.168.31.2:123) → 外部IP:端口 (20.20.20.20:1456) |
我们以前文说的 [UDP 打洞](#点对点 (P2P) 网络通信) 为例, 说说为什么 对称型 NAT 无法成功打洞:
第一步都是一样的, A 和 B 同时向 Server 发送数据, 这时会分别在 NAT 设备上生成对应的 NAT 记录, 同时 Server 记录设备 A 和 B 对应的外网 IP 和端口:
第二步是 Server 将对应的公网 IP 和外部端口发送给 A 和 B, 让它们互相访问:
此时在两端的 NAT 设备上各新增了一条 NAT 记录, 但因为 对称型 NAT 的特性, 因为目标地址不同(IP 或端口不同), 即使是同一个内网 IP 通过相同的端口发送数据包, 在 NAT 设备生成的 NAT 记录的外部端口也会不一样, 即这次生成的外部端口为 1456
, 经 NAT 转换后, 源地址为: 20.20.20.20:1456
目标地址为 40.40.40.40:789
.
而 B 端 NAT 记录中的 40.40.40.40:789
只能被源地址为 30.30.30.30:5678
访问, 所以 A 发送给 B 的数据包被丢失, 导致打洞失败.
NAT 类型总结
基本的 NAT, 它仅将内网主机的私有 IP 地址转换成公网 IP 地址, 但并不将 TCP/UDP 端口信息进行转换, 有动态与静态之区分. 由于现在大部分都属于另一种类型, 即 NAPT, 其中对称 NAT 打洞困难很高, 但是安全性好;而锥型 NAT 打洞比较容易.
实际上大部运营商提供的 光猫上网服务都是锥形 NAT. 而光纤入户, 4G, 5G 网络, 公共 WiFi 等因为安全因素都是对称 NAT, 另外目前绝大多数的路由器都是非对称型 NAT(Cone NAT). 只要请求链接的对方是非端口限制锥型 nat 就都能实现打洞 P2P 链接的.
只有双方都是 对称 NAT 是一定无法实现, 或一方对称一方是 端口限制锥型 NAT 的情况也无法实现打洞. 下面是各种类型打洞总结:
发送端 NAT 类型 | 接收端 NAT 类型 | 是否能打洞 |
---|---|---|
完全锥形 NAT | 完全锥形 NAT | ✅ |
完全锥形 NAT | IP 限制性锥形 NAT | ✅ |
完全锥形 NAT | 端口限制性锥形 NAT | ✅ |
完全锥形 NAT | 对称式 NAT | ✅ |
IP 限制性锥形 NAT | IP 限制性锥形 NAT | ✅ |
IP 限制性锥形 NAT | 端口限制性锥形 NAT | ✅ |
IP 限制性锥形 NAT | 对称式 NAT | ✅ |
端口限制性锥形 NAT | 端口限制性锥形 NAT | ✅ |
端口限制性锥形 NAT | 对称式 NAT | 🚫 |
对称式 NAT | 对称式 NAT | 🚫 |
NAT 类型提升
简单回顾一下, NAT 的 4 个类型, 它们分别是:NAT1、NAT2、NAT3、NAT4
- NAT1: Full Cone NAT, 全锥形 NAT, 这是最宽松的网络环境, 你想做什么, 基本没啥限制 IP 和端口都不受限
- NAT2: Address-Restricted Cone NAT, 受限锥型 NAT, 相比 NAT1, NAT2 增加了地址限制, 也就是 IP 受限, 而端口不受限
- NAT3: Port-Restricted Cone NAT, 端口受限锥型, 相比 NAT2, NAT3 增加了端口限制, 即 IP、端口都受限
- NAT4: Symmetric NAT, 对称型 NAT, 对称型 NAT 具有端口受限锥型的受限特性, 内部地址每一次请求一个特定的外部地址, 都会绑定到一个新的端口. 这种类型基本上就告别 P2P 了
从 NAT1 到 NAT4 限制越来越多, 为了满足各种需求, 我们希望提升 NAT 类型. 提升 NAT 类型的好处有, 浏览网页、观看视频、游戏等更顺畅, 下载速度更稳定快速, 特别是对那些玩游戏的, 提升改善 NAT 类型后联机速度更快, 游戏体验明显提高.
低延迟方案
想要游戏网速快, 延迟低, 就要 nat1, 公网, 桥接, unpn, 硬件 nat 加速
修改光猫工作模式
把光猫工作模式设置为桥接模式(需要超级管理员账号密码, 很多都是默认, 可以根据地区上网搜索, 新款的直接联系维修工人), 修改模式, 因为运营商一般默认设置光猫工作在路由模式. 无线路由器直接连到猫上就可以上网的, 那么光猫是路由模式. 无线路由器需要 PPPoE 拨号上网的就是桥接模式.
更改路由器设置
启用无线路由器的 uPnP 功能, uPnP 大部分路由器都支持. 把要提升 NAT 类型的主机 IP 设置为静态, 然后开启 DMZ(通过路由器拨号, 路由器最好要刷机, 然后选择 NAT1 模式)
总结
路由器层数越少, 越可能得到 NAT1 和 NAT2 类型
NAT1 是最宽松的网络环境, 基本没限制. NAT4 是最严格的网络环境, 可能会玩不了游戏、P2P 下载都没速度
如果光猫是桥接模式, 路由器拨号上网的有可能是 NAT2 和 NAT3, 对上网、游戏和下载都没有太多限制
拨号能获得公网 IP 的, 可以优化到 NAT1, 拨号获得内网 IP 基本是 NAT4
中国电信、中国联通宽带一般是公网 IP, 中国移动、中国广电、长宽等基本是内网 IP.
因为移动公网 ip 池比其他运营商少, 所以一般都用对称型 nat(节约公网 ip, 因为断开连接就会解绑映射, 不过绑定关系的建立和解除会消耗 cpu 性能, 所以移动打游戏时不时跳 ping)
UPnP
UPnP (Universal Plug and Play) 是一种网络协议, 允许设备在网络中自动发现彼此, 并通过网络进行互操作. UPnP 使设备能够在网络中动态地发现、控制和配置其他设备, 而无需手动配置. 它广泛应用于家庭和办公环境中, 特别是在涉及到网络设备之间的协作时.
主要特点
自动发现:设备能够自动发现网络中的其他设备, 并能够与其进行通信. 例如, 智能家电、路由器、打印机等设备通过 UPnP 协议可以自动连接并相互配合.
零配置:设备不需要用户进行复杂的网络配置 (如 IP 地址或端口映射) , UPnP 自动完成这些操作.
设备控制:通过 UPnP 协议, 可以控制其他设备的功能, 如播放音乐、控制视频播放、网络摄像头的调节等.
UPnP 与 NAT 的关系
NAT (Network Address Translation) 是一种用于网络层的技术, 用来将内网设备的私有 IP 地址转换为公共 IP 地址, 使得多个设备能够共享一个公共 IP 地址. NAT 的典型应用场景是家庭路由器, 它将内网设备的请求映射到一个公共的 IP 地址上, 从而允许多个设备通过一个公共 IP 地址访问互联网.
然而, NAT 会带来一些问题, 尤其是当多个设备需要与外部设备进行点对点通信时. 例如, NAT 不会自动将外部设备的请求转发到内网设备, 因此需要手动配置端口映射 (端口转发) , 才能允许外部设备通过公共 IP 地址访问内网设备.
UPnP 如何帮助 NAT 穿透
具体来说, UPnP 协议允许内网设备通过 UPnP 协议自动请求路由器开放特定的端口并进行端口映射. 这使得内网设备能够在不手动配置端口转发的情况下, 允许外部设备访问内网服务, 突破了 NAT 的限制.
UPnP 工作原理
设备发现:内网设备 (如计算机、游戏主机、智能摄像头等) 通过发送 SSDP (Simple Service Discovery Protocol) 请求, 寻找支持 UPnP 协议的路由器.
端口映射请求:内网设备通过 UPnP 向路由器发送请求, 要求路由器将指定的端口映射到设备的 IP 地址和端口上. 路由器通常会响应并将端口映射添加到 NAT 表中.
外部访问:外部设备通过路由器的公共 IP 地址和开放的端口访问内网设备. 路由器根据 UPnP 配置的端口映射, 将请求转发到正确的内网设备.
NAT 穿透的应用场景
UPnP 特别适用于以下几种情况:
VoIP 和视频通话:通过 UPnP 自动配置端口映射, 使得 VoIP 或视频会议可以穿透 NAT, 直接进行通信.
P2P 文件共享:如 BitTorrent、在线游戏等, 内网用户通过 UPnP 自动创建端口映射, 使得外部用户能够直接连接到内网用户.
游戏控制台:如 Xbox 或 PlayStation, 设备通过 UPnP 请求开放端口以便与其他设备进行联网对战.
UPnP 的安全性问题
虽然 UPnP 提供了便利性, 但也存在一些安全隐患:
自动端口映射:如果 UPnP 功能启用, 路由器会允许内网设备自动请求端口映射, 这意味着恶意软件也可以通过 UPnP 请求将某些端口暴露到外部网络.
未经授权的设备访问:未经授权的设备可能会通过 UPnP 请求端口映射, 允许外部攻击者访问内网设备.
防火墙绕过:恶意软件可以通过 UPnP 自动打开端口, 从而绕过防火墙, 获取不应有的网络访问权限.
总结
UPnP 是一种使设备能够自动发现并互相通信的协议, 广泛应用于家庭和办公网络中.
NAT 会阻止外部设备直接访问内网设备, 但 UPnP 可以自动化端口映射过程, 解决 NAT 穿透问题.
UPnP 对 NAT 进行了优化, 使得内网设备能够自动配置路由器进行端口映射, 从而使外部设备能够访问内网服务.
DMA
上文中介绍的 NAT, 路由器会根据内网设备发出的报文, 自动形成 NAT 表项. 实际上, 用户还可以在路由器上手动配置端口映射关系, 让内网设备可被外部访问.
其中, DMZ 功能, 可以指定一台内网设备为 DMZ 主机. 到达路由器上的报文, 如果没有匹配 NAT 表项, 就会转发到 DMZ 主机. 从而使 DMZ 主机可被外部访问.
DMZ 功能能让一台内网设备上的所有端口, 都能被公网访问. 但这样做也影响了内网设备的安全性, 如果没有特殊需要, 不建议打开这一功能.
端口映射
端口映射是指将外部网络 (通常是公共网络) 上的某个端口映射到内网设备上的相应端口, 允许外部用户通过路由器访问内网设备的服务. 它通常与 NAT 配合使用, 在路由器或防火墙上设置映射规则, 从而实现外部与内网的通信.
举个例子:
假设你有一台内部设备, IP 地址为 192.168.1.10, 并且这台设备上的某个服务监听的是端口 8080.
你希望外部用户能够访问这个服务, 但内网的 192.168.1.10 地址无法直接暴露给外部网络.
你可以在路由器上设置端口映射规则, 将外部的某个公共端口 (例如 80) 映射到内网设备的端口 8080. 这样, 外部用户访问路由器的 80 端口时, 实际上会转发到内网设备的 192.168.1.10:8080.
作用:
通过端口映射, 外部设备可以访问内网中的特定设备或服务.
它用于解决 NAT 带来的“内网设备无法直接被外部访问”的问题.
NAT 和端口映射区别
NAT 是一种技术或机制, 用于将私有 IP 地址转换为公共 IP 地址.
端口映射 是 NAT 的一种配置, 通过设置规则, 将外部访问的端口映射到内网设备的端口, 使得外部设备能够访问内网设备.
检测 NAT 类型
pystun3 是一个用于获取 NAT 类型和外部 IP 的 Python STUN 客户端
安装:
1 | pip install pystun3 |
也可以使用自定义 STUN 服务器:
1 | pystun3 -d -H stun.l.google.com -P 19302 |
pystun3 默认的 STUN Server 在 stun/__init__.py
中定义:
1 | STUN_SERVERS = ( |
自己也可以搭建一个 STUN Server:
1 | git clone https://github.com/jselbie/stunserver |
使用自建服务器
1 | pystun3 -d -H [STUN Server 服务的域名或 IP] -P {STUN Server 的端口号} |
如果你做 WebRTC 相关工作的开发, 那么 Always Online: STUN servers 这个开源项目可以关注一下.
参考
- 42 张图详解 NAT : 换个马甲就能上网
- 家庭网络中的「NAT」到底是什么?
- 入网指南 04 | IP 地址大揭秘 - 少数派
- 局域网游戏串流:让我们都做一回「云」玩家 - 少数派
- 小白也能看懂的网络基础 04 | IP 地址是如何工作的 - 少数派
- 小白也能看懂的网络基础 05 | IP 地址深度学习 - 少数派
- 小白也能看懂的网络基础 07 | TCP 和 UDP 是如何工作的? - 少数派
- NAT 科普与类型提升
- 互联网网关设备协议 - 维基百科, 自由的百科全书
- NAT 端口映射协议 - 维基百科, 自由的百科全书
- 解决 NAT 错误和多人游戏问题 | Xbox Support
- Port Control Protocol (PCP) - RFC6887
- How NAT traversal works · Tailscale
- How Tailscale works · Tailscale
- QUIC, a multiplexed transport over UDP - The Chromium Projects
- awesome-home-networking-cn
相关文章:
- 先导篇:我的 HomeLab 概要;
- 硬件篇:介绍我所拥有的硬件设备;
- 网络篇:包括网络环境、异地组网与网络安全;
- 服务篇:使用 Docker 搭建的各类服务;
- 数据篇:包括数据存储方案、备份方案和数据恢复方案;
- HomeLab数据同步:构建高效的数据同步网络
- HomeLab数据备份:打造坚实的数据安全防线
- HomeLab 网络续集:升级 10G 网络-再战 10 年
- NAT 内网穿透详解:揭秘网络连接背后的奥秘