日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

UDP打洞原理与N2N内网穿透

發布時間:2023/12/18 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UDP打洞原理与N2N内网穿透 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

UDP打洞原理與N2N內網穿透

      • UDP打洞原理
        • 原理
        • Server 端部分代碼
        • Client 端部分代碼
      • N2N網絡穿透
        • 安裝N2N
        • 配置Supernode
        • 配置Edgenode
        • Ping測試
        • 一鍵腳本代碼

UDP打洞原理

通過UDP路由驗證實現NAT穿越是一種在處于使用了NAT的私有網絡中的Internet主機之間建立雙向UDP連接的方法。由于NAT的行為是非標準化的,因此它并不能應用于所有類型的NAT。
其基本思想是這樣的:讓位于NAT后的兩臺主機都與處于公共地址空間的、眾所周知的第三臺服務器相連,然后,一旦NAT設備建立好UDP狀態信息就轉為直接通信,并寄希望于NAT設備會在分組其實是從另外一個主機傳送過來的情況下仍然保持當前狀態。
這項技術需要一個圓錐型NAT設備才能夠正常工作。對稱型NAT不能使用這項技術。
這項技術在P2P軟件和VoIP電話領域被廣泛采用。它是Skype用以繞過防火墻和NAT設備的技術之一。
相同的技術有時還被用于TCP連接——盡管遠沒有UDP成功。

原理


假設有兩臺分別處于各自的私有網絡中的主機:A和B;NA和NB是兩個網絡的NAT設備,分別擁有IP地址P1和P2;S是一個使用了一個眾所周知的、從全球任何地方都能訪問得到的IP地址的公共服務器

步驟一:A和B分別和S建立UDP連接;NAT設備NA和NB創建UDP轉換狀態并分配臨時的外部端口號

步驟二:S檢查UDP包,看A和B的端口是否是正在被使用的(否則的話N1和N2應該是應用了端口隨機分配,這會讓路由驗證變得更麻煩)

步驟三:如果端口不是隨機化的,那么A和B各自選擇端口X和Y,并告知S。S會讓A發送UDP包到P2:Y,讓B發送UDP包到P1:X

步驟四:A和B通過轉換好的IP地址和端口直接聯系到對方的NAT設備;

Server 端部分代碼

//這里是對UDT的啟動記性初始化操作if (UDT::ERROR == UDT::startup()){cout<<"startup: "<<UDT::getlasterror().getErrorMessage()<<endl;}else{cout<<"startup suc..."<<endl;}//socket//像聲明一個普通的socket一樣聲明一個UDTSOCKETUDTSOCKET serv = UDT::socket(AF_INET, SOCK_DGRAM, 0);if (UDT::ERROR == serv){cout<<"socket: "<<UDT::getlasterror().getErrorMessage()<<endl;}else{cout<<"client suc..."<<endl;}//聲明udp socket,這里是udp的哈,不是udtint sersocket = socket(AF_INET,SOCK_DGRAM,0);if (SOCKET_ERROR == sersocket){cout<<"udp socket error!"<<endl;}else{cout<<"clientsocket suc..."<<endl;}//為了能夠在局域網中直接進行處理,先默認設置兩個sockaddr_in my_addr,client_addr;my_addr.sin_family = AF_INET;my_addr.sin_port = htons(atoi(argv[1]));my_addr.sin_addr.s_addr = INADDR_ANY;memset(&(my_addr.sin_zero), '\0', 8);bind(sersocket,(struct sockaddr*)&my_addr,sizeof(my_addr));client_addr.sin_family = AF_INET;client_addr.sin_port = htons(atoi(argv[3]));client_addr.sin_addr.s_addr = inet_addr(argv[2]);//client_addr.sin_addr.s_addr = inet_addr("127.0.0.1");memset(&(client_addr.sin_zero), '\0', 8);int mss = 1052;//最大傳輸單位//設置收發緩沖區大小 接收限時 和地址重用if( !( UDT::ERROR != (UDT::setsockopt(serv, 0, UDT_SNDBUF, new int(32000), sizeof(int)))&& UDT::ERROR != (UDT::setsockopt(serv, 0, UDP_RCVBUF, new int(32000), sizeof(int)))&& UDT::ERROR != (UDT::setsockopt(serv,0,UDT_REUSEADDR,new int(1),sizeof(int)))&& UDT::ERROR != (UDT::setsockopt(serv, 0, UDT_RENDEZVOUS, new bool(true), sizeof(bool))))&& UDT::ERROR != (UDT::setsockopt(serv, 0, UDT_MSS, &mss, sizeof(int)) )){cout<<"udt socket: "<<UDT::getlasterror().getErrorMessage()<<endl;UDT::close(serv);return 0;}//這里是直接將udp的接口綁定在udt的接口之上,如果不這樣做的話是沒法使用UDT中的SOCK_DGRAM的if (UDT::ERROR == UDT::bind2(serv,sersocket)){cout<<"udt bind2:"<<UDT::getlasterror().getErrorMessage()<<endl;return 0;}else{cout<<"bind2 suc"<<endl;}//這里也是關鍵部分,與client端對應的connect操作,就是相互之間的打洞處理if (UDT::ERROR == UDT::connect(serv, (sockaddr*)&client_addr, sizeof(client_addr))){cout << "connect: " << UDT::getlasterror().getErrorMessage();UDT::close(serv);return 0;}else{cout<<"connetc suc"<<endl;}

