跳转到主要内容

使用 Curl 检查 DoH 可用性

简单快速检测、一般 Linux 和 Windows 10 版本 1803 后都自带 Curl。
文末带有示例,复制执行即可。

标准请求

根据 RFC 8484,DNS over HTTPS (DoH)支持通过 HTTP GET 和 POST 两种方法发送请求。

  1. GET 请求

    • 在 GET 请求中,DNS 查询被编码为一个查询参数。这个参数使用 Base64URL 编码的 DNS 请求内容,并附加到 URI 上。例如,一个 GET 请求的 URI 可能类似于 https://dnsserver.example.net/dns-query?dns=<base64url-encoded-query>
    • 使用 GET 请求的优点是它更友好于许多 HTTP 缓存实现,可以利用 HTTP 缓存来缓存响应。
  2. POST 请求

    • 在 POST 请求中,DNS查询被包含在 HTTP 请求的主体中,媒体类型为 application/dns-message。例如,POST 请求的内容类型和长度需要在 HTTP 头中指定,且 DNS 查询以 DNS wireformat 编码放在请求体中。
    • POST 请求通常比 GET 请求更小,因为不需要将请求内容编码到 URI 中。

无论是 GET 还是 POST 方法,DoH 服务器都需要实现这两种方法来处理 DNS 查询。
RFC 8484 还规定,DoH 客户端应该包含 HTTP Accept 头字段,以指示可以处理的响应类型,并且必须能够处理 application/dns-message 类型的响应​。

请求例如:

curl -vH "accept: application/dns-message" "https://cloudflare-dns.com/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB"

你或许尝试过对 

AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB

进行 Base64URL 解码,但你会得到一些乱码。那是因为这个 Base64URL 是二进制编码转 Base64URL 而不是字符串转 Base64URL,但是我没找到具体定义。(看起来是 RFC 1035 中定义的 DNS wireformat)

而且这种请求返回的响应 application/dns-message 也是一个二进制,该格式在 RFC 1035 中定义,因此标准 DoH 请求非常不利于人类查看和使用。

7.1.  Registration of the "application/dns-message" Media Type

   Type name: application

   Subtype name: dns-message

   Required parameters: N/A

   Optional parameters: N/A

   Encoding considerations: This is a binary format.  The contents are a
      DNS message as defined in RFC 1035.  The format used here is for
      DNS over UDP, which is the format defined in the diagrams in
      RFC 1035.

   Security considerations: See RFC 8484.  The content is a DNS message
      and thus not executable code.

   Interoperability considerations: None.

   Published specification: RFC 8484.

   Applications that use this media type:
      Systems that want to exchange full DNS messages.

摘自 RFC 8484

所以在我们人类快速检查可用性时,大概应该使用下面的 JSON API 形式。

JSON API

RFC 8427 定义了以下 JSON 对象成员来表示 DNS 消息​:

  • ID:整数,范围为 0 到 65535。
  • QR:布尔值,表示查询或响应。
  • Opcode:整数,范围为 0 到 15,表示操作码。
  • AA:布尔值,表示是否权威回答。
  • TC:布尔值,表示是否被截断。
  • RD:布尔值,表示是否递归期望。
  • RA:布尔值,表示是否递归可用。
  • AD:布尔值,表示是否经过 DNSSEC 验证。
  • CD:布尔值,表示是否禁用 DNSSEC 验证。
  • RCODE:整数,范围为 0 到 15,表示返回码。
  • QDCOUNT:整数,范围为 0 到 65535,表示问题计数。
  • ANCOUNT:整数,范围为 0 到 65535,表示回答计数。
  • NSCOUNT:整数,范围为 0 到 65535,表示权威记录计数。
  • ARCOUNT:整数,范围为 0 到 65535,表示附加记录计数。

然而并没有人在乎 RFC 8427,我也没有看到哪个 RFC 规定了 JSON API 实现方式。

