Mythologyli / zju-connect

ZJU RVPN 客户端的 Go 语言实现
GNU Affero General Public License v3.0
338 stars 23 forks source link

feat: support tun mode #44

Closed Mythologyli closed 11 months ago

Mythologyli commented 11 months ago

此 PR 希望为 zju-connect 带来 TUN 模式,具体的好处有:

  1. 更方便地进行 SSH/RDP 等连接
  2. 运行在主路由时带来便利
  3. 便于对接 Android VpnService

目前的初步想法为:

  1. TUN 接口默认路由 10.0.0.0/8。如果路由 0.0.0.0 可能分流比较复杂
  2. 在 Windows 平台上主要作为 SOCKS5/HTTP 代理的补充,使得 zju-connect 在 SSH/RDP/正版软件认证等方面的体验与 EasyConnect 类似

存在的问题:

  1. 当前版本开启 TUN 模式后禁用 SOCKS5/HTTP 代理、端口转发等功能,因为这些功能是基于 gVisor 网络栈实现的。目前想法是开启 TUN 后禁用 gVisor 网络栈,然后 net.Dial 走 TUN 网卡
  2. Linux 下设置 TUN 网卡是用 ifconfig 实现的,某些发行版可能不自带 ifconfig,如果能用别的方法实现更好
  3. github.com/songgao/water 对 Android 的支持似乎不好,所以目前暂未实现 Android
Mythologyli commented 11 months ago

tun mode下强制开始dns server,用户可以配置文件中选择绑定/不绑定到ip:port

这个是为了在不配置系统代理的情况下正确访问 xxx.zju.edu.cn 吗。那我觉得后期还需要完善一下这个内置的 DNS,毕竟只实现了 A 和 AAAA 的解析

macos下修改dns服务器到某个ip A,配置路由A到tun设备。

macos 下 dns 如果可以走命令行设置的话,能不能像现在 Windows 的实现那样监听 0.0.0.0:53 然后设置为 127.0.0.1

还有一个想法:初步实现中,使用配置文件中指定的SecondaryDns感觉没啥问题,但是后续改成可以自动使用用户机器原本的dns

我也有这个想法。有什么方法获取用户之前使用的 DNS 嘛

cxz66666 commented 11 months ago

这个是为了在不配置系统代理的情况下正确访问 xxx.zju.edu.cn 吗。那我觉得后期还需要完善一下这个内置的 DNS,毕竟只实现了 A 和 AAAA 的解析

是的,感觉这个需求在tun mode下是非常重要的,确实需要完善一下除了A和AAAA,不过也初步够用了

macos 下 dns 如果可以走命令行设置的话,能不能像现在 Windows 的实现那样监听 0.0.0.0:53 然后设置为 127.0.0.1

这个肯定是可以的,就是怕用户自己其他程序可能用了53端口,劫持dns毕竟还是更加的透明

我也有这个想法。有什么方法获取用户之前使用的 DNS 嘛

感觉可以后面研究一下,现在我只能想到mac上可以用scutil --dns命令,linux/macos下可以查看/etc/resolve.conf

Mythologyli commented 11 months ago

感觉 Clash 的 TUN 模式是没有做自动获取之前的 DNS 这个功能的,开启 TUN+DNS 后似乎必须要手动设置一个 nameserver

cxz66666 commented 11 months ago

感觉 Clash 的 TUN 模式是没有做自动获取之前的 DNS 这个功能的,开启 TUN+DNS 后似乎必须要手动设置一个 nameserver

确实,clash for windows是默认了三个nameserver

Mythologyli commented 11 months ago

https://github.com/Mythologyli/zju-connect/tree/refactor

我在这个分支上做了一些重构。对于在路由器上跑 zju-connect 的用户,感觉最后的体积还是蛮重要的。现在这样重构比较方便未来在做一个只用 TUN 的版本,去掉 gVisor 体积应该能减少不小

