18 KiB
内网 DNS 架构调研与优化建议
状态:2026-08-12 调研定稿,Linear W1N-56。Phase 0 验证(2026-08-12)全部完成,最终裁决(用户定稿)已对齐;本期未改动任何生产 DNS 路径。 2026-08-12 现场核查修正:gfw 上 mosdns 不是闲置——它是 OpenClash clash 的
nameserver/default-nameserver(DIRECT 规则真实 IP 解析),处于活动链路,裁决第 5 条 的"删除闲置 mosdns"前提不成立,处置改为"正式纳管并文档化"。 相关:docs/lan-overview.md、hosts/dns.windy.lan.md、hosts/gfw.windy.lan.md、W1N-40。 2026-08-13 (W1N-62):gfw mosdns 国外分支已从"明文国内公网 DNS"改为加密 DoH (自建https://adg.chans.xyz/dns-query,hk2),新增foreign_upstream/foreign_fallback(primary=DoH, secondary=明文国内 DNS, threshold 1000ms),bootstrap用现有国内公网 IP (防自举循环)。实测:mosdns 平面国外域名 A/AAAA 恢复(google AAAA2607:f8b0…)、dup.baidustatic.com→0.0.0.0(AGH 拦截保留)、clash 7874 fake-ip 平面不变。 重要修正(定稿):DoH 流量实测为 gfw→hk2 直连,未经 clash 代理——nft output 链 (mangle mark/tcp redirect)计数为 0、/proc/net/tcp存在到 hk2:443 的 established 连接,路由自身 TCP 输出当前并未被 OpenClash 重定向,故"经代理访问加密 DNS"的假设不成立。 最终决策:接受直连,不强行走代理——foreign_upstream以自建解析器adg.chans.xyz(hk2)为主力,自有 VPS 直连即可达、无被墙/污染问题、DoH/TLS 已加密、应答干净, 走代理毫无增益反而把 DNS 平面耦合进 clash;实测 kill clash 期间国外查询 0.01s 正常应答, watchdog 自动拉起,直连使 DNS 平面独立于代理(优于过代理)。 多上游冗余(同日):concurrent: 3,新增https://dns.quad9.net/dns-query与https://dns.cloudflare.com/dns-query(2026-08-13 本网络实测可达;dns.quad101.netTLS 握手失败已排除)——hk2 故障时仍由干净的国外 DoH 应答,最后才退化明文国内兜底。 验证:google AAAA 由 hk2 的2607:f8b0…变为新上游的2404:6800…,国内外/拦截/代理平面无回归。 备份:config.yaml.bak-foreign-doh-20260813-103746/config.yaml.bak-foreign-doh-20260813-103813/config.yaml.bak-multi-doh-20260813-105421。
1. 现状(实测 2026-08-12)
| 角色 | 部署 | 职责 | 是否在活动路径 |
|---|---|---|---|
| AdGuard Home | 192.168.66.36(PVE VM 120,Docker host 网络) |
EdgeRouter DHCP 通告给 LAN55/66 客户端的唯一 DNS;广告/过滤、查询统计、Web 面板 | ✅ 是(LAN 客户端唯一入口) |
| mosdns | 192.168.66.1(gfw OpenWrt)监听 127.0.0.1:6052(仅本机) |
clash 的 nameserver/default-nameserver:DIRECT 规则真实 IP 分流(国内 → AGH .36:53,国外 → 223.5.5.5/119.29.29.29) |
✅ 网关侧(clash 消费,不面向客户端) |
| OpenClash / clash(meta) | 192.168.66.1(gfw) |
gateway 自身/被劫持流量的 fake-ip + 代理;DNS 走 dnsmasq→clash #7874 |
仅网关侧与 VLAN10 |
关键事实(全部实测):
- LAN 客户端 DNS 直连
66.36,不经过 gfw(EdgeRouterservice dns forwardingcache 512,通告.36)。 - AGH 上游:DoH
dns.alidns.com(→223.5.5.5/223.6.6.6)+doh.pub(→120.53.53.53/1.12.12.12),upstream_mode: load_balance、fastest_timeout: 1s、upstream_timeout: 10s;bootstrap223.5.5.5/223.6.6.6(公网 IP,无自举循环);兜底 DoHadg.chans.xyz(→hk2.chans.xyz→154.36.174.161)。 DNS 监听 UDP/TCP v4 only(0.0.0.0:53),无 v6 监听;enable_dnssec: false;cache 4 MB;ratelimit 20。 - AGH 宿主出网:默认路由
via 192.168.66.254(EdgeRouter),直连,不经 gfw;DoH 实测可达 (223.5.5.5:443 → HTTP 400/0.05s,120.53.53.53 → 502/0.06s,adg.chans.xyz 冷连接 ~3.5s)。 - gfw 自身出网:OpenClash
openclash_mangle_output对非本地区域/国内 IP 流量统一mark 0x162 → tproxy 127.0.0.1:7895(gfw 自身流量默认走代理,含 clash 的 nameserver-policy DoH);mosdns 的上游(AGH.36本地区域、223.5.5.5国内 IP)均被 bypass,保持直连。 - gfw DNS 链:
server=127.0.0.1#7874(dnsmasq)→ clash:nameserver: [127.0.0.1:6052](mosdns)、default-nameserver: [127.0.0.1:6052]、nameserver-policy国外域名 → DoHhttps://1.1.1.1/dns-query、enhanced-mode: fake-ip(198.18.0.1/16)、ipv6: false;nft 有 UDP/53 hijack → dnsmasq。 - mosdns 配置缺陷(2026-08-12 发现并修复):
mainsequence 的国内分支 (matches: qname $domestic_domains → exec: $domestic_upstream)之后缺少matches: has_resp → accept守卫。mosdns v5 的sequence在forward成功后不会停止, 只有accept/reject/return或错误会终止——因此命中geosite_cn的查询会被转发两次 (AGH 与 223.5.5.5/119.29.29.29),最终应答来自最后一个 forward(国内公网 DNS),AGH 的 拦截/rewrite 对 DIRECT 国内域名静默失效。实测证据:dup.baidustatic.com(在geosite_cn且在 AGH 拦截表)经 mosdns 返回真实 IP183.60.227.49而非0.0.0.0。已修复(备份/etc/mosdns/config.yaml.bak-20260812),修复后同一域名返回0.0.0.0,taobao/google 解析 与 clash 链均无回归。§6 的二期示例同款缺陷已一并修正。 同日追加加固:domestic_fallback(fallback 插件:primary: domestic_upstream(AGH)、secondary: default_upstream(223.5.5.5/119.29.29.29)、threshold: 500ms)使 AGH 宕机时 DIRECT 国内真实 IP 查询回退国内公网 DNS,不再直接报错;实测:AGH 停止时缓存未命中查询由 fallback 应答(NXDOMAIN/真实 IP),AGH 恢复后主路径即时应答且拦截(0.0.0.0)恢复。 备份:/etc/mosdns/config.yaml.bak-fallback-20260812。 - AGH rewrites(实测):
hass.windy.lan/hass.local→192.168.55.11;dns.windy.lan→.36;ubnt.windy.lan→.46;gfw.windy.lan→.1;nas.windy.local→.32。 - 拦截:仅启用 AdGuard DNS filter(filter_1);实测
doubleclick.net/googleadservices.com→0.0.0.0。
现状缺口(实测确认):
- AGH 上游是固定 DoH,无"国内/国外分流"能力;国外域名解析质量依赖唯一兜底路径。
- 兜底失效(kill-test 证实):主上游黑洞时,兜底
adg.chans.xyz在客户端 15s 窗口内不生效 (upstream_timeout: 10s+ TCP 重试行为),缓存未命中查询无有界降级——见 §8。 - 国外域名 AAAA 经国内路径全部置空(见 §8),v6 解析缺位。
2. 最终裁决对齐(用户定稿 2026-08-12)
| # | 裁决 | 本issue处理 |
|---|---|---|
| 1 | 保留 AGH .36 为唯一 LAN DNS 入口(现有方案增强版),不改 EdgeRouter DHCP 通告 |
✅ 现状保持;本期零改动 |
| 2 | 否决"AGH 全局转发到 Clash fake-IP"——DNS 平面必须与流量转发平面一致 | ✅ 分层方案(§4)明确 AGH 上游为真实 IP 解析路径,不与 fake-ip 混用 |
| 3 | AGH → mosdns 仅为二期可选项(经实测确有需求后启用) | ✅ §4 为二期方案;§8 kill-test 已给出"实测需求"证据(降级缺口) |
| 4 | 代理 VLAN10 将来用独立 OpenClash DNS 平面(fake-ip + TPROXY),不污染普通 LAN | ✅ 现状即此(dnsmasq→clash,非面向 LAN 客户端);文档记录 |
| 5 | 删除或明确禁用 .1 上未使用的 mosdns |
⚠️ 前提修正:mosdns 是 clash 的 nameserver,处于活动链路(§1)。处置改为正式纳管并文档化(本文件 + hosts/gfw.windy.lan.md),不删除 |
| 6 | 先完成验证再改动生产路径 | ✅ 本期完成全部 Phase 0 验证(§8),未改任何生产 DNS 路径 |
| 7 | 建立 home.arpa 内部域(替代 .local) |
⏳ 后续任务:当前命名空间为 .lan(AGH rewrites + EdgeRouter DHCP domain),hass.local 兼容保留至迁移完成;home.arpa 需联动 AGH rewrites、DHCP domain、客户端,另行排期 |
| 8 | 高可用时增加第二个等价 AGH(独立物理故障域) | ⏳ 备用方案,记录不实施 |
3. 两个候选方案评估
方案 A:AGH 单独作为统一入口(现状演进)
- 优点:单解析点、面板/拦截/日志集中、维护简单。
- 缺点:AGH 对 geo 分流 + 防污染支持弱(官方定位是"过滤/家长控制")。固定 DoH 上游无法按域名 region 选路;且 §8 kill-test 显示主上游全挂时缓存未命中查询无有界降级。→ 不足以解决防污染/分流/降级问题。
方案 B:mosdns 作为智能上游分流器
mosdns(v5)用 sequence 编排:geosite/geoip 匹配器 → 国内域名转发国内 DoH、国外域名转发加密 DoH(防污染),可加 cache、reject。
- 优点:真正解决"国内快 / 国外不被污染"的分流;性能高。
- 缺点:纯转发器,无 Web 面板、无每客户端统计、拦截靠域名表。→ 单独当入口会退回原始体验。
结论:两个方案互补,不是二选一。 单用 A 无法分流防污染且降级无界;单用 B 失去 AGH 管理体验。
4. 二期可选项:分层架构(AGH 前端 + mosdns 后端,经实测需求后启用)
局域网客户端(DHCP DNS = 192.168.66.36)
│
▼
AdGuard Home (66.36) ── 前端:广告/过滤、拦截表、每客户端统计、Web 面板
│ 上游 = mosdns
▼
mosdns(66.36 伴生容器) ── 后端:智能分流 + 防污染
│ - geosite:cn → 国内 DoH/UDP(aliDNS / 腾讯 DNSPod)
│ - 其他 → 加密 DoH(自建 adg.chans.xyz 等)
▼
上游 DoH
职责分离:
- AGH = 策略/拦截/可观测(拦截表、每客户端日志、面板)。
- mosdns = 智能转发(geo 分流 + 加密防污染 + 内置 cache,可显著缩短降级窗口)。
- OpenClash(gfw)= 代理选路(fake-ip + 规则)。与 DNS 解析选上游是两个独立决策,分开放最干净。
部署位置:mosdns 与 AGH 同机(66.36 伴生容器),而非 gfw(.1):单点即 AGH 所在;不受网关重启/ OpenClash churn 影响;可纳入现有 compose/ansible 管理;不占用 OpenWrt 资源。放 gfw 会与 clash 的 DNS 处理互相干扰、耦合,且网关重启即断全 LAN DNS。不推荐放 .1。
启用条件(kill-test 实测需求,§8):主上游全挂时,当前 AGH 单入口对缓存未命中查询无有界降级。 分层方案(或下调
upstream_timeout+ 改 failover 模式)可修;启用与否由用户在二期决定。
5. 更优替代方案(一并考虑)
- 分层(推荐二期,见 §4):AGH(66.36)→ mosdns(66.36 伴生)→ 上游。体验最好、职责最清。
- 纯 mosdns + 前端面板:损失拦截/统计管理体验。不推荐用于替换。
- AGH 只挂一个带分流的上游(第三方 DoH 聚合):失去可控性且不可信。不推荐做主路径。
- 全部交给 OpenClash fake-ip,关闭 AGH:让"代理网关"成为全 LAN DNS 单点;且 AGH 拦截/日志也没了。不推荐。
6. mosdns 配置要点(mosdns v5,二期实施预留)
核心是 sequence + 上游拆分 + 缓存 + 屏蔽:
plugins:
- tag: main
type: sequence
args:
- exec: cache 1024 # 缓存加速
- matches: has_resp
exec: accept
# 国内分流:命中 geosite:cn → 国内 DoH
- matches: [ qname &geosite:cn ]
exec: forward https://dns.alidns.com/dns-query
# 广告域名屏蔽交 AGH 前置,不重复维护
# 其余(国外)→ 加密 DoH 防污染
- exec: forward https://adg.chans.xyz/dns-query
- type: udp_server
args: { entry: main, listen: "127.0.0.1:5353" }
- type: tcp_server
args: { entry: main, listen: "127.0.0.1:5353" }
注意:
sequence中每个forward分支之后必须跟matches: has_resp → accept(或改用goto/jump+return结构),否则查询会继续执行后续规则被二次转发, 最终应答来自最后一个 forward——gfw 上 mosdns 的同类缺陷(2026-08-12)已实测并修复(见 §1)。
要点:
- 上游可加
upstream的concurrent > 1与多地址故障切换;mosdns 自带 cache,能保证上游故障时 缓存命中仍即时应答(对应 §8 认定的降级缺口)。 geosite:cn/geoip:cn数据自动更新;国内 aliDNS/腾讯,国外可用自建adg.chans.xyz(实测 唯一能返回国外 AAAA 的路径,§8)。- 屏蔽交 AGH 前置,AGH 与 mosdns 不各自维护拦截表。
7. 迁移 / 实施顺序(二期,待用户确认启用)
- 在 66.36 起 mosdns 伴生容器(
/opt/mosdns+ compose,按 digest 固定镜像,纳入 ansible)。 - AGH「上游 DNS 服务器」改为指向 mosdns(
127.0.0.1:5353,bootstrap 仍用公网 IP,避免 AGH → mosdns → AGH 死循环);只保留一条语义一致的上游路径,保持可回滚(备份 yaml +--check-config)。 - 验证:国内域名、国外域名、被拦截域名、每客户端日志、AAA A 解析(§8 基线)。
- 回归:EdgeRouter 通告不变(仍
.36),LAN 客户端无感;重启 AGH/mosdns 单点验证(§8 kill-test 模板)。 - 上线后重跑 §8 kill-test,确认降级窗口有界。
8. Phase 0 验证证据(2026-08-12 全部实测)
8.1 基线与功能
| 项 | 结果 |
|---|---|
rewrites:hass.windy.lan / hass.local |
→ 192.168.55.11 ✅(兼容保留) |
rewrites:dns.windy.lan / gfw.windy.lan / ubnt.windy.lan / nas.windy.local |
→ .36 / .1 / .46 / .32 ✅ |
国内解析 taobao.com(经 AGH) |
真实 CN IP(59.82.x 等)✅ |
国外解析 google.com / github.com(经 AGH) |
真实 IP(142.250.x / 20.205.x),无 fake-IP 泄漏 ✅ |
广告拦截 doubleclick.net / googleadservices.com |
→ 0.0.0.0 ✅ |
clash 7874 google.com |
198.18.1.101(fake-ip,仅网关/VLAN10 平面)✅ |
clash 7874 taobao.com |
真实 IP(经 mosdns→AGH)✅ |
dnsmasq :53(.1)google.com / taobao.com |
fake-ip / 真实 IP ✅ |
mosdns 6052 直连 taobao.com / google.com |
真实 IP(59.82.x / 142.250.73.78)✅ |
DNSSEC:dnssec-failed.org(经 AGH) |
返回正常应答 96.99.227.255(非 SERVFAIL)→ 当前路径不校验,W1N-40 结论复现,维持关闭 |
8.2 出口路径与 fake-IP 泄漏
- AGH 宿主默认路由
via 192.168.66.254(EdgeRouter),直连出网,不经 gfw;DoH 端点实测可达 (见 §1)。LAN 客户端经 AGH 的解析结果全部为真实 IP,无198.18/16泄漏。 - gfw 自身流量默认进代理(
openclash_mangle_outputmark 0x162 → tproxy :7895), clash nameserver-policy 的1.1.1.1DoH 实测 35ms 可达(走代理链路,不依赖直连)。 - mosdns 上游(AGH
.36、223.5.5.5)命中本地/国内 bypass 规则,保持直连——设计意图达成。
8.3 IPv6 / RDNSS / AAAA
- LAN 有 IPv6 SLAAC(EdgeRouter dhcpv6-pd /60 → eth0 host-address + switch0,仅
service slaac, 无 RDNSS/dns-server 通告);.36有全局 v6 地址 + RA 默认路由。 - RDNSS 未通告 → v6 客户端无 v6 DNS,回退 v4 DNS(
.36);AGH 仅监听0.0.0.0:53(v4 only),无 v6 DNS 服务。 - AAAA 解析实测:
baidu.com公网本就无 AAAA(dns.google NOERROR/0,权威 NS 而已);taobao.comAAAA 经国内路径正常(2408:4001:f10::6f等);国外域名(google.com)经223.5.5.5UDP、alidns DoH、8.8.8.8UDP 全部返回空,而 dns.google 与adg.chans.xyzDoH 均能返回2404:6800:4005:81a::200e→ 国内路径对国外域 AAAA 置空;adg.chans.xyz兜底是当前唯一能返回国外 AAAA 的路径。clashipv6: false亦不返回 AAAA。
8.4 自举(bootstrap)循环
- AGH
bootstrap_dns: [223.5.5.5, 223.6.6.6](公网 IP,非 AGH 自身)→ 无自举循环;AGH 解析 DoH 主机名不经过自身。二期方案要求 AGH→mosdns 时 bootstrap 仍用公网 IP(§7)。
8.5 Kill-test 矩阵(2026-08-12,全部实测)
| # | 场景 | 结果 |
|---|---|---|
| 1 | 重启 .1 mosdns(init.d) |
✅ 直连 6052 与 clash 链恢复 |
| 2 | 重启 .1 dnsmasq |
✅ 真实 IP 与 fake-ip 双路径恢复 |
| 3 | kill .1 clash 核心 |
✅ LAN DNS(AGH)不受影响;gfw dnsmasq→clash 有界 3s 失败(无卡死);OpenClash watchdog ~15s 自动拉起 |
| 4 | stop/start .1 OpenClash |
✅ DNS 平面独立于代理;clash 与 tproxy 规则恢复 |
| 5 | 重启 .36 AGH 容器 |
✅ 全量恢复:rewrites/拦截/国内外解析/DNSSEC 行为不变 |
| 6 | 黑洞 alidns DoH(223.5.5.5/223.6.6.6:443) | ✅ ~0.5s 内经 doh.pub 应答(load_balance 生效) |
| 7 | 黑洞全部主上游,兜底存活(adg.chans.xyz) | ⚠️ 客户端 15s 内无应答——兜底未在窗口内生效 |
| 8 | 黑洞全部上游(含兜底),缓存未命中 | ⚠️ 25s 内无应答、无 SERVFAIL——解析器对缓存未命中查询"卡死" |
| 9 | 黑洞全部上游,缓存命中 | ✅ 瞬时 NOERROR(cache 兜底) |
结论(Phase 0 门禁): 国内解析在代理停止/上游单点故障/组件重启下均维持可用;
但**"主上游全挂"时缓存未命中查询无有界降级**——upstream_timeout: 10s 与 TCP 重试行为使
兜底 adg.chans.xyz 在实践中无法在客户端期望窗口内生效。这是 §4 二期分层方案(或下调
upstream_timeout + failover 模式)的实测需求依据;按最终裁决,本期不改生产路径。
9. 风险与备注
- mosdns 仅监听
127.0.0.1(不对外),由 clash 消费;二期若启用,保持同样的边界,避免 LAN 出现两套入口。 - AGH 上游指向本机 mosdns 时务必配公网 bootstrap,否则自举死循环。
- 本方案不改 EdgeRouter DHCP/通告、不改 gfw OpenClash 代理规则,只动 66.36 上的 DNS 链路,风险可控。
- 已知降级缺口(§8.5 #7/#8):主上游全挂时缓存未命中查询无有界降级;启用二期前,LAN 客户端会感知 超时(约 10s+)。缓解:AGH cache 已覆盖高频域;根治需二期。
- 与 W1N-40「审查并修正 AdGuard Home」联动:该 issue 侧重 AGH 本身,本 issue 侧重整体 DNS 分层。