mosdns - docker 配置&使用

  • mosdns 配置 & 使用 & docker-compose

  • 资料来源:

    https://github.com/IrineSistiana/mosdns
    https://kb.adguard.com/en/general/dns-providers#cloudflare-dns

  • 更新

    1
    2
    3
    4
    5
    6
    2021.12.23 初始
    2022.03.17 同步更新配置,增加 dockerfile
    2022.07.27 同步 4.x 配置
    2022.10.09 更新一些配置
    2022.10.21 更新测试命令
    2023.09.14 更新一些 v4 配置,v5 尚在观望.

导语

最近终于有时间重新升级基础设施了,先从 DNS 开始.

2022.03.17 mos 腹泻式更新,版本号从 v2.1.2 飙到了 v3.5.2,谢谢开发者,大家有 github 账号记得给开发者点个 start 😂

  • 同步更新配置
  • 增加自编译的 dockerfile

2022.07.27 mosdns 版本号还在飙升…4.x 配置与之前不兼容,因此花点时间重写了部分内容.

2022.10.09 目前最新版本号 v4.4.2,这次本文主要增加了域名文件定期重新加载.

2023.09.14 目前 v5 版本,已经稳定 但 功能上与 v4 相比还是有些欠缺.尤其是 缓存 ecs 结果…

  • 尝试了配置相同功能的 v5 与 v4 尚没有很多差别,暂时停留在 v4 ,直到 v5 有更好的功能.

2023.09.14 今天是更新 v4 自己常用的配置,已经 稳定运行 7 个月了.

前言

现有的 DNS 是 overture 已经稳定运行了超过 1 年半了,但是有几个遗憾

  • 分流的 ip/域名文件更新比较麻烦
  • overture 整个的运行逻辑还是稍微有点不满意,备份线路实现稍显麻烦.

于是找到了 mosdns,简而言之可以把 mosdns 当作是乐高,提供了 dot/doh 等等插件,怎么组合,怎么定义逻辑全看需要.

折腾的结果还算满意.

mosdns 的使用/插件说明等,仓库文档已经写的非常清楚了,再介绍就班门弄斧了.

  • Home
  • Configuration
  • Plugin

如果不需要自定义,也提供了一键上手版本: mosdns-cn

目标

目标

  • 无污染 DNS
  • 全称加密 DOT/DOH/DOQ
  • 国内外分流,按照域名 / ip
  • 多线备份
  • edns 支持 (可选)
  • 延迟尽量低 (可选)

上游 DNS

Known DNS Providers 这似乎是 adguard 提供的已知 dns 服务集合,包括 dot doh 等等,仅供参考.

dns 污染分成两种

  • gfw 的封锁污染,这一点国内的公共 dns 都一样
  • 运营商的 dns 污染,三家都不一样.基本上 dot/doh 就能避免.

因此上游 dns 分成两种,一种是国内 dns 一种是国外 dns 提供无污染 dns.

国内上游: ali DNS + dnspod (腾讯)

  • 全部 dot doh + ecs 保证加密和解析准确
  • 阿里 dns 在我的网络环境中延迟个位数,主力,dnspod 备选,本地 dns 备用.

无污染上游: Cloudflare + Google + AdGuard

  • 似乎各个地区 Cloudflare/Google dot/doh 连接情况都不一样,为了稳定 dot doh ,ipv4 ipv6 我全都要.千万不要在搭建公共 DNS 服务器时这样弄
  • AdGuard 支持 dns over quic ,作为无污染的备用.
  • 国外的能正常返回结果就好了,ecs 对我而言意义不是很大. 主要是常用网站 cdn 覆盖很好,不加 ecs 正好….

分流

之前 overture 的 ip 和 域名来自好几个仓库的组合,好在 mosdns 直接兼容了 v2ray-rules-dat,这就不用再自行组合了.