我的 golang 纯纯野路子水平,有空的话希望帮忙看看整个结构设计的有没有问题(哭

cxz66666 commented 11 months ago

过了一遍感觉水平很高 👍

现在感觉除了dns相关的,tun mode已经比较完善了(可以merge的感觉)。但linux和macos上的tun模式下dns我还是有点挠头

所以一个可以接受的方案就是直接替换dns的配置文件/etc/resolve.conf,这就需要先实现优雅停机,程序结束前将/etc/resolve.conf.bak 复原。

anyway,后面可以新开一个pr做优雅停机和其他的改进,感觉这个tun mode已经基本可用了

Mythologyli commented 11 months ago

也许可以看看 clash meta 的实现?

cxz66666 commented 11 months ago

看了一下clash meta的思路,他们是用这一套https://github.com/MetaCubeX/sing-tun ,同时基于tun配套实现了一个system的stack

我们这最简单的方法就是只管udp,把53端口的请求拿出来,单独resolve,然后把把返回的包的源ip和源port改成之前的目的ip和目的port。

我们感觉可以用这个tun替换现在的water.tun,这个tun对route和ip rule的支持也很完善

Mythologyli commented 11 months ago

看了一下clash meta的思路,他们是用这一套https://github.com/MetaCubeX/sing-tun ,同时基于tun配套实现了一个system的stack

我们这最简单的方法就是只管udp,把53端口的请求拿出来,单独resolve,然后把把返回的包的源ip和源port改成之前的目的ip和目的port。

我们感觉可以用这个tun替换现在的water.tun,这个tun对route和ip rule的支持也很完善

感觉不错!

cxz66666 commented 11 months ago

现在分支dns-hijack已经可以正确拦截基于udp的dns请求

nslookup baidu.com 223.5.5.5

2023/10/28 19:14:56 hijack dns 10.190.68.144:55526 -> 223.5.5.5:53 2023/10/28 19:14:56 baidu.com -> 110.242.68.66 Server: 223.5.5.5 Address: 223.5.5.5#53 Non-authoritative answer: Name: baidu.com Address: 110.242.68.66

nslookup cspo.zju.edu.cn 223.5.5.5

2023/10/28 19:06:59 hijack dns 10.190.69.185:45533 -> 223.5.5.5:53 2023/10/28 19:06:59 cspo.zju.edu.cn -> 10.203.4.79 Server: 223.5.5.5 Address: 223.5.5.5#53 Non-authoritative answer: Name: cspo.zju.edu.cn Address: 10.203.4.79

但仍然还有一些问题:

  1. 需要手动设置一下路由表,linux下设置如下的ip rule。同时 使用ip route add default dev tun0 table 1234 添加route默认路由。

    9500:   not from all dport 53 lookup main #注意这里不能用前缀抑制!!!!
    9510:   not from all iif lo lookup 1234
    9520:   from 0.0.0.0 iif lo uidrange 0-4294967294 lookup 1234
    9530:   from 10.190.69.185 iif lo lookup 1234

    考虑到后面如果换sing-tun或者其他tun实现,这里我就没用command写死

  2. 只能抓到目的ip是非localhost的包,因为localhost的优先级一般是最高的,如果像openwrt用户,非得用Dnsmasq这种,就只能用设置Dnsmasq上游dns,然后zju-connect监听10.a.b.c:53 解决

  3. 考虑dns超过mtu的情况,不过正常使用的话问题不大

cxz66666 commented 11 months ago

分支dns-hijack已经将linux和macos的tun切换到sing-tun,支持了自动配置ip route 和 ip rule

linux下可以拦截非localhost下的dns请求,macos下只能在实现了优雅停机之后手动设置用户dns解析为一个fake ip,然后路由route这个fake ip到tun设备

macos下还存在问题: 使用proxy代理访问需要代理的、非10.0.0.0/8的网站现在发现还是报错no route to host,之前测试的有问题。我找了半天原因,最后看到这一篇 https://learn.microsoft.com/zh-cn/previous-versions/technet-magazine/cc137807(v=msdn.10)?redirectedfrom=MSDN

macos下使用的是强主机模型,

如果源接口上启用了强主机发送,IP 将在路由表中对数据包的目标地址执行受约束的查询。在受约束的查询中,仅考虑带有源接口的下一跃点接口的路由。根据所选目标路由,IP 确定下一跃点地址。IP 具有了源地址和目标地址、下一跃点接口和下一跃点地址。请注意,如果在源接口上启用强主机发送行为,下一跃点接口将始终与源接口相同。图 2 显示发送主机进程的普通 IP。

macos只能有一个默认路由,看这句话的样子就是说如果路由表中没有 ip为非10.0.0.0/8的、走tun设备的路由条目,则就算实用bindtodevice看起来也没法路由出去

使用proxy下测试访问cnki.net ,只有10.0.0.0/8的路由情况下报错 dial tcp4 10.190.65.184:0->115.31.65.10:80: connect: no route to host,添加 sudo route -n add 115.31.65.10 -interface utun10后,可以正常访问。

所以后面考虑开启tun模式下,macos上所有访问非10.0.0.0/8的可能得一律direct

cxz66666 commented 11 months ago

或许后面可以考虑将windows的tun也切到sing-tun下,我fork了一份sing-tun,修改了部分设置优先级、路由策略的方法,如果windows需要修改里面的路由设置啥的我可以帮忙

Mythologyli commented 11 months ago

我记得 Windows 也是强主机模型,当时一开始测试的时候也会 no route to host,最后是通过加一条到 0.0.0.0/0 的低优先级路由解决的

cxz66666 commented 11 months ago

我记得 Windows 也是强主机模型,当时一开始测试的时候也会 no route to host,最后是通过加一条到 0.0.0.0/0 的低优先级路由解决的

确实,我也以为这样可以,但是在sonoma14.0上面发现没法设置多个默认路由,netstat -rn 看不到跃点数,很烦

Mythologyli commented 11 months ago

要不要先不管 dns-hijack 了,先把 refactor 合并到 main,dns-hijack 单独开一个 PR

cxz66666 commented 11 months ago

要不要先不管 dns-hijack 了,先把 refactor 合并到 main,dns-hijack 单独开一个 PR

合理,感觉改下readme就能合