位于不同地点、配备不同私有IP的两用户设备(一在NAT后,一在NAT外)无法直接通过NAT通信。根本原因在于外部主机无法首先进入NAT后的内部主机(即发送数据包)。例如,若设备1(图中的A主机)向设备2(B主机)发送数据包,设备2前的NAT会丢弃该包;反之亦然,设备2发给设备1的包会被设备1前的NAT拒绝。
为解决这一问题,标准化了诸如会话遍历实用程序(STUN, RFC 5389/RFC 5780)、穿越NAT的中继(TURN, RFC 5766)以及交互式连接建立(ICE, RFC 5245)等NAT穿越技术。这些技术可概括如下:
选择哪种NAT穿越技术取决于NAT的具体工作特性。故此,2007年RFC 4787制定了“有效NAT穿越的NAT行为要求”。
接下来的三篇文章将详述RFC 4787中针对P2P应用的理想NAT行为规范。
内部端点:具有公网IP地址且位于NAT后面的用户设备,例如上图的主机A(例如与NAT位于同一运营商网络中的设备) 外部端点(External Endpoint):具有公网IP地址且位于NAT相对侧的用户设备,例如上面的主机B(例如与NAT不同运营商网络中的设备) 出站数据包(流量):通过NAT从内部端点发送到外部端点的数据包(流量) ) 入站数据包(流量):通过NAT从外部端点发送到内部端点的数据包(流量) 内部地址和内部端口:内部端点(主机A)发送的数据包的源IP(10.1.1.1)和源端口(5000) 外部地址和外部端口:经过NAT转换后发送到外部端点(主机B)的数据包的源IP(5.5.5.1)和源端口(1000) 一般来说,内部端点(主机A)发送报文的目的信息(即目的IP(1.1.1.1)和目的端口(80))会被透明转发到外部端点(主机B),而产生经过外部端点的转换。网络地址转换。 当外部端点(主机 B)收到数据包时,它会向内部端点返回包含以下信息的数据包作为响应: 目的IP=接收到的数据包的源IP,即外部地址(5.5.5.1) 目的端口=接收数据包的源端口,即外部端口(1000) 源IP = 接收到数据包的目的IP地址(1.1.1.1),即外部端点(主机B)的IP地址 源端口 = 接收数据包的目标端口( 80)
1. 网络地址和端口转换行为
1.1 地址与端口映射
Endpoint-Independent Mapping(不关心对端地址和端口的转换模式):只要是来自相同源地址和源端口号的报文,不论其目的地址是否相同,通过PAT映射后,其源地址和源端口号都被转换为同一个外部地址和端口号。这就是文章learning: nat 插件说明(1)描述的NAT-ei模式基于源端口+源IP+协议号组成的三元组NAT。
如下图所示,来自主机A的内部端点的报文具有相同的源IP地址(10.1.1.1)和相同的源端口(5000),不论其目标IP地址是(1.1.1.1还是2.2.2.2),也不论目标端口是(80或8080),这些报文都会被分配到同一个外部端口映射值(转换后的端口=1000)。这种映射方式不依赖于报文的目的地配置,仅依据报文的来源特征进行映射。
Address-Dependent Mapping(关心对端地址的转换模式):将相同的外部端口映射值(转换端口=1000)由主机A发送的数据包,只要这些数据包满足以下条件:1) 源IP地址相同(10.1.1.1),2) 源端口相同(5000),3) 目标IP地址相同(1.1.1.1),而不关心目标端口,无论目的端口是80还是8080,均映射到相同的公网ip地址及端口号1000。
如下图所示,针对源IP地址(10.1.1.1)和源端口(5000)相同,但目标IP地址分别为(1.1.1.1和2.2.2.2)的两个数据包,采用了不同的外部端口映射值(转换端口=1000和1002)。这体现了根据目标地址差异进行端口映射的策略。
Address and Port-Dependent Mapping (关心对端地址和端口的转换模式):如主机A发出的数据包具有以下特征:1) 相同的源IP地址,2) 相同的源端口,3) 相同的目的IP地址,4) 相同的目的端口,才会分配相同的外部端口映射值。如下图所示,由于两数据包的目标IP地址不同(分别为1.1.1.1和2.2.2.2),故转换了不同的外部端口(外部端口=1000和1002),体现了该映射方式的地址与端口依赖性。
目前主线版本VPP中,默认使用NAT-ED模式就是上面这种转换关系。使用宝文五元组+vrf-id做key,分配不同的公网ip和端口号。
在下图中,由于两个数据包具有不同的目标端口(80 和 8080),因此使用了不同的外部端口映射值(转换端口 = 1000 和 1004)。
IP地址池技术:家庭无线接入点(Home APs)及Wi-Fi热点AP通常使用单一公共IP地址执行NAPT(网络地址端口转换)。然而,在3G/LTE网络中采用的大规模NAT(LSNs,也称作运营商级NAT(CGNs))则利用多个公共IP地址(NAT外部侧的IP地址池)来进行转换。
任意IP地址分配:这类NAT对于内部端点发出的数据包,即使它们源自相同的源IP地址,只要其会话(即{源IP、源端口、目标IP、目标端口}的组合)不同,就会分配不同的外部IP地址。
如下图所示,NAT为内部端点10.1.1.1(主机A)与外部端点1.1.1.1(主机B)建立的两个不同会话分配了两个不同的外部IP地址(5.5.5.1和5.5.5.2)。
这种机制展示了NAT如何根据不同的会话需求灵活地从IP地址池中分配外部IP地址,以实现更高效的公网资源利用和连接管理。
配对IP地址分配:配对NAT(Paired NATs)对于内部端点发出的数据包,即使它们的会话(即{源IP、源端口、目标IP、目标端口}的组合)不同,只要源自相同的源IP地址,也会分配相同的外部IP地址。
如下图所示,无论会话内容如何,NAT为内部端点10.1.1.1(主机A)与外部端点1.1.1.1(主机B)建立的两个不同会话都分配了相同的外部IP地址(5.5.5.1)。
在VPP的NAT-ED模式下申请公网ip地址和端口号时,就使用报文src ip地址做hash选择一个公网ip。
static int
nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index,
u32 tx_sw_if_index, u32 nat_proto,
u32 thread_index, ip4_address_t s_addr,
ip4_address_t d_addr, u32 snat_thread_index,
snat_session_t *s, ip4_address_t *outside_addr,
u16 *outside_port)
{
if (vec_len (sm->addresses) > 0)
{
/*根据报文src ip地址hash 出一个公网ip地址。*/
u32 s_addr_offset = (s_addr.as_u32 + (s_addr.as_u32 >> 8) +
(s_addr.as_u32 >> 16) + (s_addr.as_u32 >> 24)) %
vec_len (sm->addresses);
}
}
这意味着,在这种NAT配置下,尽管内部主机发起了多个去往不同端口或服务的连接请求,但所有这些请求在转换到公网时都会显示为来自同一个外部IP地址,这可能对某些依赖于端到端直接连接的应用程序(例如某些P2P应用和在线游戏)产生影响。
端口分配规则:
端口保持(Port Preservation):采用端口保持的NAT设备在执行NAT转换后,会保留内部端点发送数据包时使用的源端口值(即内部/本地端口),使得外部端口等于内部端口(External Port = Internal Port)。这意味着,数据包在经过NAT转换后,其源端口号不会发生变化,从而有助于维持某些应用程序的端到端连接兼容性,减少配置复杂性,并可能简化对依赖特定端口通信的网络服务的支持。
不保留端口(No Port Preservation):在这种情况下,NAT设备不对内部端点使用的源端口(内部端口)进行保留,在执行NAT转换时会随机分配一个新的源端口值(外部端口),导致外部端口与内部端口不相同(External Port ≠ Internal Port)。这种方法可以有效避免端口冲突,提高地址资源的利用率,但可能需要应用程序不依赖于特定的端口号进行通信,或者需要额外的机制来跟踪和管理这些动态分配的端口映射,以确保数据包的正确路由和应用层协议的正常运行(VPP中目前默认采用此策略)。
端口复用(Port Overloading)
假设一个支持端口保持的NAT设备耗尽了可用的外部IP地址(即公有IP地址)。如果此时接收到一个具有相同源端口值的外出数据包,NAT应如何处理?
**端口复用**是一种简单但存在风险的方法。当遇到端口冲突时,NAT设备会简单地覆盖已存在的绑定条目。也就是说,它坚持使用端口保持策略。如下图所示,为Host B生成的绑定条目会被Host A的数据包所覆盖。
结果是,Host A和Host B通过NAT发送给Host C的每个数据包都将拥有相同的外部地址(5.5.5.5)和外部端口(5000)。这将导致NAT将来自Host C的所有入站数据包都转发给Host A,最终使得Host B与Host C之间的通信变得不可能。当然,没有制造商实际生产支持这种方法的产品,因为这显然会导致严重的网络通信问题。
无端口复用(No Port Overloading):当遇到端口冲突的情况时,NAT设备不采用端口保持策略,而是为外部端口分配一个与内部端口不同的值。这种方法确保了即使多个内部主机使用相同的内部端口与不同目的地通信,它们在NAT外部的表现也是唯一的,因为每个会话都会被映射到不同的外部端口上。
具体来说,如果Host A和Host B同时尝试使用端口5000与外部的不同主机通信,NAT设备会为Host A的连接分配一个独特的外部端口(比如5001),为Host B的连接分配另一个不同的外部端口(比如5002),尽管它们的内部端口都是5000。这样,NAT能够正确地区分并转发回两个不同主机的流量,从而保证了Host A和Host B都能成功且独立地与外部目标进行通信,避免了端口复用可能导致的问题。这种方法更常见且稳健,广泛应用于现代NAT设备中,以支持多用户环境下的有效网络通信。
端口分配规则:RFC文档中还包括了针对“不保留端口”支持的NAT设备的“出口端口分配规则”。互联网编号分配管理局(IANA)定义了以下端口范围:
依据NAT设备的具体实现,可采用以下几种外部端口分配规则:
这些规则帮助NAT设备有效地管理端口资源,平衡性能与兼容性,同时确保网络通信的安全与效率。
映射定时器(NAT会话管理):NAT表中由内向外的流量生成的绑定条目,只要存在使用该条目的映射流量,就保持有效。但是,如果没有相应的流量,当映射定时器(也称为绑定刷新定时器或绑定生命周期)到期时,该条目就会从表中删除。
如果NAT设备设置的映射定时器较短,为了保持NAT会话活跃,设备(尤其是支持NAT友好的应用程序)就必须频繁发送保活包。对于使用有线或Wi-Fi网络的用户来说,这可能不是问题。但对于按流量计费的3G/LTE网络用户来说,这可能会增加额外的成本负担,成为问题所在。
以下图为例,NAT的映射定时器设置为两分钟。在时间t=0时,主机A发送首个数据包并生成相应的绑定条目。随后在一分钟后,当主机A再次发送数据包时,该绑定条目会被刷新(重置),重新开始为期两分钟的计时周期。这样的机制确保了活跃会话的持续性,同时也通过定期的流量交换避免了不必要资源的占用。
与此相反,下图中的NAT绑定条目在没有流量的两分钟后被删除。
RFC 4787建议(REQ-5)明确指出:NAT中的UDP映射不能少两分钟即过渡,除非REQ-5a的情况适用。下面是REQ-5a及后续建议的详细解释: a) 对于后续建议端口范围(端口0-1023)内的特定目标端口,NAT可以针对运行在这些特定端口上的已注册IANA(互联网编号分配管理局)应用设置更短的UDP映射计时器。这意味着,如果应用程序有特殊要求或行为模式,NAT 可以灵活调整其映射策略以适应这些需求。 b) NAT 的 UDP 映射映射的值应该是可配置的。这灵活允许网络管理员根据网络的具体情况和应用需求来调整定时器的长度,从而在保持资源有效利用与降低用户成本之间取得平衡。 c) 建议 NAT 的 UDP 映射定时器的默认值设置为五分钟或更长。助于减少对依赖 NAT 观看的应用程序(特别是那些在移动网络上运行的应用)的干扰,降低了因计时器重复导致的间隔中断风险,从而提升了用户体验,尤其是在用户需要支付流量费用的情况下更为重要。 这些建议维护旨在确保NAT操作既能网络资源的有效管理,又能兼顾各种网络环境下应用的正常运行,特别是为那些依赖长期稳定连接的应用提供了更好
总结,本文介绍了NAT一些基本转换模式及端口及地址分配原则。在阅读VPP源码中NAT模块有一些基本的理论依据。下一篇我们继续介绍IETF (RFC 4787) 定义的 NAT 行为要求 - 第 2 部分:过滤行为。
本文分享自 DPDK VPP源码分析 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!