# NAT 穿越技术
# NAT 技术背景
解决 IPV4 中 IP 地址不足问题,是 IPV4 向 IPV6 时期的过渡方案(IPV4 与 IPV6 可能共存较长时间,故仍有现实价值)。IPV6 全是公网地址。
# NAT 技术原理
NAT(Network Address Translation) 是一种将本地 IP 地址映射到一个公网 IP
# NAT 分类
# 静态 NAT
- 定义: 静态 NAT 是一种一对一的地址映射,其中一个私有 IP 地址固定地映射到一个公共 IP 地址。每个私有 IP 地址都有对应的唯一的公共 IP 地址。
- 配置: 静态 NAT 需要手动配置,网络管理员事先为每个内部设备指定一个静态映射规则,将内部设备的私有 IP 地址映射到一个公共 IP 地址。
- 适用场景: 静态 NAT 适用于那些需要保持固定映射关系的场景,如在服务器提供服务的情况下,确保特定的服务始终由特定的公共 IP 地址提供。
- 优点: 固定映射关系使得管理和维护相对简单,适用于一些特定的应用场景。
# 动态 NAT
- 定义: 动态 NAT 是一种一对多的地址映射,其中多个私有 IP 地址共享一组公共 IP 地址。动态 NAT 不需要为每个内部设备手动配置映射规则,而是动态地根据需求分配公共 IP 地址。
- 配置: 动态 NAT 需要配置一个地址池,包含一组可用的公共 IP 地址。当内部设备发起对外访问时,动态 NAT 会从地址池中动态选择一个公共 IP 地址,将其映射到内部设备的私有 IP 地址。
- 适用场景: 动态 NAT 适用于那些内部设备需要临时访问外部资源的场景,且不需要固定映射关系。
- 优点: 节省公共 IP 地址的使用,因为不同时间可能有不同的内部设备共享同一个公共 IP 地址。
# NAPT(Network Address Port Translation)
NAPT(Network Address Port Translation)是一种地址转换技术,也被称为 PAT(Port Address Translation)或 Overloading。NAPT 是 NAT 的一种扩展形式,它不仅映射私有 IP 地址,还映射了端口号。这允许多个内部设备共享同一个公共 IP 地址,每个设备通过唯一的端口号与外部通信。
NAPT 包含两种转换方式
- 源 NAT (SNAT,Source NAT):修改数据包的源地址。源 NAT 改变第一个数据包的来源地址,它永远会在数据包发送到网络之前完成,数据包伪装就是一具 SNAT 的例子。
- 目的 NAT (DNAT,Destination NAT):修改数据包的目的地址。Destination NAT 刚好与 SNAT 相反,它是改变第一个数据懈的目的地地址,如平衡负载、端口转发和透明代理就是属于 DNAT。
- 对于
TCP/UDP
使用:Host's 私有 IPv4 + Port <------> NAT 公网 IPv4 + Port - 对于
ICMP
使用:Host's 私有 IPv4 + session ID <------> NAT 公网 IPv4 + session ID
# NAPT 映射方式
# 全锥型 NAT(Full Cone NAT)
全锥型 NAT 也叫一对一型 NAT
一旦一个内部 IP 地址和端口号被映射为某个外部 IP 地址和端口号,所有从这个内部 IP 地址和端口发出的包都会被映射为固定的外部 IP 地址和端口。并且任何外部主机都可以通过这个映射的外部地址发包给内部主机
# 限制锥型 NAT(Restrict Cone NAT)
此方式的 NAT 与 Full Cone NAT 的唯一的区别是只有收到内网主机发出的数据包的主机才可以返回数据包到此内网主机。
# 端口限制锥型 NAT(Port Restrict Cone NAT)
端口限制锥型 NAT 与限制锥型 NAT 相似。但是端口限制锥型 NAT 不但限定 IP 地址还限定端口号。一个源 IP 地址为 x 和源端口为 p 的外部主机只有在内部主机先前发送了包给 IP 地址 x 和端口 p 的情况下才能内部主机。
# 对称型 NAT(Symmetric NAT)
在对称型 NAT 中,任何来自一个内部 IP 地址和端口发到某个 IP 地址和端口的请求都将被映射为一个唯一的外部 IP 地址和端口。如果同一个主机用同一个源 IP 和端口发包到不同的目标地址,就会有不同映射,即:Symmetric NAT(对称 NAT)发往不同目的主机或端口的数据包会被映射到不同的外网地址和端口。只有接到了来自内部主机发出的请求包的外部主机才可以发 UDP 包回来给这个内部主机。
# 映射表
NAT 的工作基础在于建立内网主机地址(端口)和外网主机地址(端口)映射表,数据包的转发均依赖于此映射表,映射表的一行是 9 元组:{协议,持续时间,描述,内网主机 IP,内网主机 Port,NAT 外网 IP,NAT 外网 Port,外网主机 IP,外网主机 Port},其中协议指 TCP、UDP 等,持续时间指映射存活时间,描述是对映射的文字解释,而后 6 项是此 9 元组的核心,它们决定了 NAT 的类型,即主要的 6 元组:{内网主机 IP,内网主机 Port,NAT 外网 IP,NAT 外网 Port,外网主机 IP,外网主机 Port}, NAT 的穿越实际上就围绕 9 元组的构造、内容展开。
# NAT 穿透
前提条件
- 有一个公网的 Server 并且绑定了两个公网 IP,分别为 IP1,IP2
- Server 做 UDP 监听 S1 (IP1,PORT1),S2 (IP2,PORT2),并根据用户客户端要求进行应答
- 待检测的用户可以进行 UDP 通信
# 探测流程
# 现有穿越 NAT 方法
- 应用层网关方式(ALG)
- UPnP
- STUN(Simple Traversal of UDP Through NAT)
- TURN(Traversal Using Relay NAT)采用中继的 NAT 穿越
- ICE(Interactive Connectivity Establishment)互动式连接
# 应用层网关方式(ALG)
NAT 穿透之所以成为问题是因为 NAT 设备作为 IP 网关在允许网络包通过时只修改网络层和传输层的地址,位于应用层中的网络地址并没有得到修改,因此解决 NAT 穿透的一个最直接的想法是要求 NAT 设备在修改网络层和传输层地址的同时也要修改应用层中的地址,这就是 ALG 方案的由来。
# UPnP
UPnP 是由 UPnP 论坛提出的一个计算机网络协议集合。UPnP 架构允许开发出个人计算机,联网设备,和各种无线设备的点对点网络。当一个新的主机需要连接,一个 UPnP 设备可以自动配置一个网路地址,在子网中宣告自己的存在,交换设备和服务的描述。目前,很多因特网网关厂商都提供带 UPnP 功能的设备。在 UPnP 里进行 NAT 穿越就是因特网网关设备协议 IGDP。但是 UPnP 的其中一个不好是它要求网络上所有的设备都必须支持 UPnP,即使只有一个设备没有确认支持 UPnP 标准,我们都不能实现点点的网络通信。
# STUN
STUN 协议为终端提供一种方式能够获知自己经过 NAT 映射后的地址,从而替代位于应用层中的私网地址,达到 NAT 穿透的目的。STUN 是用于客户端和服务器通信的一个协议。如果一个点对点通信的软件包包含了 STUN 客户端,它会发一个请求到一个 STUN 服务器。这个服务器之后会回给 STUN 客户端它的 NAT 路由的公网 IP 地址。它也会汇报回 NAT 路由为内网接收而打开的端口号。
# TURN
TURN 的 NAT 穿透与 STUN 类似,都是通过修改应用层中的私网地址达到 NAT 穿透。与 STUN 不同的是,TURN 是通过两方通讯的 “中继器(或转发器)” 的方式实现穿透,即双方在 NAT 之后的计算机,首先能够与 TURN 服务器通信,然后由该 TURN 服务器在双方之间进行任何数据的转发。
# TCP 穿透
我们假设在两个不同的局域网后面分别有 2 台客户机 A 和 B,AB 所在的局域网都分别通过一个路由器接入互联网。互联网上有一台服务器 S。
现在 AB 是无法直接和对方发送信息的,AB 都不知道对方在互联网上真正的 IP 和端口, AB 所在的局域网的路由器只允许内部向外主动发送的信息通过。对于 B 直接发送给 A 的路由器的消息,路由会认为其 “不被信任” 而直接丢弃。
要实现 AB 直接的通讯,就必须进行以下 3 步:
A 首先连接互联网上的服务器 S 并发送一条消息(对于 UDP 这种无连接的协议其实直接初始会话发送消息即可),这样 S 就获取了 A 在互联网上的实际终端(发送消息的 IP 和端口号)。
接着 B 也进行同样的步骤,S 就知道了 AB 在互联网上的终端(这就是 “打洞”)。
接着 S 分别告诉 A 和 B 对方客户端在互联网上的实际终端,也即 S 告诉 A 客户 B 的会话终端,S 告诉 B 客户 A 的会话终端。这样,在 AB 都知道了对方的实际终端之后,就可以直接通过实际终端发送消息了(因为先前双方都向外发送过消息,路由上已经有允许数据进出的消息通道)。
一、采用端口复用方式 SO_REUSEADDR 实现 TCP 穿透
- AB 分别与 S 建立连接,并且 S 记录 AB 的 ip 和端口号,并发送到对方
- AB 双方都在同一个本地端口监听到来的连接(也可以先监听,再 connect 更好)
- 在对方 connect 请求到达本地的监听端口时,路由器会认为这个请求是刚刚那个 connect 会话的一部分,是已经被许可的,本地监听端口就会用 SYN-ACK 响应,同意连接