How to Configure DNS over HTTPS (DoH) Using DNSCrypt-Proxy in OPNsense

Add more privacy by encrypting your DNS queries!

How to Configure DNS over HTTPS (DoH) Using DNSCrypt-Proxy in OPNsense Photo by Simon from Pixabay

Introduction

Historically, DNS is a service that was designed to be unencrypted. Whenever a device from your network is trying to go to a web address, it needs to determine the IP address of the website in order to access it. With the increasing levels of tracking and data sharing/selling, a growing awareness that having DNS traffic unencrypted is not a good idea from a privacy and security standpoint. ISPs and other entities are able to know which sites you visit even if all of your web traffic is encrypted.

Lately there has been a growing desire to encrypt DNS traffic as much as possible – an attempt to escape from some of the madness of increased data colllection and tracking. There are a number of ways DNS can be encrypted and there are various pros/cons to each. DNS over HTTPS (DoH) is quickly becoming a popular way to encrypt DNS traffic. Instead of sending DNS traffic on UDP port 53, it is sent over TCP port 443 just like all other encrypted web traffic. The DNS server has to support DoH in order for the DNS lookup to success.

Install the DNSCrypt-Proxy Plugin in OPNsense

When I first looked into configuring DoH in OPNsense, I saw some forum posts about how to do this by manually installing packages via SSH command line and tweaking the configuration. Since then, there is now a DNSCrypt-proxy plugin that can be installed which simplifies the process by exposing the configuration in the web GUI of OPNsense.

To install DNSCrypt-proxy in OPNsense, go to System > Firmware > Plugins. Click the “+” icon beside the os-dnscrypt-proxy plugin to begin the installation. There should be a new menu option under “Services” for “DNSCrypt-Proxy”.

Configuring DNSCrypt-Proxy

Go to the Services > DNSCrypt-Proxy > Configuration page to begin configuring DNSCrypt-proxy. You will need to check “Enable DNSCrypt-Proxy” to enable the service. For the “Listen Address”, it will be defaulted to 127.0.0.1:5353 for IPv4 DNS queries and [::1]:5353 for IPv6 queries (remember that [::1] in IPv6 is equivalent to localhost 127.0.0.1 in IPv4). If you wish to use the default Unbound DNS service in OPNsense, leaving these values at the default is ok.

Warning: If you are also using the multicast DNS (MDNS-Repeater) plugin in OPNsense, you will need to change the default DNSCrypt-proxy port of 5353 to something else. I am using 5300 to keep it similar the unencrypted port 53 of DNS. It is likely they chose 5353 as the default since it similar to 53, but they likely did not think about the conflicts when enabling the multicast DNS plugin (multicast DNS is designed to use port 5353).

If you are planning to exclusively use DNSCrypt-proxy, you could check the “Allow Privileged Ports” box and then change the “Listen Address” to use port 53. However, in my example I am using Unbound DNS so using DNSCrypt-proxy on port 53 is beyond the scope of this how-to. If you are not using IPv6, you could uncheck “Use IPv6 Servers” box. The next 5 checkboxes (“Use DNSCrypt Servers”, “Use DNS-over-HTTPS”, “Require DNSSEC”, “Require NoLog”, and “Require NoFilter”) I have checked except for “Use DNSCrypt Servers”. Since I am going to later choose specific DNS servers, none of these settings matter as stated in the DNSCrypt-proxy documentation. Those options are the filters used when you allow DNSCrypt-proxy to randomly choose the fastest DNS servers to allow you have control over the types of services you wish to use.

DNSCrypt-Proxy Settings

The “Fallback Resolver” value defaults to 9.9.9.9:53 which is for the Quad9 DNS service. You may change it to 1.1.1.1 if you prefer to use Cloudflare. This setting is used to obtain the IP addresses of upstream DNS resolvers in case the normal system DNS is not functioning properly. It is not used to resolve any other domain names that you wish to have encrypted. You may check the “Block IPv6” box if you are not using IPv6. The help information says that there could be a slight performance gain by disabling this option. I suppose that is due to the fact that it does not have to query any IPv6 servers when it is not necessary. It immediately returns a blank response. You may tweak any of the cache settings, but I left mine at the default settings. Finally, there is the “Server List” which allows you to manually specify servers rather than allow a random DNS server selection. I personally feel more comfortable knowing which servers my DNS queries are being performed. I picked Cloudflare and Quad9 since they seem to be trusted, well-known DNS providers. Note that you have to use the name of the server and not the IP addresses. The list of servers can be found here.

DNSCrypt-Proxy Settings

Configuring Unbound DNS (Optional)

If you wish to use Unbound DNS along with DNSCrypt-proxy, this is entirely possible. The main reason I chose to keep using Unbound DNS is that I have it set up to resolve hostnames on my local network. Unbound DNS also automatically advertises itself as the DNS server via DHCP for any LAN/VLAN networks you have set up to use DHCP. I do not know if DNSCrypt-proxy could also be configured to do so if you make it your sole DNS server for your network.

To make Unbound DNS work with DNSCrypt-proxy, go to Services > Unbound DNS > General. Since DNSCrypt-proxy supports DNSSEC, you can check “Enable DNSSEC Support” box if you do not already have it enabled for your existing DNS servers. I do not think this option is necessary since Unbound and DNSCrypt-proxy are running on the same machine. The most important thing is that you need to add the following section to your “Custom options” text box:

