DNS 越叠越乱?我用 OxiDNS 把匹配、转发、回退写进了同一条管线

家里的 DNS 这件事,从一开始只用路由器自带的 dnsmasq,到后来挂上 AdGuard Home 加一层过滤,再后来装 SmartDNS 区分国内外解析,每多一层就多一堆配置、多个面板、几套规则。它们之间怎么协作、谁先谁后、哪条规则先匹配,只能靠手写顺序和注释撑着。

直到最近看到 OxiDNS 这个项目,它的思路不一样:不是再给你一个 DNS 服务器,而是给你一套「可组合的策略管线」——把匹配、转发、回退、改写、联动防火墙全部拆成插件,用声明式 YAML 把它们按顺序串起来跑。它的作者是国产开发者,从 mosdns 那里受到启发,但把核心做得更可观测、可验证。

OxiDNS

它到底是什么

OxiDNS(项目仓库 svenshi/oxidns)是一个用 Rust 写的、面向软路由、OpenWrt、Homelab 和高级自建网络的「DNS 策略编排引擎」。它的核心思路借鉴了 mosdns,但胜在两点:

  • 策略可编排:内置的 sequence 插件能把 matcher(匹配器)、executor(执行器)和 provider(上游)像管道一样拼起来,条件跳转、回退链这些都能声明地写。
  • 决策可解释:每一次查询的匹配路径、执行路径、上游选择都会被记录下来,配上 Prometheus 指标和实时日志。出问题时能复盘出「为什么解析成这个 IP」,这在传统 dnsmasq 体系里几乎做不到。

它的上游/接入协议支持得很完整——UDP、TCP、DoT、DoQ、DoH(含 HTTP/1.1/2/3)都收。还能把解析结果联动到 Linux 的 ipset/nftset、RouterOS 的地址列表上,做「按域名自动出防火墙规则」这种事。

有状态可观测要求的人(比如我这种隔三差五想看路由为什么飘到某个奇怪节点的人),这点吸引力很大。

它跑起来像什么

一行命令装最新 release,默认注册成系统服务:

curl -fsSL https://oxidns.org/install.sh | sudo sh

Windows 管理员 PowerShell 一行命令同效。装完默认监听 UDP/TCP 53 和一个管理 HTTP 端口 9199(WebUI + REST API)。它可以选择 裸跑、二进制直接跑、Docker 跑,也提供了 Debian 包。对 OpenWrt 用户有专门的 luci-app-oxidns 插件。

YAML 配置是这个项目的灵魂。官方 README 给了个最小例子——把 corp.lan 交给内网 DNS,其余走加密上游:

plugins:
  - tag: internal_domains
    type: domain_set
    args:
      exps: ["domain:corp.lan"]

  - tag: forward_internal
    type: forward
    args:
      upstreams:
        - addr: "udp://192.168.1.1:53"

  - tag: forward_public
    type: forward
    args:
      upstreams:
        - addr: "tls://dns.quad9.net:853"
          bootstrap: "9.9.9.9:53"

  - tag: main
    type: sequence
    args:
      - matches: "qname $internal_domains"
        exec: "$forward_internal"
      - matches: "!has_resp"
        exec: "$forward_public"
      - exec: accept

  - tag: dns_server
    type: udp_server
    args:
      entry: main
      listen: ":5335"

这套结构的优点是 逻辑和协议入口解耦——同一个 main 序列可以挂到 UDP、TCP、DoH 三个 listener 后面,一次定义多处复用

它的硬实力:性能基准

作者在 docs/static/img/benchmarks/staged/ 放了一张对比基准:

OxiDNS 性能基准 (vs mosdns/AdGuard Home/SmartDNS)

看图就清楚——在 6 个常见场景(缓存热路径、本地 UDP、本地 TCP、本地应答、通用域名集、负缓存)下,OxiDNS 和 mosdns 咬得很紧,两者都比 AdGuard Home 和 SmartDNS 高出明显一截。对家庭 NAS 这种轻负载来说这个量级的性能优势用不太上,但对真正在跑高 QPS 的网关来说有意义。

哪些坑要先踩

从我自己捋 README 和文档站的过程中挑了几条值得提前知道的:

  • 不是开箱即用的图形化面板。项目自己也承认:「OxiDNS 更适合愿意用一定配置复杂度换取控制力和可解释性的用户」。如果你的首要需求是「点几下鼠标就能拦截广告」,AdGuard Home 那种更合适,OxiDNS 不是来抢这个市场的。
  • 53 端口冲突。系统 systemd-resolved、dnsmasq、其它 DNS 服务都会占 53。装它之前要么改成别的(比如文档里示例用的 :5335),要么先把原来的停掉。
  • 管理 API 不能直接裸奔到公网9199 有 Basic Auth,但 静态文件不受 Auth 保护,只靠 Basic Auth 等于半裸。文档强烈建议要么只监听 127.0.0.1,要么走 nginx 反代,要么开防火墙。
  • WebUI 前端路由刷新要 fallback。反向代理(如 nginx)必须配 try_files $uri $uri/ /index.html;,否则刷新 /settings 这种深链会 404。
  • DNS 配置就是网络配置。任何 DNS 服务的 bug 都会直接断网。变更前必须有可恢复的备份和旁路方案——作者也在 README 显眼位置强调了这一点。
  • 迁移成本。如果你已经在跑 mosdns,作者提供了「从 mosdns 迁移」的文档一键搬配置。但从 SmartDNS / AdGuard Home / dnsmasq 搬过来就需要重写一遍,没有现成的迁移工具

适合谁

我读完文档后觉得它最合适的画像是:

  • 家用网关、旁路由、OpenWrt、NAS、HOMELAB 这种需要长期稳定运行的环境;
  • 想按域名、客户端 IP、查询类型做精细策略路由的人;
  • 有多上游并发、主备回退、加密 DNS 与自定义出口叠加需求的人;
  • 想用 DNS 结果直接驱动 ipset/nftset 或 RouterOS 地址列表做软路由策略路由的人。

反过来,它不适合「想 30 秒搞定广告过滤」的人,也不适合当权威 DNS(那是 BIND/NSD 的活)。

小结

DNS 这个事大多数人不愿意再折腾——它看不见摸不着,出了问题又很难诊断。OxiDNS 的核心诚意是把决策过程摆到台面上:匹配了什么、执行了什么、为什么选了当前结果,都能查。这点对愿意花时间写 YAML 的人来说很值。

目前 433 个 star、昨天还在 commit 的活跃度对它来说偏少,还不算主流——但 GPL-3.0、文档清晰、性能过得去。如果你在折腾多层的 DNS 分流、想试一种不同于面板/拦截器的新思路,可以拿它当折腾对象玩一玩;要不要上生产,自己评估。

发表评论