V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mikewang
V2EX  ›  宽带症候群

Natter: 在 NAT1 下开放公网 TCP 端口

  •  
  •   mikewang · 2022-09-12 23:52:08 +08:00 · 13998 次点击
    这是一个创建于 562 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Natter

    GitHub: https://github.com/MikeWang000000/Natter


    目前公网 IP 越来越稀缺,有些地区已经无法申请公网 IP 了。
    不过,在 NAT 1 网络下,我们可以通过一种 “打洞” 的方式,将本地的 TCP 端口暴露至公网上,运行 HTTP 服务等。
    经过一番研究,我使用 Python 写了一个工具,起名叫 Natter 。

    简洁地说,Natter 的原理就是端口重用:

    1. 由本地端口 A 向外发起 TCP 长连接,维持 NAT 端口映射关系;
    2. 同时监听端口 A ,对外提供服务。

    Natter 应当运行于路由器上,因为这样只经过一层 NAT 。不过,正确设置 DMZ 主机,经过多层 NAT 也是 OK 的。

    好消息是国内运营商级 NAT 多数已经转为 NAT 1 了,因此开放公网 TCP 端口应该是比较容易的。
    目前我在中国移动的家庭宽带上已经成功使用 Natter 开放公网 TCP 端口。

    第 1 条附言  ·  2022-09-13 11:06:25 +08:00
    目前来说,这还是一个实验性质的工具。
    会有不少 bug ,对于不同网络环境可能有考虑不周的情况。欢迎各位提 Issue 。

    另外,测试打洞成功用的 HTTP 服务器,实现十分简陋,有待改进,有时打不开其实是我这的问题…
    第 2 条附言  ·  2022-09-13 20:34:27 +08:00
    新版本 Natter 将集成端口转发功能,解决使用 iptables 等转发不起作用的问题。
    这样就能把端口指向你们的服务了。等我更新吧哈哈
    118 条回复    2024-01-01 23:46:11 +08:00
    1  2  
    wslzy007
        101
    wslzy007  
       2022-09-16 22:31:16 +08:00
    @qingmuhy0 客户端 app 可以配置服务端间映射,配置好后就不需要走客户端了,实现 A 机器(局域网 1 )-》 B 机器(局域网 2 )的直接 tcp 穿透,还能做转发
    qingmuhy0
        102
    qingmuhy0  
       2022-09-17 07:46:40 +08:00 via iPhone
    @wslzy007 没太看懂,类似这个需求可以满足嘛。
    https://qingmuhy.com/index.php/archives/71/
    你这个局域网间穿透? subnet 的方式?如果是也不行啊,很多软件都可以,还是不能解决我博客中说到的场景啊。
    heiher
        103
    heiher  
       2022-09-28 17:03:48 +08:00
    @mikewang 借 OP 的思路已经在自己环境中用起来了,我的需求是将访问内网的代理服务端口映射在移动宽带的局端公网 IPv4 上,从而利用移动较大的上行带宽。

    关于端口转发: 我没有采用转发方案,而是在内网代理服务侧开启了 Reuseport ,允许 TCP 打洞也绑定在相同的端口上发起对外连接。这样 TCP 打洞成功后,入站连接只会被内网代理服务处理,避免配置转发规则。
    关于动态端口: 我的场景里内网代理服务的客户端是专用的,所以有增加地址模式的可能性,所以我利用 DNS AAAA 记录的 16 字节空间编码了 4 字节的 IPv4 和 2 字节的端口。这样打洞成功后只需要把获得的外网地址、端口更新到域名的 AAAA 记录上,客户端只通过一个常量的域名就能访问到。

    感谢~
    mikewang
        104
    mikewang  
    OP
       2022-09-29 00:57:03 +08:00
    @heiher AAAA 记录不错的思路~ 我选择 TCP 的原因有一点就是一些地区的 UDP 环境可能不太好,TCP 可以最大限度利用带宽。我自建的服务也是直接使用 Reuseport ,转发则是因为大多软件没做这个 hhh
    heiher
        105
    heiher  
       2022-10-01 15:11:22 +08:00
    @mikewang #104

    我发现如果打洞程序的 socket 开启 reuseport 且先于目标服务做端口 bind ,那么则不影响后续服务做端口 bind 。

    即使在服务先运行的情况下,从 Linux kernel 5.6 开始,也有修改服务进程中 socket 为 reuseport 的方法。通过 pidfd_getfd 系统调用在打洞程序中通过 /proc/net/tcp{,6}和 /proc/[pid]/fd/扫出服务进程的 pid 和 fd ,在打洞程序中 dup 出 fd ,再通过 setsockopt 改为 reuseport 。
    heiher
        106
    heiher  
       2022-10-01 19:37:36 +08:00
    xiaolei0125
        107
    xiaolei0125  
       2023-02-28 12:18:43 +08:00
    @heiher 这个代码的链接失效了 https://gist.github.com/heiher/261d3a9cd102c69592e0e0544713ccde#file-portmap-c-L129-L265 , 能重新分享一下这个修改服务进程中 socket 为 reuseport 的方法的代码吗? 非常感谢!
    heiher
        108
    heiher  
       2023-02-28 12:52:07 +08:00 via Android
    letmefly
        109
    letmefly  
       2023-03-28 20:30:46 +08:00
    在 openwrt 尝试了一下,出错了。我是看了青木幻境的文章
    https://qingmuhy.com/index.php/archives/71/
    就照着在 openwrt 上跑了一下,出现这个提示,特来请教。
    python natter.py 80
    File "/root/natter.py", line 74
    <title>Natter/natter.py at master · MikeWang000000/Natter · GitHub</title>
    ^
    SyntaxError: invalid character '·' (U+00B7)
    mikewang
        110
    mikewang  
    OP
       2023-03-28 21:21:44 +08:00
    @letmefly 看起来你的 natter.py 下载错了
    可以用文本编辑器看一下,应该是下载成了 html
    letmefly
        111
    letmefly  
       2023-03-29 18:12:07 +08:00
    重新下载了 zip 包,这次信息变成了 python natter.py -t 3456
    [INFO] - Getting STUN server IP...
    [INFO] - Checking NAT Type for UDP...
    [INFO] - NAT Type for UDP: [ Port restricted (NAT 3) ]
    [WARNING] - The NAT type of your network is not full cone (NAT 1). TCP hole punc
    [INFO] - Checking NAT Type for TCP...
    [INFO] - NAT Type for TCP: [ Cone NAT ]
    [INFO] - Start punching...
    [INFO] - The TCP hole punching appears to be successful. Please test this addres01.21', 23810)

    ================================
    ('125.xx.201.91', 23810)
    ================================

    HTTP test server is enabled. Please check [ http://125.xx.201.91:23810/ ]

    [INFO] - TCP keep-alive...
    可是访问这个网址,返回信息是 invalid request ,这个打洞也不知道算不算成功。
    mikewang
        112
    mikewang  
    OP
       364 天前
    @letmefly NAT 3 是不行滴,检查光猫桥接情况,防火墙等等。
    如果运营商给的确实是 NAT 3 ,那就玩不了了
    letmefly
        113
    letmefly  
       364 天前
    在用 natter 打洞之前,用 Nattypetester 测试过是 Fullcone 的。之前因为路由器是 nat3 还特意把固件换成 openwrt 。看过光猫是桥接的,防火墙也是关闭的。又重新下载了 0.9 版本,python natter.py 3456
    [INFO] - Getting STUN server IP...
    [INFO] - >>> [TCP] ('100.64.3.112', 3456) -> ('1yy.94.2xx.21', 24320) <<<

    我直接把 utorrent 的转发端口改成 24320 ,过一段时间后可以看到 utorrent 显示网络正常,出现了绿色的对勾,也不知道真假,但好歹心理有点安慰。
    mikewang
        114
    mikewang  
    OP
       364 天前 via iPhone
    @letmefly 访问
    https://ifconfig.co/port/24320
    ( 24320 就是您的端口号)
    看到 true 就是打开,false 就是关闭。
    garibellee
        115
    garibellee  
       325 天前
    得注意下 test 的机器自身防火墙
    zhhww57
        116
    zhhww57  
       86 天前
    @mikewang
    有条件可以研究下下面这个:
    一种利用 dns 的且不需要第三台服务器的 p2p nat 打洞方案
    实现情况:双方都是内网,一方具有 ddns ,可以通过 ddns 知道对方的 ip
    关键词:随机森林算法 端口猜解 双方都是 nat4 的 udp 打洞
    zhhww57
        117
    zhhww57  
       86 天前
    @mikewang
    这篇里面提到了一个端口预测 其实就是端口猜解 针对 nat4 的 然后之前看了一篇文章 正常来猜测是很慢的 然后用随机森林算法配合来猜解 可以缩短时间
    https://zhuanlan.zhihu.com/p/353838320
    通过 ddns 来标识一方的公网 ip ,然后另一方通过域名知道了公网 ip 之后 然后展开端口猜解


    里面提到了一句:
    上述 tcp 连接过程,仅对 NAT1 、2 、3 有效,对 NAT4 (对称型)无效。
    由于对称型 nat 通常采用规律的外部端口分配方法,对于 nat4 的打洞,可以采用端口预测的方式进行尝试。
    mikewang
        118
    mikewang  
    OP
       86 天前
    @zhhww57 Natter 打洞的 NAT 要求更为严苛,因为它只在服务端运作,用户可以无客户端直接访问:

    举例:
    10.0.1.12:8080 通过 Natter (使用 STUN 协议)知道自身映射为公网的 203.0.113.10:12345
    那么公网上的任何用户都能直接访问 203.0.113.10:12345 ,到达 10.0.1.12:8080 ,不需要客户端。

    其他 NAT 类型就必须需要服务端和客户端相互配合才能完成打洞,因此 Natter 没有支持其他 NAT 类型的计划 :(
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3159 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 12:30 · PVG 20:30 · LAX 05:30 · JFK 08:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.