目录 ← 首页
CS168

NAT:网络地址转换

动机:IPv4 地址耗尽

回想一下,我们只有 2³² 个不同的 IPv4 地址,这不足以标识互联网上的每一台主机。我们已经知道 IPv6 是解决 IPv4 地址耗尽的可靠方案,但 IPv6 的采用速度相当缓慢。

与此同时,为了节省地址,IANA 分配了特殊的 RFC 1918 私有 IP 地址范围,这些地址可用于任何不需要互联网地址的网络:192.168.0.0/16、10.0.0.0/8 和 172.16.0.0/12。事实证明,这些地址也经常在你的家庭网络中使用,这样你的个人设备就不需要唯一的 IP 地址了。但是,你确实需要互联网访问,那么如何使用私有 IP 地址呢?

NAT:概念

在 NAT 中,目标是使用一个公共 IP 地址来代表本地网络中的多台主机。关键在于让网关路由器在发送消息之前,将私有 IP 地址转换为单一的公共地址。然后,路由器在接收回复时,再将公共地址转换回私有地址。

爱丽丝、鲍勃和查克都在乔的轮胎店工作。他们拥有私有 IP 地址 A、B 和 C,这些地址不能在广域网上使用,因为它们不是唯一的。相反,乔的轮胎店的所有人必须共享一个公共 IP 地址,这是他们拥有的唯一的、可被公共网络识别的 IP 地址。

img

爱丽丝想要向一个拥有公共 IP 地址 S 的外部公共服务器发送消息。她发送的数据包会显示 “源:A,目的:S”。如果我们直接发送这个数据包,服务器 S 将无法发送回复,因为 A 是私有 IP 地址。

img

相反,当数据包到达网关路由器时,路由器会重写包头,使其显示 “源:R1,目的:S”。路由器还会做一个记录:如果收到任何来自 S 的回复,都应该发送给 A。

img

现在,当 S 收到数据包时,它可以向公共地址 R1 发送回复:“源:S,目的:R1”。当网关路由器 R1 收到回复时,它会查看记录,并将包头重写为 “源:S,目的:A”。然后,数据包就会被发送回 A。

img

现在,爱丽丝、鲍勃和查克都可以发送出站数据包了。当路由器收到数据包时,它必须记住外部目的地和内部发送者之间的映射(“B 刚刚向 N 发送了一个数据包,所以任何来自 N 的回复都应该发送给 B”)。

如果爱丽丝和鲍勃都想与 S 通信,就会出现一个问题。

img

如果有回复从 S 到达,就会产生歧义:路由器应该将这个回复发送给 A 还是 B?

img

我们可以通过使用第四层的逻辑端口来解决这个问题。爱丽丝的连接会显示:“源:A,端口 50000,目的:S,端口 80”。路由器会像之前一样,将其重写为 “源:R1,端口 50000,目的:S,端口 80”。现在记录的内容是:如果收到任何来自 S 的、端口为 80、发往 R1 的端口 50000 的回复,都应该发送给 A。

img

鲍勃可以创建一个单独的连接,显示:“源:B,端口 60000,目的:S,端口 80”。路由器会像之前一样,将其重写为 “源:R1,端口 60000,目的:S,端口 80”。这个连接的记录内容是:如果收到任何来自 S 的、端口为 80、发往 R1 的端口 60000 的回复,都应该发送给 B。

img

更一般地说,路由器现在使用源 IP、目的 IP、协议、源端口和目的端口这 5 元组来跟踪连接。当路由器收到出站数据包时,它会将私有源 IP 改为公共源 IP,并记录这个 5 元组。然后,当路由器收到入站数据包时,它会查找该数据包所属的连接,并将数据包发送到相应的客户端(使用其私有 IP)。

img

重写客户端端口号

我们还有最后一个问题:如果爱丽丝和鲍勃没有使用端口 50000 和 60000,而是选择了相同的端口号(例如端口 50000),会发生什么?

img

现在,路由器会记录两个连接:(A 的端口 50000 到 S 的端口 80)和(B 的端口 50000 到 S 的端口 80)。如果路由器收到一个入站数据包 “源:S,端口 80,目的:R1 的端口 50000”,就无法确定这个数据包是来自 A 的连接还是 B 的连接。

img

我们需要做的最后一项修正,是允许路由器重写端口号。当鲍勃发送 “源:B,端口 50000,目的:S,端口 80” 时,路由器意识到已经有其他设备使用端口 50000 连接到 S 的端口 80 了。因此,路由器会为鲍勃分配一个 “假” 端口号(假设使用 60000),并同时重写源 IP 和源端口,得到:“源:R1,端口 60000,目的:S,端口 80”。

和之前一样,路由器会记录活跃连接(A 的端口 50000 到 S 的端口 80),但对于鲍勃,路由器会额外记录这个假端口号:(B 的端口 50000,伪装为 60000,到 S 的端口 80)。

img

现在,如果路由器收到一个入站数据包 “源:S,端口 80,目的:R1,端口 50000”,这个数据包一定是给爱丽丝的。相反,如果收到一个入站数据包 “源:S,端口 80,目的:R1,端口 60000”,带有这个假端口号,那么这个数据包一定是给鲍勃的。

img

需要注意的是,鲍勃并不知道路由器在更改他的端口号。当路由器将数据包转发回鲍勃时,必须将假端口号改回原始端口号。“源:S,端口 80,目的:R1,端口 60000” 必须重写为 “源:S,端口 80,目的:B,端口 50000”。更一般地说,所有私有客户端都无需知道或关心他们的数据包被重写了。路由器应该给他们一种错觉,即他们正在使用自己的私有 IP 地址和所选的任何端口发送和接收数据包。

