使用 VPN 打通内网
前言
在上一篇文章中已经介绍了使用 SSH 隧道 的方式来打通内网环境,好处是极小依赖 ( 只要支持 ssh 即可 ) , 不过使用下来也有几点问题比较明显:
-
无密码安全性很差,IP 变动或者换地方了设置防火墙白名单也比较麻烦
-
浏览器可以通过设置全局的HTTP代理来访问,但在其他软件中就需要单独配置比较麻烦,比如我的 SSH 终端工具要连接几十台服务器,每台服务器的配置都要单独修改想想就头大
-
只支持 TCP 及在它之上的协议,不支持 UDP
使用 VPN 就可以很好的解决上面的几个问题
方案
- 在内网搭建 VPN 服务器
- 将 VPN服务 暴露到公网中
- 通过公网连接到 VPN 网络,通过 VPN 网络访问内网资源
搭建 VPN 服务器
- 在当前目录下新建 VPN 配置文件
vpn.env
用于管理 VPN 的帐号密码# 预共享密钥 VPN_IPSEC_PSK='vpn' # 帐号 VPN_USER='vpn' # 密码 VPN_PASSWORD='vpn'
- 为了方便,采用 docker 的方式来搭建
docker run --name vpn \ -d --privileged --restart=always \ --env-file `pwd`/vpn.env \ -p 500:500/udp -p 4500:4500/udp \ -v /lib/modules:/lib/modules:ro hwdsl2/ipsec-vpn-server
先测试下内网下是否能够连接 VPN ( 选择 使用预共享密钥的L2TP/IPsec )
暴露VPN服务到公网
由于 VPN 服务器搭建在内网环境,外部无法直接访问,所以按上一篇文章中的方式借助一台公网的服务器做跳板机将 VPN 服务的端口暴露在公网中。这里就遇到一个问题:VPN 服务的端口是 UDP 协议的,而 SSH 隧道是不支持 UDP 的,有点小尴尬啊。不过好在可以通过 TCP/UDP 互相转换的方式来"曲线救国",具体原理另外开文讲解,这里就只给最终的操作:
-
在 VPN 主机上执行
# 将本机1337端口(TCP)接收到的数据转发到本机的500端口(UDP) docker run \ --name vpn500 -p 1337:80 \ -d --restart=always \ alpine/socat tcp-listen:80,fork,reuseaddr udp-connect:172.17.0.1:500 # 将本机1338端口(TCP)接收到的数据转发到本机的4500端口(UDP) docker run \ --name vpn4500 -p 1338:80 \ -d --restart=always \ alpine/socat tcp-listen:80,fork,reuseaddr udp-connect:172.17.0.1:4500 # 将本机1337端口通过ssh隧道暴露到跳板机的1337端口上,123.123.123.123改为跳板机的公网ip ssh -p 22 -Nf -R 0.0.0.0:1337:127.0.0.1:1337 root@123.123.123.123 # 将本机1338端口通过ssh隧道暴露到跳板机的1338端口上 ssh -p 22 -Nf -R 0.0.0.0:1338:127.0.0.1:1338 root@123.123.123.123
-
在跳板机上执行
# 将本机500端口(UDP)接收到的数据转发到本机的1337端口(TCP) docker run --name vpn500 -p 500:80/udp \ -d --restart=always \ alpine/socat udp-listen:80,fork,reuseaddr tcp-connect:172.17.0.1:1337 # 将本机4500端口(UDP)接收到的数据转发到本机的1338端口(TCP) docker run --name vpn4500 -p 4500:80/udp \ -d --restart=always \ alpine/socat udp-listen:80,fork,reuseaddr tcp-connect:172.17.0.1:1338
测试下通过跳板机的公网 IP 是否能够连接 VPN ( 选择 使用预共享密钥的L2TP/IPsec )
优化
通过上面的步骤已经初步实现了本文的目的,但是由于使用了蛋疼的 TCP/UDP 转换的方式,性能非常差劲,网速最快也只有 20 kb/s 左右,远程连个服务器什么的还好说,开网页就算了吧。其实,除了这种蹩脚的转换方式,还可以用 frp(v0.24.1) 做内网穿透:
-
在 VPN 主机上执行
# 写入frp客户端配置 cat > frpc.ini <<EOF [common] server_addr = 119.27.177.81 server_port = 7000 # 与服务端的token一致才能认证通过 token=123456 [range:vpn] type = udp local_ip = 172.17.0.1 local_port = 500,4500 remote_port = 500,4500 EOF docker run --name frpc \ -d --restart=always \ -v `pwd`/frpc.ini:/etc/frpc.ini \ leonismoe/frpc
-
在跳板机上执行
# 写入frp服务端配置 cat > frps.ini <<EOF [common] server_port = 7000 token=123456 dashboard_port = 7500 # dashboard 用户名密码,默认都为 admin dashboard_user = admin dashboard_pwd = admin EOF # 7000是frp的服务端口;400/4500是VPN的端口;7500是frp的web管理界面端口,可有可无; docker run --name frps \ -d --restart=always \ -p 7000:7000 -p 7500:7500 -p 500:500/udp -p 4500:4500/udp \ -v `pwd`/frps.ini:/etc/frps.ini \ leonismoe/frps
连接 VPN 后,速度上有了明显的提升但还是很慢,不过上传能跑满跳板机的带宽,具体原因还有待研究。
另外,frp 还支持点对点内网穿透,有空也可以试下。
使用 SoftEther VPN
出现上面的问题,主要还是因为搭建 SSH 隧道带来的"惯性思维",为什么非得远程转发 UDP 端口呢?搜寻了一圈就发现了非常强大的 SoftEther VPN ,它就提供 TCP 协议的连接方式,远程转发它的 TCP 端口就行了。
-
在 VPN 主机上先关闭之前搭建的 VPN 服务
docker rm -f vpn
-
在 VPN 主机上搭建 SoftEther
docker run --name=vpn2 \ -d --privileged --restart=always --cap-add NET_ADMIN \ -p 500:500/udp -p 4500:4500/udp -p 1701:1701/tcp \ -p 1194:1194/udp \ -p 5555:5555/tcp \ -e USERS=vpn:vpn -e SPW=vpn123456 -e PSK=vpn \ siomiz/softethervpn # USERS格式:username:password;user2:pass2;user3:pass3 # PSK是预共享密钥,SPW是管理密钥(用于登录 SoftEther Server 管理器) # 将 VPN 主机的服务端口暴露到跳板机上 ssh -p 22 -Nf -R 0.0.0.0:5555:127.0.0.1:5555 root@123.123.123.123
-
下载 SoftEther 的客户端,通过客户端连接 VPN 即可,此时的网速取决于跳板机的公网带宽
当然,也可以配合上面的内网穿透步骤使用系统自带的 VPN 客户端直连。