java - 什么是 STUN,它是否需要端口转发服务器?

标签 java tcp udp portforwarding stun

我在没有基本服务器的情况下对 p2p 通信进行了一些研究,并且研究了 STUN。从我读过的内容来看,STUN 是一种 NAT“打洞”方式,不需要对等端进行端口转发即可连接。这是正确的,打洞究竟是什么意思?如果不需要端口转发,这一切似乎都非常脆弱,因为它会通过防火墙,而且我不完全理解 STUN 的作用。
STUN 是否可以用在 Java 或其他语言的 p2p 程序中,例如聊天客户端,它通过 TCP/UDP 端口向对等方发送消息而无需基本服务器或无需用户转发端口?

最佳答案

考虑两台机器想要相互通信的任务。如果两台机器直接连接到公共(public)互联网(而不是在路由器后面),那么两台机器只需将数据包来回发送到彼此的公共(public) IP。通常,机器位于一个或多个路由器之后。为了简化问题,我们假设只有一层路由器。

NAT 遍历解决了路由器将数据包的传出端口号转换为其他内容的问题(例如,您从端口 X 发送请求,路由器将数据包转换为好像它是从端口 Y 离开的)。如果路由器是端口转发,则路由器实际上不会进行任何转换(端口 X->X)。然而,大多数家庭/公司/等路由器都不是端口转发,因此 NAT 穿越开始发挥作用。见 NAT traversal和不同类型的 NATs .

考虑一个路由器的防火墙,它执行上述文章中的任何非端口转发转换(例如全锥)。如果路由器收到一些到端口 X 的数据包,但路由器没有从端口 Y 发送任何数据包,它就会丢弃数据包(毕竟,数据包是给谁的?路由器不知道!)。只有当某个私有(private)机器发送数据包并且路由器进行转换以将端口 X 从该私有(private)机器映射到外部端口 Y 时,外部数据包才会转发到端口 Y 到私有(private)机器。

STUN 遍历

为了让两个客户端 A 和 B 都在 Internet 上的防火墙后面直接通信,它们必须以某种方式知道路由器映射。一般的解决方案是使用 STUN 服务器来确定它们的端口映射。机器 A 向 STUN 发送一个来自端口 X 的数据包。路由器将端口转换为 Y,STUN 服务器看到这一点并回复 A 告诉他外部端口是什么。 B 也一样。然后,A 和 B 交换他们翻译的端口(通过使用其他一些中央服务器......举个简单的例子,Skype 可能有一个中央登录服务器,其中 A 和 B 告诉 Skype 服务器他们的端口转换,Skype 分别告诉 A 和 B关于端口映射)。然后,B 使用端口 Y 而不是 X 向 A 的公共(public) IP 发送一个数据包。机器 A “打洞”了它的防火墙,允许它从外部端口 Y 接收数据包。

安全的?

您提到了安全性:打洞是否会导致网络安全违规?可能......我没有研究过这个主题,但考虑一个完整的锥形 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 .

我们可以在 Java 聊天程序中使用它吗?

任何具有网络库支持(Java、C 等)的语言(Java、C 等)可以从任意端口发送数据包,都可以使用 STUN 来遍历 NAT(只要它不是对称 NAT 等)。一般来说,一个总是需要一个中央服务器(在这种情况下两个:STUN 和一个登录服务器)。登录服务器的使用方法如 Skype 示例中所述;一旦两个客户端知道他们的端口映射,他们必须在 p2p 通信开始之前以某种方式相互通信(参见 chicken or the egg)。但是一旦 A 和 B 知道彼此的公共(public) IP 和 NAT 映射,它们就可以直接通信。

警告

虽然我不可能列出所有的 NAT 穿越警告,但一个重要的概念是保持 Activity :一旦路由器进行了端口映射,它会持续多久?假设我连接到 STUN 服务器,然后等待 10 分钟让 B 在我告诉它映射后向我发送一个数据包。路由器可能会丢弃映射(路由器必须定期清除旧映射,以便为新映射腾出空间,并尽量减少安全性尝试)。我找不到我的引用资料,我认为它因 TCP 与 UDP 数据包而异,但我熟悉的应用程序每约 60 秒或更短时间发送一个保持 Activity 数据包,以确保路由器不会丢弃映射。一旦路由器丢弃映射并且机器尝试发送数据包,数据包将被丢弃(导致我数小时的困惑......)。

文章

  • RFC 5389 STUN
  • RFC 5766 TURN
  • Peer-to-Peer Communication Across Network Address Translators. B. Ford, et al.

  • 最后一篇文章很好地介绍了路由器和 NAT 穿越的许多想法。不久前我在实现一些 TURN 服务器/客户端程序时阅读了它,作者真的知道他们在说什么!

    关于java - 什么是 STUN,它是否需要端口转发服务器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13501288/

    相关文章:

    java - Java 中的集合

    java - 从 JSP 页面的表单操作调用 servlet

    c - 防止 getpeername() 返回 127.0.0.1

    networking - TCP可以通过UDP实现吗?

    c - 使用消息结构的 UDP 聊天服务器

    java - Chronometer 初始值错误

    tcp - iperf 如何计算网络统计信息

    Java UDP 服务器 IP 碎片

    java - Java中的UDP广播

    java - 使用okhttp3时空HTTP获取响应体