DNS over https (DOH) with quad9

Hello,

I unsuccessfully searched the mikrotik forum for a straight-to-the-objective how-to for this, but could not find one. Luckily, Quad9 created one:

Link to the article from the original author: “Zachary” from quad9
https://support.quad9.net/hc/en-us/articles/4616420178061-Setup-MikroTik-RouterOS-and-DNS-over-HTTPS

Copy of the article is attached below:

Introduction

This article describes how to configure your MikroTik router using RouterOS to send encrypted DNS queries to Quad9 using DNS over HTTPS.

RouterOS >=6.4.7 is required. These instructions were tested using RouterOS 7.1.3.

Steps

  1. Connect to your MikroTik router’s management interface via SSH or console. The username and password will be the same as if using Webfig (GUI).

  2. In order for MikroTik to perform certificate verification of the Quad9 DNS over HTTPS domain, we need to download and import the DigiCert Global Root CA certificate.

2.1 Download the certificate to your MikroTik router:

/tool/fetch mode=https url="https://support.quad9.net/hc/en-us/article_attachments/4618235579021/digicert-root-ca.pem"

2.2 Import the certificate into the local certificate store. When prompted for a passphrase, just hit enter for no passphrase:

/certificate/import file-name=digicert-root-ca.pem

2.3 The resulting output should be:

passphrase: 
certificates-imported: 1
private-keys-imported: 0
files-imported: 1
decryption-failures: 0
keys-with-no-certificate: 0
  1. Log into Webfig (GUI), and navigate to IP → DNS on the left-side menu.

  2. In the Servers field, set:

  9.9.9.9
    149.112.112.112
    2620:fe::fe
    2620:fe::9

Note: If your network does not have IPv6, which you can test here, then the IPv6 addresses should not be added, as it may result in a percentage of your DNS requests failing.

  1. Use DoH Server:
https://dns.quad9.net/dns-query
  1. Verify DoH Certificate: Enabled

  2. Allow Remote Requests: Enabled
    Note: It’s recommended to prevent non-local IP address from querying the MikroTik router directly by creating the appropriate firewall rules.

  3. Click Apply at the top.

Confirm Configuration

  1. To confirm that the MikroTik router is sending DNS queries to Quad9 using DNS over HTTPS, you can use the packet sniffer tool to filter for packets being sent to/from Quad9 IP addresses using port 443 (HTTPS):
tool/sniffer/quick port=443 ip-address=9.9.9.9,149.112.112.112
  1. If DNS queries sent to the MikroTik router are being forwarded to Quad9 using DNS over HTTPS, you will see any output:
tool/sniffer/quick port=443 ip-address=9.9.9.9,149.112.112.112
Columns: INTERFACE, TIME, NUM, DIR, SRC-MAC, DST-MAC, SRC-ADDRESS, DST-ADDRESS, PROTOCOL, SIZE, CPU
INTERFACE TIME NUM DIR SRC-MAC DST-MAC SRC-ADDRESS DST-ADDRESS PROTOCOL SIZE CPU
ether1 6.886 5 <- 04:F0:21:45:C9:0C 08:00:27:7D:3B:33 9.9.9.9:443 (https) 192.168.1.222:59348 ip:tcp 66 0
ether1 6.887 6 <- 04:F0:21:45:C9:0C 08:00:27:7D:3B:33 9.9.9.9:443 (https) 192.168.1.222:59348 ip:tcp 1514 0
ether1 6.887 7 -> 08:00:27:7D:3B:33 04:F0:21:45:C9:0C 192.168.1.222:59348 9.9.9.9:443 (https) ip:tcp 66 0
ether1 6.887 8 <- 04:F0:21:45:C9:0C 08:00:27:7D:3B:33 9.9.9.9:443 (https) 192.168.1.222:59348 ip:tcp 1514 0
ether1 6.887 9 -> 08:00:27:7D:3B:33 04:F0:21:45:C9:0C 192.168.1.222:59348 9.9.9.9:443 (https) ip:tcp 66 0
  1. If you do not yet have endpoints using the MikroTik router for DNS, you can manually query the MikroTik router to facilitate testing and checking for the output generated above from Terminal (Linux/macOS) or Command Prompt (Windows), replacing 192.168.1.1 with the LAN IP address of your MikroTik router.
nslookup quad9.net 192.168.1.1

https://help.mikrotik.com/docs/display/ROS/DNS#DNS-DNSoverHTTPS(DoH)

https://www.youtube.com/watch?v=w4erB0VzyIE

My recipe for DOH on MT for adguard. ( using normis, excellent video )
/ip dns
set allow-remote-requests=yes servers=94.140.14.15,94.140.15.16 use-doh-server=https://family.adguard-dns.com/dns-query verify-doh-cert=yes *****

The tricky part is the first part adding the CerT!!
Go to this website…
https://adguard-dns.io/en/welcome.html

Click on the LOCK SIGN right next to the URL itself.
Select “CONNECTION SECURE” in the popup.
Select “MORE INFORMATION” at the bottom of the popup!
In the next popup select the LOCK ICON SECURTY ( it should default to this selection )
Choose VIEW CERTIFICATE
Select the USERTRUST RSA certificate (far right option)
Scroll down to Miscellaneous and download the PEM (cert)

Upload the downloaded file into your files folder in MT device.
Then go to SYSTEM–> Certificates on MT
Use import function to select the certificate just uploaded and put in files.

Ensure the settings above are now entered. ******

Ensure no ISP dns dynamic servers are available.
Go to IP FIREWALL NAT
add chain=dstnat action=redirect protocol=tcp dst-port=53
add chain=dstnat action=redirect protocol=udp dst-port=53

DONE.

Hi,

