根據Wiki的資料
UDP打洞實現了私有網絡中的Internet主機之間建立雙向UDP連接的方法。不過由於NAT的行為是非標準化的,這方法不能應用於所有類型的NAT。
基本上就是讓位於NAT後的兩台主機都連上某個擁有Public IP 的伺服器,當兩個主機與伺服器建立好UDP連線後,轉成直接連線來傳送資料,其原理簡單來說是讓NAT以為他連線的是原本的那台伺服器主機。
下面是我用了python來實驗UDP打洞的原始碼
Server.py
import socket
#建立 UDP Scoket
UDPSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#監聽 所有IP的 3386 端口
listen_addr = ("", 3386)
UDPSock.bind(listen_addr)
#儲存IP用的 Array
ips = []
while True:
#接收資料
data, addr = UDPSock.recvfrom(1024)
print addr , 'is connected.'
#將Client IP:Port 儲存到Array內
ips.append(str(addr[0]) + ':' + str(addr[1]))
#當第二個Client連上時,進行IP交換動作
if(len(ips) == 2):
dest = ''
for ip in ips:
for i in ips:
if ip != i:
dest = i # 對方的IP
#將A的IP傳給B,B的IP傳給A
UDPSock.sendto(dest, (ip.split(':')[0],int(ip.split(':')[1])))
Client.py
import socket
from threading import Thread
from time import sleep
UDPSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
data = 'hello'
#先連線到公開的伺服器
addr = ("X.X.X.X", 3386)
#接收到封包之後傳給另一台躲在NAT後的主機
def threaded_function(arg):
for i in range(100):
print 'Send ' , i ,'to ', arg
UDPSock.sendto(str(i), (arg.split(':')[0], int(arg.split(':')[1])))
sleep(1)
#先丟給SERVER封包,讓伺服器取得IP資訊
UDPSock.sendto(data,addr)
#接收伺服器回傳的另一台主機IP:PORT
dest,adr = UDPSock.recvfrom(1024)
print 'send ping to ' , dest
#進行打洞
UDPSock.sendto('ping', (dest.split(':')[0], int(dest.split(':')[1])))
thread = Thread(target = threaded_function, args = (dest, ))
thread.start()
#持續接收封包
while True:
data,adr = UDPSock.recvfrom(1024)
print 'Recv' , data , 'from' ,adr
測試結果圖
Server
Client1
Client2
測試的滿成功的,兩頭躲在NAT後面的主機互相連像傳送了封包,感覺這東西可以來寫Botnet之類的。