NAT:实现

当家庭路由器首次连接到 ISP 时,它可以运行 DHCP 来获取 IP 地址(之前我们讨论过主机运行 DHCP,但路由器也可以运行 DHCP)。ISP 的 DHCP 服务器会回复并为家庭路由器分配一个 IP 地址。这是该路由器所在家庭网络中的所有主机将共享的唯一公共地址。

img

NAT 有几种不同的模式。我们刚才看到的那种称为端口地址转换(PAT),它使我们能够引入刚才看到的假端口号。PAT 模式要求路由器了解第四层协议,以便解析数据包、跟踪连接和重写包头。

PAT 是最复杂且使用最广泛的 NAT 模式,但也存在更简单的一对一地址转换模式。如果每个主机实际上都有自己的 IP 地址,但它们从私有地址发送数据包,路由器可以进行一对一转换,将 10.0.0.1(私有)映射到 42.0.2.1(公共),将 10.0.0.2(私有)映射到 42.0.2.2(公共),依此类推。这种更简单的模式无法通过将多个主机隐藏在一个公共地址后面来节省 IP 地址,但在其他情况下仍然有用。

img

NAT 的应用场景

NAT 增加了路由器转发数据包的复杂性。路由器现在必须能够解析第四层包头,以及第三层包头。此外,路由器必须能够重写第三层和第四层包头。最后,路由器必须维护一个连接状态表来跟踪所有通过路由器的流。所有这些功能都增加了转发每个数据包所需的 CPU 周期,也增加了路由器上每个流所需的内存量。

由于 NAT 增加了路由器的复杂性,因此它被部署在尽可能靠近网络边缘的位置,以限制通过路由器的流的数量。在家庭路由器上运行 NAT 是个好主意,因为家庭中通过家庭路由器发送连接的设备数量不多。相比之下,在高性能数据中心路由器上运行 NAT 则不是个好主意。

实际上,即使在今天,小规模的 NAT 几乎被用于所有个人(家庭 / 办公室)IPv4 网络中。随着 IPv4 地址耗尽,ISP 无法为每个客户(即每个家庭路由器)分配一个公共地址。因此,ISP 网络本身也必须运行一种更复杂的 NAT,称为运营商级 NAT(CGNAT)。这种 NAT 部署在网络更深层,要求路由器跟踪更多的连接。

需要注意的是,我们通常不会在 IPv6 中使用 NAT,因为 IPv6 有足够的地址,可以为世界上每台计算机分配一个唯一的公共地址。

入站连接

到目前为止,我们假设连接总是由具有私有 IP 地址的客户端发起。换句话说,第一个数据包总是出站的,从客户端到服务器。这与大多数家庭网络的运行方式一致。当你在浏览器中加载网页时,你是发起连接的客户端。通常情况下,不会有其他人试图连接到你。

但是,如果你正在运行一个服务器,并且希望外部世界的人能够发起连接到这个服务器,该怎么办呢?外部用户无法向私有 IP 地址发送数据包。他们可以尝试向路由器的 IP 地址发送数据包,但如果路由器收到一个类似 “源:外部用户,目的:R1,端口 28” 的数据包,路由器不知道应该将这个数据包转发给哪个私有客户端。这是一个新连接的第一个数据包,所以路由器的表中没有关于这个连接的信息。

img

为了允许入站连接,执行 NAT 的路由器需要一个端口映射表。爱丽丝位于网络内部,只有一个私有 IP 地址,她告诉路由器:我要运行一个新服务器,并在端口 28 上监听请求。现在,如果路由器看到某个外部用户发送到 R1 的端口 28 的数据包,就知道要将这个数据包转发给爱丽丝。

这个端口映射表中的条目可能需要手动指定(例如,爱丽丝手动配置路由器)。诸如 UPnP(通用即插即用)和 NAT-PMP(NAT 端口映射协议)之类的动态协议允许动态配置开放端口。这些协议有时被用于需要入站连接的应用程序,如在线游戏。

NAT 的安全影响

NAT 打破了端到端原则。到目前为止,我们已经知道在第三层,互联网上的任何人都可以到达其他任何人。然而,由于 NAT 默认不允许入站连接,家庭网络中只有私有 IP 地址并共享一个公共 IP 地址的用户无法被自动访问。他们需要配置路由器才能接收入站数据包。

NAT 具有默认不允许入站连接的特性。这可以被视为一种安全功能,尽管这更多是一个副作用,而非有意设计的功能。NAT 默认阻止入站连接,这可能有助于阻止攻击者试图连接到网络内部的主机。这种行为实际上与防火墙(更多信息参见加州大学伯克利分校 CS 161 课程笔记)非常相似,防火墙通常也默认阻止入站连接。也就是说,这主要是一种巧合,因此 NAT 并不是在实施有原则的安全策略,不应被视为一种无懈可击的防御措施。

NAT 还有一个副作用,即有助于保护客户端隐私。同样,这也不是真正有意设计的安全功能。由于路由器重写了客户端的 IP 地址,当服务器收到数据包时,它不知道原始发送者的身份(可能是爱丽丝、鲍勃或查克)。

相比之下,如果我们不使用 NAT,服务器可以知道发送者的确切身份。此外,如果我们不使用 NAT 而使用 IPv6,服务器可能能够知道发送者使用的确切计算机,因为 IPv6 地址有时是使用 MAC 地址自动配置的(将 MAC 地址的位复制到 IP 地址中)。如果我们使用 IPv6 但仍希望保护客户端隐私,也存在一些替代解决方案,如 IPv6 临时 / 隐私地址。

(注:文档部分内容可能由 AI 生成)