ehang-io / nps

一款轻量级、高性能、功能强大的内网穿透代理服务器。支持tcp、udp、socks5、http等几乎所有流量转发,可用来访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析、内网socks5代理等等……,并带有功能强大的web管理端。a lightweight, high-performance, powerful intranet penetration proxy server, with a powerful web management terminal.
https://ehang.io/nps/documents
GNU General Public License v3.0
30.53k stars 5.52k forks source link

npc客户端当通过域名连接时,如果在网络不可用情况下启动,则网络可用后也不能恢复正常 #967

Open laeni opened 2 years ago

laeni commented 2 years ago

Describe the bug 当npc使用域名连接nps的情况下,如果npc启动时网络不可用,则网络恢复后npc不能自动恢复。 因为npc常安装与个人笔记本电脑中,并且设置了自启动,所以在这种情况下,刚刚开机时网络可能还没准备好,从而导致需要重启npc才行。

To Reproduce Steps to reproduce the behavior:

  1. 确保npc属于停止状态。
  2. 断开网络。
  3. 使用域名启动npc。
  4. 连通网络后npc一直无法自动恢复。
  5. 将域名换成IP后重复上述 1~4 步骤发现网络正常后npc也能恢复正常。

Expected behavior 使用域名应该和使用IP一样,当网络恢复后能恢复正常。

Screenshots or logs 使用域名时: npc-1 使用IP时: npc-2

Server (please complete the following information):

Client (please complete the following information):

Additional context

tinyluck commented 2 years ago

不是网络连接问题,而是npc默认按域名去找对应的ipv6,找不到就报错。而我们的动态域名,一般都是ipv4。最简洁的办法是在客户端的系统里把ipv6网络给禁用。 我是在termux里遇到这个问题,找不到禁用ipv6的方法。最后是安装了alpine子系统,默认不支持ipv6,然后运行正常。 你的情况应该在docker里禁用ipv6。

如果nps能增加个功能,只走ipv4就更好了

SIXiaolong1117 commented 1 year ago

时隔一年,我也遇到了这个问题。 我是想在一台Android13设备上运行npc,我的nps假设在了家里的软路由上,同时开启了DDNS,结果是它总是报这样的错误。 这个错误的根源如tinyluck所述,因为npc在解析域名的时候默认去解析IPv6,但是一般情况下我们配置的DDNS都是在IPv4上的,自然无法正常解析。 我目前暂时想到的解决办法是,提前解析一次域名的IPv4地址,然后将结果IPv4作为参数传给npc运行,shell脚本如下:

# 定义要解析的域名
domain=<你的域名>

# 使用ping命令解析域名并提取IP地址
ip_address=$(ping -c 1 $domain | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)

# 输出IP地址
echo "域名 $domain 的IP地址是: $ip_address"

# 执行./npc命令
(./npc -server="$ip_address:<你的端口>" -vkey=<你的vkey> -type=<隧道类型>)

这其实是一个治标不治本的办法,因为npc本质上还是在对解析后的静态IP发送连接请求,如果DDNS的IP地址变动,就会导致npc与nps失去连接。 但从另一个角度来看,Android的ping命令本身也存在很多问题,例如他会和我的Clash TUN模式打架(开启Clash TUN模式后,ping可能无法获得正常的IP地址),如果不是为了将npc当作后门或者有其他特殊需求的话,上面的脚本足以作为一个便捷启动npc的办法来使用。

laeni commented 1 year ago

你们的问题和我的问题似乎不是同一个。你们是ipv6引起的问题;而我遇到问题是网络正常后不会自动恢复(期望“网络正常后自动重新解析域名连接”或者“直接报错退出进程”),否则进程一直挂着,管理软件很难判断是否需要重启。

SIXiaolong1117 commented 1 year ago

只看报错的话,你遇到的就是将域名错误解析到IPv6上的问题。 使用域名的报错是将域名解析成一个IPv6地址后,与其对应端口发起通信被拒绝。 使用IP(v4)地址的报错就是单纯的网络断开连接。 所以网络恢复后,使用域名的方式仍然在对一个IPv6地址发送请求,结果肯定还是失败。使用IP(v4)的方式则因为网络恢复而重新连接。

SIXiaolong1117 commented 1 year ago

另外值得一提的是当前这个Repo已经停止更新了,有人Fork在继续开发(nps),可以去提一个issue。 其实实现起来应该很简单,只需要加一个选项选择通过IPv4还是IPv6穿透即可,但奈何本人并不会Go语言,近期工作繁忙,所以无能为力。 不修改源码的解决办法,一个是上面tinyluck提到的直接关闭IPv6,你是一台PC,这么做肯定是可以的。如果设备(例如Android)不能完全关闭IPv6或者关闭了也无效,那可以试试像我一样写个脚本,先解析成IPv4,然后把这个IPv4地址作为参数传给npc。

laeni commented 1 year ago

只看报错的话,你遇到的就是将域名错误解析到IPv6上的问题。 使用域名的报错是将域名解析成一个IPv6地址后,与其对应端口发起通信被拒绝。 使用IP(v4)地址的报错就是单纯的网络断开连接。 所以网络恢复后,使用域名的方式仍然在对一个IPv6地址发送请求,结果肯定还是失败。使用IP(v4)的方式则因为网络恢复而重新连接。

你这么说的话好像确实是IPV6的问题。

其实我个人一直是主要用WireGuard,在某些场景下使用frp作为补充,而nps作为frp的同类的产品,所以当时就对比一下而已。

SIXiaolong1117 commented 1 year ago

只看报错的话,你遇到的就是将域名错误解析到IPv6上的问题。 使用域名的报错是将域名解析成一个IPv6地址后,与其对应端口发起通信被拒绝。 使用IP(v4)地址的报错就是单纯的网络断开连接。 所以网络恢复后,使用域名的方式仍然在对一个IPv6地址发送请求,结果肯定还是失败。使用IP(v4)的方式则因为网络恢复而重新连接。

你这么说的话好像确实是IPV6的问题。

其实我个人一直是主要用WireGuard,在某些场景下使用frp作为补充,而nps作为frp的同类的产品,所以当时就对比一下而已。

合适才是更重要的,nps只是轻量化。 但是考虑到nps现在已经停止维护这么长时间了,其实也不是很建议继续使用。