DoH接口说明

本文统一说明阿里云 HTTPDNS 的 DoH(DNS over HTTPS)端点、请求/响应格式、错误语义。

1. 前提条件

在完成配置DoH服务后,您可以通过直接调用DoH接口,获取解析 IP。

2. DoH接口说明

接口符合 RFC 8484 标准,支持 GET 与 POST 两种方式:GET 通过 dns 参数(Base64URL)提交 DNS 报文,POST 通过二进制请求体提交 DNS 报文。

2.1 GET 接口

用于通过 URL 查询参数传递 DNS 报文(Base64URL 编码),请求和响应如下:

请求

  • 方法:GET

  • 路径:/dns-query?dns=<base64url(dns_wire_message)>

  • 请求头:

    • Accept: application/dns-message

  • 查询参数:

    • dns(必填):DNS 二进制报文经 Base64URL 编码后的字符串(无 = 补位)。

响应

  • 200:成功,Body 为 application/dns-message(DNS 二进制应答)。

  • 400:参数错误(未开启 DoH、缺失/非法 dns 参数等)。

  • 5xx:服务端错误。

说明

对于不在解析域名列表的域名,DoH 会返回 200 的状态码但没有解析结果。

2.2 POST 接口

用于在请求体中直接传输 DNS 二进制报文,请求和响应如下:

请求

  • 方法:POST

  • 路径:/dns-query

  • 请求头:

    • Content-Type: application/dns-message

    • Accept: application/dns-message

  • 请求体:

    • DNS 二进制报文(wire format)。

响应

  • 200:成功,Body 为 application/dns-message(DNS 二进制应答)。

  • 400:参数错误(未开启 DoH 或报文非法)。

  • 5xx:服务端错误。

说明

对于不在解析域名列表的域名,DoH 会返回 200 的状态码但没有解析结果。

2.3 请求示例

下面以python为例,依赖网络库 dnspythonrequests,演示如何通过 DoH 请求,获取www.aliyun.com的解析结果。

GET请求示例

  • 示例代码

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import requests
    import base64
    import dns.message
    
    def query_doh(domain, rrType):
        # 创建DNS请求
        request = dns.message.make_query(domain, rrType)
        request_data = request.to_wire()
    
        # 将请求编码为base64URL格式
        base64_query = base64.urlsafe_b64encode(request_data).decode().rstrip("=")
    
        # 使用HTTPDNSDoH接入点
        url = f"https://1xxxx3.aliyunhttpdns.com/dns-query?dns={base64_query}"
    
        # 发送GET请求
        headers = {
            "Accept": "application/dns-message"
        }
        response = requests.get(url, headers=headers)
    
        # 错误检查
        if response.status_code != 200:
            print(f"Error: {response.status_code}")
            return
    
        # 解析响应
        response_data = response.content
        dns_response = dns.message.from_wire(response_data)
    
        # 提取和打印IP地址
        for answer in dns_response.answer:
            ttl = answer.ttl
            for item in answer.items:
                print(f"Answer: {item} TTL: {ttl}")
    
    if __name__ == "__main__":
        # 查询的域名
        domain = "www.aliyun.com"
        rrType = "A"
        query_doh(domain, rrType)
        
  • 预期结果

    Answer: www-jp-de-intl-adns.aliyun.com. TTL: 3600
    Answer: www-jp-de-intl-adns.aliyun.com.gds.alibabadns.com. TTL: 3600
    Answer: www.aliyun.com.w.cdngslb.com. TTL: 3600
    Answer: 61.164.xxx.xxx TTL: 3600
    Answer: 183.146.xxx.xxx TTL: 3600
    Answer: 60.188.xxx.xxx TTL: 3600
    Answer: 122.228.xxx.xxx TTL: 3600

POST请求示例

  • 示例代码

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import requests
    import dns.message
    
    def query_doh_post(domain, rrType):
        # 创建DNS请求
        request = dns.message.make_query(domain, rrType)
        request_data = request.to_wire()
    
        # 使用HTTPDNSDoH接入点
        url = "https://1xxxx3.aliyunhttpdns.com/dns-query"
    
        # 发送POST请求
        headers = {
            "Accept": "application/dns-message",
            "Content-Type": "application/dns-message"
        }
        
        # 直接发送DNS wire format数据作为POST body
        response = requests.post(url, headers=headers, data=request_data)
    
        # 错误检查
        if response.status_code != 200:
            print(f"Error: {response.status_code}")
            return
    
        # 解析响应
        response_data = response.content
        dns_response = dns.message.from_wire(response_data)
    
        # 提取和打印IP地址
        for answer in dns_response.answer:
            ttl = answer.ttl
            for item in answer.items:
                print(f"Answer: {item} TTL: {ttl}")
    
    if __name__ == "__main__":
        # 查询的域名
        domain = "www.aliyun.com"
        rrType = "AAAA"
        query_doh_post(domain, rrType)
        
  • 预期结果

    Answer: www-jp-de-intl-adns.aliyun.com. TTL: 120
    Answer: www-jp-de-intl-adns.aliyun.com.gds.alibabadns.com. TTL: 300
    Answer: www.aliyun.com.w.cdngslb.com. TTL: 120
    Answer: 240e:f7:7c00:xxxx:xxxx::xxxx TTL: 60
    Answer: 240e:f7:7c00:xxxx:xxxx::xxxx TTL: 60

    3. 总结

    本文介绍了HTTPDNS 提供的 DoH 接口,您可以参考接口说明和示例代码访问 DoH 接入点进行域名解析。