P2P,UDP和TCP穿透NAT

原创 2009年11月29日 14:56:00

 1. NAT 简介

NAT(Network Address Translation ,网络地址转换) 是一种广泛应用的解决IP 短缺的

有效方法, NAT 将内网地址转和端口号换成合法的公网地址和端口号,建立一个会话,与公网主机进行通信。

1.1. NAT 分类

NAT 从表面上看有三种类型:静态 NAT 、动态地址 NAT 、地址端口转换 NAPT 。  

1 )静态NAT :静态地址转换将内部私网地址与合法公网地址进行一对一的转换,且每个内部地址的转换都是确定的。

    2 )动态NAT :动态地址转换也是将内部本地地址与内部合法地址一对一的转换,但是动态地址转换是从合法地址池中动态选择一个未使用的地址来对内部私有地址进行转换。

    3NAPT :它也是一种动态转换,而且多个内部地址被转换成同一个合法公网地址,使用不同的端口号来区分不同的主机,不同的进程。

从实现的技术角度,又可以将NAT 分成如下几类:全锥NAT(Full Cone NAT) 、限制性锥NATRestricted Cone NAT )、端口限制性锥NAT( Port Restricted Cone NAT) 、对称NAT ( Symmetric NAT)

1 )全锥NAT :全锥NAT 把所有来自相同内部IP 地址和端口的请求映射到相同的外部IP 地址和端口。任何一个外部主机均可通过该映射发送数据包到该内部主机。

2 )限制性锥NAT :限制性锥NAT 把所有来自相同内部IP 地址和端口的请求映射到相同的外部IP 地址和端口。但是, 和全锥NAT 不同的是:只有当内部主机先给外部主机发送数据包, 该外部主机才能向该内部主机发送数据包。

3 )端口限制性锥NAT :端口限制性锥NAT 与限制性锥NAT 类似, 只是多了端口号的限制, 即只有内部主机先向外部地址:端口号对发送数据包, 该外部主机才能使用特定的端口号向内部主机发送数据包。

4 )对称NAT :对称NAT 与上述3 种类型都不同, 不管是全锥NAT ,限制性锥NAT 还是端口限制性锥NAT ,它们都属于锥NATCone NAT )。当同一内部主机使用相同的端口与不同地址的外部主机进行通信时, 对称NAT 会重新建立一个Session ,为这个Session 分配不同的端口号,或许还会改变IP 地址。

1.2. NAT 的作用

    NAT 不仅实现地址转换,同时还起到防火墙的作用,隐藏内部网络的拓扑结构,保护内部主机。 NAT 不仅完美地解决了 lP 地址不足的问题,而且还能够有效地避免来自网络外部的攻击,隐藏并保护网络内部的计算机。 这样对于外部主机来说,内部主机是不可见的。但是,对于P2P 应用来说,却要求能够建立端到端的连接,所以如何穿透NAT 也是P2P 技术中的一个关键。

 

 

2. P2P 穿透NAT

要让处于NAT 设备之后的拥有私有IP 地址的主机之间建立P2P 连接,就必须想办法穿

NAT ,现在常用的传输层协议主要有TCPUDP ,下面就是用这两种协议来介绍穿透NAT 的策略。

2.1. 网络拓扑结构

下面假设有如图1 所示网络拓扑结构图。


 

1. 网络拓扑结构图

Server 129.208.12.38 )是公网上的服务器,NAT-ANAT-B 是两个NAT 设备(可能是集成NAT 功能的路由器,防火墙等),它们具有若干个合法公网IP ,在NAT-A 阻隔的私有网络中有若干台主机【ClientA-1ClientA-N 】,在NAT-B 阻隔的私有网络中也有若干台主机【ClientB-1ClientB-N 】。为了以后说明问题方便,只讨论主机ClientA-1ClientB-1

假设主机ClientA-1 和主机ClientB-1 都和服务器Server 建立了“连接”,如图2 所示。


