(Python) UDP 打洞進行 NAT 穿越測試

根據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

udp-nat-serv

Client1

udp-nat-client1

Client2

udp-nat-client2

測試的滿成功的,兩頭躲在NAT後面的主機互相連像傳送了封包,感覺這東西可以來寫Botnet之類的

留言

comments

發佈留言