DNS-over-HTTP/3 和 DNS-over-QUIC 两种协议都基于 UDP,且传输数据都经过 TLS 加密,但是这两种协议是完全不同的


QUIC

先来简单了解下 QUIC 协议:

QUIC 和 TCP、UDP 一样,是传输层协议,不过 QUIC 协议是基于加密 UDP 的(使用 TLS 1.3 来加密),QUIC 还具有 TCP 的一些优点。

DNS-over-QUIC

DNS-over-QUIC 是通过 QUIC 加密的 DNS 协议,有时会被简写为 DoQ,这个协议于 2022 年 5 月 发布为 RFC 9250,它比较类似 DNS-over-TLS,但是 DNS-over-QUIC 会比 DNS-over-TLS 更快一些

curl 无法与 DNS-over-QUIC 服务器进行握手和数据交换,因为 DNS-over-QUIC 只是经过 QUIC 封装的原生 DNS,并不能处理 HTTP 请求。
尝试使用 curl 来连接 DNS-over-QUIC 服务器,得到的输出如下:

1
2
3
4
5
6
7
8
9
10
11
$ curl https://dns.mbrjun.cn:784 --http3 -v
* Trying 127.0.0.1:784...
* Connect socket 5 over QUIC to 127.0.0.1:784
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: none
* ngtcp2_conn_handle_expiry returned error: ERR_HANDSHAKE_TIMEOUT
* connect to 127.0.0.1 port 784 failed: Failed sending data to the peer
* Failed to connect to dns.mbrjun.cn port 784 after 10050 ms: Failed sending data to the peer
* Closing connection 0
curl: (55) ngtcp2_conn_handle_expiry returned error: ERR_HANDSHAKE_TIMEOUT

可以看到 QUIC 套接字已经创建完成,但是服务器并不响应这个 HTTP 请求

DNS-over-QUIC = QUIC + DNS

DNS-over-HTTP/3

DNS-over-HTTP/3,有时也会被称作 DoH3,也是一种加密的 DNS 协议,这种协议在 Android 11 中通过增量更新得到了 Android 的原生支持

DNS-over-HTTP/3 使用 HTTP 作为传输层协议,本质上是 DNS-over-HTTPS 的一种:
DNS-over-HTTPS 允许使用 HTTP/3、HTTP/2、HTTP/1.1、HTTP/1.0、HTTP/0.9 作为底层协议(实际上,只有前三种常被使用),而 DNS-over-HTTP/3 是指使用 HTTP/3 做底层协议的 DNS-over-HTTPS

HTTP/3 协议基于 QUIC,可以说 HTTP/3 = QUIC + HTTP

DNS-over-HTTP/3 = QUIC + HTTP + DNS

curl 可以和 DNS-over-HTTP/3 服务器进行握手和数据交换,因为 DNS-over-HTTP/3 是经过 QUIC 封装的 HTTP,在 HTTP 上提供 DNS 查询的功能,因此可以处理 HTTP 请求。
尝试使用 curl 来连接 DNS-over-HTTP/3 服务器,得到的输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ curl https://dns.mbrjun.cn/dns-query --http3 -vI
* Trying 127.0.0.1:443...
* Connect socket 5 over QUIC to 127.0.0.1:443
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: none
* subjectAltName: host "dns.mbrjun.cn" matched cert's "*.mbrjun.cn"
* Verified certificate just fine
* Connected to dns.mbrjun.cn (127.0.0.1) port 443 (#0)
* h2h3 [:method: HEAD]
* h2h3 [:path: /dns-query]
* h2h3 [:scheme: https]
* h2h3 [:authority: dns.mbrjun.cn]
* h2h3 [user-agent: curl/7.87.1-DEV-MBRjun]
* h2h3 [accept: */*]
* Using HTTP/3 Stream ID: 0 (easy handle 0x5612c27f71b0)
> HEAD /dns-query HTTP/3
> Host: dns.mbrjun.cn
> user-agent: curl/7.87.1-DEV-MBRjun
> accept: */*
>
* ngh3_stream_recv returns 0 bytes and EAGAIN
* ngh3_stream_recv returns 0 bytes and EAGAIN
* ngh3_stream_recv returns 0 bytes and EAGAIN
< HTTP/3 400
HTTP/3 400
< (headers)
(headers)
...

可以看到握手成功,服务器返回了 HTTP 状态码 400(这是正常的。为什么?因为 dns-query 没有提供 DNS 查询的参数,所以服务器返回了 Bad Request)

对比和总结

1
2
DNS-over-QUIC = QUIC + DNS
DNS-over-HTTP/3 = QUIC + HTTP + DNS

DoH3 比 DoQ 多了一层 HTTP 封装,因此可以使用类似 curl 的工具进行查询

由于 DoH3 有一层 HTTP 封装,所以它在传输时会带上 Request Header 和 Response Header,这其中可能包含了 User-Agent 之类的信息,这种信息对于 DNS 来说通常是毫无作用的,理论上,DoH3 会比 DoQ 更慢,但实际上带来的影响是极其少的(可能只会慢个 1-2ms)

端口号:DoQ 更类似于 DoT,通常使用端口号 443、784 和 853,而 DoH3 是 DoH 的一种,通常使用端口 443。

兼容性:从 Android 11 开始,DoH3 得到了部分支持(谷歌设置了白名单,只有少数公共 DNS 服务器会启用 DoH3),从 iOS 15 (macOS Monterty)开始,Apple 设备支持了 DoQ(仅可通过 iCloud Private Relay 开启,不支持自定义服务器),现在 DoH3 的用户数量和 DoQ 的差不多


附:AdGuard 认为使用 HTTP 作为传输层协议会引起很多不必要的风险,使用 HTTP 发送 DNS 请求会导致下列结果:

  • HTTP cookies
  • 其他 HTTP 消息头(HTTP headers)(包括 Authentication, User-Agent, Accept-Language)
  • 给预谋犯更多机会
  • Tracking using ETag