Internet centralization and the original sin of NAT

Internet centralization and the original sin of NAT

互联网的中心化与 NAT 的原罪

Internet centralization and the original sin of NAT File Transfer, Randall Munroe, https://xkcd.com/949, Creative Commons Attribution-NonCommercial 2.5 In this comic, the concept of an ordinary person having an FTP server is quickly dismissed. And yes, it’s not common. To the average computer user, the idea that someone could just… connect to your computer feels exotic, or even dangerous — see the very common ironic fear of your IP address being known to other people on the internet.

互联网的中心化与 NAT 的原罪(文件传输,Randall Munroe,https://xkcd.com/949,知识共享署名-非商业性使用 2.5 协议)。在这幅漫画中,普通人拥有 FTP 服务器的概念被迅速否定了。确实,这并不常见。对于普通计算机用户来说,有人能直接“连接”到你的电脑这种想法显得很陌生,甚至很危险——看看那种非常普遍且讽刺的恐惧:担心自己的 IP 地址被互联网上的其他人知道。

If you take someone who’s “good with computers” but not a networking person, their mental model of The Internet probably involves a definition of “servers” or “the cloud” that distinguishes them from personal computers in some meaningful way. True peer‐to‐peer, if they ever think about it, is an endeavor: WebRTC, STUN, TURN, ICE, what have you. Given that we live in a world of NAT, CGNAT, and restrictive ISPs, this isn’t entirely wrong, but it breaks the elegant design of the original Internet.

如果你找一个“精通电脑”但并非网络专业的人,他们对互联网的心理模型通常包含对“服务器”或“云”的定义,并将其与个人电脑在某种意义上区分开来。如果他们思考过真正的点对点(P2P)连接,那将是一项艰巨的任务:WebRTC、STUN、TURN、ICE 等等。鉴于我们生活在一个充满 NAT、CGNAT 和限制性 ISP 的世界里,这种认知并不完全错误,但它确实破坏了原始互联网优雅的设计。

Why you don’t have an FTP server

为什么你没有 FTP 服务器

Network address translation (NAT) was first formally proposed in RFC 1631 in 1994. In its abstract, it says: The two most compelling problems facing the IP Internet are IP address depletion and scaling in routing. Long‐term and short‐term solutions to these problems are being developed. The short‐term solution is CIDR (Classless InterDomain Routing). The long‐term solutions consist of various proposals for new internet protocols with larger addresses.

网络地址转换(NAT)最早于 1994 年在 RFC 1631 中被正式提出。其摘要中写道:IP 互联网面临的两个最紧迫的问题是 IP 地址枯竭和路由扩展性。针对这些问题的长期和短期解决方案正在开发中。短期解决方案是 CIDR(无类别域间路由)。长期解决方案则包括各种针对具有更大地址空间的新互联网协议的提案。

Classless interdomain routing is not the point of this post, but basically we started giving people more options for network sizes, and while complex in implementation, it was philosophically virtually uncontroversial. RFC 1631 proposed a second short‐term solution to IP address depletion and scaling in routing: NAT. While it is not exactly the same type of NAT omnipresent on home routers today, the basic idea is the same: it allows multiple devices to share an IP address (from the perspective of a device on the other end of a routing device) by modifying the network address information in the IP packet headers while transferring the packet across a traffic routing device.

无类别域间路由并非本文重点,但简而言之,我们开始为人们提供更多网络规模的选择,虽然实现起来很复杂,但在哲学层面上几乎没有争议。RFC 1631 提出了解决 IP 地址枯竭和路由扩展性的第二个短期方案:NAT。虽然它与今天家用路由器上无处不在的 NAT 不完全相同,但基本思想是一致的:它允许多个设备共享一个 IP 地址(从路由设备另一端的设备视角来看),方法是在数据包通过流量路由设备时,修改 IP 数据包头中的网络地址信息。

We then later reserved certain addresses for private use, and these things are used in conjunction on most IP networks — private addresses within the network, NATing to one public address at the router. On your typical home router, here’s how you usually connect to an external server with NAT:

后来,我们保留了某些地址供私有使用,这些技术在大多数 IP 网络中结合使用——网络内部使用私有地址,并在路由器处通过 NAT 转换为一个公网地址。在典型的家用路由器上,你通常通过 NAT 连接到外部服务器的过程如下:

Your computer sends a packet like this: Source IP 10.11.70.21, Source Port 50413, Destination IP 67.215.249.229, Destination Port 70. It hits your router, and it modifies it to this: Source IP 146.7.15.85, Source Port 60612, Destination IP 67.215.249.229, Destination Port 70. The server replies: Destination IP 146.7.15.85, Destination Port 60612. Your router rewrites it back: Destination IP 10.11.70.21, Destination Port 50413.

你的电脑发送一个数据包:源 IP 10.11.70.21,源端口 50413,目标 IP 67.215.249.229,目标端口 70。数据包到达路由器后,被修改为:源 IP 146.7.15.85,源端口 60612,目标 IP 67.215.249.229,目标端口 70。服务器回复:目标 IP 146.7.15.85,目标端口 60612。你的路由器将其重写回:目标 IP 10.11.70.21,目标端口 50413。

If you’ve thought this through, you might be asking: in the situation that an external server wants to talk to you first, how does that happen? It sends a packet to 146.7.15.85, and your router… Oh no. It has no idea where to send it.

如果你仔细思考过这个问题,你可能会问:如果外部服务器想先与你通信,该怎么办?它向 146.7.15.85 发送数据包,然后你的路由器……噢,不。它根本不知道该把数据包发给谁。

Working around it

绕过它

Naturally, people noticed this was a problem almost immediately, because people have wanted to run game servers, FTP servers, and web servers from their bedrooms since roughly the beginning of time. So a whole ecosystem of workarounds grew up around NAT, none of which restore the fundamental intention of the internet, and none of which work for everything.

自然地,人们几乎立刻就注意到了这个问题,因为自互联网诞生之初,人们就一直想在自己的卧室里运行游戏服务器、FTP 服务器和 Web 服务器。因此,围绕 NAT 产生了一整套绕过方案,但没有一个能恢复互联网的初衷,也没有一个能解决所有问题。

Port forwarding

端口转发

The most direct fix is to just tell your router “hey, when a packet comes in on port 60612, send it to 10.11.70.21 on port 50413, no questions asked.” This is port forwarding, and it’s the workaround to NAT that the most people are aware of. One of the problems with port forwarding, conceptually, is that one public IP+port can still only map to one device at a time, which means that two devices can’t operate a service on the same public IP+port at the same time.

最直接的解决方法就是告诉路由器:“嘿,当 60612 端口收到数据包时,直接把它发给 10.11.70.21 的 50413 端口,别问为什么。”这就是端口转发,也是大多数人所知的 NAT 绕过方案。从概念上讲,端口转发的一个问题是,一个公网 IP+端口在同一时间只能映射到一个设备,这意味着两个设备无法同时在同一个公网 IP+端口上运行服务。

This is more of a problem than it sounds like; on big enterprise or university networks that choke down to a small number or even just one private IP, this basically kills on‐prem hosting without doing even more complicated shit. And sometimes, your ISP has put your external IP behind NAT too — which is called carrier‐grade NAT (CGNAT) — and now you don’t control the device doing the translation, so you can’t forward a port. You’re getting a fraction of a fraction of an IP address. Also, another problem with NAT is that nobody wants to bother with it, which is why we invented:

这比听起来要严重得多;在大型企业或大学网络中,由于出口被压缩到极少数甚至只有一个公网 IP,这基本上扼杀了本地托管的可能性,除非进行更复杂的操作。有时,你的 ISP 也会将你的外部 IP 置于 NAT 之后——这被称为运营商级 NAT (CGNAT)——此时你无法控制执行转换的设备,因此无法进行端口转发。你得到的只是一个 IP 地址的一小部分。此外,NAT 的另一个问题是没人愿意折腾它,这就是我们发明以下技术的原因:

UPnP

UPnP

UPnP, and its modern cousins NAT‐PMP and PCP, tried to solve the “nobody wants to bother with it” problem by letting software ask the router directly to forward ports. Like manual port forwarding, it’s a request to your router — if your ISP is screwing with you, you’re out of luck. It’s also frequently disabled because of misguided security thinking — partially because of a couple buggy early implementations, and partially because the idea that someone could just connect to your computer feels exotic or even dangerous to a lot of people. There are plenty of valid reasons to want a firewall, but if you do, intentionally implement one instead of relying on NAT just not knowing where to send packets.

UPnP 及其现代变体 NAT-PMP 和 PCP 试图通过让软件直接请求路由器转发端口来解决“没人愿意折腾”的问题。和手动端口转发一样,这本质上是对路由器的请求——如果你的 ISP 在搞鬼,那你就没辙了。它也经常因为错误的安全性考量而被禁用——部分原因是早期实现中存在一些 Bug,部分原因是许多人觉得“有人能直接连接到你的电脑”这种想法很陌生甚至很危险。想要防火墙有很多正当理由,但如果你需要它,请刻意去配置一个,而不是依赖 NAT 因为“不知道把数据包发给谁”而产生的被动防御。

STUN, TURN, and ICE

STUN、TURN 和 ICE

STUN (Session Traversal Utilities for NAT), instead of trying to get cooperation from the firewall, simply asks a server on the public internet “what does my packet look like by the time it gets to you?” The STUN server hands back the public IP and port your NAT assigned, say, 146.7.15.85:60612. Under a “cone NAT”, where the router uses an identical external port mapping for all outbound connections, this works great. You can tell this mapping to a peer, and then they can send packets directly to you. This technique is known as hole punching. However, under a “symmetric NAT” — common on CGNAT and institutional networks — you get a different public port for every distinct destination. In this case, the STUN mapping…

STUN(NAT 会话穿透工具)不再试图寻求防火墙的配合,而是简单地询问公网上的服务器:“我的数据包到达你那里时是什么样子的?”STUN 服务器会返回你的 NAT 分配的公网 IP 和端口,例如 146.7.15.85:60612。在“锥形 NAT”(Cone NAT)下,即路由器对所有出站连接使用相同的外部端口映射时,这种方法效果很好。你可以将此映射告知对端,然后他们就可以直接向你发送数据包。这种技术被称为“打洞”(Hole Punching)。然而,在“对称 NAT”(Symmetric NAT)下——这在 CGNAT 和机构网络中很常见——你对每个不同的目标都会获得不同的公网端口。在这种情况下,STUN 映射……