DNS-over-HTTPS Introduction and Implementation

Introduction

I’ve introduced the potential flaws of regular DNS queries and responses protocol and a practical solution to address it, which is called ‘DNS-over-TLS protocol’, in the most recent post: DNS-over-TLS Introduction and Implementation. However, since messages are transmitting through an uncommon port 853, public DNS servers implementing ‘DNS-over-TLS protocol’ are likely to be detected and restricted by controlling TCP traffics on that port.

Thus, introduced in RFC 8484, another protocol called ‘DNS-over-HTTPS’ was designed by researchers, which runs on common port 443. By implementing this protocol, all DNS messages are transmitted through regular HTTP requests and encrypted with SSL.

Technical details

HTTP method

GET

Using the GET method can reduce latency, as it is cached more effectively. GET requests must have a “?dns=” url parameter with a Base64Url encoded DNS message.

For instance, if you are using Google Public DNS as your DNS-over-HTTPS server, here’s the structure of your GET query:

  • method = GET
  • scheme = https
  • authority = dns.google
  • path = /dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB

Thus, the url of the query above is: https://dns.google /dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB

POST

The POST method uses a binary DNS message with Content-Type “application/dns-message” in the request body and in the DoH HTTP response.

For instance, if you are using Google Public DNS as your DNS-over-HTTPS server, here’s the structure of your POST query:

  • method = POST
  • scheme = https
  • authority = dns.google
  • path = /dns-query
  • accept = application/dns-message
  • content-type = application/dns-message
  • content-length = 33

Python implementation

To implement a DNS-over-HTTPS client, http.client module provided by Python could be used to establish an HTTPS connection with DNS server and transmit messages. To make regular Base64 string URL compatible, we should alter it slightly by deleting ‘=’, replacing ‘+’ with ‘-‘, replacing ‘/’ with ‘_’.

import http.client


class HTTPSUpstream:
    def __init__(self, client, port, upstream_url, https_connection):
        self.client = client
        self.port = port
        self.upstream_url = upstream_url
        self.https_connection = https_connection

    def query(self, query_data):
        base64_query_string = self.struct_query(query_data)
        base64_query_string = base64_query_string.replace('=', '')
        base64_query_string = base64_query_string.replace('+', '-')
        base64_query_string = base64_query_string.replace('/', '_')
        print('base64_query_string:', base64_query_string)

        query_parameters = "?dns=" + base64_query_string + "&ct=application/dns-message"
        query_url = '/dns-query' + query_parameters
        query_headers = {'host': self.upstream_url}
        self.https_connection.request('GET', query_url, headers=query_headers)
        response_object = self.https_connection.getresponse()
        query_result = response_object.read()
        print('response:', query_result)

    @staticmethod
    def struct_query(query_data):
        base64_query_data = base64.b64encode(query_data)
        base64_query_string = base64_query_data.decode("utf-8")

        return base64_query_string

For using the class implemented above, simply replace the variable ‘query_data’ with other plain DNS query messages.

query_data = b''  # plain DNS query data
https_connection = http.client.HTTPSConnection('8.8.8.8', 443, timeout=10)
upstream_object = HTTPSUpstream(, 53, 'dns.google', https_connection)
upstream_object.query(query_data)

References

DNS-over-TLS Introduction and Implementation: https://siujoeng-lau.com/2019/08/dns-over-tls/

RFC 8484: https://tools.ietf.org/html/rfc8484

DNS-over-HTTPS Wikpedia: https://en.wikipedia.org/wiki/DNS_over_HTTPS

DNS-over-HTTPS Introduction by Google Public DNS: https://developers.google.com/speed/public-dns/docs/doh/

Cloudflare DoH service: https://developers.cloudflare.com/1.1.1.1/dns-over-https/

Published by

Siujoeng Lau

Liberty will never perish.

2 thoughts on “DNS-over-HTTPS Introduction and Implementation”

Leave a Reply

Your email address will not be published. Required fields are marked *