Crafting a DNS-over-HTTPS GET request manually
Let's say I want to create an external health check for AdGuard that exercises both the HTTP interface and the DNS resolution, because I do. Unlike Cloudflare, AdGuard doesn't take an easy name
parameter, and I found it quite difficult to find existing documentation on how to craft a DoH request manually. Here's how to do it in Python.
Requirements
- Python 3
- Ideally
dnspython
>= 2.2.0 (so, Ubuntu 22.04'spython3-dnspython
package will not work. Use pip or a python docker image). Earlier versions will work without settingid=0
. requests
for testing
One-liner
Change example.com
:
DOMAIN="example.com" python3 -c "import os, dns.message, requests, base64; req = dns.message.make_query(os.environ['DOMAIN'], 'A', id=0).to_wire(); print(base64.urlsafe_b64encode(req).decode('utf-8').rstrip('='))"
Script
Set DOMAIN environment variable before running:
import os
import dns.message
import requests
import base64
req_raw = dns.message.make_query(os.environ['DOMAIN'], 'A', id=0).to_wire()
req_str = base64.urlsafe_b64encode(req_raw).decode('utf-8').rstrip('=')
print("Query path and encoded string to use with a GET request to a DNS-over-HTTPS server:")
print("/dns-query?dns=" + req_str)
print("\nTesting query with Cloudflare...")
resp = requests.get("https://cloudflare-dns.com/dns-query?dns=" + req_str)
resp.raise_for_status()
msg = dns.message.from_wire(resp.content)
print("DNS response:")
print(msg)
Example output
$ DOMAIN=example.com python3 ./doh.py
Query path and encoded string to use with a GET request to a DNS-over-HTTPS server:
/dns-query?dns=AAABAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE
Testing query with Cloudflare...
DNS response:
id 0
opcode QUERY
rcode NOERROR
flags QR RD RA
;QUESTION
example.com. IN A
;ANSWER
example.com. 82324 IN A 93.184.216.34
;AUTHORITY
;ADDITIONAL
References
https://github.com/dohwg/draft-ietf-doh-dns-over-https/issues/30#issuecomment-345850479