欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

p2p NAT 渗透

最编程 2024-03-13 15:59:43
...

什么是NAT

NAT(Network Address Translation),网络地址转换。是1994年提出的。当在专用网内部的一些主机本来已经分配到了本地IP地址(即仅在本专用网内使用的专用地址),但现在又想和因特网上的主机通信(并不需要加密)时,可使用NAT方法。
。装有NAT软件的路由器叫做NAT路由器,它至少有一个有效的外部全球IP地址。这样,所有使用本地地址的主机在和外界通信时,都要在NAT路由器上将其本地地址转换成全球IP地址,才能和因特网连接。
同样还有NAPT,网络地址、端口转换。现在一般穿透规则就是通过获取ip、端口来实现的,重点是实现穿透,所以以下统称NAT即可。

为什么要穿透NAT

NAT可以有效的减缓全球IP枯竭的问题。但是同时NAT也屏蔽了内部设备。

比如在局域网A下有一个内网IP地址为192.168.1.155的设备A,现在一个设备B想要访问这个设备A,根据设备B所在网络可分为一下情况。

  • 设备B同在局域网A中:
    设备B可直接通过设备内网ip 192.168.1.155 地址访问设备A;
  • 设备B在外网:
    设备B无法通过设备A内网访问设备A;
  • 设备B在不同局域网A的局域网B中:
    设备B在通过ip 192.168.1.155 访问的时候可能访问到局域网B下内网IP也为192.168.1.155的设备C,也可能找不到该ip,但是无法访问设备A。

这就是为什么在内网建立一个tcp或者udp服务,内网客户端可以通过ip和端口号直接通信,而外网却无法访问该内网建立的服务。
要实现p2p(Peer to Peer),首先我们的要知道客户端ip和端口号,但是通过局域网路由器的NAT转换,生成的外网ip和端口我们无法预知,这样我们就无法建立p2p连接。

NAPT转换

如果你还是不明白NAT为什么屏蔽了内部设备,接下来举个NAT转换例子就明白了。
例:
内网机器A ip(192.168.1.188) 端口(9999) - 访问外网目标主机B ip(220.233.28.42) 端口(8888):

1.数据包

目的主机:220.233.28.42
目的端口:8888

源主机:192.168.1.188
源端口:9999 (用户自定义或随机)

2.地址转换

目的主机:220.233.28.42
目的端口:8888

源主机:123.206.41.242 (NAPT转换,为路由器外网ip)
源端口:17309 (NAPT转换)

3.记录地址映射

192.168.1.188:9999 ---- 123.206.41.242:17309

4.外网主机B向内网主机A返回响应消息

目的主机:123.206.41.242
目的端口:17309

源主机:220.233.28.42
源端口:8888

5.NAPT查找地址映像并转换

目的主机:192.168.1.188
目的端口:9999

源主机:220.233.28.42
源端口:8888

通过地址转换,主机A的内网地址被映射之后我们是无法预知的,而且我们无法通过主机A的内网地址直接访问A,所以NAT屏蔽了主机A。

通过例子可以看到,当主机A访问外网主机B时,通过NAT随机分配一个(外网ip为路由器外网ip)端口,这样就把内网地址映射成了一个唯一的外网地址。然后外网主机B响应主机A时,主机B不直接访问主机A,而是通过NAT转换后的地址访问路由器,路由器就会通过映射把数据分配给内网主机A。这也就是NAT穿透的原理。

NAPT穿透原理

通过双方所在网络环境不同可分为一下模式:

  • 一个在局域网,另一个在外网
  • 都在不同的局域网
  • 都在相同的局域网

