使用UDP进行NAT穿透小记
如题
现在家庭的宽度默认情况下都不给公网IP,需要宽带办理人打电话给运营商要求换成公网IP。如果是租房的情况下,就很麻烦了。就开始研究NAT穿透的方式,其中UDP穿透的原理经过研究后发现之前的理解不对,所以在这里记录一下。
假设的场景如下:
- 家里的设备A,网关设备不可控,所以没有公网IP
- 其他地方任意一个内网设备B
- 有一台公网服务器S
之前,在我的理解中,UDP穿透是S监听一个UDP端口8888,A访问S的8888端口,S可以获得A的公网IP和一个端口,B设备可以往这个IP端口发送数据,A就能收到数据了。不过这种思路测试没通过,一开始以为是socket写法有特殊要求。
不过后续的研究中,发现我的理解有误。正确的思路应该如下:
A往服务器S发包:
1 | import socket |
B往服务器S发包:
1 | import socket |
S服务器获取客户端的相关信息:
1 | import socket |
A往B发包:
1 | s.sendto(b"1", ('y.y.y.y', 27684)) |
B往A发包:
1 | s.sendto(b"1", ('x.x.x.x', 31829)) |
然后A和B就能直接通信了,不需要经过服务器S,而TCP是没办法跳过服务器S的,这是UDP穿透的一个优点。
原理很简单,首先A的端口a往外部发送UDP包,A的网关会根据客户端的ip端口随机绑定一个端口进行数据传输,测试如下,写一个UDP发包脚步,绑定好端口,每次运行,服务端接收到的端口都是一样的,代码如下:
1 | import socket |
多次运行这个脚本,服务端接收到的结果:
1 | import socket |
虽然会根据内网的源IP端口绑定一个端口,但是NAT转发表却不是根据这个端口作为规则进行转发的。
当A往S的8888端口发送数据包以后,S的8888端口也是能往A发送数据包的,因为是UDP协议,所以不存在握手的操作。所以NAT表记录的是:当A往s.s.s.s:S发送数据包以后,会开启一个端口a进行数据传输,当这个端口接收到源地址端口为s.s.s.s:S的数据包后,讲回讲数据包转发给A。
原理如上,概括一下使用UDP协议进行的NAT穿透就是:
两台内网设备,通过服务器S,让各自的网关开启一个数据传输端口,然后各自获取对方的数据传输端口。然后互相往对方的数据传输端口发送数据来建立隧道。
使用UDP进行NAT穿透小记