v2ray-rules-dat 是适配 V2Ray 的规则文件增强版.包含 geoip.dat 和 geosite.dat 两个文件,实在是省了我们很多功夫.

geoip.dat

  • 包含了大量的 ip 类别,最重要的是 cnip 数据替换成了 ipip.net 这个数据源比 MaxMind GeoLite2 的 cnip 更准确,之前 overture-docker 也是用的这个.

geosite.dat

  • 各种的域名分类,这里只关心两种 cncategory-ads-all,cn 是国内域名,ad 是广告域名.
  • 还有更多分类暂时用不上.

流程

overture 的处理流程已经是比较合理了,不过还有小点需要修改,这里就以 overture 流程为模板, 附加 GitHub issue 和 discuss 给出的配置:

  • 预处理
    • qtype65 与无效查询? – 丢弃;
    • qtype12 or qtype255 ? – _no_ecs 走国内上游 ttl_1h, return;
    • 其他则 替换 edns , 进入缓存,缓存未命中则进入下一步.
  • 主流程
    • ad 域名? -> 空应答
    • cn 域名? -> 附加 ecs ->国内上游
      • 返回是国内 ip ? -> 返回结果,结束.
      • 不是国内 ip 继续下一步.
    • 非 cn 域名? -> 无污染上游
      • 返回非国内 ip ? -> 返回结果,结束.
      • 返回国内 ip 继续下一步.
    • 其他所有情况,优先无污染上游结果.

结合 mosdns 其他配置

  • 无论国内/无污染上游,一律 dot doh v4 v6 并发,这会带来带宽的浪费,仅个人使用还好,作为 dns 服务器最好不要这样.
  • 国内上游带上 ecs
  • 双栈优先 ipv4 ipv6 基本够了,因此不再优先 ipv4
  • 填充 & 调整 ttl

配置

官方给了两个 配置模板,这里为文件是在复杂配置基础上调整.

配置在各个方面肯定并非完美,有错误请留言/邮件.

官方也提供了 docker 镜像,这里使用 docker-compose 方便部署.

(2022.03.17) 增加一个自编译 dockerfile 文件,添加 geoip.datgeosite.dat,方便更新.

(2022.07.27) dockerfile 适配 4.x 版本

(2022.10.09) 域名文件重加载,每天 2 点. GitHub 被干扰越来越厉害,定期更新没有意义了.

(2023.09.14) 删减无效配置.

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
FROM irinesistiana/mosdns:v4.5.3
LABEL maintainer="JH"

COPY ./config.yaml /etc/mosdns/config.yaml
COPY ./entrypoint.sh /entrypoint.sh
RUN chmod a+x /entrypoint.sh

RUN set -xe \
&& apk add --no-cache curl \
&& cd / \
&& curl -LJO https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat \
&& curl -LJO https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat \
&& apk del curl

VOLUME /etc/mosdns
EXPOSE 53/udp 53/tcp
# CMD /usr/bin/mosdns start --dir /etc/mosdns

ENTRYPOINT [ "/entrypoint.sh" ]

entrypoint.sh

1
2
3
4
#!/bin/sh
# crond
/usr/sbin/crond -b -l 8
/usr/bin/mosdns start --dir /etc/mosdns

Docker-compose

dockerfile 和 entrypoint.sh 放在 mosdns 文件夹下

1
2
3
4
5
6
7
8
9
10
11
version: '3'

services:
mosdns:
build:
context: ./mosdns
image: mosdns:latest
volumes:
- ./mosdns:/etc/mosdns
restart: always
network_mode: host

config.yaml

如果使用官方 docker image 运行需要用到 v2ray-rules-dat 下载 geoip.dat 和 geosite.dat,挂载到根目录.

