Show HN: 运行第二个公共ODoH中继
摘要
Numa v0.14 将ODoH客户端和中继整合在一个Rust二进制文件中,无需账户即可实现匿名DNS;本文介绍了其设计以及部署第二个公共ODoH中继的过程。
每个注重隐私的DNS服务都需要一个账户:NextDNS、Cloudflare家庭版、Apple的iCloud私有中继(付费,仅限iOS)。而无需账户的协议——ODoH——基本上只有一个知名的公共中继运营商(Frank Denis在Fastly Compute上运行,是dnscrypt-proxy的默认选项)。我构建了第二个中继以及与之通信的客户端。
查看缓存全文
缓存时间: 2026/05/14 12:23
# 将 ODoH 客户端和中继打包到一个 Rust 二进制文件中 — Numa
来源:https://numa.rs/blog/posts/odoh-anonymous-dns-without-an-account.html
## 无需账户的匿名 DNS:将 ODoH 客户端和中继打包到一个 Rust 二进制文件中
如果你运行 Pi-hole、AdGuard Home 或任何转发解析器,你的每个查询都会经过一个操作者,他既能看到你的 IP 地址,也能看到问题。如果你切换到像 Unbound 这样的递归解析器,你的 IP 则会暴露给每个权威域名服务器——`.com` 会知道你存在,`google.com` 会知道你存在,链路上的每个 CDN 边缘节点也会知道你存在。DoH 和 DoT 加密的是*传输*过程;它们不会改变*谁知道了什么*。
Apple 的 iCloud Private Relay 通过拆分路径为 Apple 用户解决了这个问题:入口代理看到你的 IP 但看不到请求,出口代理看到请求但看不到你的 IP。DNS 在系统范围内被匿名化,但仅限于 iCloud+(每月 0.99 美元)、仅在 iOS/macOS 上、且仅通过 Apple 策划的出口合作伙伴。NextDNS、Cloudflare for Families、Quad9——所有这些注重隐私的 DNS 服务——都需要账户、遥测或两者兼有。自托管用户实际上没有任何无需账户或平台锁定的匿名 DNS 选项。
看到{你的 IP,你的问题}的跳数
{1, 1} → {不相交}
中继看到 IP,目标看到问题
加密原语
全部经过审计
odoh-rs (HPKE) · rustls (TLS) — 零自定义
是否需要账户
否
单个二进制,MIT 许可,默认配置即可工作
ODoH(RFC 9230,“Oblivious DNS over HTTPS”)是 IETF 为此目的制定的 DNS 协议。Numa v0.14 将一个客户端、一个中继和一个公共部署打包到同一个二进制文件中。这篇文章将介绍它的功能、它没有解决的问题,以及部署生态系统中第二个公共中继所需要做的工作。
---
## 工作原理
独立运营商 — 不得勾结[加密 ████]A example.com?93.184.216.34[加密 ████]你 NUMA 中继 CLOUDFLARE 权威**你**在目标的 HPKE 公钥下加密查询。包含一个用于响应的对称密钥。
**Numa 中继**看到你的 IP。在两个方向上只看到密文。
**Cloudflare 目标**解密问题。看不到 IP——只看到中继的。
**权威**标准 DNS 递归。这是 Cloudflare 的工作,不是你的。
**返回**Cloudflare 使用你提供的对称密钥加密答案,并通过相同的路径发送回去。中继仍然只看到密文。同样的隐私属性,方向相反。
加密使用 HPKE(RFC 9180)——与 TLS 加密客户端问候(Encrypted ClientHello)相同的原语。Cloudflare 发布了 `odoh-rs` (https://crates.io/crates/odoh-rs) 用于密封/打开操作,我使用了它。Numa 的“自己动手”原则是*不使用 DNS 库*;HPKE 是另一回事,而自己动手写加密是一种决策,其中每小时的“我想完全控制”都会换来十倍的审计焦虑。
## 构建所需的工作
ODoH 客户端模式作为第四种传输方式(与 UDP、DoH、DoT 并列)插入 Numa 现有的转发管道。中继是一个单独的模式(`numa relay [PORT]`)——同一个二进制,不同的入口点,只暴露 `POST /relay` 和 `GET /health`。中继中有两件事比预期的需要更多关注:
**SSRF 加固的主机名验证器。**中继会打开一个到请求 URL 中指定的目标的出站连接。如果没有验证,这就是教科书式的 SSRF——恶意客户端可以要求它“转发”到 `169.254.169.254` 并窃取云元数据。验证器使用严格的正则表达式(RFC 1035 ASCII 标签,无 IDN,无 IP 字面量,无非 443 端口)。
**eTLD+1 同一运营商检查。**ODoH 的保证依赖于中继和目标由*不同*组织运营。如果它们共享一个 eTLD+1,那么一个运营商就可以在两条路径上关联 IP 和问题,整个构造就变成了演戏。Numa 默认拒绝同一运营商的配置(有意的同一运营商设置仍然可能)。
`odoh-relay.numa.rs` 作为一个 systemd 单元运行在 Hetzner VPS 上,前端使用 Caddy 提供 TLS。默认的 Numa 配置将其与 `odoh.cloudflare-dns.com` 配对——路径中开箱即用有两个独立运营商,没有共享的 eTLD+1。探测脚本 `tests/probe-odoh-ecosystem.sh` 一次运行即可检查整个公共生态系统。
## 它没有解决的问题
- **目标能看到问题。**ODoH 转移信任,但没有消除信任。如果 Cloudflare 想记录他们收到的每个 ODoH 查询,他们可以这样做,并且没有任何加密保护可以阻止这一点。保护是操作层面的:目标不知道你是谁,因此问题无法归属于你。
- **递归模式仍然在目标的出口处泄露信息。**如果你的目标以递归模式运行,那么到根/TLD/权威的遍历是明文 UDP/TCP。ODoH 保护客户端→目标的跳数;目标之后的任何东西都是目标的问题,而不是协议的问题。
- **针对小中继可以进行流量分析。**处理少量查询的中继会泄露关联信息:如果你的 IP 是唯一与中继 A 通信的,而 Cloudflare 之后正好收到一个查询,那么仅凭时间信息就能重新识别你。防御措施是流量——更多用户使用同一个中继,更多填充流量,更大的匿名集。这就是为什么单用户自托管中继在隐私方面*不如*繁忙的公共中继。
- **公钥分发是中心化的。**客户端通过明文 HTTPS 从目标自己的知名端点获取目标的 HPKE 配置。如果你不信任 WebPKI 能提供正确的配置,你就不信任 ODoH。使用 Pkarr 发布目标密钥是明显的下一步,但尚未发布。
- **DNSSEC 是正交的。**ODoH 保护路径;DNSSEC 保护答案的真实性。你仍然需要两者,而 Numa 的递归模式两者都做——加密到目标,并针对 IANA 根密钥进行验证。
## 公共生态系统
DNSCrypt 的策划列表 (https://github.com/DNSCrypt/dnscrypt-resolvers/blob/master/v3/odoh-relays.md) (`v3/odoh-relays.md`,最后更新于 2025 年 9 月) 包含一个中继条目,上游 README 指出 *“odohrelay-crypto-sx 似乎是唯一剩下的 ODoH 中继。”* Frank Denis 在 Fastly Compute 上运行着著名的公共中继 `odoh-relay.edgecompute.app`——它是 `dnscrypt-proxy` 中的默认配置,也是唯一广泛使用的开源 ODoH 客户端。Numa 在 `odoh-relay.numa.rs` 上添加了第二个著名的运营商,并发布了一个可以连接到这两个中继的客户端。
这不是一个产品——这是我维护的基础设施,因为 Numa 需要它,而现有的生态系统很薄弱。**我很乐意看到其他人搭建中继。**使用 Numa 用户已经运行的同一个二进制文件;将模式切换为 `relay`,将 Caddy 指向它,一个周日下午就能完成(docker-compose 指南 (https://github.com/razvandimescu/numa/tree/main/packaging/relay))。协议的隐私属性随着运营商多样性的增加而扩展。
## 下一步计划
对于今天的匿名 DNS:`cargo install numa`,在 `numa.toml` 中设置 `mode = "odoh"`,你的查询将路由经过两个独立组织——两者都是开源的,都可检查。Docker 用户:有一个现成的 compose 配方 (https://github.com/razvandimescu/numa/tree/main/packaging/client) 预配置了 ODoH 模式。
---
Numa 是一个在你笔记本或手机上运行的 DNS 解析器。ODoH 客户端 + 自托管中继,从根开始递归解析并支持 DNSSEC,广告拦截,带自动 TLS 的 `.numa` 本地域名,REST API 和实时仪表板。github.com/razvandimescu/numa (https://github.com/razvandimescu/numa)。
*讨论:GitHub Issues (https://github.com/razvandimescu/numa/issues) · Hacker News (https://news.ycombinator.com/from?site=numa.rs)。*
相似文章
互联网边缘的社区建设
本文介绍了基于Nostr的社区建设,使用Pyramid中继软件和Jumble客户端,实现去中心化、可移植的社区,无需依赖中央服务器。
Show HN: Antenna – 内置 MCP 服务器的 RSS 阅读器
Antenna 是一款本地优先的 RSS 阅读器,使用 SQLite 存储订阅源,并通过邮件摘要和面向 AI 代理的 MCP 服务器提供内容,完全基于 MIT 许可证开源。
Show HN: OpenGravity – 一款零安装、BYOK 的 Vanilla JS 版 Antigravity 克隆
OpenGravity 是 Google Antigravity 的零安装 Vanilla JS 克隆版,支持使用 Gemini 模型和 WebContainer API 进行 BYOK 代理式编码。旨在绕过速率限制,它提供了一个基于浏览器的 IDE,具备自主任务编排和本地文件同步功能。
Show HN: 用汇编语言构建 Web 服务器,为我的生命赋予(些许缺乏的)意义
ymawky 是一个专为 macOS 编写的 ARM64 汇编 Web 服务器,其特点是不依赖 libc 仅使用系统调用,并具备基本的 HTTP 功能。
Show HN:独立网络/博客索引的索引
展示一个经过精心策划的独立网络和博客目录索引,聚合了各种用于发现个人网站、RSS 订阅源以及基于限制条件的网络社区的工具。