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

2022-09-12 23:52:08 +08:00
 mikewang

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 端口。

20061 次点击
所在节点    宽带症候群
120 条回复
mikewang
2022-09-14 01:45:11 +08:00
@Zy143L 对的,因为 TCP STUN 公共服务器都是境外的,我没有找到国内可用的服务器 : (
而且如果运营商对某些境外地址,改变了出口 IP ,那么也会影响判断结果 emmm
可能暂时不太好解决
1423
2022-09-14 03:08:31 +08:00
不太明白,为什么 tcp 连接 stun server 用到的公网端口会恰好与后续 keepalive 连接的公网端口相同?
1423
2022-09-14 03:51:25 +08:00
@1423 随便写了几行代码抓包试了下果真如此。。这么多年,没想到 tcp 穿透如此简单。。
https://gist.github.com/wen-long/0bda5c5eeaf837f6e485269aee65bb26
jasonliu769
2022-09-14 09:16:50 +08:00
@1041412569 Windows 其实有 netsh interface portproxy 实现端口转发功能
mikewang
2022-09-14 10:06:10 +08:00
@1423 有意为之的,这样才能打洞。原理十分简单,重点在于维持 TCP 连接的思路,以及外部地址的获取( Natter 相当于把 STUN 协议的客户端重新实现了一次)

@jasonliu769 我不在用 Windows ,不过印象中 netsh 的端口转发会独占端口。
shikkoku
2022-09-14 11:08:51 +08:00
mikewang
2022-09-14 11:32:08 +08:00
@shikkoku 这两个已经内置在 Natter 里了,作为 UDP 的探测。可惜两个都不支持 TCP 模式。
Verizon
2022-09-14 13:11:14 +08:00
跟 frp 有什么区别吗
Wenpo
2022-09-14 13:16:52 +08:00
@Verizon frp 要经过服务器中转,这个不需要;
matzoh
2022-09-14 13:56:49 +08:00
和 tailscale/zerotier 这类的打洞原理上有区别吗
mikewang
2022-09-14 14:22:32 +08:00
@matzoh tailscale/zerotier 打洞时一般都是 UDP ,Natter 使用 TCP 。

另外,Natter 的“打洞”其实只做了一半:只有服务端打洞,向外暴露端口;客户端则是没有感知的,不借助任何软件,手输外部 IP:端口号即可访问。
mikewang
2022-09-14 14:24:18 +08:00
YAFEIML
2022-09-14 15:11:27 +08:00
比较叼,联通、移动都轻松打洞成功,都改的桥接,路由都是 openwrt ,rdp 协议复制了下文件,速度不错。
https://img.gejiba.com/images/c0669216d535c1458a45ad3b72702cc9.png
mrzx
2022-09-14 17:04:55 +08:00
@mikewang 请教下,没看懂原理,尤其是 www.qq.com:80 和 STUN server 之间发生了什么?
mrzx
2022-09-14 17:13:47 +08:00
@mikewang 我不可以这么理解,虽然不需要像 FRP 那种数据包全部由公网服务器中转了。但对对外连接的端口的端口信息,需要告知 STUN server 服务器,然后外面的客户端通过从 STUN server 的这些信息,直接连过来?

至于为什么要连 qq:80 ,是故意想将 TCP session 时间延长,避免默认的 300 秒超时,导致 session 丢失和端口产生变化?


这些都是我猜测的。原理是这样吗?
1423
2022-09-14 19:17:40 +08:00
@mrzx 看我上面的代码,自己跑一下抓个包就能看明白怎么回事

另外我试了下,其实 tcp 穿透不需要任何工具,路由器配置端口 10000-50000 tcp 全部转发到指定服务,外部端口直接用 masscan 扫描,扫出来的都可以用。如下图扫到的自己宽带的公网开放端口,都可以使用
mikewang
2022-09-14 21:03:40 +08:00
@mrzx
详细地说,原理是这样的。

假设本机获得了运营商分配的局域网 IP (100.64.32.10):
当本地 100.64.32.10 向 www.qq.com (109.244.211.100) 发起 HTTP 请求时,NAT 会做转换。

1. 本地发起请求,来源端口为 100.64.32.10:3456 ,想建立 (100.64.32.10:3456 至 109.244.211.100:80) 的连接。
2. ISP NAT Server 察觉到本地想要请求,在公网 IP 空闲端口中挑一个,在映射表中新增 (100.64.32.10:3456 ~ 203.0.113.10:14500) 映射关系。
3. 100.64.32.10:3456 转发 203.0.113.10:14500 至 109.244.211.100:80 ,本机和 www.qq.com 成功建立连接。
4. 本机断开与 www.qq.com 的连接,NAT Server 释放端口,清除 (100.64.32.10:3456 ~ 203.0.113.10:14500) 映射关系

因此,在第 4 步之前,第 3 步的时候 (100.64.32.10:3456 ~ 203.0.113.10:14500) 已经成立了映射关系,NAT1 下,两者是等同关系。此时,端口被“临时地”暴露至公网。
当该端口还提供服务时,相当于开了一个“洞”,外部的连接就能“趁虚而入”。
一旦到达第 4 步,NAT Server 回收 14500 端口,就无法继续“趁虚而入”了。

然而,这是上帝视角看整个连接的过程。实际操作中,我们不知道出口的 IP 和端口号,www.qq.com 也不会告诉我。
因此,我们需要问一个路人:“打扰一下,您看看我外面 IP 和端口号是多少”。这个路人就是 STUN 服务器。
STUN 服务器没那么多闲工夫,告诉你 IP 端口之后就立即关闭连接了。而 www.qq.com 比较客气,只要你提出我想要保持连接不关闭,它就不会关闭,外部端口也就不会被回收。
Natter 会每 10 秒说一次:“求求你别关连接”。

如果没有 STUN 服务器,但您知道自己的出口 IP ,就可以做全端口扫描,不过这就很费事了。
mikewang
2022-09-14 21:09:03 +08:00
@1423
您的做法符合 Natter 最基础的思路,原理是一致的。

1. Natter 使用 STUN 服务器,避免端口扫描(全端口转发猜端口)。
2. Natter 自己维护对外连接,因此公网的端口有效期理论无限长。

批量转发只能对单个端口有效果,同时运行多个 Natter 可以向公网暴露多个端口。
mikeluckybiy
2022-09-14 21:28:39 +08:00
@1423 宽带的公网开放端口有很多,怎么判断哪个端口是对应自己路由器的某个端口转发的?
1423
2022-09-15 02:28:43 +08:00
@mikeluckybiy 宽带的公网端口有服务在监听的并不多,除非你的网上邻居都这么玩
syn scan 显示握手成功的端口有若干,是因为家里的设备总是有 tcp 对外连接
你的网上邻居一般不会去 listen 端口,他们不会 tcp 握手成功,所以握手成功的都是你的(端口都映射到同一服务了)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/879549

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX