所用属于和代号。
A : 私网中的主机,设私网IP为192.168.1.2
B : 另一私网中的主机,设私网IP为192.168.245.10
S : 公网中的主机,在此做中间服务器,设IP为223.11.11.11
NAT: Net Address Transmission,在此可以理解为路由器
NAT-A:A所在的私网路由器,假设公网IP为188.11.11.11
NAT-B:B所在的私网路由器,假设公网IP为199.11.11.11
打洞需要突破几个关键的壁垒,
1. A,B互相无法知道对方公网IP,A,B也不知道自己公网IP。
解决办法:借助公网服务器S牵线搭桥。
2. NAT会阻挡不明来源的信息货连接。就是说,即使A知道B的公网地址(包括IP和端口)也无法给B连接请求或信息,因为NAT-B会阻挡不明来源的 信息或连接,此举是NAT过去阻挡SYN攻击的有效手段。
解决办法:让B先突破NAT-B试图连接NAT-A后的A,当然此举会失败,但是会在NAT-B上留下一个印记:“NAT-A是可识别的地址”,所以,随后的
A-->NAT-A-->NAT-B-->B就会被NAT-B放行。于是连接成功。
3. 还有很多NAT不支持hairpin,即不支持曲线路由,即假设C,D处于同一内网的主机,那么他们不可通过NAT通信。即: C-->(NAT-C-->NAT-D)--D是不行的。所以这种情况只能直接用私网地址通信C--->D。
有幸的是,现在绝大部分NAT都支持将私网主机地址与NAT地址的稳固一致隐射,即:
假设A(192.168.1.2::1000)第一次经由NAT-A时隐射到地址(188.11.11.11::1111)到达S,那么以后从A(192.168.1.2::1000)出来的信息或连接都会到NAT-A (188.11.11.11::1111)后,再到公网。也就是说,(188.11.11.11::1111)总是A(192.168.1.2::1000)的公网地址,这一映射会在NAT-A上保留一段时间(大于20秒),这使得穿越成为可能,不管是Tcp还是Udp,原理一样。
Udp穿越步骤:
1) A发Udp包给S,保重附带有A的私网地址(IP::Port),S又从Udp头中可以获得A的公网地址。
2) B发Udp包给S,保重附带有A的私网IP地址,S又从Udp头中可以获得B的公网地址。
3) S将A的公网地址和私网地址告诉B, 将B的公网地址和私网地址告诉A
4) A,B分别向对方的公网和私网地址发送信息,并等待接受对方发过来的信息。最早返回回来的信息的源地址,将被采纳为对方的有效地址,不管是公网的还是私网的地址,此后就直接与这一有效地址通信。需要说明的是:假设A先于B发出了第一个消息,那么A的第一个消息会被NAT-B阻挡而失败,这一发出的消息会在NAT-A上留下印记,标明B的公网地址为可信的,然后B的任何消息就可以顺利到达A,同时B第一消息会在NAT-B上留下印记,标明A为可信地址,此后A的消息就可以到达B。
这样,AB就可以正常通信。即使AB除以同一私网。
Tcp穿越步骤:
原理基本和Udp穿越类似,不同的是Tcp在使用私网IP发起连接(connect and recv)的同时,要在此私网地址上启动侦听:listen and Accept. 但是自XP Service Pack 2之后的Windows系统和所有Unix或linux系统的 socket都有属性SO_REUSEADDR,这就可以实现。对于
不支持socket
SO_REUSEADDR属性的系统,可以采用顺序连接来打洞的方式。即A与S连接通信之后,断开连接,然后尝试与B连接,失败后listen and AccpetB的连接。
希望是对你有意义的一段文字。
参考文档:
http://www.brynosaurus.com/pub/net/p2pnat/#rfc3489
这里有demo代码,可看看是怎么实现的。
代码演示了udp打洞技术的实现;
http://download.csdn.net/detail/supermagician/5945753