2022.03.17 更新

  • 删除一些已经失效配置
  • 因为国内的 dns 查询使用了 edns,因此 cache 启用了 cache_everything,如果不是有大量 edns 查询,简易关闭.
  • 通过脚本获取公网 ip 4.x 已不支持运行 shell 命令.
    • 使用 curl -s https://v4.myip.lacurl -s https://v6.myip.la
    • 如果你有国内的分流,只能手动指定.
  • mosdns 现在有 dot/doh 的 http3 支持,但是在我本地的环境测试效果不佳,因此暂不加入相关配置.还有类似的 UDPME 支持,个人处于观望态度.

(2022.07.27) 适配 4.x 版本配置

  • 启用 doh 的 http3,测试效果不错,请因地制宜修改.
  • 替换一些 forward -> fast_forward
  • 修正一些地址错误.
  • ecs ip 目前只能手动配置
      1. 启动前通过脚本替换配置文件
    • 2. 等待 远程动态数据更新 完成

(2022.10.09) 规则文件的重加载

  • 目前的规则是每天 2 点重新下载规则文件

(2023.09.14) 更新流程.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
log:
level: info
file: ""

# 数据源
data_providers:
- tag: geoip
file: /geoip.dat
auto_reload: true
- tag: geosite
file: /geosite.dat
auto_reload: true

plugins:
################# 可执行插件 ################
# 匹配无效域名的插件
- tag: query_is_non_domain
type: query_matcher
args:
domain:
- "keyword::"

# 匹配TYPE12类型请求的插件
- tag: qtype12
type: query_matcher
args:
qtype: [12]

# 匹配TYPE65类型请求的插件
- tag: qtype65
type: query_matcher
args:
qtype: [65]

# 匹配TYPE255类型请求的插件
- tag: qtype255
type: query_matcher
args:
qtype: [255]

# 匹配RCODE2的插件
- tag: response_server_failed
type: response_matcher
args:
rcode: [2]

- tag: "ecs-cn"
type: "ecs"
args:
auto: false # 仅适用于公网的服务器。本地运行不要启用这个功能。
ipv4: "202.120.35.132"
ipv6: "2001:da8:8000:1:202:120:2:101"
force_overwrite: true # 强制覆盖
mask4: 24 # 用于 ipv4 地址的掩码 默认: 24。
mask6: 48 # 用于 ipv6 地址的掩码 默认: 48。

- tag: cache
type: cache
args:
size: 8192
#redis: "redis://127.0.0.1:6379/0"
lazy_cache_ttl: 86400
cache_everything: true
lazy_cache_reply_ttl: 1

# 调整TTL的插件
# [1m|5m|1h]
- tag: ttl_1m
type: ttl
args:
minimal_ttl: 60
maximum_ttl: 3600
- tag: ttl_5m
type: ttl
args:
minimal_ttl: 300
maximum_ttl: 86400
- tag: ttl_1h
type: ttl
args:
minimal_ttl: 3600
maximum_ttl: 86400

################ DNS #################
# 阿里 dns
- tag: ali
type: forward
args:
upstream:
- addr: "https://dns.alidns.com/dns-query" # 服务器地址
ip_addr: # 手动指定服务器的 IP 地址 可以配置多个
- "2400:3200:baba::1"
- "223.5.5.5"
- "2400:3200::1"
- "223.6.6.6"
trusted: true # 是否是可信服务器
- addr: "tls://dns.alidns.com" # 服务器地址
ip_addr: # 手动指定服务器的 IP 地址 可以配置多个
- "2400:3200:baba::1"
- "223.5.5.5"
- "2400:3200::1"
- "223.6.6.6"
trusted: true # 是否是可信服务器

bootstrap:
- "tls://1.1.1.1"
- "https://223.5.5.5/dns-query"
timeout: 5 # 请求超时时间秒

# dnspod
- tag: dnspod
type: forward
args:
upstream:
- addr: "https://doh.pub/dns-query" # 服务器地址
ip_addr: # 手动指定服务器的 IP 地址 可以配置多个
- "2402:4e00::"
- "119.29.29.29"
trusted: true # 是否是可信服务器
- addr: "tls://dot.pub" # 服务器地址
ip_addr: # 手动指定服务器的 IP 地址 可以配置多个
- "2402:4e00::"
- "119.29.29.29"
trusted: true # 是否是可信服务器

