使用UDP进行NAT穿透小记

如题

现在家庭的宽度默认情况下都不给公网IP,需要宽带办理人打电话给运营商要求换成公网IP。如果是租房的情况下,就很麻烦了。就开始研究NAT穿透的方式,其中UDP穿透的原理经过研究后发现之前的理解不对,所以在这里记录一下。

假设的场景如下:

  1. 家里的设备A,网关设备不可控,所以没有公网IP
  2. 其他地方任意一个内网设备B
  3. 有一台公网服务器S

之前,在我的理解中,UDP穿透是S监听一个UDP端口8888,A访问S的8888端口,S可以获得A的公网IP和一个端口,B设备可以往这个IP端口发送数据,A就能收到数据了。不过这种思路测试没通过,一开始以为是socket写法有特殊要求。

不过后续的研究中,发现我的理解有误。正确的思路应该如下:

A往服务器S发包:

1
2
3
>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.sendto(b"abcdefg", ('S', 8888))

B往服务器S发包:

1
2
3
>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.sendto(b"ggggggggg", ('S', 8888))

S服务器获取客户端的相关信息:

1
2
3
4
5
6
7
8
9
10
11
>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.bind(('0.0.0.0', 8888))
>>> while True:
... data, addr = s.recvfrom(1024)
... print('Received from %s:%s.' % addr)
... print('data: %s'%data)
Received from x.x.x.x:31829.
data: b'abcdefg'
Received from y.y.y.y:27684.
data: b'ggggggggg'

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
2
3
4
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", 9000))
s.sendto(b"110", ('S', 8888))

多次运行这个脚本,服务端接收到的结果:

1
2
3
4
5
6
7
8
9
10
11
>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.bind(('0.0.0.0', 8888))
>>> while True:
... data, addr = s.recvfrom(1024)
... print('Received from %s:%s.' % addr)
... print('data: %s'%data)
Received from x.x.x.x:31762.
data: b'110'
Received from x.x.x.x:31762.
data: b'110'

虽然会根据内网的源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穿透小记

https://nobb.site/2021/04/06/0x5F/

Author

Hcamael

Posted on

2021-04-06

Updated on

2021-04-07

Licensed under