v0.81.10 — 上游同步、DoQ/缓存改进与 DoH3 竞态修复
本版本同步上游至 f214e79,纳入 AdguardTeam/dnsproxy 的 DoQ 与 DNS 缓存行为更新,并对本 fork 的 HTTP/3(DoH)并发做加固。标签 v0.81.10 指向 9b12982(DoH3 串行化最终方案);中间尝试(cd2b354、b0af9cf)仅作实验,以本 tag 为准。
亮点
- 上游:Go 1.26.3、DoQ 空闲/accept 超时、DNS 缓存区分 DNSSEC DO 位、UDP 查询 ID 处理、从 tag 解析版本号、GitHub Actions 安全加固。
- 本 fork:修复 HTTP/3(DoH)握手竞态(有意串行化);CI/测试稳定性(DNSCrypt
-race、DoH 0-RTT qlog);Codecov v5。 - 相对 v0.81.9 未变:PPv2、GHCR 镜像、DoQ
streamOpenMu、TLS 会话恢复 / TFO 相关行为。
行为变更
DNS 缓存与 DO 位(上游)
查询带 DNSSEC DO 位时,缓存 key 包含该位;带/不带 DO 的查询不再共用同一缓存项。参见 AdGuard Home #8384。
DoQ 超时(上游)
QUIC 空闲超时由 5 分钟 缩短为 30 秒;accept 循环增加超时,异常退出时更不易遗留 goroutine。
其它上游修复
- UDP 查询 ID 为 0 时的处理(AGDNS-3952)。
- 构建版本可从
GITHUB_REF/ 发布 tag 解析。
Fork 专属行为
本 fork 在可行处与上游语义对齐;以下为有意的偏离说明。
DoH HTTP/3 — 串行化 RoundTrip(9b12982)
问题。 多个 goroutine 并发进入 http3Transport.RoundTrip 时,可能与 quic-go 的 QUIC 握手重叠(handleTransportParameters 与打开 stream),在高压测试(go test -race、高并行)下表现为 HTTP/3 DoH 路径上的 DATA RACE。
上游。 AdguardTeam 在 RoundTrip 全程使用 sync.RWMutex 的 RLock,同一 transport 上允许多个并发读者。
本 fork。 http3Transport 使用 sync.Mutex:整次 RoundTrip(含 OnlyCachedConn 与拨号)在 Lock 下执行;仍使用 quic.DialAddrEarly,0-RTT 语义不变,仅限制对同一 transport 并发进入 quic-go。
取舍。 经同一 DoH upstream 实例的 HTTP/3 查询会串行化。对典型 DNS 上游负载,这一取舍通常可接受。若你依赖大量 goroutine 对单个 DoH3 upstream 并行打满吞吐,升级前请自行压测。
Bisect 说明。 cd2b354(无锁快路径)与 b0af9cf(恢复 RLock)未能完全稳定 CI;本 tag 以 9b12982 为准。
沿用自更早 fork 版本
- 支持监听上的 PPv2。
- DoQ:
OpenStreamSync外有streamOpenMu(本 fork 独有;本版未改)。 - GHCR 容器发布(
ghcr.io/fcchbjm/dnsproxy)。
运维说明
- DoQ:空闲超时采用上游更短的默认值(30s)。长时间空闲的 DoQ 连接可能比以前更早被断开。
- DoH HTTP/3:同一 upstream 实例上的请求在本 fork 中串行化,以避免 quic-go 握手竞态(见上)。DoT、DoQ、UDP 及 HTTP/2 DoH 不受此互斥锁影响。
- DNS 缓存:升级后,启用 DO 时,带 DO 与不带 DO 的查询将使用不同缓存项。
- PPv2 / TFO / TLS 会话恢复:与 v0.81.9 一致。
- 镜像:
ghcr.io/fcchbjm/dnsproxy:v0.81.10(本 tag 的 Docker workflow 成功后可用)。
升级说明
- 多数部署可直接替换二进制或拉取新镜像。
- 若依赖长时间空闲的 DoQ,请结合防火墙/中间设备检查 30s 空闲超时。
- 仅当你刻意对单个 DoH3 upstream 对象做极高并行查询时,需关注 HTTP/3 串行化 影响。
维护(CI 与测试)
- Codecov 上传:v5,
slug: fcchbjm/dnsproxy。 - DNSCrypt 测试:
-race下先 shutdown 再 wait serve goroutine。 - DoH 0-RTT 测试:用
require.Eventually等待 qlog(macOS CI 稳定性)。
自 v0.81.9 以来(参考)
| 范围 | 说明 |
|---|---|
| 上游合并 | 缓存 DO 位、DoQ 超时、Go 1.26.3、Actions 安全、版本修复、UDP ID |
| Fork — DoH3 | 9b12982 Mutex 串行化(最终) |
| Fork — CI/测试 | Codecov v5、DNSCrypt race、DoH 0-RTT 测试 |
完整变更:v0.81.9...v0.81.10
v0.81.10 — Upstream sync, DoQ/cache improvements, and DoH3 race fixes
Highlights (EN)
- Upstream sync through
f214e79(Go 1.26.3, DoQ timeouts, DNS cache DO bit, UDP ID fix, tag-based version). - Fork: DoH HTTP/3 race fix via full
RoundTripmutex; CI/test hardening. - Unchanged from v0.81.9: PPv2, GHCR, DoQ
streamOpenMu.
Behavior changes (EN)
- DNS cache: DO bit included in cache key when set (#8384).
- DoQ: QUIC idle timeout 5m → 30s; accept loop timeout reduces goroutine leak risk on abnormal exit.
- Other: UDP query ID 0 handling; version from release tags.
Fork-specific behavior (EN)
DoH HTTP/3 (9b12982). Upstream uses RWMutex.RLock for the full RoundTrip. This fork uses sync.Mutex (Lock for the entire RoundTrip, including dial) to avoid quic-go handshake races under concurrent use. quic.DialAddrEarly is unchanged (0-RTT preserved). HTTP/3 queries on the same upstream instance are serialized; this tradeoff is generally acceptable for typical DNS upstream workloads. 9b12982 is authoritative; cd2b354 and b0af9cf are experimental only.
Carried forward: PPv2, DoQ streamOpenMu, GHCR images.
Operational notes (EN)
- DoQ idle timeout: 30s (upstream default).
- Same-instance DoH3: serialized; DoT/DoQ/UDP/H2 DoH unaffected.
- PPv2 / TFO / TLS session resumption: same as v0.81.9.
- Image:
ghcr.io/fcchbjm/dnsproxy:v0.81.10.
Upgrade notes (EN)
Drop-in for most users. Review DoQ idle timeout if you keep long-lived QUIC sessions. Review DoH3 concurrency only if you maximize parallel queries on a single DoH3 upstream object.
Full changelog: v0.81.9...v0.81.10