MikeWang000000 / Natter

Expose your TCP/UDP port behind full-cone NAT to the Internet.
GNU General Public License v3.0
1.31k stars 107 forks source link

support upnp portforward #47

Closed Gankyun closed 3 months ago

Gankyun commented 4 months ago

特性

通过第三方UPnP库upnpclient,支持添加UPnP端口转发,在本地测试通过。 通过 UPnP 直接通过路由器转发到本地实际服务的端口,Natter只负责端口发现和KeepAlive保持端口映射。

测试环境

路由器:RedMi AX3000T 固件版本:1.0.64 脚本运行环境:Debian 11 网络环境:中国广东 / 中国移动 / 路由器拨号 NAT类型: 路由器 NAT 1 / 设备 NAT 3

测试结果

natter

可能存在问题

  1. UPnP 规则生存时间问题,目前设置无限期。或有潜在风险。 一般路由器重启后会清空规则。通过KeepAlive部分去更新转发规则或许可行。

  2. 多个路由器情况下只会添加第一个发现的路由器设备,或许会导致映射失败。

  3. 其他品牌路由器可能存在不兼容的情况。需要更多场景测试。

  4. 实际入站请求转发请求和出站NAT映射不对等。某些情况下或有可能会影响KeepAlive功能。

Zy143L commented 4 months ago

有测试过局域网内多个Upnp设备的情况么

Gankyun commented 4 months ago

有测试过局域网内多个Upnp设备的情况么

在网内有 Jellyfin + 开启Upnp的路由器的情况下 测试没问题。 但是没有多个路由器的测试环境。

业界应该有很成熟的方案,但是也没搜到他们具体是怎么处理upnp转发的。

Zy143L commented 4 months ago

我自己是对比网关IP和Upnp地址

MikeWang000000 commented 4 months ago

感谢贡献。 我会新建一个 upnp 分支专门处理 UPnP 的相关特性,直至稳定后合入主线。


关于 UPnP,我有两种功能的想法:

  1. Natter 作为 UPnP Client,让路由器开启转发;
  2. Natter 作为 UPnP Server,应用程序发送 UPnP 请求给 Natter,Natter 打洞成功后返回响应。

目前实现 UPnP Client 通过第三方库比较简单,虽然带来了依赖问题,但是可以设计为可选特性。 UPnP Server 的库比较少,有待研究,优先级低。


关于出站入站 NAT 不对等的问题:

其实是有解决方法的,就是从 Natter 本地向打出去的 公网IP:公网端口 发起 TCP 连接去保活,这样就肯定经过入站 NAT 了。 不过这会带来新的问题,因为会影响到源端口上的应用程序(一般程序都会忽略掉端口上无意义的流量,但不能保证所有程序都如此)。

因此目前没有实现上述功能,不过以后我也会加上的,通过新的开关控制。

MikeWang000000 commented 4 months ago

Reference:

Gankyun commented 4 months ago

感谢贡献。 我会新建一个 upnp 分支专门处理 UPnP 的相关特性,直至稳定后合入主线。

关于 UPnP,我有两种功能的想法:

  1. Natter 作为 UPnP Client,让路由器开启转发;
  2. Natter 作为 UPnP Server,应用程序发送 UPnP 请求给 Natter,Natter 打洞成功后返回响应。

目前实现 UPnP Client 通过第三方库比较简单,虽然带来了依赖问题,但是可以设计为可选特性。 UPnP Server 的库比较少,有待研究,优先级低。

关于出站入站 NAT 不对等的问题:

其实是有解决方法的,就是从 Natter 本地向打出去的 公网IP:公网端口 发起 TCP 连接去保活,这样就肯定经过入站 NAT 了。 不过这会带来新的问题,因为会影响到源端口上的应用程序(一般程序都会忽略掉端口上无意义的流量,但不能保证所有程序都如此)。

因此目前没有实现上述功能,不过以后我也会加上的,通过新的开关控制。

UPnP Server 问题

UPnP Server 环境要求还是比较高,需要可编程的路由系统,替换原先UPnP组件。而且进程还要自带有UPnP映射功能。 Client 只需要路由器开启UPnP映射即可,绝大多数路由器——甚至运营商提供的光猫都有支持。

关于回包的问题。

我这里抓包发现,Natter的探活请求还是能正常接收到回包的。估计是路由器系统端口映射规则优先级还是低于NAT的优先级的。我这跑了两周运行良好。 不过最好是能配置是 UPnP 直通 或 经Natter转发,这样能适配更多的情况。

NAT-PMP规则的生存时间问题

调查了一下,微信语音的 NAT-PMP 设置 TTL 是一个很大的数字,约54年(而不是0)。 依照微信的用户基数,应该是个稳妥的方案。 出于安全因素考虑(一些不适合长期暴露到公网的服务),可以随着Natter退出就删除映射规则,或设置一个比较小的TTL (如1小时)然后再定时刷新映射。

Gankyun commented 3 months ago

主分支特性已支持。

MikeWang000000 commented 3 months ago

感谢您的工作!此PR为Natter的UPnP开发提供了思路。

没有采用此PR的原因主要在于依赖问题,抱歉。考虑到便携性,我使用标准库将UPnP协议部分重写了一遍。

代码进入master分支后,我会添加您作为Natter的Contributor。