考虑两台机器想要相互通信的任务。如果两台机器直接连接到公共互联网(不在路由器后面),则两台机器只需将数据包来回发送到彼此的公共 IP。通常,机器位于一台或多台路由器后面。为了简化问题,我们假设只有一层路由器。
NAT 穿越解决了路由器将数据包的传出端口号转换为其他内容的问题(例如,您从端口 X 发送请求,路由器将数据包转换为就像从端口 Y 离开一样)。如果路由器是端口转发,则路由器实际上不执行任何转换(端口 X->X)。然而,大多数家庭/公司/等路由器都没有端口转发,因此 NAT 穿越开始发挥作用。看NAT穿越 http://en.wikipedia.org/wiki/NAT_traversal以及不同类型的NATs http://en.wikipedia.org/wiki/Network_address_translation#Methods_of_Port_translation.
考虑执行上述文章中任何非端口转发转换的路由器防火墙(例如全锥)。如果路由器收到一些数据包到端口 X,但路由器尚未从端口 Y 发送任何数据包,则会丢弃该数据包(毕竟,该数据包是发给谁的?路由器不知道!)。只有当某个私有机器发送数据包并且路由器进行转换以将端口 X 从该私有机器映射到外部端口 Y 时,到端口 Y 的外部数据包才会被转发到私有机器。
STUN遍历
为了使两个客户端(A 和 B 都位于 Internet 上的防火墙后面)能够直接通信,它们必须以某种方式知道路由器映射。一般的解决方案是使用 STUN 服务器来确定它们的端口映射。机器 A 从端口 X 发送数据包到 STUN。路由器将端口转换为 Y,STUN 服务器看到这一点并向 A 做出响应,告诉他外部端口是什么。 B 也做同样的事情。然后,A 和 B 交换其转换后的端口(通过使用其他一些中央服务器...举个简单的例子,Skype 可能有一个中央登录服务器,其中 A 和 B 告诉 Skype 服务器它们的端口转换,Skype 分别告诉 A 和 B关于端口映射)。然后,B 使用端口 Y(而不是 X)向 A 的公共 IP 发送数据包。机器 A“突破”其防火墙,允许其从外部端口 Y 接收数据包。
Secure?
您提到安全性:打洞是否会导致网络出现安全违规?可能...我还没有研究过这个主题,但考虑一下全锥 NAT。一旦映射完成,任何外部机器都可以向机器 A 的路由器发送数据包,并且 A 将会收到数据包,即使 A 从未向某些恶意机器 Z 发送过数据包。当然,机器 Z 必须以某种方式发现映射。一些维基百科文章中,图表仅显示了具有此漏洞的全锥 NAT,但不要相信我的话。从使用打洞的应用程序数量(Skype、xbox live...)来看,除了路由器防火墙措施之外,网络似乎还依赖于应用程序和系统级防火墙保护。
下面福特的文章简要提到了安全性:“与它的名字所暗示的相反,打洞不会损害专用网络的安全性。”网络似乎比路由器防火墙更依赖系统级防火墙。
对称 NAT 和 TURN 遍历
STUN 并不总是有效:某些路由器“表现不佳”。机器 A 可能会从端口 X 发送两个数据包,一个发送到 stackoverflow.com,另一个发送到 facebook.com。路由器映射来自端口 Y 的 stackoverflow.com 数据包和来自端口 Z 的 facebook.com 数据包(即使机器 A 从内部端口 X 发送这两个数据包)。这是对称 NAT。这些 NAT 是有问题的,因为上面的 STUN/Skype 连接不起作用。将 stackoverflow.com 替换为 STUN,将 facebook.com 替换为机器 B(您尝试与之进行 Skype 通话的人)。不幸的是,STUN 可以找出 A 发送到 STUN 的数据包的 NAT 映射,但发送到 B 的数据包使用完全不同的映射。一般来说,不可能(如果您无法跟踪出站路由器数据包)确定对称 NAT 的端口映射。因此,客户端之间的通信需要一个中央路由服务器,但这违背了 p2p 的初衷。看TURN http://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT.
我们可以在 Java 聊天程序中使用它吗?
任何具有网络库支持的语言(Java、C 等),您可以从任意端口发送数据包,都可以使用 STUN 来遍历 NAT(只要它不是对称 NAT 等)。一般来说,一always需要一个中央服务器(在本例中是两个:STUN 和一个login服务器)。这login服务器的使用方式如 Skype 示例中所述;一旦两个客户端知道他们的端口映射,他们必须以某种方式相互通信beforep2p 通信已经开始(参见先有鸡还是先有蛋 http://en.wikipedia.org/wiki/Chicken_or_the_egg)。但是一旦 A 和 B 知道彼此的公网 IP 和 NAT 映射,他们就可以直接通信。
Caveat
虽然我不可能列出所有 NAT 穿越注意事项,但一个重要的概念是保持活动状态:一旦路由器进行了端口映射,它会持续多久?假设我连接到 STUN 服务器,然后等待 10 分钟,让 B 在我告诉 B 映射后向我发送数据包。路由器可能会删除该映射(路由器必须定期清除旧映射,以便为新映射腾出空间,并进行最低限度的安全尝试)。我找不到我的参考,我认为它根据 TCP 与 UDP 数据包的不同而有所不同,但我熟悉的应用程序每隔约 60 秒或更短时间发送一个保持活动数据包,以确保路由器不会丢弃映射。一旦路由器丢弃映射并且机器尝试发送数据包,数据包就会被丢弃(导致我几个小时的困惑......)。
Articles
- RFC 8489 眩晕 https://www.rfc-editor.org/rfc/rfc8489
- RFC 5766 回合 https://www.rfc-editor.org/rfc/rfc5766
- 跨网络地址转换器的点对点通信。 B.福特等人。 http://www.brynosaurus.com/pub/net/p2pnat/
上一篇文章很好地介绍了路由器和 NAT 穿越的许多想法。我不久前在实现一些 TURN 服务器/客户端程序时读过它,作者真的知道他们在说什么!