Stéphane Bortzmeyer

Quad9, a Public DNS Resolver - with Security

Stéphane Bortzmeyer

12 min read

1 You have liked this article 0 times.

Quad9 is a public DNS resolver, with promises of better privacy, and a DNS-over-TLS access.


Last week, the new DNS resolver Quad9 has been announced. It is a public DNS resolver with the additional benefit that it is accessible in a secure way over TLS (RFC 7858).

There are plenty of public DNS resolvers. The best known one is Google Public DNS, but there are many others, each of them with different policies and technical features. The fact that so many users blindly use Google Public DNS, despite the huge amount of data that Google already collects about us, is worrisome. But there is also a technical problem, common to most public resolvers: the link to them is not secure. This allows hijackings, as seen in Turkey, as well as third-party monitoring.

The new Quad9 service on the other hand is operated by the not-for-profit Packet Clearing House (PCH), which manages large parts of the DNS infrastructure, and it allows access to the DNS over TLS. This makes it very difficult for third parties to listen in. And it makes it possible to authenticate the resolver (I have not yet tested this yet, Quad9 does not seem to distribute its public keys in an authenticated way, but they plan to do so).

Note that Quad9 claims not to store your IP address. Also note that their resolver is sometimes lying: it does not (deliberately) provide an answer for domain names that are considered to be related to harmful activities like malware distribution. You can have a non-lying resolver by using other addresses, but then you lose DNSSEC. In that case Quad9 uses an indication of the client's network (see RFC 7871), a bad privacy practice. Hopefully we will soon have an address for non-false responses, with DNSSEC and without indication of the customer's network.

Now, let's move on to practice on a Unix machine. The IPv4 address of Quad9, as the name implies, is Its IPv6 address is 2620:fe::fe (see the FAQ). First, let's start with classic UDP access:

% dig +nodnssec @ AAAA   

; <<>> DiG 9.10.3-P4-Ubuntu <<>> +nodnssec @ AAAA
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11544
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

; EDNS: version: 0, flags:; udp: 4096

;; ANSWER SECTION:		1325 IN	AAAA 2001:1900:3001:11::2c

;; Query time: 4 msec
;; WHEN: Thu Nov 16 09:49:41 +08 2017
;; MSG SIZE  rcvd: 65

This shows that Quad9 validates with DNSSEC (the answer contains the AD - Authentic Data - bit).

If the domain is on the blacklist of Quad9 (thanks to Xavier Claude for having found such a name to test), the resolver answers with NXDOMAIN (No Such Domain - this domain does not exist):

%  dig @

; <<>> DiG 9.10.3-P4-Debian <<>> @
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 1143
;; flags: qr rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

; EDNS: version: 0, flags: do; udp: 4096
;	IN A

;; Query time: 17 msec
;; WHEN: Sat Nov 18 20:30:41 CET 2017
;; MSG SIZE  rcvd: 45

