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

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

参考方案

考虑两台希望互相通信的机器的任务。如果两台计算机直接连接到公共Internet(而不是在路由器后面),则两台计算机只是将数据包来回发送到彼此的公共IP。通常,机器位于一个或多个路由器之后。为了简化该问题,我们假设仅一层路由器。

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

考虑一个路由器的防火墙,该防火墙可以执行以上文章中的任何非端口转发转换(例如,全锥)。如果路由器从端口X接收到一些数据包,但路由器没有从端口Y发送任何数据包,则它将丢弃该数据包(毕竟,数据包是指向谁的?路由器不知道!)。仅当某些专用计算机发送数据包并且路由器进行转换以将端口X从该专用计算机映射到外部端口Y时,外部数据包TO端口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接收数据包。

安全?

您提到安全性:打孔是否会使网络违反安全性?可能...我尚未研究过该主题,但考虑使用完整的锥体NAT。映射完成后,任何外部计算机都可以将数据包发送到计算机A的路由器,并且即使A从未向某个恶意计算机Z发送数据包,A也会获取数据包。计算机Z当然必须以某种方式发现映射。在Wikipedia上的某些文章中,该图仅显示了具有此漏洞的完整锥状网络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连接不起作用。用STUN替换stackoverflow.com,并用机器B(您要与之进行Skype的人)替换facebook.com。不幸的是,STUN可以找到发送给STUN的数据包NAT映射,但是发送给B的数据包使用完全不同的映射。通常,不可能(无法跟踪出站路由器数据包)确定对称NAT的端口映射。因此,客户端需要一个中央路由服务器进行通信,但是这破坏了p2p的重点。请参见TURN。

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

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

警告

尽管我不可能列出所有NAT遍历警告,但其中一个重要的概念仍然存在:路由器完成端口映射后,它将持续多长时间?假设我连接到STUN服务器,然后等我告诉它映射,然后等待10分钟,以便B向我发送一个数据包。路由器可能会放弃映射(路由器必须定期清除旧的映射,以便为新的映射腾出空间,并以最小的安全性尝试)。我找不到我的参考,并且我认为它随TCP和UDP数据包的不同而不同,但是我熟悉的应用程序每隔60秒或更短的时间发送一次保持活动数据包,以确保路由器不会丢失映射。一旦路由器丢弃了映射并且机器尝试发送数据包,数据包将被丢弃(这给我造成了数小时的混乱……)。

文章

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

上一篇文章很好地介绍了有关Genreal中路由器和NAT遍历的许多想法。前一段时间,当我实现一些TURN服务器/客户端过程时,我读了它,而作者真的知道他们在说什么!

java:继承 - java

有哪些替代继承的方法? java大神给出的解决方案 有效的Java:偏重于继承而不是继承。 (这实际上也来自“四人帮”)。他提出的理由是,如果扩展类未明确设计为继承,则继承会引起很多不正常的副作用。例如,对super.someMethod()的任何调用都可以引导您通过未知代码的意外路径。取而代之的是,持有对本来应该扩展的类的引用,然后委托给它。这是与Eric…

Java:BigInteger,如何通过OutputStream编写它 - java

我想将BigInteger写入文件。做这个的最好方式是什么。当然,我想从输入流中读取(使用程序,而不是人工)。我必须使用ObjectOutputStream还是有更好的方法?目的是使用尽可能少的字节。谢谢马丁 参考方案 Java序列化(ObjectOutputStream / ObjectInputStream)是将对象序列化为八位字节序列的一种通用方法。但…

Java-如何将此字符串转换为日期? - java

我从服务器收到此消息,我不明白T和Z的含义,2012-08-24T09:59:59Z将此字符串转换为Date对象的正确SimpleDateFormat模式是什么? java大神给出的解决方案 这是ISO 8601标准。您可以使用SimpleDateFormat simpleFormat = new SimpleDateFormat("yyyy-MM…

Java:从类中查找项目名称 - java

仅通过类的实例,如何使用Java反射或类似方法查找项目名称?如果不是,项目名称(我真正想要的是)可以找到程序包名称吗? 参考方案 项目只是IDE使用的简单组织工具,因此项目名称不是类或JVM中包含的信息。要获取软件包,请使用Class#getPackage()。然后,可以调用Package#getName()将包作为您在代码的包声明中看到的String来获取…

JAVA 8具有任何匹配属性的对象的过滤器列表 - java

我的要求是通过匹配任何属性的字符串来过滤对象列表。例如,假设Contact类具有三个属性:街道,城市,电话。我知道java流过滤器是如何工作的,在这里我必须将输入字符串与每个属性进行比较,如下所示:contactList.stream().filter(contact -> contact.getStreet().equals("dubai&…