I got working quad9 when I uploaded the full certificate chain. If I try to use single PEM, I get
“DoH server connection error: SSL: handshake failed: unable to get local issuer certificate (6)”
With adguard I did not have much luck, either family.adguard-dns.com or dns.adguard-dns.com,
either single PEM or chain, I got
“DoH server connection error: SSL: handshake failed: unable to get local issuer certificate (6)”
Software is on v6.49.7

BR

This thread helped me a lot, so I’ve embraced and extended this knowledge into something I’ve wanted to do for a very l-o-n-g time … switch-up DoH servers, so those providers lose some capability to data mine my queries. This is a script I run periodically, and it so far seems to work pretty well. The only lookups that happen on a clear-text server are one immediately after the switch — when the address of the DoH server has to be resolved. I’m not sure how to solve that, but it isn’t keeping me up at night.

P.S. I’d love to see anyone else’s list of DoH servers so I can expand what I’m using.

# List of (tested) public DoH providers
:local dohList {
"https://dns.quad9.net/dns-query";
"https://cloudflare-dns.com/dns-query";
"https://doh.opendns.com/dns-query";
"https://dns.google/dns-query";
"https://private.canadianshield.cira.ca/dns-query";
"https://doh.xfinity.com/dns-query";
"https://freedns.controld.com/p0";
"https://firefox.dns.nextdns.io";
}

# need zero-indexed value to pick from
:local ListMax ([len $dohList]-1);

# pick a random value and assign it to a var
:local RandNum [:rndnum 0 $ListMax];
:local ThePick [:pick $dohList $RandNum ($RandNum + 1)]

# execute the command to make the change
/ip/dns set use-doh-server="$ThePick" verify-doh-cert=yes

# log it
/log info "DoH server now $ThePick"

It is offtopic here, but I recommend using https://1.1.1.1/dns-query (Cloudflare).
Because it contains “IP address” it does not need standard DNS for the first connection.

This is the script I use for quad9:

{
  :do {
      /ip dns set servers=9.9.9.9,149.112.112.112 use-doh-server="https://dns.quad9.net/dns-query"
      /tool fetch url="https://support.quad9.net/hc/en-us/article_attachments/4618235579021/digicert-root-ca.pem" dst-path="digicert-root-ca.pem"
      /certificate remove [find where authority expired]
      /certificate import file-name="digicert-root-ca.pem"
      /file remove "digicert-root-ca.pem"
      /ip dns set verify-doh-cert=yes
      :log warning ("DoH certificate updated")
  } on-error={
      :log error ("Failed to update DoH certificate")
  }
}

Thanks for posting — FWIW, I specifically decided to rotate through a list of DoH providers instead of settling on one for the duration because I don’t want to trust any of them not to monetize the information about my lookups, even if it’s “in aggregate” and not easily linked directly to me by name. I figure with a list of eight randomly chosen servers, they get about 8-minutes worth of data per hour, then spend 52 minutes wondering if I’ve disconnected from the internet. (I run the script every 11 minutes so the timing of the change “walks” around the clock)

My quibble with using any IP address for the URL of a DoH provider is that it subverts certificate validation. You can’t validate an IP address even if the server there presents a valid cert. Getting a valid cert is simple and cheap enough to not be a barrier any more. But I don’t just care about the encryption, I care about the validation. Nobody, except maybe a government-level threat, is going to have a certificate matching the particular URL set up in the query. Per some steps I found at NextDNS for setting up their DoH provider on MikroTik I imported the CA roots used by ‘curl’ (it’s over 100! but I trust them to do appropriate vetting and the large community there to let me know if they pull a fast one) so I should be 5x5 for any legit DoH provider I encounter.

Checking the results of that in /System/Certificates for expirations it seems the SHORTEST expirations in my list are actually the self-signed root and Webfig certs which are good until 2033 … by which time if I’m still using this particular MikroTik confg I’d be pretty shocked because we’ll all be using 600Ghz WiFi 2∏6 or whatever. There’s one CA that has an expiration of 12K+ days, which is in like 2058. I’ll possibly be dead by then.

On my to-do list is : verifying no unexpected traffic is being sent on the WAN port to my ISP’s DNS servers. Then I’ll probably add a list of “normal” servers to randomly assign as /DNS/Static IPs to remove even that leak of information. As an additional protection I’m considering whether to try blocking common DoH providers from pass-through (but not the router as source) is worthwhile, but it would require maintaining a list over time and I’m not yet that paranoid.

Theoretically, it shouldn’t subvert validation. Whether Mikrotik looks at the specifically listed “IP address” fields in Cloudflare’s TLS cert, IDK – but IP address can be valid with TLS certs & Cloudflare’s cert has them.

Today my Mikrotik running V7.12.2 stopped validating Quad9 DOH server with the message:

DoH server connection error: SSL: ssl: no trusted CA certificate found (6)

To solve this, I was forced to remove the “old” DigiCert root certificate (that was still valid!) and install a brand new DigiCert Root Certificates downloaded from https://www.digicert.com/kb/digicert-root-certificates.htm.

Mauricio

Hi Mauricio,

Can you please specify the name/filename of the brand new certificate that solved the problem for you?
Best regards,

I double this, because https://cacerts.digicert.com/DigiCertGlobalRootCA.crt.pem did not work and shows an error.

you can see the chain on https://dns.quad9.net/dns-query site
see attach
Screenshot 2024-07-25 at 19-41-51 Certificate for dns.quad9.net.png

Hi!
Please, look for “DigiCert Global Root G3” (for both “dns” and “dns9” secured Quad9 servers). You may always check appropriate root certificate via your Internet browser (proceed with dns-server url and click on lock icon prior address bar).

Quad9 has updated instructions on their website now:
https://docs.quad9.net/Setup_Guides/Open-Source_Routers/MikroTik_RouterOS_(Encrypted)/