2.ClientA-1ClientB-1Server 之间通信

    由于NAT 的透明性,所以ClientA-1ClientB-1 不用关心和Server 通信的过程,它们只需要知道Server 开放服务的地址和端口号即可。根据图1 ,假设在ClientA-1 中有进程使用socket192.168.0.27000 )和Server 通信,在ClientB-1 中有进程使用socket192.168.1.12:8000 )和Server 通信。它们通过各自的NAT 转换后分别变成了socket202.103.142.295000 )和socket221.10.145.846000 )。

2.2. 使用UDP 穿透NAT

通常情况下,当进程使用UDP 和外部主机通信时,NAT 会建立一个Session ,这个Session 能够保留多久并没有标准,或许几秒,几分钟,几个小时。假设ClientA-1 在应用程序中看到了ClientB-1 在线,并且想和ClientB-1 通信,一种办法是Server 作为中间人,负责转发ClientA-1ClientB-1 之间的消息,但是这样服务器太累,会吃不消。另一种方法就是让ClientA-1ClientB-1 建立端到端的连接,然后他们自己通信。这也就是P2P 连接。根据不同类型的NAT ,下面分别讲解。

1 )全锥NAT ,穿透全锥型NAT 很容易,根本称不上穿透,因为全锥型NAT 将内部主机的映射到确定的地址,不会阻止从外部发送的连接请求,所以可以不用任何辅助手段就可以建立连接。

2 )限制性锥NAT 和端口限制性锥NAT (简称限制性NAT ),穿透限制性锥NAT 会丢弃它未知的源地址发向内部主机的数据包。所以如果现在ClientA-1 直接发送UDP 数据包到ClientB-1 ,那么数据包将会被NAT-B 无情的丢弃。所以采用下面的方法来建立ClientA-1ClientB-1 之间的通信。

1 ClientA-1202.103.142.29:5000 )发送数据包给Server ,请求和ClientB-1221.10.145.84:6000 )通信。

2. Server ClientA-1 的地址和端口(202.103.142.29:5000 )发送给ClientB-1 ,告诉ClientB-1ClientA-1 想和它通信。

3. ClientB-1 ClientA-1202.103.142.29:5000 )发送UDP 数据包,当然这个包在到达NAT-A 的时候,还是会被丢弃,这并不是关键的,因为发送这个UDP 包只是为了让NAT-B 记住这次通信的目的地址:端口号,当下次以这个地址和端口为源的数据到达的时候就不会被NAT-B 丢弃,这样就在NAT-B 上打了一个从ClientB-1ClientA-1 的孔。

4. 为了让ClientA-1 知道什么时候才可以向ClientB-1 发送数据,所以ClientB-1 在向ClientA-1202.103.142.29:5000 )打孔之后还要向Server 发送一个消息,告诉Server 它已经准备好了。

5. Server 发送一个消息给ClientA-1 ,内容为:ClientB-1 已经准备好了,你可以向ClientB-1 发送消息了。

6. ClientA-1 ClientB-1 发送UDP 数据包。这个数据包不会被NAT-B 丢弃,以后ClientB-1ClientA-1 发送的数据包也不会被ClientA-1 丢弃,因为NAT-A 已经知道是ClientA-1 首先发起的通信。至此,ClientA-1ClientB-1 就可以进行通信了。

2.3. 使用TCP 穿透NAT

使用TCP 协议穿透NAT 的方式和使用UDP 协议穿透NAT 的方式几乎一样,没有什么本质上的区别,只是将无连接的UDP 变成了面向连接的TCP 。值得注意是:

1.     ClientB-1 在向ClientA-1 打孔时,发送的SYN 数据包,而且同样会被NAT-A 丢弃。同时,ClientB-1 需要在原来的socket 上监听,由于重用socket ,所以需要将socket 属性设置为SO_REUSEADDR

2.     ClientA-1 ClientB-1 发送连接请求。同样,由于ClientB-1ClientA-1 方向的孔已经打好,所以连接会成功,经过3 次握手后,ClientA-1ClientB-1 之间的连接就建立起来了。