bootstrap:
- "tls://1.1.1.1"
- "https://223.5.5.5/dns-query"
timeout: 5 # 请求超时时间秒

# google doh dot h3
- tag: google
type: fast_forward
args:
upstream:
- addr: "https://dns.google/dns-query"
dial_addr: "2001:4860:4860::6464"
trusted: true
enable_pipeline: true
- addr: "https://dns.google/dns-query"
dial_addr: "2001:4860:4860::0064"
trusted: true
enable_pipeline: true
- addr: "https://dns.google/dns-query"
dial_addr: "2001:4860:4860::8844"
trusted: true
enable_pipeline: true
- addr: "https://dns.google/dns-query"
dial_addr: "2001:4860:4860::8888"
trusted: true
enable_pipeline: true
- addr: "https://dns.google/dns-query"
dial_addr: "8.8.4.4"
trusted: true
enable_pipeline: true
- addr: "https://dns.google/dns-query"
dial_addr: "8.8.8.8"
trusted: true
enable_pipeline: true

- addr: "tls://dns.google"
dial_addr: "8.8.4.4"
trusted: true
enable_pipeline: true
- addr: "tls://dns.google"
dial_addr: "2001:4860:4860::8888"
trusted: true
enable_pipeline: true
- addr: "tls://dns.google"
dial_addr: "8.8.8.8"
trusted: true
enable_pipeline: true
# h3
- addr: "https://dns.google/dns-query"
dial_addr: "2001:4860:4860::8844"
trusted: true
enable_http3: true
- addr: "https://dns.google/dns-query"
dial_addr: "8.8.4.4"
trusted: true
enable_http3: true
- addr: "https://dns.google/dns-query"
dial_addr: "2001:4860:4860::8888"
trusted: true
enable_http3: true
- addr: "https://dns.google/dns-query"
dial_addr: "8.8.8.8"
trusted: true
enable_http3: true

# cloudflare doh dot h3
- tag: cloudflare
type: fast_forward
args:
upstream:
- addr: "https://cloudflare-dns.com/dns-query"
dial_addr: "2606:4700:4700::1001"
trusted: true
enable_pipeline: true
- addr: "https://cloudflare-dns.com/dns-query"
dial_addr: "1.0.0.1"
trusted: true
enable_pipeline: true
- addr: "https://cloudflare-dns.com/dns-query"
dial_addr: "2606:4700:4700::1111"
trusted: true
enable_pipeline: true
- addr: "https://cloudflare-dns.com/dns-query"
dial_addr: "1.0.0.1"
trusted: true
enable_pipeline: true

- addr: "tls://1dot1dot1dot1.cloudflare-dns.com"
dial_addr: "2606:4700:4700::1001"
trusted: true
enable_pipeline: true
- addr: "tls://1dot1dot1dot1.cloudflare-dns.com"
dial_addr: "1.0.0.1"
trusted: true
enable_pipeline: true
- addr: "tls://1dot1dot1dot1.cloudflare-dns.com"
dial_addr: "2606:4700:4700::1111"
trusted: true
enable_pipeline: true
- addr: "tls://1dot1dot1dot1.cloudflare-dns.com"
dial_addr: "1.0.0.1"
trusted: true
enable_pipeline: true
- addr: "https://cloudflare-dns.com/dns-query"
dial_addr: "2606:4700:4700::1001"
trusted: true
enable_http3: true
- addr: "https://cloudflare-dns.com/dns-query"
dial_addr: "1.0.0.1"
trusted: true
enable_http3: true
- addr: "https://cloudflare-dns.com/dns-query"
dial_addr: "2606:4700:4700::1111"
trusted: true
enable_http3: true
- addr: "https://cloudflare-dns.com/dns-query"
dial_addr: "1.1.1.1"
trusted: true
enable_http3: true