实践中,各大公共 DNS 几乎都支持以如下方式请求:

curl -vH "accept: application/dns-json" "https://cloudflare-dns.com/dns-query?name=example.com&type=A"

但部分公共 DNS 似乎也存在分歧,有的也会要求使用 /resolve 路径:

curl -vH "accept: application/dns-json" "https://dns.google/resolve?name=example.com&type=A"

返回的 JSON 示例如下:

{
   "Status":0,
   "TC":false,
   "RD":true,
   "RA":true,
   "AD":true,
   "CD":false,
   "Question":[
      {
         "name":"example.com",
         "type":1
      }
   ],
   "Answer":[
      {
         "name":"example.com",
         "type":1,
         "TTL":2080,
         "data":"93.184.215.14"
      }
   ]
}

与 RFC 8427 定义不同,这似乎是事实标准。

所以也许应该是 Cloudflare Style 和 Google Style?

但即使这样,返回格式也不一定是一样的(比如 dns.sb),所以如果你写程序,最好还是不要用 JSON API 了。

快速检测请使用文末的示例。

Curl 原生

curl 7.62.0 版本中原生支持了 DoH。

请求如:

curl --doh-url https://cloudflare-dns.com/dns-query https://www.example.com

详情请参阅:https://github.com/curl/curl/wiki/DOH-implementation

但我并不推荐使用,因为我们只是测试,而且你的版本不一定达标,而且此命令的目的是通过 DoH 解析后请求目标网址。

那么 DoT 呢?

很遗憾,我并没有找到简单快速且 Linux/Windows 自带的工具。

你也可以尝试这些全平台工具:

或这些 Linux Only 工具:

不过在 Linux 中如果你的 dig (BIND) 版本大于 9.17.10,那么你很可能已经有了 DoH 支持。

请求如:

dig +https @cloudflare-dns.com example.com A

详情请参阅:https://www.isc.org/blogs/bind-doh-update-2021/

JSON API 请求示例

中国大陆

Dnspod 公共 DNS

https://docs.dnspod.cn/public-dns/dot-doh/

虽然有文档,但是完全没说请求方式,相当于没有文档。

地区:CN、有部分全球接入能力

域名

curl -vH "accept: application/dns-json" "https://doh.pub/dns-query?name=example.com&type=A"

IPv4

curl -vH "accept: application/dns-json" "https://1.12.12.12/dns-query?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://120.53.53.53/dns-query?name=example.com&type=A"

IPv6

看起来没有,2402:4e00:: 并不能用。

阿里公共 DNS

https://alidns.com/articles/6018321800a44d0e45e90d71

特别注意,阿里 DNS 的 JSON API 查询路径不是 /dns-query 而是 /resolve

地区:CN、有部分全球接入能力

域名

curl -vH "accept: application/dns-json" "https://dns.alidns.com/resolve?name=example.com&type=A"

IPv4

curl -vH "accept: application/dns-json" "https://223.5.5.5/resolve?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://223.6.6.6/resolve?name=example.com&type=A"

IPv6

看起来没有,2400:3200::12400:3200:baba::1 并不能用,但是文档说可以。

curl -vH "accept: application/dns-json" "https://[2400:3200::1]/resolve?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://[2400:3200:baba::1]/resolve?name=example.com&type=A"


360安全 DNS

https://sdns.360.net/index.html

IP 有亿点多,但是没有 BGP 和全球接入能力。

地区:CN

域名

curl -vH "accept: application/dns-json" "https://doh.360.cn/resolve?name=example.com&type=A"

IPv4

curl -vH "accept: application/dns-json" "https://180.163.249.75/resolve?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://101.198.192.33/resolve?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://101.198.191.4/resolve?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://101.226.4.6/resolve?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://218.30.118.6/resolve?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://123.125.81.6/resolve?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://140.207.198.6/resolve?name=example.com&type=A"

IPv6

无?

EasyMosdns

https://apad.pro/dns-doh/

