TCP打孔(NAT穿越)库还是啥?

Posted

技术标签:

【中文标题】TCP打孔(NAT穿越)库还是啥?【英文标题】:TCP Hole Punch (NAT Traversal) Library or something?TCP打孔(NAT穿越)库还是什么? 【发布时间】:2011-01-27 11:01:50 【问题描述】:

我想在 C# 中进行 TCP 打孔(NAT 遍历)。如果需要,可以使用集合服务器来完成。我找到了http://sharpstunt.codeplex.com/,但无法让它工作。理想情况下,我需要一些方法,我将端口号(int)作为参数,在调用此方法后在 NAT 处可用(“端口转发”)。如果该方法只返回一些端口号,该端口号随后可在 NAT 上使用,也可以。有人在 C# 中做过这个吗?你能给我一些关于sharpstunt或其他东西的工作例子吗?

【问题讨论】:

嗯...为什么需要这种特殊情况?如果它只是关于连接,请安装任何代理,并在 Webclient 中配置它。应该也能解决。 代理很慢而且不安全。 【参考方案1】:

在每个网络场景中,TCP 打孔的操作方式与 UDP 打孔类似。例如,如果两个对等点 A 和 B 在不同的 NAT 后面,每个对等点发送给另一个对等点的第一个 SYN 数据包在其各自的 NAT 中打开一个与其公共地址相关联的漏洞。如果 A 到 B 的第一个 SYN 数据包在 B 到 A 的第一个 SYN 数据包到达 B 的 NAT 之前到达 B 的 NAT,则 B 的 NAT 认为 A 的 SYN 数据包是未经请求的并丢弃它。但是,随后 B 的第一个 SYN 数据包可以成功通过 A 的 NAT,因为 A 的 NAT 将 B 的公共地址识别为 A 发起的传出会话的目的地。

所以是的。 TCP打孔是可能的。我不明白为什么有人会不这么认为。

另外,你不能手动创建这种类型的行为吗?它不需要依赖任何特定的协议,只要收集所有必需信息的步骤相同即可。

一般来说,TCP 打孔(3.2.1)的过程如下:

客户:A、B 服务器:S

• A 使用它与 S 的连接向 S 请求连接 与 B。 • S 用 B 的私人和公共地址回复 A, 同时将 A 的地址发送给 B。

• A 和 B 异步建立传出连接 - 诱惑(发送 SYN 数据包)到彼此的公共和 私有地址,来自他们使用的同一端口 向 S 注册。同时,他们倾听 本地 TCP 上的 TCP 传入连接尝试 端口。

• A 和 B 等待对其输出的 SYN-ACK 响应 SYN 数据包,或传入的连接请求 (SYN 数据包)。如果连接失败,对端可以重试 最长超时时间。

• 三次握手过程完成后, 对等方相互验证。如果认证- 失败,对等方关闭该连接并等待直到 另一个连接已成功验证。这 将使用第一个成功验证的连接 传输 TCP 数据。

(我知道这不是一个很好的答案,但没有足够的空间发表评论)。

【讨论】:

