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内网穿透相关推荐

  1. n2n内网穿透打洞部署全过程 + nginx公网端口映射

    内网穿透.打洞工具有很多,此前在windows上使用的是vidcc这个玩意,也正因为linux不支持.自此在linux尝试过一些打洞工具,ssh 反向代理这些,因为安全性不便捷等多种原因,最终选择了n ...

  2. p2p打洞源码,p2p内网穿透源码,NAT内网穿透源码,NAT穿透源码

    一.p2p是什么? p2p是点对点的缩写(peer-to-peer networking),其可以定义为:端对端的资源共享,每一端即可是服务端,也可以是客户端.既可以是资源的提供者,也可以是资源的共享 ...

  3. n2n内网穿透及代理服务

    文章目录 安装配置 服务端 Windows客户端 确认两端能够访问 服务暴露 以代理方式实现 以端口转发方式实现 实现内网穿透 将内网服务的HTTP/HTTPS.任意服务暴露代理 安装配置 服务端 n ...

  4. 内网安全:内网穿透详解

    目录 内网穿透技术 内网穿透原理 实验环境 内网穿透项目 内网穿透:Ngrok 配置服务端 客户端配置 客户端生成后门,等待目标上线 内网穿透:Frp 客户端服务端建立连接 MSF生成后门,等待上线 ...

  5. 外网访问内网(内网穿透)方法总结

    自建服务器或者监控时,如何使外网设备访问到内网,是个麻烦问题. 这个任务称为内网穿透,解决方法通常是端口映射与端口转发. 网上关于端口映射与端口转发之间区别的讨论很多,观点也不尽相同,在此我也无意争辩 ...

  6. Ngrok: 使用 Ngrok 实现内网穿透

    Jan 10,2017 in 教程 read (14235) | 百度已收录 | Author: Leonn 目录 背景 NAT 穿透原理 一个栗子 Ngrok 准备工作 编译服务端 服务端 测试连接 ...

  7. 用ngrok做内网穿透

    背景 很多时候,我们都有这样的需求:需要将本地正在开发的服务暴露在公网上,也就是从外网直接访问我们本机上的服务. 正常情况下,这是办不到的,因为我们的本机并没有公网 IP,我们的本机处在内网当中. N ...

  8. FastTunnel Win10内网穿透实现远程桌面

    目录 一.需求 二.购买公网服务器 三.远程公网服务器 四.FastTunnel 的使用 1.下载 FastTunnel 2.启动服务器端 3.启动客户端 五.测试 六.安装服务 结束 一.需求 Fa ...

  9. p2p内网穿透技术-udp打洞

    在公司如何访问家里的电脑?实现方法有很多,其它p2p传输文件最快,能否实现? udp打洞原理 假设有两台分别处于各自的私有网络中的主机:A和B:N1和N2是两个网络的NAT设备,分别拥有IP地址P1和 ...

  10. UDP无法打洞咋办? 对称NAT无法穿透?IPV6将终结内网穿透

    我的上几篇文章讲了IPV6的优势.现在我们再来讲讲IPV6如何"终结"udp无法穿透内网的问题.        在ipv4网络下,编程的朋友们或许会遇到udp无法穿透内网的情况,特 ...

最新文章

  1. C++中try/catch/throw的使用
  2. linux查找大文件
  3. php单屏网站源码,关于原生js实现类似fullpage的单页/全屏滚动的方法
  4. Ubuntu:Ubuntu系统下在pycharm软件内配置anaconda环境(一张图轻松搞定!)
  5. ML之K-means:基于K-means算法利用电影数据集实现对top 100 电影进行文档分类
  6. 接口之间传递inputstream_接口测试 | 接口测试入门
  7. 永冻土层matlab图片,北极圈都32℃了!千年永冻土层快“热化”了?
  8. ABB机器人 系统参数配置
  9. 研究生新生大数据!一大波00后“涌入”同济,最小博士生20岁
  10. Radware LP 增加线路接口操作
  11. servlet-cookie实现向客户端写cookie信息
  12. 去中心化抵押借贷市场当前总借款量94.24亿美元
  13. 滴滴为什么接不到长途单?
  14. Android仿人人客户端(v5.7.1)——网络模块处理的架构
  15. Android 面试那些事儿
  16. 视频教程-Xamarin技术讲座——初级篇-其他
  17. 如何让html 兼容IE和chrome,IE Tab(让Chrome兼容IE)
  18. 三日月くるみ - 魔法みたいな恋したい
  19. 【转】ARM经典300问
  20. Ubuntu折腾记录

热门文章

  1. 百度云开发clouda学习(一)
  2. flashfxp使用图文教程,flashfxp使用图文教程简单介绍
  3. pvid与access的关系_浅谈PVID和VID区别
  4. 驱动器存在问题-U盘量产-主控SM3255AB
  5. tomcat升级版本升级
  6. 【教学类-20-02】20221203《世界杯16强国旗-定量版》(大班)
  7. 鼠标按下并移动事件的解决方案
  8. 最新BBS上的变态网名大全
  9. matlab 菱形符号,matlab 图形符号
  10. Unity—英雄无敌(前方高能)