无公网如何实现内网穿透
如何判断自己是否具备公网IP:
访问 http://cip.cc 查看路由器或者拨号软路由拨号后的IP是否与其一致若不一致,则说明大概率处于拨号后处于 NAT 网络,当然也可能处于 DMZ 模式下,这需要做一些测试
1. NAT网络1.1. NAT
NAT 的全称是 Network Address Translation,即网络地址转换,指的是路由器等网络设备,在传输数据的过程中,改变数据中的 IP 地址的一种技术
NAT 技术示意图
随着全球联网设备越来越多,但 IPv4 地址资源有限,所以 NAT 技术在 IPV6 普及前都会是相当广泛的应用
1.2. NAT类型
NAT 分为好几种类型:
Full Cone NAT:“完全圆锥形 NAT”,内部设备与某个外部服务建立tcp链接后(如示意图),在未关闭该tcp链路前,任何外部设备可以通过此链路端口访问到内部端口 Restricted Cone NAT:“受限圆锥形 NAT”,在 Full Cone NAT 基础上,增加对访问链路的设备的 IP 限制,仅允许 tcp 链路的目标设备发送 tcp 数据包到内部设备 Port-Restricted Cone NAT:“端口受限圆锥形 NAT”,在 Restricted Cone NAT 的基础上,再增加端口检查,仅允许 tcp 链路的目标设备和目标端口发送tcp数据包到内部设备 Symmetric NAT:“对称 NAT”,与前三种不同,对称 NAT 会为每个新连接分配一个新的外部端口,即使是从同一个内部端口发起的连接有许多服务依赖与网络通信,尤其是 P2P、游戏等,例如在Xbox、PlayStation上,可以检测对网络类型进行检测,结果分别如下:
open:拥有公网IP,最佳网络环境 moderate:对应前三种 NAT 类型,可用的网络环境 strict: 对称NAT,不可用的网络环境1.3. 打洞
NAT 打洞技术是指通过一系列的技巧和协议,尝试在 NAT 上创建临时的映射或规则,使得两个设备可以在 NAT 网络后进行直接通信
Full Cone NAT 是最容易打洞的环境,而且对访问来源没有限制,可用于 NAS 文件分享、Web 服务等
而对于 Restricted Cone NAT 和 Port-Restricted Cone NAT 来说,打洞的效果则要打些折扣,打洞过程如下:
Restricted Cone NAT 和 Port-Restricted Cone NAT 的打洞流程复杂,且对客户端也有一定要求,但基本也满足游戏对战、P2P下载等服务
2. NAT 打洞
按照前面介绍的 NAT 类型,明确可以进行内网穿透的是 Full Cone NAT、Restricted Cone NAT、Port-Restricted Cone NAT三中
对称NAT 打洞成功率很低,Full Cone NAT 是最理想的打洞环境
2.1. 检测 NAT 类型
Windows:
https://github.com/HMBSbige/NatTypeTesterLinux/MacOS:
https://github.com/jtriley/pystunWindows下载后运行即可,其他操作系统可以使用 pystun 来做检测,以 pystun 为例
在 debian12 下为例,首先安装 Python 的包管理器:
Bashcontent_copy# 根据你的 python 版本来安装虚拟环境套件
sudo apt install python3.xx-venv
创建一个虚拟环境,然后安装 pystun:
Bashcontent_copypython3.xx-venv -m venv venv
source venv/bin/active
安装 pystun :
Bashcontent_copypip install pystun
运行 pystun :
Bashcontent_copypystun3
下面是我的输出
Bashcontent_copy(venv) ~$ pystun3 NAT Type: Full Cone External IP: 12.125.45.119 External Port: 6622
可以看到我的 nat 类型是 Full Cone NAT
2.2. NAT 打洞实践
natmap 用于从ISP NAT公网地址到本地私有地址建立 TCP/UDP 端口映射
以 web 服务为例,运行一个 librespeed 测速服务为例,docker 运行如下:
Bashcontent_copysudo 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 并编译:
Bashcontent_copygit clone --recursive https://github.com/heiher/natmap.git cd natmap make # 可选 cp bin/natmap /usr/bin/natmap
运行 natmap 建立一个端口映射
Bashcontent_copy/usr/bin/natmap -i ppp0 -s turn.cloudflare.com -h qq.com -t localhost -p 8080
参数解析:
-i:指定网卡,这里指定了宽带拨号产生的ppp0 -s:使用的外网 TURN 服务器 -h: 对于tcp而言,需要一个保持 tcp 长连接的对象,这里填了腾讯的服务器 -t/-p:指内网设备的IP和端口运行输出如下:
Bashcontent_copy/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
2.3. 自动更新
从前面对 nat 技术的介绍不难看出,映射到公网IP和公网端口会随时间改变,所以可以结合 DDNS 等技术来实现长时间打洞效果
以 https://api.chancel.me/rest/api/v1/anyjson 接口为例实现长期打洞,该 API 使用如下:
Bashcontent_copy$ 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 如下:
Bashcontent_copy#!/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 会在打洞成功后执行该脚本将打洞结果上传到接口中
运行试试:
Bashcontent_copychmod +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来获取打洞结果
Bashcontent_copycurl https://api.chancel.me/rest/api/v1/anyjson\?id\=secret {"ip":"12.125.45.119","port":"4467"}
可以看到,成功获取到了打洞结果,在其他网络中就可以利用这个结果来访问对应服务
以上为示例,可以灵活结合 DDNS 技术来实现各种内网服务穿透
最后,结合 supervisor 来实现 natmap 后台自动运行:
INIcontent_copy[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
3. 对称NAT
2024年后,广东大部分地区的宽带都变成了 Symmetric NAT,这非常糟糕
在光猫拨号情况下,即使是 Full Cone NAT 也会被识别为 Symmetric NAT
所以需要将光猫更改为桥接,拨号由路由器/软路由来拨号,再结合DMZ来做网络类型测试
光猫更改为桥接,这一点需要光猫的管理员账户,可以通过
找装宽带运维的师傅要 淘宝找店铺解决文章来源:
Author:chancel
link:http://www.chancel.me/markdown/home-network-nat-traversal