(With a non-lying resolver, we would have gotten the NOERROR return code and the IP address

Now let's test the important benefit of this service, DNS over TLS. It's TLS so we can go with openssl:

% openssl s_client -connect \[2620:fe::fe\]:853 -showcerts
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN =
verify return:1
Certificate chain
 0 s:/
   i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
   i:/O=Digital Signature Trust Co./CN=DST Root CA X3
Server certificate
issuer=/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
Peer signing digest: SHA512
Server Temp Key: ECDH, P-256, 256 bits
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384

We see that Quad9 responds well in TLS, and that it has a Let's Encrypt certificate.

Next, let's test the getdns_query programme distributed with getdns:

% getdns_query @ -s -l L AAAA
  "answer_type": GETDNS_NAMETYPE_DNS,
  "canonical_name": <bindata for>,
      "address_data": <bindata for 2001:67c:2218:30::24>,
      "address_type": <bindata of "IPv6">

Yes, getdns_query is very talkative. The -l L option tells it to use DNS over TLS.

I've also used tshark to check that we are actually using TLS:

% tshark -n -i wlp2s0  -d tcp.port==853,ssl host 
Capturing on 'wlp2s0'
1 0.000000000 →      TCP 74 37874 → 853 [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=233018174 TSecr=0 WS=128
2 0.002518390 → TCP 74 853 → 37874 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 SACK_PERM=1 TSval=873811762 TSecr=233018174 WS=256
3 0.002551638 →      TCP 66 37874 → 853 [ACK] Seq=1 Ack=1 Win=29312 Len=0 TSval=233018175 TSecr=873811762
4 0.002642065 →      SSL 371 Client Hello
5 0.022008585 → TLSv1.2 1514 Server Hello
6 0.022042645 →      TCP 66 37874 → 853 [ACK] Seq=306 Ack=1449 Win=32128 Len=0 TSval=233018180 TSecr=873811781
7 0.022050371 → TLSv1.2 108 [TCP Previous segment not captured] , Ignored Unknown Record
8 0.022054712 →      TCP 78 [TCP Window Update] 37874 → 853 [ACK] Seq=306 Ack=1449 Win=35072 Len=0 TSval=233018180 TSecr=873811781 SLE=2897 SRE=2939
9 0.022667110 → TCP 1514 [TCP Out-Of-Order] 853 → 37874 [ACK] Seq=1449 Ack=306 Win=30208 Len=1448 TSval=873811781 TSecr=233018175
10 0.022679278 →      TCP 66 37874 → 853 [ACK] Seq=306 Ack=2939 Win=37888 Len=0 TSval=233018180 TSecr=873811781
11 0.023537602 →      TLSv1.2 192 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
12 0.037713598 → TLSv1.2 117 Change Cipher Spec, Encrypted Handshake Message
13 0.037888417 →      TLSv1.2 225 Application Data
14 0.093441153 → TCP 66 853 → 37874 [ACK] Seq=2990 Ack=591 Win=31232 Len=0 TSval=873811853 TSecr=233018184
15 0.742375719 → TLSv1.2 178 Application Data

The -d tcp.port == 853, ssl is there to tell tshark to interpret everything that goes through port 853 (DNS-over-TLS) as TLS. We can see the TLS dialogue, but obviously not the DNS queries and answers since everything is encrypted.

Now that these tests have been going well, let's use Quad9 for true name resolution. We will use Stubby to talk to Quad9. The Stubby configuration file looks like this:

  - 0::1@8053


# Quad9
   - address_data:
     tls_auth_name: ""
   - address_data: 2620:fe::fe
     tls_auth_name: ""

Stubby is told to listen to the local address ::1 on port 8053, and to forward DNS queries over TLS to or to 2620:fe::fe. Then we launch Stubby:

% stubby
[12:28:10.942595] STUBBY: Read config from file /usr/local/etc/stubby/stubby.yml
[12:28:10.942842] STUBBY: Starting DAEMON....

And we can test it, using dig to query the specified address and port:

% dig @::1 -p 8053 A 

; <<>> DiG 9.10.3-P4-Ubuntu <<>> @::1 -p 8053 A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20910
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

; EDNS: version: 0, flags: do; udp: 65535
;	IN A


;; Query time: 974 msec
;; SERVER: ::1#8053(::1)
;; WHEN: Thu Nov 16 20:29:26 +08 2017
;; MSG SIZE  rcvd: 77

We can then check with tshark or tcpdump that Stubby does speak with Quad9, and that it is using TLS.

Stubby has the advantage of managing TCP well, especially by reusing connections (it would be very expensive to establish a TCP connection for each DNS query, especially over TLS). But it does not cache the answers, which can be annoying if you're far away from the Quad9 server. In that case, it's best to add a real resolver, for instance Unbound. It is configured as follows:

   do-not-query-localhost:  no
  name: "."
    forward-addr: ::1@8053

With this configuration, Unbound will listen on (on the default port, 53, the DNS port) and relay the queries for which it does not already have an answer in its cache to Stubby (::1, port 8053). So, let's ask Unbound:

% dig @ A

; <<>> DiG 9.10.3-P4-Ubuntu <<>> @ A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40668
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

; EDNS: version: 0, flags: do; udp: 4096
;	IN A


;; Query time: 2662 msec
;; WHEN: Thu Nov 16 20:36:09 +08 2017
;; MSG SIZE  rcvd: 64

Unbound has a memory (the cache) so if we send the query again, the answer will arrive much faster and we will see the TTL (here 600 seconds) decreased.

If you find that all this is very complicated to install or configure, you can use a Docker image, contributed by Juzam (also available on GitHub).

Note that it is not easy to find an IPv4 address that is so easy to remember as DNSDB shows that this address has been used a lot before arriving at PCH, and partially for activities that some may find questionable. This IP address is blacklisted in several places. If that does not work for you, talk to your provider, or try Quad9 over IPv6. We can see this imperfect connectivity by testing with RIPE Atlas and the atlas-resolve programme, comparing Quad9 and Google Public DNS:

% atlas-resolve -r 200 -e --nsid -t AAAA
[ERROR: SERVFAIL] : 1 occurrences
[TIMEOUT] : 9 occurrences
[2001:1900:3001:11::2c] : 177 occurrences
Test #10205081 done at 2017-11-16T01:41:40Z

% atlas-resolve -r 200 -e -g 10205081 --nsid -t AAAA
[TIMEOUT] : 1 occurrences
[2001:1900:3001:11::2c] : 186 occurrences
Test #10205089 done at 2017-11-16T01:46:38Z

 The situation is better with IPv6, this time on par with Google (the second IPv6 test):

% atlas-resolve -6 -r 200 -e 2620:fe::fe -t AAAA
Nameserver 2620:fe::fe
[TIMEOUT(S)] : 5 occurrences
[2001:1900:3001:11::2c] : 191 occurrences
Test #10268718 done at 2017-11-20T15:15:32Z

% atlas-resolve -6 -r 200 -e 2001:4860:4860::8888 -t AAAA
Nameserver 2001:4860:4860::8888
[TIMEOUT(S)] : 6 occurrences
[2001:1900:3001:11::2c] : 190 occurrences
Test #10268732 done at 2017-11-20T15:19:27Z

Many thanks to Sara Dickinson for her technical help.


This article was first published in French on my personal blog.



1 You have liked this article 0 times.

You may also like

View more

About the author

Stéphane Bortzmeyer Based in Paris (France)

I work at AFNIC (the registry of .fr domain names), in the R&D department, on, among other things, DNS, security, statistics.

Comments 7