2.4. 穿透对称NAT

    上面讨论的都是怎样穿透锥(ConeNAT ,对称NAT 和锥NAT 很不一样。对于 对称NAT ,当一个私网内主机和外部多个不同主机通信时,对称NAT 并不会像锥(Cone ,全锥,限制性锥,端口限制性锥)NAT 那样分配同一个端口。而是会新建立一个Session ,重新分配一个端口。参考上面穿透限制性锥NAT 的过程,在步骤3 时:ClientB-1221.10.145.84: ?)向ClientA-1 打孔的时候,对称NAT 将给ClientB-1 重新分配一个端口号,而这个端口号对于ServerClientB-1ClientA-1 来说都是未知的。同样, ClientA-1 根本不会收到这个消息,同时在步骤4ClientB-1 发送给Server 的通知消息中,ClientB-1socket 依旧是(221.10.145.84:6000 )。而且,在步骤6 时:ClientA-1 向它所知道但错误的ClientB-1 发送数据包时,NAT-1 也会重新给ClientA-1 分配端口号。所以,穿透对称NAT 的机会很小。下面是两种有可能穿透对称NAT 的策略。

2.4.1 .同时开放TCP Simultaneous TCP open )策略

如果一个 对称 NAT 接收到一个来自 本地 私有网 外面的 TCP SYN 包, 个包想 起一个 引入 TCP 接,一般来 NAT 会拒 绝这 求并扔掉 SYN 包,或者回送一个TCP RSTconnection reset ,重建 接)包 给请 求方。但是,有一 情况 却会接受这个“引入”连接。

RFC 规定:对于对称NAT 个接收到的 SYN 包中的源IP 地址 端口、目 IP 地址 端口都与NAT 的一个已 激活的 TCP 中的地址信息相符 NAT 将会放行 SYN 包。 需要 指出 的是:怎样才是一个已经激活的TCP 连接?除了真正已经建立完成的TCP 连接外,RFC 规范指出: 如果 NAT 恰好看到一个 刚刚发 送出去的一个 SYN 包和 随之 接收到的SYN 包中的地址 :端口 信息相符合的 ,那 NAT 将会 认为这 TCP 接已 被激活,并将允 许这 个方向的 SYN NAT 内部。 同时开放TCP 策略就是利用这个时机来建立连接的。

如果 Client A -1 Client B -1 彼此正确的 方的 NAT 将会 下一个 TCP 接分配的公网 TCP 端口,并且两个客 端能 起一 个面向对方的 外出 TCP 请求 ,并在 方的 SYN 包到达之前,自己 刚发 送出去的 SYN 包都能 利的穿 自己的 NAT ,一条端 端的 TCP 接就 成功地建立了

2.4.2. UDP 端口猜测策略

同时开放TCP 策略非常依赖于猜测对方的下一个端口,而且强烈依赖于发送连接请求的时机,而且还有网络的不确定性,所以能够建立的机会很小,即使Server 充当同步时钟的角色。下面是一种通过UDP 穿透的方法,由于UDP 不需要建立连接,所以也就不需要考虑“同时开放”的问题。

为了介绍ClientB-1 的诡计,先介绍一下STUN 协议。STUNSimple Traversal of UDP Through NATs )协议是一个轻量级协议,用来探测被NAT 映射后的地址:端口。STUN 采用C/S 结构,需要探测自己被NAT 转换后的地址:端口的ClientServer 发送请求,Server 返回Client 转换后的地址:端口。

参考4.2 节中穿透NAT 的步骤2 ,当ClientB-1 收到Server 发送给它的消息后,ClientB-1 即打开3socketsocket-0STUN Server 发送请求,收到回复后,假设得知它被转换后的地址:端口( 221.10.145.84:600 5 ),socket-1ClientA-1 发送一个UDP 包,socket-2 再次向另一个STUN Server 发送请求,假设得到它被转换后的地址:端口( 221.10.145.84:60 20 )。通常,对称NAT 分配端口有两种策略,一种是按顺序增加,一种是随机分配。如果这里对称NAT 使用顺序增加策略,那么,ClientB-1 将两次收到的地址:端口发送给Server 后,Server 就可以通知ClientA-1 在这个端口范围内猜测刚才ClientB-1 发送给它的socket-1 中被NAT 映射后的地址:端口,ClientA-1 很有可能在孔有效期内成功猜测到端口号,从而和ClientB-1 成功通信。

