Lucas' Blog

Privacy on the internet is a big deal and it seems like all anyone ever talks about is VPNs. There is something else that you should pay attention to and that is your DNS server. This shows you how to encrypt your DNS on macOS.

Published by Lucas Burns on

Install Stubby and DNSMasq on macOS

Lucas Burns

Installing Stubby and DNSMasq on macOS

If you know anything about privacy on the internet, you've probably heard of a VPN and could be using one to view this web page. However, one thing that I hadn't heard much about was Domain Name System (DNS) encryption. It is what allows you to view web pages in your browser by converting domain names into IP addresses. For example, the URL of the web page you are viewing right now is on a subdomain of https://lmburns.com. The browser you are viewing this in converted the URL into this IP address: 144.202.14.204. You can find the IP address of a URL by using one of the two following commands:

Using nslookup:

$ nslookup blg.lmburns.com

Server:     127.0.0.1
Address:    127.0.0.1#53

Non-authoritative answer:
Name:   lmburns.com
Address: 144.202.14.204

Or using dig:

$ dig lmburns.com

;; ANSWER SECTION:
lmburns.com.        10  IN  A   144.202.14.204

If your DNS is not encrypted, then all of your DNS queries are sent in plaintext, which means that your Internet Service Provider (ISP) is aware of, and has access to, all of the DNS queries that you make. This would mean that all of the websites that you have visited are available to anyone who decides to look at these queries. A VPN will mask your IP address and encrypt your connection; however, some VPNs still send your DNS queries your ISP in plaintext. To prevent this from happening it is best to use a DNS resolver that uses QNAME minimization. You can find providers at privacytools.io.

QNAME minimization prevents full DNS queries from being sent to the server you are connecting to by minimizing the amount of information that is sent between each query. An example of this can be explained when trying to connect to a long domain such as https://burnsac.blog.co.uk. QNAME minimization only allows domains that are next to one another to be able to talk to one another. So, the DNS resolver will ask for the top-level-domain of the site (.uk), which then asks for the secondary-domain of the site (.co.uk), and so on. Without QNAME minimization the full DNS query is known by your ISP.

Installing Stubby

Stubby is a program found on a wide range of distributions that allows one to encrypt their DNS queries.

Install Homebrew if you haven't already

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Install stubby

$ brew install stubby

Edit the configuration

$ nvim /usr/local/etc/stubby/stubby.yml

Configure the DNSs to use

There are a lot of servers to be used by default, just uncomment the ones that you would like to use. I chose to use NextDNS.

round_robin_upstreams: 0
upstream_recursive_servers:
  - address_data: 45.90.28.0
    tls_auth_name: "2798aa.dns1.nextdns.io"
  - address_data: 2a07:a8c0::0
    tls_auth_name: "2798aa.dns1.nextdns.io"
  - address_data: 45.90.30.0
    tls_auth_name: "2798aa.dns2.nextdns.io"
  - address_data: 2a07:a8c1::0
    tls_auth_name: "2798aa.dns2.nextdns.io"

Other settings I have enabled

resolution_type: GETDNS_RESOLUTION_STUB
dns_transport_list:
  - GETDNS_TRANSPORT_TLS
tls_authentication: GETDNS_AUTHENTICATION_REQUIRED
tls_query_padding_blocksize: 128
edns_client_subnet_private : 1
idle_timeout: 10000
listen_addresses:
  - 127.0.0.1@5590
  - 0::1@5590
dnssec: GETDNS_EXTENSION_TRUE

Choose a port to use, mine here is 5590.

Start stubby as a service

$ doas brew services start stubby

Check to see that Stubby is using the port you specified

Replace 5590 with the port number you chose:

$ doas lsof +c 15 -niP :5590

COMMAND   PID       USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
stubby  21935 lucasburns    3u  IPv4 0x945e158b6e92cf11      0t0  UDP 127.0.0.1:5590
stubby  21935 lucasburns    5u  IPv4 0x945e158b81ccf559      0t0  TCP 127.0.0.1:5590 (LISTEN)
stubby  21935 lucasburns    6u  IPv6 0x945e158b67235369      0t0  UDP [::1]:5590
stubby  21935 lucasburns    7u  IPv6 0x945e158b7b6bef29      0t0  TCP [::1]:5590 (LISTEN)

Installing DNSMasq

Install DNSMasq

$ brew install dnsmasq

Edit the configuration file

$ nvim /usr/local/etc/dnsmasq.conf

Uncomment the following line:

conf-dir=/usr/local/etc/dnsmasq.d

Create a configuration file for Stubby

$ nvim /usr/local/etc/dnsmasq.d/stubby.conf

Add the following lines, choosing whichever port number you chose to use with Stubby:

no-resolv
proxy-dnssec
server=::1#5590
server=127.0.0.1#5590
listen-address=::1,127.0.0.1

Start DNSMasq as a service

$ doas brew services start dnsmasq

Verify that DNSMasq is listening on the correct port

DNSMasq uses port 53, so to check that it is working, run:

$ doas lsof +c 15 -niP :53

COMMAND   PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
dnsmasq 24251 nobody    4u  IPv4 0x945e158b64fa9651      0t0  UDP 127.0.0.1:53
dnsmasq 24251 nobody    5u  IPv4 0x945e158b658f12e1      0t0  TCP 127.0.0.1:53 (LISTEN)
dnsmasq 24251 nobody    6u  IPv6 0x945e158b64fa8ab1      0t0  UDP [::1]:53
dnsmasq 24251 nobody    7u  IPv6 0x945e158b7b6c0249      0t0  TCP [::1]:53 (LISTEN)

Change your network's DNS server

You can set the DNS servers by doing one of the two following commands:

# 1
$ doas /usr/local/opt/stubby/sbin/stubby-setdns-macos.sh

# 2
$ networksetup -setdnsservers Wi-Fi 127.0.0.1 ::1

You can reverse this by doing one of the two following commands:

# 1
$ doas /usr/local/opt/stubby/sbin/stubby-setdns-macos.sh -r

# 2
$ networksetup -setdnsservers Wi-Fi empty

To confirm that the servers are configured correctly run one of the two following commands:

# 1
$ doas /usr/local/opt/stubby/sbin/stubby-setdns-macos.sh -l

# 2
$ networksetup -getdnsservers Wi-Fi

127.0.0.1
::1

Verify that all requests are using the loopback address 127.0.0.1

$ scutil --dns

DNS configuration

resolver #1
  search domain[0] : Home
  nameserver[0] : 127.0.0.1
  nameserver[1] : ::1
  flags    : Request A records, Request AAAA records
  reach    : 0x00030002 (Reachable,Local Address,Directly Reachable Address)

Test that QNAME minimization is working

$ dig +short txt qnamemintest.internet.nl

a.b.qnamemin-test.internet.nl.
"HOORAY - QNAME minimisation is enabled on your resolver :)!"

Test DNSSEC validation

$ dig +dnssec lmburns.com

;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45864
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
...
lmburns.com.        30  IN  RRSIG   A 13 2 10 20210325000000 202103

Check for ad, NOERROR and RRSIG to confirm DNSSEC validation is working.

Test encrypted DNS in your browser on Cloudflare

Go to their website and click ‘Check Browser’

Tags: command-linemacOSencryptionDNS.

Comments: