Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add dns-hijack for tun mode #45

Merged
merged 16 commits into from
Nov 13, 2023
Merged

feat: add dns-hijack for tun mode #45

merged 16 commits into from
Nov 13, 2023

Conversation

cxz66666
Copy link
Collaborator

@cxz66666 cxz66666 commented Nov 1, 2023

此PR旨在为zju-connect提供基本可用的dns劫持,使用户可以在tun模式下更方便的访问*.zju.edu.cn

目前tun模式使用的是10.0.0.0/8的路由,无法劫持所有流量,所以不同os下实现的方法不同。

通用的实现细节:

  • tun网卡对所有进网卡的流量检查协议和port,如果是udp53,且目的地址不是10.10.0.21(默认dns地址)和114.114.114.114(第二dns地址),则进行劫持,将dns请求交给zjuconnect解析后,交换请求的目的地址和源地址,达到dns劫持的效果
  • 仿照clash-meta定义了一套zctcpip模块,用于解析ip/tcp/udp/icmp请求
  • 对connection的读写添加了mutex,防止竞争
  • 对linux和macos切换使用sing-tun,相比于目前的water更加的完整,且配置ip rule更加方便

os相关的细节:

  • windows: 目前实现或许已经够用?待补充/进一步研究
  • linux: 添加如下的路由规则
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.a.b.c iif lo lookup 1987

ip route add default dev tun0 table 1987
  • macos: 由于缺少ip rule和ip route,在10.0.0.0/8的tun模式下无法方便的做到dns劫持,后面有两个方向可行的解决方法
    • 实现优雅停机后,将用户的dns解析设置成一个无用的公网ip,然后路由这个ip到tun设备
    • 用户手动配置dns server

@cxz66666
Copy link
Collaborator Author

cxz66666 commented Nov 1, 2023

mac上第一个可能的方案是不是类似于fake-ip,但据我所知clash的fake-ip只支持A, AAAA和CNAME记录,至少测了SRV不支持,我不知道是不是原理限制(完全不懂网络哈哈哈

我感觉和fake-ip还有一些区别,在tun只接管10.0.0.0/8的前提下没法做正常的dns劫持,所以只能将用户的/etc/resolve.conf 改成比如举个例子 1.2.3.4, 然后路由表里面加一条规则 1.2.3.4的ip去tun设备,这样用户对1.2.3.4的udp dns请求就会被发送到tun设备中,就可以进行劫持

mac由于是强主机模型 https://learn.microsoft.com/zh-cn/previous-versions/technet-magazine/cc137807(v=msdn.10)?redirectedfrom=MSDN

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

@cxz66666
Copy link
Collaborator Author

@Mythologyli https://github.com/Mythologyli/zju-connect/blob/403c98d6aaf05360665d7c1dfacafed7842de2b9/main.go#L141C1-L143 这里是否应该启一个协程,更符合其代码语义,测试过使用协程对程序执行逻辑没有影响

@Mythologyli
Copy link
Owner

@Mythologyli https://github.com/Mythologyli/zju-connect/blob/403c98d6aaf05360665d7c1dfacafed7842de2b9/main.go#L141C1-L143 这里是否应该启一个协程,更符合其代码语义,测试过使用协程对程序执行逻辑没有影响

啊,这个是我写的时候疏忽了,确实应该启一个协程

@cxz66666
Copy link
Collaborator Author

确实应该启一个协程

已在该分支修复,后续合入即可解决

@Mythologyli
Copy link
Owner

另外考不考虑不在 rvpn_conn.go 里 panic,把 panic 挪到 stack 里面

主要是 Android 需要以库的形式调用,因此整个函数里不能 panic,参考 030bddc

@cxz66666
Copy link
Collaborator Author

另外考不考虑不在 rvpn_conn.go 里 panic,把 panic 挪到 stack 里面

Android有这种需求的话我觉得也完全OK 👍

@cxz66666
Copy link
Collaborator Author

macos下发现了一种十分甚至9分优雅的方法,创建/etc/resolver/hostname 的文件,向其中写入 nameserver a.b.c.d 即可做到对hostname后缀的域名使用a.b.c.d进行解析,这种用法相当符合我们的场景,只需要创建zju.edu.cn和cc98.org等文件即可,a.b.c.d是tun网卡的ip。 cc

btw,macos这种区分domain和search domain的行为感觉其实更加合理,linux就没法(不使用其他软件的情况下)做到根据域名使用不同的dns。

至此windows/linux/macos都可以以一种比较优雅的方法实现dns-hijack

@cxz66666
Copy link
Collaborator Author

现在dns-hijack已经基本可用,相比于最初的设计有如下的改动,clientIP代指拿到的10.a.b.c的ip

  • 现在tun mode下默认开启监听 clientIP:53 作为dns服务器,和dns_server_bind属于是正交关系,两者可以同时存在,所以一般无特殊需要的话,用户不需要额外配置dns_server_bind
  • 将tun_dns_server配置项修改为dns_hijack配置项,该配置开启后会做如下操作
    • windows: 使用netsh interface ipv4 add dnsservers clientIP,添加dns服务器,达到拦截所有dns请求效果
    • linux: 使用ip rule配置ip route,拦截所有目的port是53的udp请求到tun设备
    • macos: 在/etc/resolver/下创建 zju.edu.cn 和 cc98.org的dns解析规则,只对这两个地址进行dns拦截
  • 提供优雅停机方法,tun设备应该注册清理函数,程序退出前统一执行
  • rvpn_conn永不halt

@Mythologyli 辛苦测试下windows的效果,俺不太懂windows 🙇🙇

stack/tun/stack.go Outdated Show resolved Hide resolved
main.go Show resolved Hide resolved
internal/terminal_func/terminal_func.go Outdated Show resolved Hide resolved
main.go Show resolved Hide resolved
@Mythologyli
Copy link
Owner

感觉差不多可以合并了~

@cxz66666 cxz66666 merged commit 96ff112 into main Nov 13, 2023
@cxz66666 cxz66666 deleted the dns-hijack-new branch November 14, 2023 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants