P2P:UDP穿透NAT防火墙

来源:互联网 发布:天刀脸型数据怎么捏好 编辑:程序博客网 时间:2024/04/29 19:47
在大部分网络使用NAT,或者像我们学校,虽然IP是公网的,但是网关防火墙都不允许外面的访问我们内部,这样的情况就得用p2p技术了。因为这次做的东西需要用到p2p传输,就找了一些资料,整理了一下。

 

对于UDP:一种是Cone NAT,简单说就是NAT每次分配给内网的端口是一样的,即使连接不同的主机,NAT上的端口还是不变(除非过期)。类似这样的NAT或防火墙,已经有比较可靠的解决方法:Peer-to-Peer (P2P) communication across middleboxes

 

另外一种是Symmetric NAT,对于这种NAT,内网连接不同的其他主机,NAT分配给它的是不同的端口。这种情况下,使用上面的方法就已经无效了。可能的办法就是猜测NAT下次将要分配的端口,也有算法可以比较准确得猜测到端口:Symmetric NAT Traversal using STUN

 

虽然还是没有办法完全猜对,但也是一种办法。我已经用实现Cone NAT,因为考虑到现在大部分的NAT不是Symmetric的,因此,就不去考虑Symmetric的实现了,也许日后有时间可以考虑。

 

对于TCP,也有办法:Establishing TCP Connections Between Hosts Behind NATs

TCP现在还没用上,估计很快就要用到了。 

 
 

这里总结一下UDP穿透NAT:

 

   对于Cone NAT,是这样的情况:

           Server S1                                     Server S2

        18.181.0.31:1235                             138.76.29.7:1235

               |                                             |

               |                                             |

               +----------------------+----------------------+

                                      |

          ^ Session 1 (A-S1) ^      |      ^ Session 2 (A-S2) ^

          | 18.181.0.31:1235 |      |      | 138.76.29.7:1235 |

          v 155.99.25.11:62000 v      |      v 155.99.25.11:62000 v

                                      |

                                   Cone NAT

                                 155.99.25.11

                                      |

          ^ Session 1 (A-S1) ^      |      ^ Session 2 (A-S2) ^

          | 18.181.0.31:1235 |      |      | 138.76.29.7:1235 |

          v   10.0.0.1:1234    v      |      v   10.0.0.1:1234    v

                                      |

                                   Client A

                                10.0.0.1:1234

 

下面是Symmetric NAT

 

           Server S1                                     Server S2

        18.181.0.31:1235                             138.76.29.7:1235

               |                                             |

               |                                             |

               +----------------------+----------------------+

                                      |

          ^ Session 1 (A-S1) ^      |      ^ Session 2 (A-S2) ^

          | 18.181.0.31:1235 |      |      | 138.76.29.7:1235 |

          v 155.99.25.11:62000 v      |      v 155.99.25.11:62001 v

                                      |

                                 Symmetric NAT

                                 155.99.25.11

                                      |

          ^ Session 1 (A-S1) ^      |      ^ Session 2 (A-S2) ^

          | 18.181.0.31:1235 |      |      | 138.76.29.7:1235 |

          v   10.0.0.1:1234    v      |      v   10.0.0.1:1234    v

                                      |

                                   Client A

                                10.0.0.1:1234

 

 

 

我实现的是Cone NAT,所有就说说Cone NAT:

 

                                Server S

                                   |

                                   |

            +----------------------+----------------------+

            |                                             |

          NAT A(NAip:NAport)                       NAT B(NBip:NBport)

            |                                             |

            |                                             |

         Client A                                      Client B

 

 

   假设上图中的NATA和NATB都是Cone NAT。

现在ClientA要向ClientB发送数据(比如文件),首先ClientA和B分别通过他们的NATA和B在ServerS上登记,ServerS记录他们NAT的IP和端口号(因为是NAT和ServerS通信的,所以ServerS能也只能得到NAT的地址和端口号)。现在ClientA通过NATA告诉ServerS说要传文件给Client,ServerS就把ClientA的NATA的IP和端口号发送给NATB(因为B的NAT端口已经在ServerS上有记录了),ClientB收到后发送连接数据给NATA,这个时候NATA是不会接受ClientB发过来的包的,因为ClientA没有连接过B,NATA就不会接受B的数据了。虽然B连接A不成功,但是B已经连接过A了,NATB记住了,这时B告诉ServerS叫A过来连,A收到命令后连接B就成功了,于是建立连接,后面的传输就成功了!

 

整个过程如下:

ClientA-->NATA-->ServerS(A在S登记NAip:NAport)
ClientB-->NATB-->ServerS (B在S登记NBip:NBport)

ClientA-->NATA-->ServerS(A告诉S,要发数据给B)
ServerS-->NATB-->ClinetB(S把NAip:NAport发给B,并告诉B,A要发数据给你了)

ClientB-->NATB-->NATA(NAip:NAport)-->Dropped-->ClientA (B发的包别NATA丢掉了,A是收不到了)
ClientB-->NATB-->ServerS(B等不到A的回应,就告诉S,叫A过来连我吧)

ServerS-->NATA-->ClinetA(S把NBip:NBport发给A,并告诉A,B连不到你,你连B吧)
ClientA-->NATA-->NATB(NBip:NBport)-->ClinetB(B收到A的连接请求,要发送应答给A)
ClientB-->NATB-->NATA-->ClientA(A收到B的应答,后面可以发送数据给NBip:NBport了)

ClientA-->NATA-->NATB-->ClientB(现在开始就从这条路发数据了)

……

 

