前言
自2023-11-3起,Clash内核已经删库并终止维护,该项目的前景十分渺茫,不建议新人使用Clash相关流程。
本系列教程所配置的网络均为Ipv4网络,所以并不适合使用Ipv6的小伙伴。
在《NAS系列 在PVE中搭建OpenWrt虚拟机》中,我们已经搭建OpenWrt虚拟机并成功地用了起来。讲到OpenWrt,就不得不提OpenClash了。OpenClash是一个非常有名的OpenWrt插件。根据官方仓库的介绍,它是一个可运行在OpenWrt 上的Clash客户端,兼容多种网络协议,根据灵活的规则配置实现策略连接:
Clash其实是一个内核,它定义了一些网络连接的基本功能。OpenClash更多地是提供一个方便交互和管理的GUI,它本质上是基于Clash内核的。其它基于Clash内核的应用,比如Clash for Windows,和OpenClash并没有本质区别。
下面是一个关于普通网络和Clash网络主要区别的简单示意图:
比如访问1
是baidu.com
,我希望让它按默认情况连接(规则1;Direct)。访问2
是https://ad.js
,是一个和广告相关的js脚本;因为我不想看到广告,所以我希望它被阻断(规则2;Block)。访问3
是单位网站,我希望它走单位提供的连接(规则3)。说到这里,如果你觉得OpenClash的功能对你的日常场景没有帮助,那么对本章内容的了解就可以到此为止了。
本教程的重点并不是讲解应该如何在OpenClash的GUI里操作某些项目;而是专注于了解Clash的配置文件。我个人认为,配置文件才是认识并自定义Clash的最佳起点。我会从一个虚拟应用场景——“远程办公”——讲述Clash的策略分流是如何帮助我们较好地协调网络。
场景
假设由于某些情况,你需要在家里远程办公。办公过程就是要访问公司的某些网站,比如财务部(以caiwu.com
为后缀)和销售部(以xiaoshou.com
为后缀)。由于办公时可能包含一些公司的敏感信息,公司给你提供了特定协议的登陆帐号(假设Clash支持该协议)和DNS服务器,以防机密数据泄露。如果你家里的路由器使用OpenWrt系统和OpenClash插件,如何设计网络以满足该场景且不影响正常上网?
分析
一般来说,只要我们通过https连接网络,非目标网站的访客是无法解密其中的内容的(原理同ssh)。不过,基于Clash内核可以让安全性进一步提升——它可以避免DNS泄露。
我们先从一般情况讲起。首先,我们在浏览器里访问caiwu.com
。我们在《了解IP地址》中提到过,互联网设备之间是通过IP来互相识别的。我们的浏览器并不知道caiwu.com
对应的是哪个IP,所以就会发起一条DNS请求。DNS即Domain Name Server,中文是“域名服务器”,它记录了许多“域名-IP”对,可以明确域名到IP的映射关系:
OpenWrt会事先指定一些DNS公共服务器,比如114.114.114.114
。114.114.114.114
是国内移动、电信和联通通用的DNS,手机和电脑端都可以使用,解析成功率高、速度快、稳定,较为常用。不过,实际情况是,该DNS查询也可能会走很多个公共DNS服务器才能找到符合条件的记录。
由于DNS查询的过程是明文的,114.114.114.114
和其它过路DNS服务器其实已经知道该DNS查询的来源IP(因为它要返回记录给你,必然要知道你的IP),这其实就是所谓的“DNS泄露”。狭义上的“DNS泄露”指保密网址(比如这里的caiwu.com
)在公共服务器中进行DNS查询后导致源IP暴露。还有另外一种情况据说也是挺常见的,叫“DNS污染”,即返回了假IP(Fake-IP)——比如caiwu.com
的真实IP是1.1.1.1
,但返回的IP是2.2.2.2
。一般而言,DNS泄露会导致安全性问题;DNS污染可能会导致网址无法正常访问。此外,DNS的加密也是DNS泄露中值得关注的重要问题。像114.114.114.114
等非加密DNS服务器,DNS解析的过程中很容易被中间人拦截并返回中间人故意插入的信息(比如返回一个指向赌博广告的IP地址),这对于DNS解析的发起者来说往往是有害的,无疑也是安全上网中的“debuff”(比如该新闻)。
总之,在本场景中,由于单位提供了专属DNS服务器,所以我们要保证关于caiwu.com
的DNS请求只能去请求该专属DNS服务器,这样就可以避免caiwu.com
的DNS泄露。当然,也要保证一般网站(比如baidu.com
)的DNS请求可以走114.114.114.114
之类的DNS公共服务器,以避免专属DNS服务器的DNS解析失败(因为我们不知道这个专属DNS服务器是否保存了baidu.com
的域名-IP对)。总之,我们需要设计某种规则,让DNS解析进行“分流”,不同类型的域名走不同的DNS服务器。
其实这个场景看似简单,但在透明代理的情况下,对于Clash内核的用户来说不是一件容易的事。Clash有一种模式叫“redir-host”,它本身会想办法获得域名的真实IP,就不可避免地向所有DNS服务器并行进行DNS请求,所以DNS泄露是在所难免的。我也是折腾了好久,才试出一种可以在Clash内核中使用的看似完美的“曲线救国”方案。下面我们通过yaml配置文件来展示这种方案的具体细节。
示例配置文件
大家需要下载好示例配置文件(Nextcloud; Alist)。用纯文本编辑器(如NotePad++或txt阅读器)即可打开。
使用过docker-compose的小伙伴应该对yaml
格式很熟悉了,Clash内核的行为基本上都可以通过yaml
格式的配置文件来定义。为了方便讲解,我调整了一些参数的顺序,它们可能与实际顺序有较大的差别。下面咱们就一块块地剖析这个Clash配置文件示例。
基本信息
---
port: 7890 # HTTP(S) 代理端口
socks-port: 7891 # SOCKS5 代理端口
redir-port: 7892 # 流量转发端口
tproxy-port: 7895 # TProxy端口
mixed-port: 7893 # 混合代理端口
mode: rule # 使用rule策略
示例文件中的开头定义了一些Clash参数,比如指定哪些用途用什么端口、使用什么模式之类的。和我们的关系不大,直接略过。
TUN模式
tun: # TUN模式
enable: true
stack: system # 网络栈类型
auto-route: false
auto-detect-interface: false
dns-hijack:
- tcp://any:53 # 53端口向DNS服务器开放
enable: true
表明使用TUN模式
(Tunnel;“隧道”之意)。Clash在TUN模式
下会建立一个虚拟网卡,从网络层托管连接;而所有发往互联网的流量都需要经过网络层,因此TUN模式
可以比较充分地接管局域网所有设备/所有应用的互联网流量。
在PVE.OpenWrt Shell里通过ip a
查看网上信息,可以发现一个叫utun
的虚拟网卡:
utun: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 9000 qdisc mq state UNKNOWN group default qlen 500
link/none
inet 198.18.0.1/16 scope global utun
valid_lft forever preferred_lft forever
inet6 fe80::1b21:4d12:XXX:XXXX/64 scope link stable-privacy
valid_lft forever preferred_lft forever
其中,网段198.18.0.1/16
是用来分配假IP的,后面会提到。
我们再看看其它参数。stack: system
表明使用操作系统自带的tcpip协议栈,兼容性更强、更稳定。另一个类似的协议是stack: gvisor
,可以在用户空间直接解析数据,性能更好;具体内容可以参考文章《gvisor的网络栈实现-简介》。这个参数我们作简单了解就行。在实际使用中,你可以试试看哪个好用;默认是使用system
。
这里注意的是dns-hijack
(DNS劫持)的相关参数——tcp://any:53
代表接管局域网中所有IP的53
端口请求。一般情况下,DNS请求就是通过53端口传递的。此时,如果你在局域网内任何一个机器访问了某网站,该网站的DNS请求会被Clash内核劫持。
DNS模块
本文的重难点内容。
dns:
enable: true
ipv6: false
enhanced-mode: fake-ip # Fake-IP模式
fake-ip-filter:
- "+.baidu.com"
- "+.bilibili.com"
fake-ip-range: 198.18.0.1/16
listen: 0.0.0.0:7874 # DNS监听端口
nameserver:
- 192.168.1.254:5336 # AdGuard Home 01,上游DNS服务器为公众所有。
fallback:
- tcp://192.168.1.254:5335 # AdGuard Home 02,上游DNS服务器为公司专用
# https://lancellc.gitbook.io/clash/clash-config-file/dns#fallback-filter
fallback-filter:
geoip: true
geoip-code: 非公司网站 # geoip=true, geoip-code=非公司网站。这样设置的结果是:非公司网站使用nameserver的DNS结果。
domain:
- "+.xiaoshou.com"
由于我们需要利用Clash内核对DNS请求进行分流,因此配置文件必须要包含dns
模块。首先,listen: 0.0.0.0:7874
表明Clash监听DNS请求的端口为7874
。一般地,OpenWrt会自带一个DNS转发器;我们需要设置127.0.0.1:7874
为默认且唯一的DNS转发端口,这样才可以保证所有的DNS请求被Clash顺利接管(原端口是TUN模式中约定的53
端口):
关于0.0.0.0
和127.0.0.1
的区别可见《127.0.0.1和0.0.0.0地址的区别 – 腾讯云开发者社区-腾讯云》。在路由器中,这两个地址似乎没区别?有了解的小伙伴可以评论区留言哈!
enhanced-mode: fake-ip
表明使用的是Clash内核的Fake-IP模式。Fake-IP模式的主要策略是通过为请求DNS解析的域名提供一个假IP(从fake-ip-range: 198.18.0.1/16
里随机选1个并保证不重复)来“骗”、来“忽悠”浏览器发出的DNS请求,从而继续后面的步骤;并且不再向其它服务器发起真正的DNS请求。
198.18.0.1/16
属于CIDR地址,我们可以用IPv4 / IPv6 CIDR计算器来看看198.18.0.1/16
对应的IP段:
因此,198.18.0.1/16
是一个非常大的网段,合计65536个IP。再结合非常短的IP有效时间和其它机制,Fake-IP模式可以保证家用环境下不同域名映射一个不同的假IP,且不发生IP重复。
下面,我们举几个例子来说明该dns策略是如何全面“照顾”我们的上网需求的。
访问caiwu.com
当我们访问caiwu.com
时,浏览器给OpenWrt发送DNS请求,从而被Clash接管。由于fake-ip-filter
名单里面并没有caiwu.com
,因此Clash会给caiwu.com
一个假IP。我们指定了一个局域网段198.18.0.1/16
提供假IP,比如最终确定了caiwu.com-198.18.0.0
的域名-IP对。此时DNS模块的流程已经完成。
由于我们一开始设定了Clash模式——mode: rule
,因此caiwu.com-198.18.0.0
将直接进入rules
中进行匹配:
rules:
- "DOMAIN-SUFFIX,caiwu.com, 财务部代理"
# - "DOMAIN-SUFFIX,xiaoshou.com, 销售部代理"
- GEOIP,CN,直连
- MATCH,代理
由于caiwu.com
满足第1条规则"DOMAIN-SUFFIX,caiwu.com, 财务部代理"
,因此走财务部代理
这个代理组(proxy-groups
):
proxy-groups:
- name: "财务部代理"
type: select
proxies:
- "公司财务部代理1"
- "公司财务部代理2"
因此是走公司财务部代理1
或公司财务部代理2
节点。它们的具体信息在proxies
模块中已经列举:
proxies:
- name: 公司财务部代理1
帐号信息
- name: 公司财务部代理2
帐号信息
此时,访问caiwu.com
的请求会通过这两个节点之一完成。由于这是公司提供的网络环境,caiwu.com
的DNS解析和后续访问会在公司的内部网络里完成。然后数据返回时再按原来的道路反方向回来并在浏览器本地解密,我们的浏览器就显示了我们想要的信息(这个过程实际上非常复杂,这里只是一个简化描述)。
纵观全程,访问caiwu.com
的过程并不会发起公共DNS请求,而是经过Fake-IP化后直接在公司服务器里完成后续的DNS解析和数据访问。因此,该网络结构有效地防止了caiwu.com
的DNS泄露。由于公司服务器必然知道自己网站(包括caiwu.com
)的真实IP,因而也防止了DNS污染。
访问baidu.com
当我们访问baidu.com
时,浏览器给OpenWrt发送DNS请求,从而被Clash接管。由于fake-ip-filter
名单里面包含了baidu.com
:
fake-ip-filter:
- "+.baidu.com"
- "+.bilibili.com"
因此Clash不会给baidu.com
分配假IP(此时fake-ip-range: 198.18.0.1/16
自然也不会生效),而是直接向Openwrt的DNS服务器发起并行DNS请求。
在本规则中,我们定义了两个DNS服务器——nameserver
和fallback
:
nameserver:
- 192.168.1.254:5336 # AdGuard Home 01,上游DNS服务器为公众所有。
fallback:
- tcp://192.168.1.254:5335 # AdGuard Home 02,上游DNS服务器为公司专用。
其中nameserver
指向192.168.1.254:5336
,它其实是一个AdGuard Home的Docker容器,包含上游DNS服务器(比如114.114.114.114
或者其它你想要加入的公共DNS)和一些广告过滤规则。fallback
是另一个AdGuard Home的Docker容器,它的上游DNS服务器则是公司专属DNS服务器。这其实就是所谓的利用“双AdGuard Home”提供差异化DNS解析服务。理论上这是一种比较消耗资源的方案,但软路由的性能一般都比较强大,因此和轻量级方案相比并没有明显的性能受限。
不管怎样,DNS解析工作已经开始了。假设baidu.com
在nameserver
中的解析时间是tn,在fallback
中的解析时间是tf。由于baidu.com
是一家非常出名的公司,它的域名-IP对遍布各大DNS服务器;而fallback
对应的公司专属DNS服务器则不一定会记录baidu.com
的域名IP对。所以,一般来说,tn<<tf,故Clash内核会优先选择nameserver
的解析结果。
当然,也可能会发生tf>tn的情况,这时就不太符合我们的预期了。没关系,我们还设计了另一层机制——fallbacke-filter
——来保证解析baidu.com
时Clash内核会优先选择nameserver
的解析结果:
fallback-filter:
geoip: true
geoip-code: 非公司网站
domain:
- "+.xiaoshou.com"
GEOIP是一个非常著名的数据库,它记录了定期更新的IP-地理位置
映射关系。我们设置了geoip=true, geoip-code=非公司网站
,这样的结果是:非公司网站均优先使用nameserver的DNS结果。由于baidu.com
是一家非常出名的公司,其IP已经被GEOIP数据库记录过,因此属于非公司网站
。总之,通过nameserver/fallback时间差和fallbacke-filter等机制,解析baidu.com
时Clash内核会优先选择nameserver
的解析结果。
由于baidu.com
是一家非常有名的国内公司,nameserver
基本上可以获得真实IP,因此避免了DNS污染。“访问baidu.com
”本身是一种普通的上网行为,并不需要像保密公司网址一样保护,故不存在狭义上的DNS泄露。
完成DNS解析后走rules
模块:
rules:
- "DOMAIN-SUFFIX,caiwu.com, 财务部代理"
# - "DOMAIN-SUFFIX,xiaoshou.com, 销售部代理"
- GEOIP,CN,直连
- MATCH,代理
由于并不匹配第1条规则,baidu.com
继续适配规则GEOIP,CN,直连
。由于baidu.com
是一家非常出名的公司,其IP已经被GEOIP数据库记录过;直接根据此前已经获得的真实IP,判定baidu.com
符合规则GEOIP,CN,直连
。最终,使用该真实IP进行直连访问(也就是普通的方式)。
访问xiaoshou.com
当我们访问xiaoshou.com
时,浏览器给OpenWrt发送DNS请求,从而被Clash接管。由于fake-ip-filter
名单里面并没有xiaoshou.com
,因此Clash会给xiaoshou.com
一个假IP。我们指定了一个局域网段198.18.0.1/16
提供假IP,比如最终确定了xiaoshou.com-198.18.0.3
的域名-IP对。此时DNS模块的流程已经完成。
由于我们一开始设定了Clash模式——mode: rule
,因此xiaoshou.com-198.18.0.3
将直接进入rules
中进行匹配:
rules:
- "DOMAIN-SUFFIX,caiwu.com, 财务部代理"
# - "DOMAIN-SUFFIX,xiaoshou.com, 销售部代理"
- GEOIP,CN,直连
- MATCH,代理
xiaoshou.com
并不符合第1条规则,因此尝试适配规则GEOIP,CN,直连
。由于不知道xiaoshou.com
的真实IP,这里会发起并行DNS请求(通过nameserver
和fallback
),此时xiaoshou.com
会发生狭义的DNS泄露。
不过,我们设置了fallback-filter
的保护机制使得xiaoshou.com
的DNS请求一定可以获得真实IP——直接在domain里添加xiaoshou.com
即可:
fallback-filter:
geoip: true
geoip-code: 非公司网站
domain:
- "+.xiaoshou.com"
根据Clash文档,添加到fallback-filter
的domain
里的域名会标记为污染域名,从而只应用fallback
请求所获得的IP。由于fallback
的上游DNS服务器则是公司专属的DNS服务器,因此必然可以获得xiaoshou.com
的真实IP。
总之,在本策略中访问xiaoshou.com
会引起狭义的DNS泄露,但可以保证xiaoshou.com
正常连接。因此,正确的做法应该是去掉rules
模块中第2行的注释,直接表明xiaoshou.com
会走公司服务器:
rules:
- "DOMAIN-SUFFIX,caiwu.com, 财务部代理"
- "DOMAIN-SUFFIX,xiaoshou.com, 销售部代理" # 添加这个规则可以防止DNS泄露
- GEOIP,CN,直连
- MATCH,代理
这样情况就会类似于访问caiwu.com
,安全性和可连接性都有保障。
访问hwb0307.com
当我们访问hwb0307.com
时,浏览器给OpenWrt发送DNS请求,从而被Clash接管。由于fake-ip-filter
名单里面并没有hwb0307.com
,因此Clash会给hwb0307.com
一个假IP。我们指定了一个局域网段198.18.0.1/16
提供假IP,比如最终确定了hwb0307.com-198.18.0.1
(与其它域名不相同)的域名-IP对。此时DNS模块的流程已经完成。
由于我们一开始设定了Clash模式——mode: rule
,因此hwb0307.com
将直接进入rules
中进行匹配:
rules:
- "DOMAIN-SUFFIX,caiwu.com, 财务部代理"
# - "DOMAIN-SUFFIX,xiaoshou.com, 销售部代理"
- GEOIP,CN,直连
- MATCH,代理
由于并不匹配第1条规则,hwb0307.com
继续适配规则GEOIP,CN,直连
。由于此前对hwb0307.com
并未发起公共DNS请求,因此Clash会发起发起DNS请求(通过nameserver
和fallback
)。然而,hwb0307.com
是一个名不见经传的博客,其IP不一定被GEOIP数据库收录,故会跳过规则GEOIP,CN,直连
。最终hwb0307.com
会走到MATCH,代理
;但公司专属DNS服务器可能并不收录hwb0307.com
的真实域名IP对。这种结果会导致hwb0307.com
无法访问。
此外,对于某些冷门网站,尽管公共DNS解析获取了正确的公网IP,访问域名还是没有办法访问,其警告信息类似:
2023-03-24 16:51:00 WRN [TCP] dial failed error=dial tcp4 公网ip:443: connect: connection refused proxy=直连 lAddr=192.168.1.247:57820 rAddr=XXX.hwb0307.com:443 rule=DomainSuffix rulePayload=hwb0307.com
具体原因比较复杂,可能与电脑/浏览器缓存假IP、使用非443端口有关,我也不甚了解。不过,解决方案是挺简单的,就是将hwb0307.com
添加到fake-ip-filter
中:
fake-ip-filter:
- "+.baidu.com"
- "+.bilibili.com"
- "+.hwb0307.com"
这样hwb0307.com
就可以不使用假IP而总是使用真实IP,从而一定可以成功访问。对Clash而言,fake-ip-filter
实际上就是指定某些可能无法正常访问的网站使用redir host
模式,它们是无法避免狭义上的DNS泄露的。
小结
配置文件中还有其它模块,不过它们不是本文的重点,故不进行讨论。在本文中,我们解释了Clash的Fake-IP模式结合双DNS服务器(基于双ADGuard Home)是如何保证不同类型的网络访问是如何有条不紊地进行策略分流。
实际上,Openclash的Fake-IP TUN模式 + fallback-filter设置、双AdGuardHome作DNS服务器的方案真心不错:
-
将敏感域名尽可能地添加至
rules
,最大限度避免DNS泄露。 -
将敏感域名加入fallback-filter的domain,可以保证远程DNS解析请求强制使用fallback,从而避免域名的DNS污染。 设置GEOIP-CN强制选择nameserver的DNS解析结果,也可以避免非敏感域名的DNS污染。
-
设置fake-ip-filter强制某些冷门但非敏感的域名不使用fake ip从而保证其可正常访问。
-
双AdGuardHome设置https/tls的加密上游DNS服务器的可以较大程度降低DNS污染和DNS泄露的影响,特别是在nameserver的AdGuard Home中的DNS黑名单中添加敏感域名的规则列表。
-
利用docker的macvlan网络模式给nas-tool和transmission分配和路由器/宿主机同网段的局域网IP,这样fake-ip模式下可以设置不走代理的局域网设备IP和排除目的地IP,从而规避PT流量:
整套方案的响应速度和下载速度也不错。不过,如果你深刻地理解了Fake-IP模式,就会发现这种方式其实不太完美。比如:
- 除了fake-ip-filter里的域名,其它域名的ping值返回的是假IP。这对于想要观察网站真实IP的人而言不太合适(查看Clash内核日志应该看得到;使用chinaz之类的站长工具是一种更好的方案)。以下是示例图:
- 测速结果不准确
- 没进行DNS解析的域名是不会有较好的广告屏蔽效果的。
不过,这些缺点我自己并不是很在意啦!此外,我感觉Clash.Meta内核的域名嗅探方式似乎更加好用,但自己的了解比较有限,以后再开坑试试看。
之后可能会讲讲如何在OpenClash的GUI里具体设置某些项目,以达到类似示例配置的效果。敬请期待!另外,相关的知识我也是刚刚学习,很多细节暂时也不太了解。如果有什么意见,欢迎评论区指教喔!
扩展阅读
- DNS泄露检测网站:https://browserleaks.com
- IPv4 / IPv6 CIDR计算器 | RAKKOTOOLS🔧:计算CIDR地址对应的IP群。
- Configuration · AdguardTeam/AdGuardHome Wiki: AdGuard Home的官方文档。
- 不良林系列:进阶•代理模式篇、进阶•DNS泄露篇、进阶•DNS分流篇、进阶•DNS代理篇和进阶•UDP穿透篇、DNS泄露实战。
- 优雅的开启双AdGardHome的NDS+广告过滤功能,让ssrp+passwall精准分流国内外DNS解析,提升打开网页速度(DNS分流服务器/DNS优化/秒解析)
- 一条视频讲清楚TCP协议与UDP协议-什么是三次握手与四次挥手_哔哩哔哩_bilibili:TCP/UDP协议的区别。这里有一个形象的例子:
---------------
完结,撒花!如果您点一下广告,可以养活苯苯😍😍😍
写的太好了!!!!!!!!终于搞懂dns模块每个板块是干嘛的了。太感谢了
能看懂说明都是老司机了,哈哈 ~
大佬写的真厉害,反复看了两遍总算看明白了
写的太好了,感谢,所有的教程都这样,谁还学不会
能看懂其实也代表已经有了一定的基础了
从个人使用角度而言(非公司,公司情况直接用VPN方便一些)Geoip加上no-resolve基本上就不会发起dns请求了,fake-ip在遍历规则后会匹配match,最终导致没被收录到Geosite和Geoip的小众网站会走代理,代理服务器再进行一次DNS查询。本地没有对非CN地区的Geoip和Geosite网站进行DNS查询,保证你上游运营商不知道你访问了海外网站。fake-ip除了部分软件对私有地址无法连接(如游戏、语音等)基本上没什么大问题了吧
有类似ADGuard Home之类的强大软件主动分流其实也是一种不错的选择;方案很多,见仁见智了 (~ ̄▽ ̄)~
这篇文章看得我头晕。看了好几遍,不明觉厉!保护隐私好重要!
看得明白自然好,看不明白也不坏 (ฅ´ω`ฅ)