feat(ednsdiag): add DoQ/DoH3/DNSCrypt transports, proxy support, probe & compare
This commit is contained in:
@@ -6,12 +6,12 @@ below were verified on 2026-08-13.
|
||||
|
||||
## Candidate providers
|
||||
|
||||
| Provider | DoH endpoint | DoT endpoint / authentication name | Official documentation | Profile |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Cloudflare | `https://cloudflare-dns.com/dns-query` | `one.one.one.one:853` | [DoH](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/make-api-requests/) / [DoT](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-tls/) | Unfiltered |
|
||||
| Google | `https://dns.google/dns-query` | `dns.google:853` | [DoH](https://developers.google.com/speed/public-dns/docs/doh) / [DoT](https://developers.google.com/speed/public-dns/docs/dns-over-tls) | Unfiltered |
|
||||
| Quad9 | `https://dns.quad9.net/dns-query` | `dns.quad9.net:853` | [Quad9 services](https://docs.quad9.net/services/) | Security filtered; HTTP/2 required |
|
||||
| AdGuard | `https://dns.adguard-dns.com/dns-query` | `dns.adguard-dns.com:853` | [AdGuard providers](https://adguard-dns.io/kb/general/dns-providers/) | Ads, tracking, and security filtered |
|
||||
| Provider | DoH endpoint | DoT endpoint / authentication name | QUIC support | DNSCrypt | Official documentation | Profile |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| Cloudflare | `https://cloudflare-dns.com/dns-query` | `one.one.one.one:853` | DoH3 at the DoH endpoint | No verified built-in stamp | [DoH and HTTP/3](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/make-api-requests/) / [DoT](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-tls/) | Unfiltered |
|
||||
| Google | `https://dns.google/dns-query` | `dns.google:853` | DoH3 at the DoH endpoint | No verified built-in stamp | [Secure transports](https://developers.google.com/speed/public-dns/docs/secure-transports) | Unfiltered |
|
||||
| Quad9 | `https://dns.quad9.net/dns-query` | `dns.quad9.net:853` | Not enabled without an official endpoint statement | No verified built-in stamp | [Quad9 services](https://docs.quad9.net/services/) | Security filtered; HTTP/2 required |
|
||||
| AdGuard | `https://dns.adguard-dns.com/dns-query` | `dns.adguard-dns.com:853` | DoQ at `dns.adguard-dns.com:853` | Official stamp for `2.dnscrypt.default.ns1.adguard.com` at `94.140.14.14:5443` | [AdGuard dnsproxy example](https://github.com/AdguardTeam/dnsproxy#encrypted-upstreams) / [AdGuard public DNS](https://adguard-dns.io/kb/en/public-dns/overview/) | Ads, tracking, and security filtered |
|
||||
|
||||
## Registry requirements
|
||||
|
||||
@@ -25,6 +25,11 @@ Each built-in provider entry must include:
|
||||
- official source URL;
|
||||
- last verification date.
|
||||
|
||||
The runtime `Provider` registry stores the official source URL and verification
|
||||
date alongside each endpoint. Update both fields whenever an endpoint or
|
||||
capability is re-verified; the markdown table alone is not authoritative for
|
||||
runtime metadata.
|
||||
|
||||
Do not infer one protocol endpoint from another. Do not treat filtering and
|
||||
non-filtering services as interchangeable. Provider comparison results must
|
||||
remain separate.
|
||||
|
||||
@@ -8,7 +8,7 @@ validation, fallback, or result claims.
|
||||
1. Never silently downgrade to plaintext DNS.
|
||||
2. Validate certificates and authentication domain names. DoT follows the
|
||||
strict privacy profile in [RFC 8310](https://www.rfc-editor.org/rfc/rfc8310.html).
|
||||
3. Treat certificate, hostname, SNI, and negotiated ALPN mismatches as hard
|
||||
3. Treat certificate, hostname, SNI, and any non-empty negotiated ALPN mismatch as hard
|
||||
failures, not fallback opportunities.
|
||||
4. Bound response sizes, per-attempt timeouts, total time, redirects, and the
|
||||
number of attempts.
|
||||
@@ -19,12 +19,62 @@ validation, fallback, or result claims.
|
||||
7. Do not enable AXFR, IXFR, or ANY queries.
|
||||
8. Do not persist full query names or client identifiers by default.
|
||||
|
||||
## Proxy policy
|
||||
|
||||
DoH and DoT may use an explicit `--proxy` or the standard Go
|
||||
[`ProxyFromEnvironment`](https://pkg.go.dev/net/http#ProxyFromEnvironment)
|
||||
selection rules for `HTTPS_PROXY` and `NO_PROXY`. An explicit URL takes
|
||||
precedence and must use `http` or `https`. DoT establishes an HTTP CONNECT
|
||||
tunnel and then performs the normal resolver TLS handshake inside it; the
|
||||
proxy never substitutes for resolver certificate, authentication-domain, SNI,
|
||||
or ALPN validation.
|
||||
|
||||
Proxy credentials may be sent as HTTP Basic authentication when embedded in
|
||||
the URL, but must never appear in result JSON or diagnostic errors. Result
|
||||
metadata contains only a sanitized proxy endpoint. An HTTP(S) proxy can observe
|
||||
the resolver destination, connection timing, and traffic volume even though it
|
||||
cannot read the resolver TLS payload.
|
||||
|
||||
DoH3, DoQ, and the current DNSCrypt transport use UDP or QUIC and do not use a
|
||||
TCP HTTP CONNECT proxy. Reject an explicit proxy for those protocols instead of
|
||||
silently connecting directly. Proxy failures are transport failures and never
|
||||
trigger plaintext DNS or an undisclosed direct connection.
|
||||
|
||||
## DoT ALPN policy
|
||||
|
||||
The client advertises the `dot` ALPN identifier. RFC 7858 and RFC 8310 do not
|
||||
require a DoT server on its dedicated port to select an ALPN protocol, so an
|
||||
empty negotiated ALPN is permitted and reported as empty. If a server selects
|
||||
a non-empty protocol other than `dot`, abort before sending the DNS query.
|
||||
The client advertises the IANA-registered `dot` ALPN identifier. An explicit
|
||||
selection other than `dot` is a hard failure before the DNS query is sent. An
|
||||
empty selection is permitted and reported because RFC 7858 and RFC 8310 do not
|
||||
make ALPN negotiation part of DoT server authentication; the dedicated port,
|
||||
PKIX chain, SNI, and configured authentication domain still identify the
|
||||
service. This deliberately restores the policy from PR #9 and supersedes the
|
||||
stricter empty-ALPN rejection introduced by PR #11.
|
||||
|
||||
## QUIC transport policy
|
||||
|
||||
DoQ requires TLS 1.3 and an exact `doq` ALPN selection. DoH3 requires TLS 1.3,
|
||||
HTTP/3, and an exact `h3` ALPN selection. Certificate, authentication-domain,
|
||||
SNI, and ALPN failures abort before a DNS query is sent. The initial
|
||||
implementation does not send 0-RTT data or enable session resumption because
|
||||
their replay and linkability properties require a separate policy decision.
|
||||
|
||||
Each DoQ query uses one client-initiated bidirectional stream, a two-octet
|
||||
length prefix, DNS Message ID 0, and STREAM FIN. Truncated frames, extra
|
||||
responses, non-zero response IDs, unexpected streams, and missing FIN are
|
||||
protocol failures; they never trigger plaintext or cross-protocol fallback.
|
||||
|
||||
Reject DNS messages with the TC bit set on every encrypted transport. In
|
||||
particular, the UDP-only DNSCrypt implementation must not expose a partial
|
||||
answer as a completed lookup.
|
||||
|
||||
## DNSCrypt transport policy
|
||||
|
||||
Accept only allowlisted DNSCrypt v2 stamps. Validate the stamp type, provider
|
||||
public key, provider name, resolver certificate signature, validity interval,
|
||||
and encrypted response. Report the stamp IP bootstrap path, provider
|
||||
authentication name, certificate serial, and crypto construction. Certificate
|
||||
or response-authentication failures are hard failures and never trigger
|
||||
plaintext or cross-protocol fallback. Anonymized DNSCrypt remains unavailable.
|
||||
|
||||
## Bootstrap transparency
|
||||
|
||||
|
||||
@@ -7,16 +7,20 @@ standard, not on summaries or provider-specific JSON APIs.
|
||||
| --- | --- | --- |
|
||||
| Agent Skills package | [Agent Skills specification](https://agentskills.io/specification) | Required package format |
|
||||
| OMP discovery | [OMP Skills documentation](https://github.com/can1357/oh-my-pi/blob/main/docs/skills.md) | Supported host |
|
||||
| DoH | [RFC 8484](https://www.rfc-editor.org/rfc/rfc8484.html) | Planned |
|
||||
| DoT | [RFC 7858](https://www.rfc-editor.org/rfc/rfc7858.html) | Planned |
|
||||
| DoH | [RFC 8484](https://www.rfc-editor.org/rfc/rfc8484.html) | Implemented over HTTP/1.1 and HTTP/2 |
|
||||
| DoH3 | [RFC 8484](https://www.rfc-editor.org/rfc/rfc8484.html) over [RFC 9114](https://www.rfc-editor.org/rfc/rfc9114.html) | Implemented |
|
||||
| DoT | [RFC 7858](https://www.rfc-editor.org/rfc/rfc7858.html) | Implemented |
|
||||
| DoT authentication profiles | [RFC 8310](https://www.rfc-editor.org/rfc/rfc8310.html) | Strict privacy only |
|
||||
| DoQ | [RFC 9250](https://www.rfc-editor.org/rfc/rfc9250.html) | Planned |
|
||||
| DoT ALPN identifier | [IANA TLS ALPN registry](https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids) | Advertise `dot`; reject a different selection; permit and report no selection |
|
||||
| DoQ | [RFC 9250](https://www.rfc-editor.org/rfc/rfc9250.html) | Implemented for single-response queries |
|
||||
| ODoH | [RFC 9230](https://www.rfc-editor.org/rfc/rfc9230.html) | Research until a maintained implementation is selected |
|
||||
| DNS privacy operations | [RFC 8932](https://www.rfc-editor.org/rfc/rfc8932.html) | Security and privacy guidance |
|
||||
| EDNS(0) padding | [RFC 7830](https://www.rfc-editor.org/rfc/rfc7830.html) and [RFC 8467](https://www.rfc-editor.org/rfc/rfc8467.html) | Evaluate per transport |
|
||||
| DNSCrypt | [DNSCrypt protocol specification](https://github.com/DNSCrypt/dnscrypt-protocol) | Planned, non-IETF |
|
||||
| DNSCrypt | [DNSCrypt protocol specification](https://github.com/DNSCrypt/dnscrypt-protocol) | DNSCrypt v2 implemented over UDP; non-IETF |
|
||||
| Anonymized DNSCrypt | [Anonymized DNSCrypt specification](https://github.com/DNSCrypt/dnscrypt-protocol/blob/master/ANONYMIZED-DNSCRYPT.txt) | Research |
|
||||
| Go DNS wire and IDNA support | [Go x/net module](https://pkg.go.dev/golang.org/x/net) | Pinned to v0.58.0; use `dnsmessage` and `idna` |
|
||||
| Go QUIC and HTTP/3 support | [quic-go documentation](https://quic-go.net/docs/) | Pinned to v0.61.0 |
|
||||
| Go DNSCrypt support | [ameshkov/dnscrypt](https://github.com/ameshkov/dnscrypt) | Pinned to v2.4.0; stamp, certificate, and protocol implementation |
|
||||
|
||||
## Deliberate exclusions
|
||||
|
||||
@@ -38,3 +42,13 @@ For DoH, accept and send `application/dns-message`. Keep HTTP status separate
|
||||
from the DNS RCODE: a valid NXDOMAIN or SERVFAIL response still uses HTTP 2xx.
|
||||
For DoT, use the strict privacy profile and verify both the PKIX chain and the
|
||||
configured authentication domain name.
|
||||
|
||||
For DoQ, use ALPN `doq`, UDP port 853, a separate client-initiated bidirectional
|
||||
stream per query, the two-octet DNS-over-TCP length field, STREAM FIN, and DNS
|
||||
Message ID 0. DoH3 retains RFC 8484 message and HTTP semantics and requires
|
||||
HTTP/3 with ALPN `h3`.
|
||||
|
||||
For DNSCrypt v2, parse only DNSCrypt stamps, fetch the provider TXT
|
||||
certificate, validate its Ed25519 signature and validity interval against the
|
||||
stamp key, and authenticate encrypted responses. The stamp-supplied provider
|
||||
name and IP endpoint are part of the authenticated resolver identity.
|
||||
|
||||
Reference in New Issue
Block a user