一、内网穿透概要
为了理解内网穿透我们先来了解几个概念:
1.1、IP地址
网络中唯一定位一台设备的逻辑地址,类似我们的电话号码,在互联网中我们访问一个网站或使用一个网络服务最终都需要通过IP定位到每一台主机,IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
内网IP可以同时出现在多个不同的局域网络中,如A公司的U1用户获得了192.168.0.5,B公司的U3用户也可以获得192.168.0.5;但公网IP是唯一的,因为我们只有一个Internet。
1.2、域名
域名是IP的别名,便于记忆,域名最终通过DNS解析成IP地址。IP V4是一个32位的数字,IP V6有128位,要记住一串毫无意义的数字非常困难,域名解决了这个问题。
DNS查询过程如下,最终将域名变成IP地址
1.3、NAT
NAT(Network Address Translation)即网络地址转换,NAT能将其本地地址转换成全球IP地址。
内网的一些主机本来已经分配到了本地IP地址(如局域网DHCP分配的IP),但现在又想和因特网上的主机通信(并不需要加密)时,可使用NAT方法。
NAT不仅能解决了lP地址不足与共享上网的问题,而且还能够有效地避免来自网络外部的攻击,隐藏并保护网络内部的计算机。
1.4、为什么需要内网穿透
当内网中的主机没有静态IP地址要被外网稳定访问时可以使用内网穿透
在互联网中唯一定位一台主机的方法是通过公网的IP地址,但固定IP是一种非常稀缺的资源,不可能给每个公司都分配一个,且许多中小公司不愿意为高昂的费用买单,多数公司直接或间接的拨号上网,电信部门会给接入网络的用户分配IP地址,以前上网用户少的时候基本分配的都是临时的静态IP地址,租约过了之后可能会更换成另一个IP地址,这样外网访问就不稳定,因为内网的静态IP地址一直变化,为了解决这个问题可以使用动态域名解析的办法变换域名指向的静态IP地址。但是现在越来越多的上网用户使得临时分配的静态IP地址也不够用了,电信部门开始分配一些虚拟的静态IP地址,这些IP是公网不能直接访问的,如以125开头的一些IP地址,以前单纯的动态域名解析就不好用了。
1.5、内网穿透的定义与障碍
简单来说实现不同局域网内的主机之间通过互联网进行通信的技术叫内网穿透。
障碍一:位于局域网内的主机有两套 IP 地址,一套是局域网内的 IP 地址,通常是动态分配的,仅供局域网内的主机间通信使用;一套是经过网关转换后的外网 IP 地址,用于与外网程序进行通信。
障碍二:位于不同局域网内的两台主机,即使是知道了对方的 IP 地址和端口号,因为出于安全起见,除非是主机主动向对方发出了连接请求(这时会在该主机的数据结构中留下一条记录),否则,当主机接收到数据包时,如果在其数据结构中查询不到对应的记录,那些不请自来的数据包将会被丢弃。
解决办法:要想解决以上两大障碍,我们需要借助一台具有公网 IP 的服务器进行桥接。
二、ngrok的作用:
ngrok是一个反向代理,它能够让你本地的web服务或tcp服务通过公共的端口和外部建立一个安全的通道, 使得外网可以访问本地的计算机服务。也就是说,我们提供的服务(比如web站点)无需搭建在外部服务器, 只要通过ngrok把站点映射出去,别人即可直接访问到我们的服务。
三、搭建ngrok服务器的方法:
3.1、前提条件
搭建ngrok服务需要有一个外网服务器及一个域名解析到外网服务器上,我已经有了一个jaleel.xyz域名,并且拥有一台阿里云ECS服务器。
在阿里云服务器的域名解析处,配置2个A记录,比如我新建2个ngrok.jaleel.xyz 和 *. ngrok.jaleel.xyz 解析到vps服务器上。
3.2、搭建ngrok服务
3.2.1 安装git
默认的git版本太低了,需要升级到最新版本,具体步骤如下:
sudo yum remove git #卸载旧版本的git
sudo yum install epel-release
sudo yum install https://centos7.iuscommunity.org/ius-release.rpm #获取最新的git
sudo yum install git2u
git –version #返回 git version 2.5.0(最新的版本号),安装成功。
3.2.2 安装GO语言:
由于在 1.4 版本后,Go 编译器实现了自举,即通过 1.4 版本来编译安装之后版本的编译器。如果不设置该环境变量的话,会产生这样一个错误“Set $GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4.”。
①下载源码包:
cd /usr/local
wget https://storage.googleapis.com/golang/go1.4-bootstrap-20170531.tar.gz
tar -xf go1.4-bootstrap-20170531.tar.gz
②安装:
cd go/src
./make.bash
mv go go1.4
vim /etc/profile
③添加:
export GOROOT_BOOTSTRAP=/usr/local/go1.4
source /etc/profile
④下载最新GO源码包:
cd /usr/local
wget https://storage.googleapis.com/golang/go1.10.src.tar.gz
tar -xf go1.10.src.tar.gz
⑤安装Go:
cd go/src
./all.bash
⑥设置环境变量:
vim /etc/profile
export GOROOT=/usr/local/go
export GOBIN=$GOROOT/bin
export PATH=$PATH:$GOBIN
source /etc/profile
⑥GO的命令需要做软连接到/usr/bin:
ln -s /usr/local/go/bin/* /usr/bin/
go version #显示出最新版本号即安装完成
3.3.3 编译ngrok:
cd /usr/local/
git clone https://github.com/inconshreveable/ngrok.git
export GOPATH=/usr/local/ngrok/
export NGROK_DOMAIN="ngrok.jaleel.xyz"
cd ngrok
3.3.4 为域名生成证书:
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -out rootCA.pem
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csr
openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 5000
在软件源代码目录下面会生成一些证书文件,我们需要把这些文件拷贝到指定位置
cp rootCA.pem assets/client/tls/ngrokroot.crt
cp server.crt assets/server/tls/snakeoil.crt
cp server.key assets/server/tls/snakeoil.key
如果是在天朝的服务器需要改,香港或者国外的服务器不需要
vim /usr/local/ngrok/src/ngrok/log/logger.go
log "github.com/keepeye/log4go"
3.3.5 编译服务端:
cd /usr/local/go/src
GOOS=linux GOARCH=amd64 ./make.bash
cd /usr/local/ngrok/
GOOS=linux GOARCH=amd64 make release-server
3.3.6 Windows的客户端编译:
cd /usr/local/go/src
GOOS=windows GOARCH=amd64 ./make.bash
cd /usr/local/ngrok/
GOOS=windows GOARCH=amd64 make release-client
3.3.7 服务端启动:
/usr/local/ngrok/bin/ngrokd -domain="$NGROK_DOMAIN" -httpAddr=":80"
3.3.8 客户端使用:
指定证书、域名和端口启动它
ngrok -config=./ngrok.cfg -subdomain=blog 80
setsid ./ngrok -config=./ngrok.cfg -subdomain=test 80 #在linux下如果想后台运行
到这一步,ngrok 服务已经跑起来了,可以通过屏幕上显示的日志查看更多信息。httpAddr、httpsAddr 分别是ngrok用来转发http、https服务的端口,可以随意指定。ngrokd还会开一个4443端口用来跟客户端通讯(可通过-tunnelAddr=”:xxx” 指定),如果你配置了iptables 规则,需要放行这三个端口上的TCP协议。