作者:Chancel Yang, 创建:2024-09-25, 字数:5838, 已阅:101, 最后更新:2024-09-25
现在很多个人宽带已经没有动态公网IP了,这使得在家庭内部署一些网络服务失去了意义
判断是否具备公网IP:
如果访问不到,则说明处于 Nat 网络中,在 Nat 内网中部署的服务需要暴露出去的话,则需要进行 Nat 打洞
NAT 的全称是 Network Address Translation,即网络地址转换,指的是路由器等网络设备,在传输数据的过程中,改变数据中的 IP 地址的一种技术
NAT 技术示意图
随着全球联网设备越来越多,但 IPv4 地址资源有限,所以 NAT 技术在 IPV6 普及前都会是相当广泛的应用
NAT 分为好几种类型:
有许多服务依赖与网络通信,尤其是 P2P、游戏等,例如在Xbox、PlayStation上,可以检测对网络类型进行检测,结果分别如下:
NAT 打洞技术是指通过一系列的技巧和协议,尝试在 NAT 上创建临时的映射或规则,使得两个设备可以在 NAT 网络后进行直接通信
Full Cone NAT 是最容易打洞的环境,而且对访问来源没有限制,可用于 NAS 文件分享、Web 服务等
而对于 Restricted Cone NAT 和 Port-Restricted Cone NAT 来说,打洞的效果则要打些折扣,打洞过程如下:
Restricted Cone NAT 和 Port-Restricted Cone NAT 的打洞流程复杂,且对客户端也有一定要求,但基本也满足游戏对战、P2P下载等服务
按照前面介绍的 NAT 类型,明确可以进行内网穿透的是 Full Cone NAT、Restricted Cone NAT、Port-Restricted Cone NAT三中
对称NAT 打洞成功率很低,Full Cone NAT 是最理想的打洞环境
Windows:
Linux/MacOS:
Windows下载后运行即可,其他操作系统可以使用 pystun 来做检测,以 pystun 为例
在 debian12 下为例,首先安装 Python 的包管理器:
# 根据你的 python 版本来安装虚拟环境套件
sudo apt install python3.xx-venv
创建一个虚拟环境,然后安装 pystun:
python3.xx-venv -m venv venv
source venv/bin/active
安装 pystun :
pip install pystun
运行 pystun :
pystun3
下面是我的输出
(venv) ~$ pystun3
NAT Type: Full Cone
External IP: 12.125.45.119
External Port: 6622
可以看到我的 nat 类型是 Full Cone NAT
natmap 用于从ISP NAT公网地址到本地私有地址建立 TCP/UDP 端口映射
以 web 服务为例,运行一个 librespeed 测速服务为例,docker 运行如下:
sudo docker run \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=Etc/UTC \
-e PASSWORD=chancel \
-p 8080:80 \
lscr.io/linuxserver/librespeed:latest
访问 http://localhost:8080 并测速,结果如下:
然后下载 natmap 并编译:
git clone --recursive https://github.com/heiher/natmap.git
cd natmap
make
# 可选
cp bin/natmap /usr/bin/natmap
运行 natmap 建立一个端口映射
/usr/bin/natmap -i ppp0 -s turn.cloudflare.com -h qq.com -t localhost -p 8080
参数解析:
运行输出如下:
/usr/bin/natmap -i ppp0 -s turn.cloudflare.com -h qq.com -t 127.0.0.1 -p 8080
12.125.45.119 4475 2001::223d:2c91:82b3 46701 tcp 14.213.121.3
第一个输出即公网IP,第二个输出则是公网端口,在其他网络下,访问 http://12.125.45.119:4475 后测速:
可以看到测速的结果有接近 50 Mbps,我的宽带是 100Mbps
从前面对 nat 技术的介绍不难看出,映射到公网IP和公网端口会随时间改变,所以可以结合 DDNS 等技术来实现长时间打洞效果
以 https://api.chancel.me/rest/api/v1/anyjson 接口为例实现长期打洞,该 API 使用如下:
$ curl -X POST https://api.chancel.me/rest/api/v1/anyjson?id=hello -H "Content-Type: application/json" -d '{"lihua": "hi!"}'
# 返回状态 1 ,表示存储成功
{"status":1,"msg":"Data stored successfully","data":null,"version":"V1.0.0"}
$ curl -X GET https://api.chancel.me/rest/api/v1/anyjson?id=hello
{"lihua":"hi!"}
这个接口可用于临时存储 json,所以写一个 bash 脚本 natmap.sh 如下:
#!/bin/sh
/usr/bin/curl -X POST https://api.chancel.me/rest/api/v1/anyjson?id=secret -H "Content-Type: application/json" -d "{\"ip\": \"${1}\",\"port\":\"${2}\"}"
其中 $1
和 $2
是由 natmap 传入的,即公网IP和公网端口,这样 natmap 会在打洞成功后执行该脚本将打洞结果上传到接口中
运行试试:
chmod +x natmap.sh
/usr/bin/natmap -i ppp0 -s turn.cloudflare.com -h qq.com -t 127.0.0.1 -p 8080 -e natmap.sh
此时在其他网络中,使用curl来获取打洞结果
curl https://api.chancel.me/rest/api/v1/anyjson\?id\=secret
{"ip":"12.125.45.119","port":"4467"}
可以看到,成功获取到了打洞结果,在其他网络中就可以利用这个结果来访问对应服务
以上为示例,可以灵活结合 DDNS 技术来实现各种内网服务穿透
最后,结合 supervisor 来实现 natmap 后台自动运行:
[program:natmap]
command=/opt/natmap/natmap -i ppp0 -s turn.cloudflare.com -h qq.com -t 127.0.0.1 -p 22 -e /opt/natmap/natmap.sh
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
stdout_logfile_maxbytes=32MB
user=app
2024年后,广东大部分地区的宽带都变成了 Symmetric NAT,这非常糟糕
在光猫拨号情况下,即使是 Full Cone NAT 也会被识别为 Symmetric NAT
所以需要将光猫更改为桥接,拨号由路由器/软路由来拨号,再结合DMZ来做网络类型测试
光猫更改为桥接,这一点需要光猫的管理员账户,可以通过