do-not-query-localhost: no
forward-zone:
name: "."
forward-addr: [email protected]

Make sure you are using the same port number in the “forward-addr” as you configured for your DNSCrypt-proxy. This will forward all of the DNS lookups from Unbound DNS from all of the devices on your network and send them to the DNSCrypt-proxy. You need to have DNSCrypt-proxy enabled and running before you save your changes because you will now be attempting to use the DNSCrypt-proxy service.

Unbound DNS Settings

Verify DoH is Configured Properly

Once I was able to get everything up and running, I wanted to verify that it is actually encrypting all of the DNS lookups. There are a number of ways you may try verifying DoH is configured properly. Many of these are described by the DNSCrypt-proxy wiki.

View the DNSCrypt-Proxy Logs

There is a setting called “Fallback Resolver” that allows unencrypted DNS queries, and I was afraid at first that if the DoH configuration was not working that it would fallback to using an unencrypted connection. The help information says it is only used get the IP address of the DNS resolver list. Upon reading more details here, it says the fallback server will not be used for any other queries so one should not have to worry about DNS queries leaking to the unencrypted resolver. Assuming that is accurate, you should be able to know if the DNS queries are encrypted if the results of the DNS queries are showing up in the DNSCrypt-proxy logs by going to Services > DNSCrypt-Proxy > Log File.

DNSCrypt-Proxy Query Log

Use SSH to Resolve a Hostname using the DNSCrypt-Proxy Command

If you are not satisfied with looking at the DNSCrypt-proxy logs, you could take another approach. In the example provided, I used Cloudflare as my DoH service provider. They provide some documentation on how to verify that DNSCrypt-proxy is running properly. Their example is written generically for those using DNSCrypt-proxy as a client that is installed on any supported platform. The same DNSCrypt-proxy client is used in OPNsense so the same concepts should apply.

If you log into your OPNsense router via SSH, you can run the following command:

dnscrypt-proxy -resolve cloudflare-dns.com

You should receive an output similar to the following:

Resolving [cloudflare-dns.com]

Domain exists:  yes, 3 name servers found
Canonical name: cloudflare-dns.com.
IP addresses:   2400:cb00:2048:1::6810:6f19, 2400:cb00:2048:1::6810:7019, 104.16.111.25, 104.16.112.25
TXT records:    -
Resolver IP:    172.68.140.217

The documentation does not state this, but I am assuming than an incorrect configuration would result in resolution of the domain name to fail. I am also assuming that if it resolves correctly, it is correctly using DNS over HTTPS to resolve the domain name and not using an unencrypted DNS service instead. I wish the documentation was more clear so that I can be assured DoH is configured properly.

I have noticed that if I try testing if DoH works with Cloudflare using their test site, it does not seem to properly detect that DoH is configured properly. I am thinking it is due to how I have my DNS set up in my home network. Since I am using Pi-hole which forwards to Unbound DNS on my OPNsense router and Unbound forwards to DNSCrypt-proxy which is also on my OPNsense router, I suspect that it may seem to Cloudflare that I am not using DoH because by the time the DNS response reaches my devices, it is no longer encrypted on my internal network. The clients in my network are not getting a direct response back from the Cloudfare DNS servers like it would if the web browser itself is configured to use DoH.

To test this theory, I set up Firefox to use DoH and it passed the tests. I feel fairly certain that the Cloudflare test will not work for my network-wide DoH configuration since DoH is not used in the internal network – only on the edge of the network on my router. For my purposes, I am ok with DNS being unencrypted internally and only encrypting all external DNS requests. It makes it easier to inspect the DNS traffic going through my network, and I can still benefit from DoH since the external DNS lookups are encrypted. Keep in mind that ISPs will still be able to see the IP addresses of where you visit, but it will be harder for them to track exactly where you are going since multiple websites can be hosted via the same IP address.

Temporarily Turn Off DNSCrypt-Proxy

One quick way to determine if your DNS lookups are being “leaked” out of your network is to turn off DNSCrypt-proxy after you have it configured properly. When you shut it down, all DNS lookups should fail when trying to open a website, for instance. Once you re-enable it, you should be able to resolve domain names again. If the DNS lookups are being leaked out of your network, you would still be able to access websites, etc. on your network. If that is the case, it means your devices are using an alternate DNS server to perform lookups.

In OPNsense, you can stop a service from running by going to the Lobby > Dashboard. You should be able to see that the DNSCrypt-Proxy service is running and be able to click the “Stop” button. You can also click the “Play” button to start the service again.

Packet Capture and Examine Outgoing Packets using Wireshark

One last thing you could try if you are super paranoid and/or more technical is to do a packet capture to ensure no DNS port 53 traffic is leaking out of your network. The only exception of unencrypted DNS traffic may be the fallback DNS server that is specified in the DNSCrypt-proxy settings, but that should only be used to get the IP's of other DNS resolvers. However, if that is happening, it could indicate that there is some configuration issue since the documentation states that the fallback server is only used when the normal means for obtaining the IP addresses of the DNS resolvers fail. OPNsense provides a mechanism to do a packet capture from the web GUI, but you will need an application like Wireshark to analyze the packets. At the time of this writing, I have not attempted to do so, but I wanted to mention this possibility for those who are technically curious (but if you are that technical, you likely do not need me to mention this possibility).