SouthFox's Garden

Search IconA magnifying glass icon. 搜索
种植日期: 2025-07-01 上次照料: 2025-07-04

2025-07-01

NAT 穿透是如何工作的

{译} NAT 穿透是如何工作的:技术原理及企业级实践(Tailscale, 2020)

  • 连接和方向都是协议设计者的概念,到了雾里传输层,每个连接都是双向的,防火墙来维护状态

  • 防火墙在受到包后就会为这个放行

  • STUN 服务器能告诉客户端它看到的客户端的 ip:port 是什么。 因此,只要将这个信息以某种方式告诉通信对端(peer),后者就知道该和哪个地址建连了! 这样就又简化为前面的防火墙穿透问题了

  • 将 easy NAT 及其变种称为 “Endpoint-Independent Mapping” (EIM,终点无关的映射)

  • 将 hard NAT 以及变种称为 “Endpoint-Dependent Mapping”(EDM,终点相关的映射),根据连接地址分配不同的出站导致 STUN 不可用

  • “运营商级 NAT”(carrier-grade NAT,或称电信级 NAT),缩写 CGNAT

    • NAT 映射规则,即对 2.2.2.2:1234 -> 2.2.2.2:5678 进行 SNAT
    • 这种 NAT 行为有个专门的术语,叫 hairpinning(直译为发卡,意思 是像发卡一样,沿着一边上去,然后从另一边绕回来)
      • 大家应该猜到的一个事实是:不是所以 NAT 都支持 hairpin 模式。 实际上,大量 well-behaved NAT 设备都不支持 hairpin 模式,
      • 因为它们都有 “只有来源是私有地址且目的是公网地址的包才会经过我” 之类的假设。
      • 因此对于这种目的地址不是公网、需要让路由器把包再转回内网的包,它们会直接丢弃。
      • 这些逻辑甚至是直接实现在路由芯片中的,因此除非升级硬件,否则单靠软件编程无法改变这种行为。

健壮 NAT 穿透

实现健壮的 NAT 穿透需要下列基础:

  • 一种基于 UDP 的协议;
  • 能在程序内直接访问 socket;
  • 有一个与 peer 通信的旁路信道;
  • 若干 STUN 服务器;
  • 一个保底用的中继网络(可选,但强烈推荐)

然后需要:

  • 遍历所有的 ip:port;
  • 查询 STUN 服务器来获取自己的公网 ip:port 信息,以及判断自己这一侧的 NAT 的“难度”(difficulty);
  • 使用 port mapping 协议来获取更多的公网 ip:ports;
  • 检查 NAT64,通过它获取自己的公网 ip:port;
  • 将自己的所有公网 ip:ports 信息通过旁路信道与 peer 交换,以及某些加密秘钥来保证通信安全;
  • 通过保底的中继方式与对方开始通信(可选,这样连接能快速建立)
  • 如果有必要/想这么做,探测对方的提供的所有 ip:port,以及执行生日攻击(birthday attacks)来穿透 harder NAT;
  • 发现更优路径之后,透明升级到该路径;
  • 如果当前路径断了,降级到其他可用的路径;
  • 确保所有东西都是加密的,并且有端到端认证。

评论