type
status
date
slug
summary
tags
category
icon
password
之前一篇文章介绍了OpenClash + MosDNS + Adguard Home的DNS泄露排查及修复记录。这里面最为核心的部分就是MosDNS,OpenClash和Adguard Home只负责最简单的解析工作,而MosDNS作为整个链条的中枢负责分流,类似于一个指挥中枢。所以今天将我的MosDNS配置分享出来。我的MosDNS是根据 Jasper-1024/mosdns_docker 的MosDNS V5配置进行二次修改的版本,所以这篇文章也可以说是一个二创文章,对原作者的配置进行了部分修改,并对整体的DNS处理流程进行讲解。
📝 付费内容
MosDNS介绍
一个 DNS 转发器 via IrineSistiana / mosdns
MosDNS可以算作是SmartDNS的一个替代品,两者作用在大部分场合相同。SmartDNS更侧重于缓存,而MosDNS的可玩性更高。
配置环境
我的MosDNS是运行在旁路由(旁路网关)的OpenWRT上,具体环境如下:
- OpenWRT:
ImmortalWrt 23.05.3 r27917-81a1f98d5b / LuCI openwrt-23.05 branch git-24.092.44091-d24c2e3
- 内核版本:
5.15.162
- 架构:
X86/64
- MosDNS版本:
v5.3.3
以上的环境只是我个人的配置环境,理论上如果你使用MosDNS,在其支持的环境下都可以正常使用我所分享的配置文件,包括Windows、Linux的发行版本、MacOS以及Docker。
Github仓库地址
使用方法
配置文件共计3个,分别为
config_custom.yaml
, dns.yaml
, dat_exec.yaml
。各部分作用如下:
config_custom.yaml
: 主配置文件,负责DNS序列定义以及DNS序列执行。需要依赖dns.yaml
和dat_exec.yaml
运行。
dns.yaml
: dns定义配置文件,负责配置公共DNS服务器及远端解析DNS地址及端口。
dat_exec.yaml
: 规则配置文件,负责定义各规则tag及规则来源文件。
下载或克隆三个yaml文件,OpenWRT放到
/etc/mosdns
文件夹内。如果是luci-app-mosdns,需要选择使用自定义配置文件。其他系统可以通过-c
参数指定配置文件为config_custom.yaml
。默认GeoSite和GeoIP的存放位置为
/var/mosdns/
,请确保文件夹下含有geoip_cn.txt
、geosite_category-ads-all.txt
、geosite_geolocation-!cn.txt
、geosite_gfw.txt
、geosite_cn.txt
以及geoip_private.txt
,OpenWRT用户可以通过luci-app-mosdns
的GeoData Export
功能自动下载解码生成:同时,在
/etc/mosdns/
下需要建立rule文件夹,并新建whitelist.txt
和greylist.txt
文件,用于自定义白名单和污染域名名单。DDNS类域名可放到白名单whitelist.txt
中。默认监听端口为
5333
,TCP和UDP均开启,如无下游DNS服务,可修改为53
端口使用。如果系统为OpenWRT,也可以直接修改dnsmasq的dns重定向到5333来使用。具体使用方法根据自己需要进行修改。修改的具体位置位于config_custom.yaml
文件最底部。MosDNS处理队列
前序列代码:
主序列代码:
合并序列:
前序列处理流程主要用于对本地域名、PTR请求、无效请求以及DNS声明等请求进行处理,不涉及到正式的域名DNS解析,不与公共DNS服务器产生数据上的交互,避免本地内部请求外泄,对解析洁癖产生安全问题的恐慌。
主序列处理流程主要用于公网的正式域名解析进行处理,根据分流规则进行直接通过公共DNS服务器进行域名解析或通过DNS转发方式将污染域名交由代理处理。
整体MosDNS的配置文件由以下部分的DNS查询片段组成:
query_lan
query_cn
query_gfw
query_nocn
query_fallback
在处理上通过对
cn
、gfw
和!cn
域名的特定处理,从而避免产生DNS泄露问题。query_lan
query_lan用于处理本地DNS请求,例如局域网内
*.lan
的域名解析以及PTR请求。PTR请求包括反查路由器域名、反查局域网组播域名、UPNP使用的SSDP服务对应域名以及DNS Service Discovery等。MosDNS作为DNS转发器,其本质是进行DNS的转发,并不能直接对DNS请求进行处理。在OpenWRT上,dnsmasq可以对PTR请求做出正确的回应,所以我将query_lan
所使用的dns_lan
配置为主路由(也是OpenWRT)的地址,由主路由的dnsmasq进行上述请求处理。在这里并不一定严格要求使用主路由使用OpenWRT系统,正常的路由器基本都可以对此进行回应。代码片段:
主配置文件:
在
query_lan
中,增加了cache_lan
的执行选项,因为本地的DNS请求也是有DNS缓存的,通过缓存可以节省一点点时间和主路由的处理压力。dns.yaml配置文件:
query_cn
query_cn
是用于对已经通过Geosite和Geoip识别到为国内网站的域名,以及配置白名单的域名进行直接解析。代码片段:
主配置文件:
首先通过
ecs_cn
为DNS请求附加上ecs信息,ecs相关配置在下面的dat_exec.yaml
文件中。请求所携带的IP地址可以填写你所在地运营商dns的地址,使DNS解析结果的IP地址在物理上更接近你所在的IP地址,降低访问延迟。个人不建议填写自己的公网IP地址,尽管使用的是阿里巴巴和腾讯的公共DNS服务,但依旧存在根据IP地址追踪的可能。同时,在通过阿里和腾讯的公共DNS服务进行请求时,如果发现响应返回的是非大陆地区的IP地址,会将该请求丢弃,视为解析错误,并将该DNS请求加入到
query_nocn
队列进行处理。这样处理的意义在于,解析结果返回非大陆地区IP地址的一种可能为ecs没有生效,公共DNS服务器认为我们在其他的国家,另一种可能为该网站进行了服务器迁移,迁移到了国外的云服务提供商。不管是哪种结果,对于我们来说,返回的结果都不是最优的结果,无法提供足够快的访问速度,所以不如交由query_nocn
去请求一个更精确的地址。在国内(cn)的公共DNS服务器选择上,我选择了阿里巴巴的公共DNS服务和DNSPOD(腾讯)的DNS服务,我没有选择运营商的DNS服务,因为运营商的DNS服务无法提供DOH或DOT。同时在使用H3、Quic以及Pipeline的基础上,同时使用ECS,解析的结果已经足够精确,速度也足够的快,没必要为了更快一点点而选择不安全的公共DNS服务。阿里DNS作为主DNS,同时DNSPOD作为备用DNS,开启副可执行插件始终待命。
dns.yaml配置文件:
在国内(cn)的公共DNS配置上,只使用DOH和DOT,同时阿里DNS的DOH开启H3,DNSPOD目前还不支持H3;两家DNS的DOT均开启pipeline;不使用Quic DNS,晚高峰时运营商对Quic的Qos太严重。并发请求数量上维持原版的最大数量为3,从并发请求结果中选择返回最快的结果,加快DNS解析速度。
dat_exec.yaml:
query_gfw
query_gfw
用于直接对已经确认污染域名进行DNS转发,将DNS解析请求通过上级代理进行远端解析。端口7874
为OpenClash所使用的dns监听端口,可根据自己所使用的程序进行修改。 代码片段:
主配置文件:
dns.yaml配置文件:
query_nocn
query_nocn
是用于对不处于GFW List中的国外域名进行解析请求的部分。由于geosite:gfw
是geosite_geolocation-!cn
的子集,所以query_nocn
在主序列中位于query_gfw的下一层级,这样配置的原因在于对于已经确认被污染的域名,没有必要通过公共DNS再继续进行解析,直接交由forward_remote
的代理直接进行解析速度更快,稳定性也更好一些,同时避免产生国内运营商的反诈劫持行为。代码片段:
主配置文件:
对国外域名所附加的ECS IP地址,我通常会选择我所使用代理服务器出口附近的IP地址,这和我家里整体的网络设计有关,对于非大陆的IP地址,在没有特殊的设置情况下,均会通过代理访问,所以配置出口附近的IP地址是最好的选择,这样所解析的地址更靠近出口位置,从而获得更好的访问速度。你可以通过ipify或者其他IP地址查询网站查看自己的出口IP地址。
同时如果通过使用国外公共DNS服务器进行解析请求的结果返回的如果是大陆的IP地址,进行
drop
(丢弃)处理。这种情况一般表示这个域名已经被污染,即便使用请求返回的IP地址,也无法正常访问。对于部分省市的劫持反诈,也可以将反诈网站所解析的IP地址进行drop
,重新使用fallback
进行查询。由于Cloudflare和Google提供的公共DNS服务在国内的延迟较高,或者无法正常使用,所以我选择了AdGuard DNS和NextDNS的dns服务,相比其他的国外无污染公共dns服务,在我这里ping下来延迟较低,且稳定性较好。你也可以根据你自己的网络情况选择自己适用的国外DNS服务。关于国外DNS服务器的选择,可以参考《国内外DNS推荐列表》这篇文章。
dns.yaml配置文件:
NextDNS在注册时候可以使用h3,同时会分配一个属于自己的dns地址,每个月的配额在300,000请求,家庭使用的话,基本上用不完。Quad9目前不支持h3,两者都支持pipeline。
在这里我配置的并发请求数(
concurrent
)为2,牺牲一些速度的同时,避免产生过多的upstream error
错误。dat_exec.yaml:
query_fallback
query_fallback
用于对不满足上述已经执行规则的解析请求进行再次请求,默认使用dns_cn
进行解析。如果担心产生DNS泄露,
fallback
也可以使用国外DNS。代码片段:
主配置文件:
DNS缓存
DNS缓存分为
lan
缓存(局域网域名)和wan
缓存(公网域名),未开启乐观缓存,因为在下游我配置了AdGuard Home会开启乐观缓存。代码片段:
dat_exec.yaml:
其他
关于pipelines
enable_pipeline
: TCP/DoT 使用RFC 7766新的query pipelining
连接复用模式。
- 启用后可大幅提高连接利用率,减少建立连接/握手的次数,进而降低响应延时。
- 并非所有服务器都支持。必须确定服务器支持后再启用该选项。
- Tips: 已知Google和Cloudflare的TCP/DoT是支持该模式的。知名的公共DNS服务商大多数都支持该模式。可以使用
mosdns probe pipeline {tcp|tls}://server_ip[:port]
测试命令测试服务器是否支持。比如mosdns probe pipeline tls://8.8.8.8
。
关于dial_addr
dial_addr
: IP协议层面建立连接时使用的地址。如果host
是域名,此处填入IP可免去每次建立连接时解析服务器域名。支持指定端口号。
目前MosDNS的bootstrap指定功能还处于实验性阶段,dial_addr相当于直接为DOH/DOT的dns服务器指定IP地址,省去解析的步骤。对于使用Cloudflare的DNS,也可以通过优选IP的方式进行筛选,从而选择最快的DNS接入点。
关于IPv6
国内DNS分流和远端解析默认使用IPv4/IPv6双栈模式,
no_cn
和fallback
会使用优先IPv4规则,可根据自己需要将exec: prefer_ipv4
选项删除。同时IPv4的公共DNS服务基本都支持IPv6解析,可不用单独再进行配置。ECS暂时不支持填充IPv6地址,同时为了避免隐私泄露,以及目前大部分用户都不太习惯为IPv6配置防火墙,所以尽量不要泄露,保护好自己的IPv6地址。
如果你的网络没有IPv6,可将
dns.yaml
中含有IPv6地址的行删掉,避免使用IPv6地址的公共DNS服务器进行解析,也从根本上杜绝这种请求。当前维持不动也不会发生什么,只是在日志中会产生Warning
。关于队列执行
如果经过上述队列执行过后依旧没有可用的DNS解析结果会发生什么?
会报错。
关于http3(H3)
为什么http3的DOH更快?
因为http3在大多数情况下,客户端和服务器之间的通信可以在第一次数据包传输时开始,不需要像TCP那样经过多次握手过程。
具体可以参见《什么是HTTP/3》这篇文章。
📎 参考文章
有关DNS的问题,欢迎您在底部评论区留言,一起交流~