个人自建的 DNS,于 2019 启用,仅提供 DoH,仅限研究用途,不承诺 SLA,在 CN 提供无污染 DNS,本质是一个 DNS 转发器。
开源项目 EasyMosdns 官方的 DNS 分流 API。

地区:CN

不支持 JSON API

域名

curl -vH "accept: application/dns-message" "https://doh.apad.pro/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB"

IPv4

183.134.17.113 不能用。

IPv6

微步 OneDNS

https://onedns.net/about

纯净版,不拦截域名。

然而完全没有反应,服务器甚至没有返回 TLS 证书。
估计已被放弃。

域名

curl -vH "accept: application/dns-json" "https://doh-pure.onedns.net/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB"

IPv4

我觉得没必要测了。

全球/中国大陆外

Cloudflare 公共 DNS

https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/

地区:Global、CN 除外

域名

curl -vH "accept: application/dns-json" "https://cloudflare-dns.com/dns-query?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://mozilla.cloudflare-dns.com/dns-query?name=example.com&type=A"

IPv4

curl -vH "accept: application/dns-json" "https://1.1.1.1/dns-query?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://1.0.0.1/dns-query?name=example.com&type=A"

IPv6

curl -vH "accept: application/dns-json" "https://[2606:4700:4700::1111]/dns-query?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://[2606:4700:4700::1001]/dns-query?name=example.com&type=A"

Google 公共 DNS

https://developers.google.com/speed/public-dns/docs/doh

特别注意,Goole DNS 的 JSON API 查询路径不是 /dns-query 而是 /resolve

地区:Global、CN 除外

域名

curl -vH "accept: application/dns-json" "https://dns.google/resolve?name=example.com&type=A"

IPv4

curl -vH "accept: application/dns-json" "https://8.8.8.8/resolve?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://8.8.4.4/resolve?name=example.com&type=A"

IPv6

curl -vH "accept: application/dns-json" "https://[2001:4860:4860::8888]/resolve?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://[2001:4860:4860::8844]/resolve?name=example.com&type=A"

DNS.SB

https://dns.sb/doh/

返回的 JSON 和相比其他家略有不同。

地区:Global(但接入能力比较有限)、CN 除外

域名

curl -vH "accept: application/dns-json" "https://doh.dns.sb/dns-query?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://doh.sb/dns-query?name=example.com&type=A"

IPv4

curl -vH "accept: application/dns-json" "https://45.11.45.11/dns-query?name=example.com&type=A"
curl -vH "accept: application/dns-json" "https://185.222.222.222/dns-query?name=example.com&type=A"

IPv6

看起来没有,2a09::2a11:: 并不能用。

Quad 101

https://101.101.101.101

无文档。

返回的 JSON 和相比其他家略有不同。

地区:TW

域名

curl -vH "accept: application/dns-json" "https://dns.twnic.tw/dns-query?name=example.com&type=A"

域名测试我没有成功,IP 倒是可以。

IPv4

curl -vH "accept: application/dns-json" "https://101.101.101.101/dns-query?name=example.com&type=A"

101.102.103.104 不能用。

IPv6

看起来没有,2001:de4::1012001:de4::102 并不能用。

NextDNS

https://nextdns.io

私人定制 DNS,免费每月 3000000 次查询,超过后可以继续应答,但是自定义规则失效。

地区:Global,似乎有 CN 节点。

域名

curl -vH "accept: application/dns-message" "https://dns.nextdns.io/c98785c/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB"

注意:c98785c 是一个临时 ID,一段时间后失效,要测试请访问其网站,获取一个零时 ID 并替换。
不支持 JSON API。

IPv4

似乎要 IP 白名单才能使用,但是并没有 IP 证书,所以不能用。

IPv6

虽然它会根据你的 ID 生成唯一 IPv6,例如 c98785c :2a07:a8c0::c9:785c 和 2a07:a8c1::c9:785c
但是并没有 IP 证书,所以不能用。