这不适用于企业 NAT(对称 NAT)。为什么 A 和 B 发送到私人地址?它们不能通过 Internet 路由。你描述的是特技 我只是在描述打孔过程。 STUNT 是一套实际的工具,可帮助打孔过程。我回答的要点是表明 TCP 打孔确实是可能的,因为有人提到它不是。我知道在某些情况下它不起作用,但这不是问题。 (至于为什么提到私人地址。我不知道。我从其他来源复制了大部分数据。 Wikipedia for STUN under "Limitations": 由于 STUN 服务器的 IP 地址与端点的 IP 地址不同,在对称 NAT 的情况下,STUN 服务器的 NAT 映射将不同于一个端点。 TURN 通过对称 NAT 提供更好的结果。 我不明白的一件事是“私人地址”是什么意思。私有地址通常指的是一个看起来像 192.168.x.x 的地址,但我不明白客户端 A 或 B 向它发送连接请求对任何事情都有帮助。我在这里不明白什么?【参考方案2】:

这个问题已经很老了,但是对于任何寻求解决方案的人来说,你应该看看Open.NAT project 它真的很容易使用,并且可以同时使用 UPNP 和 PMP NAT!

假设你要将外部1700端口转发到本地1600端口,你要做的就是:

var discoverer = new NatDiscoverer();
var device = await discoverer.DiscoverDeviceAsync();
await device.CreatePortMapAsync(new Mapping(Protocol.Tcp, 1600, 1700, "The mapping name"));

您还可以列出所有现有映射,以便验证您的端口是否尚未使用。

var sb = new StringBuilder();
var ip = await device.GetExternalIPAsync();

sb.AppendFormat("\nAdded mapping: 0:1700 -> 127.0.0.1:1600\n", ip);
sb.AppendFormat("\n+------+-------------------------------+--------------------------------+------------------------------------+-------------------------+");
sb.AppendFormat("\n| PROT | PUBLIC (Reacheable)           | PRIVATE (Your computer)        | Descriptopn                        |                         |");
sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
sb.AppendFormat("\n|      | IP Address           | Port   | IP Address            | Port   |                                    | Expires                 |");
sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
foreach (var mapping in await device.GetAllMappingsAsync())

    sb.AppendFormat("\n|  5 | 0,-20 | 1,6 | 2,-21 | 3,6 | 4,-35|6,25|",
        ip, mapping.PublicPort, mapping.PrivateIP, mapping.PrivatePort, mapping.Description, mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP", mapping.Expiration.ToLocalTime());

sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
Console.WriteLine(sb.ToString());

MSDN 上还有一篇关于 NAT Traversal 的博文:https://blogs.msdn.microsoft.com/ncl/2009/07/27/end-to-end-connectivity-with-nat-traversal/

【讨论】:

是的,要让它完美运行有点棘手,而且对于某些网络硬件,它可能根本无法运行。 要明确一点,UPnP 与防火墙打孔不是一回事。它们都是 NAT 穿越的形式,但是 UPnP 只是在 NAT 中创建端口转发条目的一种方式,而打孔可以连接两个对等方而无需明确定义这些条目。【参考方案3】:

我们整合了一个名为 IceLink 的库,该库使用 ICE/STUN/TURN 和完整的 NAT 遍历进行 P2P 流式传输。基于 STUN 的打孔技术适用于大多数路由器在对等方之间建立直接连接,而对于那里的“坏”路由器,连接会退回到基于 TURN 的中继。

【讨论】:

好像是个商业图书馆(随便说说)【参考方案4】:

http://sipsorcery.codeplex.com 有一个正常工作的 stun 服务器。

SipSorcery.core -> SipSorcery.Net -> Stun

【讨论】:

我希望有 STUNT 而不是 STUN 但谢谢它可能是一个起点 特技是特技,但使用 TCP 而不是 UDP。您不能只用 TCP 替换 UDP,它就像魔术一样工作。不幸的是 SipSorcery.core -> SipSorcery.Net -> Stun 不提供 STUNT... 没有 TCP 打孔,它是 UDP 打孔。【参考方案5】:

听起来您可能混淆了 TCP 和 UDP。 TCP 是一种面向连接的协议,很容易被防火墙和路由器理解,并且需要一个启动器(客户端)和一个侦听器(服务器)。如果客户端和服务器都在防火墙或 NAT 之后,则如果不让它们都连接到某个代理服务器(没有防火墙),就无法打洞。这样做的问题是,代理将负责中继他们的所有流量。

从您的问题来看,您似乎对 UDP 打孔更感兴趣,它利用了 UDP 是无状态的,而不是面向连接的。因此,大多数状态跟踪防火墙会对 UDP 数据流做出“最佳猜测”,并假设离开给定端口的流量将在同一端口收到回复,并自动将它们路由回去。如果使用某种通道外方式(例如 TCP 服务器,它只传递地址而不是数据),两个对等点可以在相同端口上相互传输数据,它们各自的防火墙/NAT 路由器将打开漏洞,允许流量。

至于如何做到这一点,这完全取决于您将如何获取对等方的 IP 地址。获得它后,只需在约定的端口上开始传输 UDP 数据包,然后等待回复。

【讨论】:

我可以做 UDP 打孔,现在被称为 STUN,它很容易。但是您可以进行 TCP 打孔,它只是更复杂,称为 STUNT(最后一个 T 代表 TCP)。 sharpstunt.codeplex.com 声称确实可以做到,但我无法让它工作。还有一些 JAVA 库可以做到这一点... +1 >如果客户端和服务器都在防火墙或 NAT 之后,如果不让它们都连接到某个代理服务器,您就无法打洞 请记住,STUN 不适用于所有类型的 NAT。 ICE 将 TURN 定义为后备。 TCP打孔是可以的,但是需要服务器发起连接(但是链接建立后就不需要服务器了——至少我是这么理解的)https://en.wikipedia.org/wiki/TCP_hole_punching

以上是关于TCP打孔(NAT穿越)库还是啥?的主要内容,如果未能解决你的问题,请参考以下文章

HTTPS为什么可以穿越NAT端口映射设备?

ICE协议下NAT穿越的实现(STUN&TURN)

NAT穿越技术详细介绍

VOIP NAT穿越之SIP信令穿越

P2P技术详解:P2P中的NAT穿越(打洞)方案详解(进阶分析篇)

P2P技术详解:P2P中的NAT穿越(打洞)方案详解(进阶分析篇)