Client 端部分代碼

//startupif (UDT::ERROR == UDT::startup()){cout<<"startup: "<<UDT::getlasterror().getErrorMessage()<<endl;}else{cout<<"startup suc..."<<endl;}//Initialize the UDT libraryUDTSOCKET client = UDT::socket(AF_INET, SOCK_DGRAM, 0);if (UDT::ERROR == client){cout<<"socket: "<<UDT::getlasterror().getErrorMessage()<<endl;}else{cout<<"client suc..."<<endl;}//聲明udp socketint clientsocket = socket(AF_INET,SOCK_DGRAM,0);if (SOCKET_ERROR == clientsocket){cout<<"udp socket error!"<<endl;}else{cout<<"clientsocket suc..."<<endl;}sockaddr_in serv_addr,my_addr;serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(atoi(argv[3]));serv_addr.sin_addr.s_addr = inet_addr(argv[2]);memset(&(serv_addr.sin_zero), '\0', 8);my_addr.sin_family = AF_INET;my_addr.sin_port = htons(atoi(argv[1]));my_addr.sin_addr.s_addr = INADDR_ANY;memset(&(my_addr.sin_zero), '\0', 8);bind(clientsocket,(struct sockaddr*)&my_addr,sizeof(my_addr));int mss = 1052;//最大傳輸單位//設置收發緩沖區大小 接收限時 和地址重用if( !( UDT::ERROR != (UDT::setsockopt(client, 0, UDT_SNDBUF, new int(32000), sizeof(int)))&& UDT::ERROR != (UDT::setsockopt(client, 0, UDP_RCVBUF, new int(32000), sizeof(int)))&& UDT::ERROR != (UDT::setsockopt(client,0,UDT_REUSEADDR,new int(1),sizeof(int)))&& UDT::ERROR != (UDT::setsockopt(client, 0, UDT_RENDEZVOUS, new bool(true), sizeof(bool))))&& UDT::ERROR != (UDT::setsockopt(client, 0, UDT_MSS, &mss, sizeof(int)))){cout<<"udt socket: "<<UDT::getlasterror().getErrorMessage()<<endl;UDT::close(client);return 0;}if (UDT::ERROR == UDT::bind2(client,clientsocket)){cout<<"udt bind2:"<<UDT::getlasterror().getErrorMessage()<<endl;return 0;}else{cout<<"bind2 suc"<<endl;}// connect to the server, implict bindif (UDT::ERROR == UDT::connect(client, (sockaddr*)&serv_addr, sizeof(serv_addr))){cout << "connect: " << UDT::getlasterror().getErrorMessage();UDT::close(client);return 0;}else{cout<<"connect suc"<<endl;}

以上代碼使用UDT協議進行互相打洞,沒有經過Server服務器(沒有),簡單的實現了網絡穿透,可穿越防火墻。

N2N網絡穿透

N2N是一個開放源代碼的2層跨越3層的×××程序,該程序利用了點對點的架構來處理網絡間的成員關系和路由,N2N的原理如下圖,在搭建的過程中需要一個super節點和多個edge節點,super節點建立一個通信中心,用來路由edge之間的通訊,對于×××使用來說,super node節點必須有一個公網的IP地址

安裝N2N

N2N GitHub地址

sudo apt-get install libssl-dev //安裝openssl git clone https://github.com/meyerd/n2n cd n2n/n2n_v2 cmake CMakeLists.txt make make install

需要root權限

配置Supernode

supernode -l 1000 -v >/dev/null & //監聽1000端口 root@ubuntu16:# supernode -h //可使用 -h查看命令參數 supernode usage -l <lport> Set UDP main listen port to <lport> // UDP 監聽端口 -f Run in foreground. //前臺運行 -u <UID> User ID (numeric) to use when privileges are dropped. // 指定運行所用的UID -g <GID> Group ID (numeric) to use when privileges are dropped. // 指定運行所用的GID -v Increase verbosity. Can be used multiple times. // 輸出比較詳細的log -h This help message.

配置Edgenode

edge -d n2n0 -c mynetwork -k encryptme -a 10.10.10.3 -l X.55.150.X:1000 >/dev/null & -d 虛擬網卡名 -a [static:| dhcp:](虛擬網段ip) -c 用于區分節點的組名 -k 用于加密的字符串 -l supernode的IP:端口,可以指定多個supernode

以上為節點配置,配置完成后 ifconfig 會多出個虛擬網卡

可在服務器上配置 supernode節點, 其余內網client配置edge節點,-a 自定義ip(網段需一致)-l 參數填服務器與監聽的端口