# doq 备用
- tag: adguard
type: forward
args:
upstream:
- addr: "quic://dns-unfiltered.adguard.com" # 服务器地址
ip_addr: # 手动指定服务器的 IP 地址 可以配置多个
- "2a10:50c0::1:ff"
- "94.140.14.140"
- "2a10:50c0::2:ff"
- "94.140.14.141"
trusted: true # 是否是可信服务器

################ 匹配器 #################

# 查询 - cn 域名
- tag: query_cn
type: query_matcher
args:
domain:
- "provider:geosite:cn"

# 查询 - 非 cn 域名
- tag: query_notcn
type: query_matcher
args:
domain:
- "provider:geosite:geolocation-!cn"

# 查询 - ad
- tag: query_ad
type: query_matcher
args:
domain:
- "provider:geosite:category-ads-all"

# 返回 - cn IP
- tag: response_cnip
type: response_matcher
args:
ip:
- "provider:geoip:cn"

################ 序列 #################

# dns-cn 序列
- tag: dns-cn
type: sequence
args:
exec:
- primary:
- "ali" # 执行序列
secondary:
- dnspod # 备用本地
fast_fallback: 2500 # 这里建议设置成 primary 服务器正常延时的 2~5 倍 单位: 毫秒。
always_standby: true

# remote 序列
- tag: dns-ncn
type: sequence
args:
exec:
- primary:
- cloudflare
secondary:
- google # 备用 adguard
fast_fallback: 2500 # 这里建议设置成 primary 服务器正常延时的 2~5 倍 单位: 毫秒。
always_standby: true

# pre_sequence
- tag: pre_sequence
type: sequence
args:
exec:
# 屏蔽TYPE65与无效类型请求
- if: "[qtype65] || (query_is_non_domain)"
exec:
- _new_nxdomain_response
- _return

# 优化PRT与ANY类型请求
- if: "[qtype12] || [qtype255]"
exec:
- _no_ecs
- dns-cn
- ttl_1h
- _return
- _no_ecs
- cache

# main_sequence
- tag: main_sequence
type: sequence
args:
exec:
- if: query_ad # ad
exec:
- _new_nxdomain_response # 空应答
- _return

- if: "query_cn" # cn域名
exec:
- ecs-cn # ecs china
- _pad_query
- dns-cn # 用 cn 服务器
- if: "response_cnip" # 结果是 cnip
exec:
- ttl_1m
- _return # 结束

- if: query_notcn # 已知的 非cn域名
exec:
# - _prefer_ipv4 # 优先 IPv4
- _pad_query
- ecs-cn
- dns-ncn # 无污染
- if: "!response_cnip" # 结果是 非cnip
exec:
- ttl_5m
- _return # 结束


#其他所有情况
- _no_ecs # noecs
# - _prefer_ipv4
- _pad_query
- dns-ncn
- ttl_5m

- tag: sequence
type: sequence
args:
exec:
- _misc_optm
- pre_sequence # 预处理
- main_sequence # 主执行序列

servers:
- exec: sequence
listeners:
- protocol: udp
addr: ":53"
- protocol: tcp
addr: ":53"

测试

q 是目前找到的支持 UDP TCP DoT DoH DoQ 且支持 EDNS 的 DNS 客户端

  • kdig dog doggo 似乎都有个别协议不支持
1
q --subnet=202.120.35.133 +stats A www.bilibili.com  @tls://dot.pub

尾巴

mosdns 算是跑起来能用了,看仓库的 issue 似乎是 ecs 的结果无法进入缓存..好在国内上游延迟基本上都是个位数,没有缓存也没关系.

之后就轮到 openwrt 了,需要彻底重构现在的局域网了.

(23.09.14) 有一天或许无污染 DNS 也会终结吧, 是时候进入更深的层次了.