一般防火墙原理:

防火墙的设置分未界内根界外,就像以前使用的AtGuard,如果设置界内,就是对从外面发起的连接进行检测,如果规则设置阻挡,那么从外面访问进来的连接就被阻挡。但是,这不是说这样单方面的通信,很多人对这个不清楚,以为防火墙都不让外面进来了,那文件是怎么传的?其实,如果从里面发起连接,然后外面就可以连接进来了。虽然我没有关于防火墙确切的资料,但根据我的掌握的理论,我想我的推理是正确的。先由里面发起连接对方的请求,防火墙就会记住这个信息(也许是建立了一个session,一定时间内会释放或过期),对方收到请求,反过来连接防火墙是允许的。所以,对于上面的NAT原理,当然是可以用于一般的防火墙,而且更简单,因为得到的“NAT”的IP和端口都是本机的。

 

实现:

 

NAT信息的获取和发送:

 

理论上解决了,实现这个就简单了。本来做这个就是因为自己的客户端JBQ的需要,因此直接在JBQ客户端上面做。而服务器(用于p2p的服务器另外写)。原来的JBQ消息和文件都是通过服务器中转,现在就是把文件这部分改成p2p。

按照上面的原理,发送方需要把自己在NAT上的地址信息发送给接受方,然后由接受方向发送方连接,这样就可以在接受方的防火墙上面开个session,以让发送方进行后面的连接。但接受方连接不成功的时候,把自己的NAT信息再通过服务器发送给发送发送方,然后发送方再次连接接受方,于是建立连接。这里用到的服务器有两个,一个用来发送NAT信息,还有一个用来获取NAT信息。

 

本来这个两个应该是用同一个服务器,但是我们有原来的聊天服务器,因此,发送NAT信息的任务就交给聊天服务器,现在只要完成获取NAT信息的服务器就可以了。不管是Tcp还是UDP,连接双方都可以直接得到对方得IP和端口,因为只要由需要自己的NAT信息的客户端向p2p服务器发一个消息,p2p把跟它连接的客户端使用的NAT信息发回给客户端就可以。客户端收到p2p服务器发回来的消息以后,就可以把这个消息通过聊天服务器发给对方。

 

其他的握手和连接通过上面的理论都可以比较容易的写出来。

 

存在的问题:这种方法只适用于Cone NAT,对于Symmetric NAT还需要通过猜测端口。

另外,同样不适用于TCP,因为TCP的三次握手在这样的连接中必定失败。但也可以通过一点的办法解决,这个上面提到过。

 

 

总结:总的来说,上面用的方法可以解决的这一类NAT(防火墙的问题),可以让都处于NAT或防火墙后面的双方直接连接。上面的实现解决了我的JBQ客户端里面的一系列问题,视频等都已经在这个基础上实现p2p了。
 

总结:总的来说,上面用的方法可以解决的这一类NAT(防火墙的问题),可以让都处于NAT或防火墙后面的双方直接连接。上面的实现解决了我的JBQ客户端里面的一系列问题,视频等都已经在这个基础上实现p2p了。

另外,同样不适用于TCP,因为TCP的三次握手在这样的连接中必定失败。但也可以通过一点的办法解决,这个上面提到过。

存在的问题:这种方法只适用于Cone NAT,对于Symmetric NAT还需要通过猜测端口。

其他的握手和连接通过上面的理论都可以比较容易的写出来。

本来这个两个应该是用同一个服务器,但是我们有原来的聊天服务器,因此,发送NAT信息的任务就交给聊天服务器,现在只要完成获取NAT信息的服务器就可以了。不管是Tcp还是UDP,连接双方都可以直接得到对方得IP和端口,因为只要由需要自己的NAT信息的客户端向p2p服务器发一个消息,p2p把跟它连接的客户端使用的NAT信息发回给客户端就可以。客户端收到p2p服务器发回来的消息以后,就可以把这个消息通过聊天服务器发给对方。

按照上面的原理,发送方需要把自己在NAT上的地址信息发送给接受方,然后由接受方向发送方连接,这样就可以在接受方的防火墙上面开个session,以让发送方进行后面的连接。但接受方连接不成功的时候,把自己的NAT信息再通过服务器发送给发送发送方,然后发送方再次连接接受方,于是建立连接。这里用到的服务器有两个,一个用来发送NAT信息,还有一个用来获取NAT信息。

理论上解决了,实现这个就简单了。本来做这个就是因为自己的客户端JBQ的需要,因此直接在JBQ客户端上面做。而服务器(用于p2p的服务器另外写)。原来的JBQ消息和文件都是通过服务器中转,现在就是把文件这部分改成p2p。

NAT信息的获取和发送:

实现:

防火墙的设置分未界内根界外,就像以前使用的AtGuard,如果设置界内,就是对从外面发起的连接进行检测,如果规则设置阻挡,那么从外面访问进来的连接就被阻挡。但是,这不是说这样单方面的通信,很多人对这个不清楚,以为防火墙都不让外面进来了,那文件是怎么传的?其实,如果从里面发起连接,然后外面就可以连接进来了。虽然我没有关于防火墙确切的资料,但根据我的掌握的理论,我想我的推理是正确的。先由里面发起连接对方的请求,防火墙就会记住这个信息(也许是建立了一个session,一定时间内会释放或过期),对方收到请求,反过来连接防火墙是允许的。所以,对于上面的NAT原理,当然是可以用于一般的防火墙,而且更简单,因为得到的“NAT”的IP和端口都是本机的。

一般防火墙原理:

 

 

 

 
原创粉丝点击