2.4.3. 问题总结

    从上面两种穿透对称NAT 的方法来看,都建立在了严格的假设条件下。但是现实中多数的NAT 都是锥NAT ,因为资源毕竟很重要,反观对称NAT ,由于太不节约端口号所以相对来说成本较高。所以,不管是穿透锥NAT ,还是对称NAT ,现实中都是可以办到的。除非对称NAT 真的使用随机算法来分配可用的端口。

 

使用TCP协议的NAT穿透技术

使用TCP协议的NAT穿透技术
  • chenlycly
  • chenlycly
  • 2016年08月28日 11:31
  • 2585

使用TCP协议的NAT穿透技术 (转)

其实很早我就已经实现了使用TCP协议穿透NAT了,但是苦于一直没有时间,所以没有写出来,现在终于放假有一点空闲,于是写出来共享之。    一直以来,说起NAT穿透,很多人都会被告知使用UDP打孔这个技...
  • hairetz
  • hairetz
  • 2009年04月22日 23:37
  • 10751

使用TCP协议的NAT穿透技术 (转)

其实很早我就已经实现了使用TCP协议穿透NAT了,但是苦于一直没有时间,所以没有写出来,现在终于放假有一点空闲,于是写出来共享之。     一直以来,说起NAT穿透,很多人都会被告知使用UD...
  • HK_5788
  • HK_5788
  • 2015年11月20日 22:21
  • 2912

关于使用UDP(TCP)跨局域网,NAT穿透的心得

前言:        最近我用java做了一个C/S的类似QQ之类的IM系统(即时通讯系统),遇到了不能跨局域网通讯的问题,经过在网上,和书上查阅了一些资料,了解了一些情况,现在就总结一下我的解决方...
  • q376420785
  • q376420785
  • 2012年12月12日 14:00
  • 8642

基于TCP的NAT穿透

进入P2P开发不知不觉已经有一年多,为了解决国内80%~90%NAT用户的互联互通,跟NAT穿透死磕了一段时间,基本方案和结论如下。基于UPNP的方案。现在据说很多网关都支持,曾经测试了一次,NAT用...
  • ppmate
  • ppmate
  • 2006年07月15日 15:17
  • 1689

关于使用UDP(TCP)跨局域网,NAT穿透的心得

关于使用UDP(TCP)跨局域网,NAT穿透的心得
  • chenlycly
  • chenlycly
  • 2016年08月28日 11:38
  • 4896

UDP协议点对点(P2P)通讯(或者说NAT穿越)实例

UDP协议点对点(P2P)通讯实例。 【实验环境】 一个服务端Server,两个客户端:Client1和Client2 。Server和Client1在Linux系统上运行,Client2在Win...
  • iw1210
  • iw1210
  • 2016年07月24日 11:41
  • 2224

P2P通信 原理-UDP打洞方式

在传统的集中式网络中,都是一台服务器(集群)对外提供服务,所有客户端都依赖中央服务器进行与服务端的通信或者其他客户端的通信。如图   这样的通信方式,一个数据包从一个客户端发送到另一个客户端...
  • u010402518
  • u010402518
  • 2013年11月13日 08:05
  • 2734

P2P之UDP穿透NAT的原理与实现(附源代码)

原文链接 关于UDP穿透NAT的中文资料在网络上是很少的,仅有>这篇文章有实际的参考价值。 本人近两年来也一直从事P2P方面的开发工作,比较有代表性的是个人开发的BitTorrent下载软件 ...
  • zhiboshequ
  • zhiboshequ
  • 2017年01月13日 13:43
  • 2749

P2P之UDP穿透的简单实现方式

简单介绍了NAT类型、NAT检测方式及通信的实现方式
  • Roland_Wu
  • Roland_Wu
  • 2015年03月21日 10:19
  • 1320
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:P2P,UDP和TCP穿透NAT
举报原因:
原因补充:

(最多只允许输入30个字)