上一章节已经提到了一种穿透方式,即:局域网-外网的访问模式,因为主机B在外网,ip端口确定,主机A可以直接通过B的外网地址访问B,外网主机B首先接受到了主机A的数据包,便可以知道主机A经过NAT转化后的外网地址,然后就可以进行相互通信。
但是如果双方都在不同的局域网,互相都不知道自己的外网地址怎么办。
这种情况就需要利用一个拥有唯一IP的中间服务器S,因为S ip固定并且已知,就让两个设备都向S发送数据包,S就可以的知道两个设备的公网ip,在设备p2p通信之前先去服务器查找对方的ip、端口,就可以实现通信。
两个设备同时处在同一个局域网下,可以不通过NAT,直接用内网ip进行通信,这是最节省带宽的方式。当然,也可以通过第二种,通过S服务器来得到外网ip端口,这种情况外网的IP是相同的(同一个路由器),只是分配的端口不同。

发送数据的方式利用UDP,虽然UDP不可靠,但是UDP可以轻松实现穿透。通过浏览各大博客,都没有找到通过TCP实现穿透的项目,甚至有人说TCP几乎不可能实现穿透(博主初学,还望指点)。

使用过UDP的肯定知道,首先创建一个UDP监听端口,然后可以通过这个端口发送和接收数据包。NAT会把这个监听端口映射为外网ip和端口。我们只需要通过端口发送数据包给服务器就可以让服务器拿到这个端口信息,然后可以让其他客户机通过这个端口的信息来发送数据给该端口。

在这里NAPT对UDP的端口映射(session)还有一定的规则:

  • A.源地址(内网ip)不相同,忽略其他因素,则session不同。
  • B.源地址相同,源端口不同,忽略其他因素,则session不同。
  • C.源地址相同,源端口相同,目标地址不同,对于不同的NAPT,session可能不同。(一般大部分是相同的,不同的无法进行穿透)
  • D.源地址相同,源端口相同,目标地址相同,任何端口,session一定相同。

session并不是长期存在的,不同的路由器session储存时间不同,短的有的几十秒,长的可能有的几分种。要想维持这个session可以通过心跳包来维持,比如10秒向服务器发送一个心跳包。并且对于上面第三种情况,如果最后session不同,就无法实现穿透(这种类型一般少见)。

NAT穿透UDP具体实现

本来是打算把我的java代码黏贴出来的,后来想了想,我写的只是其中一种实现方式,不同语言也有不同的实现方式,我就来说说实现的步骤,就不再写代码了。也挺简单的。

  1. 客户端建立一个UDP监听端口
  2. 客户端做一个心跳包向服务器发送数据包
  3. 服务器接收到心跳包后,储存客户端的ip、端口信息

当客户端要进行p2p通信的时候

  1. 发送方服务器查询接收方ip、端口
  2. 数据包定向ip、端口发送数据包
  3. 完成通信

注意 重点

到此,你以为结束了? 那就大错特错了。
到这里你会发现,接收方(以下统称A)可能拿不到数据包,这种情况出现在接收方在局域网内(需要穿透NAT)。
前面讲的,并不是仅仅获取到设备外网地址就可以成功穿透,还要注意NAT会把不认识的数据丢弃。
这是为什么?
NAT丢弃了你这个来源不明的包,根本没有分发给接收设备A。
为什么叫来源不明呢,这是因为首先A的UDP端口给服务器发数据包,A的NAT创建了一个session,这样A再接收到服务器的数据时,会查找这个映射(A<--->服务器),这个映射就储存在这个session里。但是发送方(B)向A的NAT发送数据(这是在B的NAT建立对A的映射),没有指向B的映射,所以数据包被A的NAT丢弃。
那怎么解决呢,其实让A也向B发一个数据包就好了,这样A的NAT会建立一个对B的session,这样再收到B的数据NAT就可以查找到对应的映射了。

之前提到的NAPT对UDP的session映射,源地址相同,源端口相同,目标地址不同,对于不同的NAPT,session可能不同。这条规则是依据不同的NAT的。Symmetric NAPT会导致session不同,Cone NAPT则是相同的。对于p2p只要一方使用的是Symmetric NAPT就会导致无法穿透。具体可自行百度。