IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    无公网如何实现内网穿透

    chancel发表于 2024-09-25 00:00:00
    love 0
    <![CDATA[

    现在很多个人宽带已经没有动态公网IP了,这使得在家庭内部署一些网络服务失去了意义

    如何判断自己是否具备公网IP:

    1. 访问 http://cip.cc
    2. 查看路由器或者拨号软路由拨号后的IP是否与其一致

    若不一致,则说明大概率处于拨号后处于 NAT 网络,当然也可能处于 DMZ 模式下,这需要做一些测试

    1. NAT网络

    1.1. NAT

    NAT 的全称是 Network Address Translation,即网络地址转换,指的是路由器等网络设备,在传输数据的过程中,改变数据中的 IP 地址的一种技术

    NAT 技术示意图

    随着全球联网设备越来越多,但 IPv4 地址资源有限,所以 NAT 技术在 IPV6 普及前都会是相当广泛的应用

    1.2. NAT类型

    NAT 分为好几种类型:

    1. Full Cone NAT:“完全圆锥形 NAT”,内部设备与某个外部服务建立tcp链接后(如示意图),在未关闭该tcp链路前,任何外部设备可以通过此链路端口访问到内部端口
    2. 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/NatTypeTester

    Linux/MacOS:

    • https://github.com/jtriley/pystun

    Windows下载后运行即可,其他操作系统可以使用 pystun 来做检测,以 pystun 为例

    在 debian12 下为例,首先安装 Python 的包管理器:

    Bash
    # 根据你的 python 版本来安装虚拟环境套件
    sudo apt install python3.xx-venv
    

    创建一个虚拟环境,然后安装 pystun:

    Bash
    python3.xx-venv -m venv venv
    source venv/bin/active
    

    安装 pystun :

    Bash
    pip install pystun
    

    运行 pystun :

    Bash
    pystun3
    

    下面是我的输出

    Bash
    (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 运行如下:

    Bash
    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 并编译:

    Bash
    git clone --recursive https://github.com/heiher/natmap.git
    cd natmap
    make
    
    # 可选
    cp bin/natmap /usr/bin/natmap
    

    运行 natmap 建立一个端口映射

    Bash
    /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和端口

    运行输出如下:

    Bash
    /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 使用如下:

    Bash
    $ 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 如下:

    Bash
    #!/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 会在打洞成功后执行该脚本将打洞结果上传到接口中

    运行试试:

    Bash
    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来获取打洞结果

    Bash
    curl https://api.chancel.me/rest/api/v1/anyjson\?id\=secret
    {"ip":"12.125.45.119","port":"4467"}
    

    可以看到,成功获取到了打洞结果,在其他网络中就可以利用这个结果来访问对应服务

    以上为示例,可以灵活结合 DDNS 技术来实现各种内网服务穿透

    最后,结合 supervisor 来实现 natmap 后台自动运行:

    INI
    [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来做网络类型测试

    光猫更改为桥接,这一点需要光猫的管理员账户,可以通过

    • 找装宽带运维的师傅要
    • 淘宝找店铺解决



沪ICP备19023445号-2号
友情链接