Traditional DNS queries and replies are sent over UDP or TCP without encryption, making them subject to surveillance, spoofing, and DNS-based Internet filtering. Responses to clients from public resolvers like Google Public DNS are especially vulnerable to this, as messages may pass through many networks, while messages between recursive resolvers and authoritative name servers often incorporate additional protections.
To address these issues, in 2016 we launched DNS over HTTPS (now called DoH) offering encrypted DNSSEC-validating DNS resolution over HTTPS and QUIC. And in 2019, we added support for the DNS over TLS (DoT) standard used by the Android Private DNS feature.
DoH and DoT enhance privacy and security between clients and resolvers, complementing Google Public DNS validation of DNSSEC to provide end-to-end authenticated DNS for DNSSEC-signed domains. With Google Public DNS, we’re committed to providing fast, private, and secure DNS resolution for both DoH and DoT clients.
Supported TLS versions and crypto suites
Google Public DNS supports TLS 1.2 and TLS 1.3 for both DoH and DoT; no earlier versions of TLS or SSL are supported. Only cipher suites with forward security and Authenticated Encryption with Additional Data (AEAD) are supported. Qualys SSL Labs shows the current set of supported cipher suites.
Endpoints
Google Public DNS uses the following endpoints for DoH and DoT:
DoT (port 853) dns.google
DoH (port 443) URI templates
RFC 8484 –
https://dns.google/dns-query{?dns}
- For POST the URL is just
https://dns.google/dns-query
and the body of the HTTP request is the binary UDP DNS payload with content type application/dns-message. - For GET this is
https://dns.google/dns-query?dns=
BASE64URL_OF_QUERY.
- For POST the URL is just
JSON API –
https://dns.google/resolve{?name}{&type,cd,do,…}
- More GET parameters are described on the
JSON API page.
Only the
name
parameter is required.
- More GET parameters are described on the
JSON API page.
Only the
Clients
There are a number of client applications that use DoT or DoH
- Android 9 (Pie) “Private Browsing” feature – DoT
- Intra (Android app) – DoH
The dnsprivacy.org website lists several other clients for DoT and DoH, but these typically require moderately technical configuration.
Command-line examples
The following command-line examples are not intended for use in an actual client and are merely illustrations using commonly available diagnostic tools.
DoT
The following commands require Knot DNS kdig
2.3.0 or later; with 2.7.4 or
later, uncomment the +tls‑sni
to send SNI as required by TLS 1.3.
kdig -d +noall +answer @dns.google example.com \
+tls-ca +tls-hostname=dns.google # +tls-sni=dns.google
;; DEBUG: Querying for owner(example.com.), class(1), type(1), server(dns.google), port(853), protocol(TCP) ;; DEBUG: TLS, imported 312 system certificates ;; DEBUG: TLS, received certificate hierarchy: ;; DEBUG: #1, C=US,ST=California,L=Mountain View,O=Google LLC,CN=dns.google ;; DEBUG: SHA-256 PIN: lQXSLnWzUdueQ4+YCezIcLa8L6RPr8Wgeqtxmw1ti+M= ;; DEBUG: #2, C=US,O=Google Trust Services,CN=Google Internet Authority G3 ;; DEBUG: SHA-256 PIN: f8NnEFZxQ4ExFOhSN7EiFWtiudZQVD2oY60uauV/n78= ;; DEBUG: TLS, skipping certificate PIN check ;; DEBUG: TLS, The certificate is trusted. ;; ANSWER SECTION: example.com. 2046 IN A 93.184.216.34
kdig -d +noall +answer @dns.google example.com \
+tls-pin=f8NnEFZxQ4ExFOhSN7EiFWtiudZQVD2oY60uauV/n78= \
# +tls-sni=dns.google
;; DEBUG: Querying for owner(example.com.), class(1), type(1), server(dns.google), port(853), protocol(TCP) ;; DEBUG: TLS, received certificate hierarchy: ;; DEBUG: #1, C=US,ST=California,L=Mountain View,O=Google LLC,CN=dns.google ;; DEBUG: SHA-256 PIN: lQXSLnWzUdueQ4+YCezIcLa8L6RPr8Wgeqtxmw1ti+M= ;; DEBUG: #2, C=US,O=Google Trust Services,CN=Google Internet Authority G3 ;; DEBUG: SHA-256 PIN: f8NnEFZxQ4ExFOhSN7EiFWtiudZQVD2oY60uauV/n78=, MATCH ;; DEBUG: TLS, skipping certificate verification ;; ANSWER SECTION: example.com. 5494 IN A 93.184.216.34
DoH
RFC 8484 POST
The Base64Url encoded string in this command is the DNS message sent by
dig +noedns example.test A
with the DNS ID field set to zero, as recommended
by RFC 8484 section 4.1. The shell command sends that DNS query as the
binary data body content, using the Content-Type application/dns-message
.
echo AAABAAABAAAAAAAAB2V4YW1wbGUEdGVzdAAAAQAB | base64 --decode |
curl -is --data-binary @- -H 'content-type: application/dns-message' \
https://dns.google/dns-query
HTTP/2 200 strict-transport-security: max-age=31536000; includeSubDomains; preload access-control-allow-origin: * date: Wed, 29 May 2019 19:37:16 GMT expires: Wed, 29 May 2019 19:37:16 GMT cache-control: private, max-age=19174 content-type: application/dns-message server: HTTP server (unknown) content-length: 45 x-xss-protection: 0 x-frame-options: SAMEORIGIN alt-svc: quic=":443"; ma=2592000; v="46,44,43,39"
RFC 8484 GET
The Base64Url encoded string in this command is the DNS message sent by
dig +noedns example.com A
with the DNS ID field set to zero. In this case it
is explicitly passed in the URL.
curl -i https://dns.google/dns-query?dns=AAABAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE
HTTP/2 200 strict-transport-security: max-age=31536000; includeSubDomains; preload access-control-allow-origin: * date: Wed, 29 May 2019 19:37:16 GMT expires: Wed, 29 May 2019 19:37:16 GMT cache-control: private, max-age=19174 content-type: application/dns-message server: HTTP server (unknown) content-length: 45 x-xss-protection: 0 x-frame-options: SAMEORIGIN alt-svc: quic=":443"; ma=2592000; v="46,44,43,39"
JSON GET
This uses the JSON API for DoH.
curl -i 'https://dns.google/resolve?name=example.com&type=a&do=1'
HTTP/2 200 strict-transport-security: max-age=31536000; includeSubDomains; preload access-control-allow-origin: * date: Thu, 30 May 2019 02:46:46 GMT expires: Thu, 30 May 2019 02:46:46 GMT cache-control: private, max-age=10443 content-type: application/x-javascript; charset=UTF-8 server: HTTP server (unknown) x-xss-protection: 0 x-frame-options: SAMEORIGIN alt-svc: quic=":443"; ma=2592000; v="46,44,43,39" accept-ranges: none vary: Accept-Encoding {"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": 10443,"data": "93.184.216.34"},{"name": "example.com.","type": 46,"TTL": 10443,"data": "a 8 2 86400 1559899303 1558087103 23689 example.com. IfelQcO5NqQIX7ZNKI245KLfdRCKBaj2gKhZkJawtJbo/do+A0aUvoDM5A7EZKcF/j8SdtyfYWj/8g91B2/m/WOo7KyZxIC918R1/jvBRYQGreDL+yutb1ReGc6eUHX+NKJIYqzfal+PY7tGotS1Srn9WhBspXq8/0rNsEnsSoA="}],"Additional":[]}
TLS 1.3 and SNI for IP address URLs
TLS 1.3 requires that clients provide Server Name Identification (SNI).
The SNI extension specifies that SNI information is a DNS domain (and not an IP address):
"HostName" contains the fully qualified DNS hostname of the server, as understood by the client. The hostname is represented as a byte string using ASCII encoding without a trailing dot. This allows the support of internationalized domain names through the use of A-labels defined in RFC5890. DNS hostnames are case-insensitive. The algorithm to compare hostnames is described in RFC5890, Section 2.3.2.4.
Literal IPv4 and IPv6 addresses are not permitted in "HostName".
These requirements can be hard to meet for DoH or DoT applications that want to take advantage of security improvements in TLS 1.3. Google Public DNS currently accepts TLS 1.3 connections that do not provide SNI, but we may need to change this for operational or security reasons in the future.
Our recommendations for DoT or DoH applications regarding SNI are the following:
- Send the dns.google hostname as SNI for any connections to the Google Public DNS DoT or DoH services.
- If no hostname is available (for example, in an application that is doing opportunistic DoT), it is better to send the IP address in the SNI rather than leave it blank.
- IPv6 addresses should appear in
[2001:db8:1234::5678]
bracketed form in theHost
header, but without brackets in the SNI.
DNS Response Truncation
Although Google Public DNS generally does not truncate responses to DoT and DoH queries, there are two circumstances when it does:
If Google Public DNS cannot get complete and un-truncated responses from authoritative name servers, it sets the TC flag in the response.
In cases where the DNS response (in binary DNS message form) would exceed the 64 KiB limit for TCP DNS messages, Google Public DNS may set the TC (truncation) flag if RFC standards require it to do so.
However, in these cases, there is no need for clients to retry using plain TCP or any other transport, since the result will be the same.