Ping測試


搭建成功則可互相ping通

一鍵腳本代碼

shell腳本代碼(抄來的,略作修改),需root權限運行,centos系統 apt-get 改為 yum

#!/bin/bash #####此腳本用來實現安裝N2N的客戶端,實現內網之間的穿透 ####應用場景: ###客服的服務器有A、B、C三臺,其中有一臺可以上外網,此處以A為例子,ABC之間的SSH互通 ####N2N的server,即super node為114.114.114.114,端口1000,在阿里云端,可以實現外網訪問 ####此腳本用來在客戶的內網搭建N2N的client,可以實現和阿里云supernode的通信,這樣通過阿里云端就可以SSH到客戶服務器內網 N2N_super_node_ip=100.100.100.100 ###改為自己的服務器IP N2N_super_node_port=1000 ###自行更改 ###N2N_edge_ip為搭建的edge的IP,需要設置,網段為10.10.10.* ####但有一個前提,設置的這個IP地址在虛擬局域網中不能沖突,所以需要先判斷IP地址是否沖突 N2N_edge_ip=10.10.10.3 ###自行更改 judge_ip_confilct() {if `ping -c 2 ${N2N_edge_ip} &>/dev/null`;thenecho -e "\033[32m ${N2N_edge_ip} can ping,has client used,please motified N2N_edge_ip,系統退出\033[0m" exit 0elseecho -e "\033[31m ${N2N_edge_ip} not can ping,N2N_edge_ip can be userd\033[0m"fi } check_super_node_service() {ping -c 6 ${N2N_super_node_ip}if `ping -c 2 ${N2N_super_node_ip} &>/dev/null`;thenecho -e "\033[32m super node :${N2N_edge_ip} can ping, N2N server can be used\033[0m"else echo -e "\033[31m super node :${N2N_edge_ip} can not ping ,n2n server can not be used ,please check system quit\033[0m"exitfi } n2n_install_super_node() {if `sudo apt-get install bc &>/dev/null`;thenecho -e "\033[32m yum can be use,starting yum install n2n relative paket:\033[0m"sudo apt-get install subversion gcc-c++ openssl-develecho "git clone install n2n:"git clone https://svn.ntop.org/svn/ntop/trunk/n2nif [ -e n2n ];thenecho "n2n file download successful,beging install n2n"cd n2n/n2n_v2cmake CMakeLists.txtmakemakesudo make installelseecho "n2n file download failed ,has some problems ,please check"exit 0fiecho "n2n install over,beginging start n2n services"supernode -l ${N2N_super_node_port} -v >/dev/null &echo "查看 ps -ef | grep supernode"ps -ef | grep supernodeecho "supernode -l ${N2N_super_node_port} -v >/dev/null &" >> /etc/rc.localelseecho -e "\033[31m yum not can be use,yum install n2 has some problem,please check\033[0m"exitfi } n2n_install_edge_node() {if `sudo apt-get install bc &>/dev/null`;thenecho -e "\033[32m yum can be use,starting yum install n2n relative paket:\033[0m"sudo apt-get install subversion gcc-c++ openssl-develecho "git clone install n2n:"git clone https://github.com/meyerd/n2n.gitif [ -e n2n ];thenecho "n2n file download successful,beging install n2n"cd n2n/n2n_v2cmake CMakeLists.txtmakemakesudo make installelseecho "n2n file download failed ,has some problems ,please check"exit 0fiecho "check super node server is ok or not"check_super_node_serviceecho "n2n install over,begining start edge node"edge -d n2n0 -c mynetwork -k encryptme -M 1200 -a $N2N_edge_ip -l $N2N_super_node_ip:$N2N_super_node_port >/dev/null &echo "查看 ps -ef | grep edge,進程是否啟動OK"ps -ef | grep edgesudo echo "edge -d n2n0 -c mynetwork -k encryptme -a $N2N_edge_ip -l $N2N_super_node_ip:$N2N_super_node_port" >> /etc/rc.localelseecho -e "\033[31m yum not can be use,yum install n2 has some problem,please check\033[0m"exitfi } real=`grep -l '\^H' /root/.bash_profile` if [ $? -eq 1 ];then echo 'stty erase ^H' >> /root/.bash_profile source /root/.bash_profile #這幾行主要就是讓在使用read鍵時能使用回刪鍵。寫錯了,回刪了,重啟寫。不用這段的話,回刪鍵會變成亂碼。 fi echo -e '\033[0;33;1m #################nagios################## \033[0m' #讓echo能弄點顏色出來好看點。。。 echo "n2n supernode install please input : 1" echo "n2n edgenode install please input : 2" echo -e '\033[0;33;1m ######################################### \033[0m' read -p "please chose : " frist #定義輸入的值 if [ $frist -eq 1 ];thenn2n_install_super_node elsen2n_install_edge_node fi

總結

以上是生活随笔為你收集整理的UDP打洞原理与N2N内网穿透的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。