Securing DNS at system level with DNS proxy

The problem with DNS queries

So, why would you need to change your DNS settings in the first place? DNS is a service designed in the 1980s, a time when privacy and security were not much of a concern.

You must know that, each time you request a server on the Internet – for example galactic-cats.meow –, your OS asks for a DNS server to resolve the domain name, that is to "translate" galactic-cats.meow to an IP address like 28.224.10.97 (an IPv4 in this case).

┌─────────────────────────────────────────────────┐
│ Local computer                                  │
│                                                 │
│  ┌───────────────────────────────────────────┐  │
│  │ Web browser                               │  │
│  │                                           │  │
│  │ Go to https://galactic-cats.meow          │  │
│  └──────────────────────────┬──▲─────────────┘  │
│                             │  │                │
│   (1)                       │  │                │
│   What is the IP address of │  │ (4)            │
│   galactic-cats.meow?       │  │ 28.224.10.97   │
│                             │  │                │
│                             │  │                │
│  ┌──────────────────────────▼──┴─────────────┐  │
│  │ OS' DNS resolver                          │  │
│  │                                           │  │
│  │ Primary: 90.32.134.76                     │  │
│  └──────────────────────────┬───▲────────────┘  │
│                             │   │               │
└─────────────────────────────┼───┼───────────────┘
    (2)                       │   │
    What is the IP address of │   │ (3)
    galactic-cats.meow?       │   │ 28.224.10.97
    (clear text)              │   │
                              │   │
                       ┌──────▼───┴───────┐
                       │ Classic insecure │
                       │ DNS server       │
                       │                  │
                       │ 90.32.134.76     │
                       └──────────────────┘

This request is not encrypted. So the problem with unencrypted requests is that they can be:

  • monitored to know what host you visit. galactic-cats.meow can be OK in some states or organizations, but not in others who do not like cats.
  • modified by a middleman (man-in-the-middle attack) or the server itself; i.e., instead of responding 28.224.10.97, it would respond 12.34.56.78, which possibly be controlled by the same attacker for phishing attempts
  • just simply blocked by the server, typically in case of censorship

The solution

One way to solve this problem is to use an encrypted DNS, designed in the 2010s, 30 years after the good old "classic" DNS.

Now, since your OS probably does not support those encrypted DNS yet, you need some kind of bridge between these two worlds. And here comes DNS proxy into place, a tool written in Go described as the following by its developer AdGuard:

Simple DNS proxy with DoH, DoT, DoQ and DNSCrypt support

Okay. Lots of acronyms here. Let's try to break down those terms to understand:

  • DoH (DNS over HTTPS)
    • protocol that encrypts DNS queries using the HTTPS protocol, which is the same protocol used for secure web browsing
    • uses TCP port 443, the standard port for HTTPS traffic, which makes it difficult for ISPs and organizations to block or manipulate DNS queries
  • DoT (DNS over TLS)
    • protocol that encrypts DNS queries using the TLS protocol, which is the same protocol used to secure HTTP
    • uses TCP port 853, a dedicated port for DNS over TLS traffic, which makes it a bit easier for ISPs and organizations to just block the port
  • DoQ (DNS over QUIC)
    • protocol that encrypts DNS queries using the QUIC (Quick UDP Internet Connections) protocol.
    • uses UDP port 784, a dedicated port for DNS over QUIC traffic, which is designed to be faster and more efficient than TCP
  • DNSCrypt
    • older protocol that encrypts DNS queries using a combination of elliptic curve cryptography and the UDP protocol
    • uses UDP port 443, but it can also use other ports
    • is not as widely supported as DoH or DoT

What you just need to understand is that, basically, the DNS queries in cleartext will be encapsulated in some secured channels.

               ┌─────────────────────────────────────────────────┐
               │ Local computer                                  │
               │                                                 │
               │  ┌───────────────────────────────────────────┐  │
               │  │ Web browser                               │  │
               │  │                                           │  │
               │  │ Go to https://galactic-cats.meow          │  │
               │  └──────────────────────────┬──▲─────────────┘  │
               │                             │  │                │
               │   (1)                       │  │                │
               │   What is the IP address of │  │ (8)            │
               │   galactic-cats.meow?       │  │ 28.224.10.97   │
               │                             │  │                │
               │                             │  │                │
               │  ┌──────────────────────────▼──┴─────────────┐  │
               │  │ OS' DNS resolver                          │  │
               │  │                                           │  │
               │  │ Primary: 127.0.0.1                        │  │
               │  └──────────────────────────┬──▲─────────────┘  │
               │                             │  │                │
               │   (2)                       │  │                │
               │   What is the IP address of │  │ (7)            │
               │   galactic-cats.meow?       │  │ 28.224.10.97   │
               │                             │  │                │
               │                             │  │                │
               │  ┌──────────────────────────▼──┴─────────────┐  │
               │  │ DNS proxy                                 │  │
               │  │                                           │  │
               │  │ Listens on 127.0.0.1                      │  │
               │  │ Bootstrap: 90.32.134.76                   │  │
               │  │ Upstream: https://doh.my-dns-server.com   │  │
               │  └───────┬───▲────────────────┬────▲─────────┘  │
               │          │   │                │    │            │
               └──────────┼───┼────────────────┼────┼────────────┘
(3)                       │   │                │    │
What is the IP address of │   │ (4)            │    │
doh.my-dns-server.com?    │   │ 56.33.219.60   │    │
(clear text)              │   │                │    │
                          │   │                │    │
                   ┌──────▼───┴───────┐        │    │
                   │ Classic insecure │        │    │
                   │ DNS server       │        │    │
                   │                  │        │    │
                   │ 90.32.134.76     │        │    │
                   └──────────────────┘        │    │
                                               │    │
                     (5)                       │    │
                     What is the IP address of │    │ (6)
                     galactic-cats.meow?       │    │ 28.224.10.97
                     (encrypted)               │    │
                                               │    │
                                   ┌───────────▼────┴──────────────┐
                                   │ Modern secure                 │
                                   │ DNS server (DoH)              │
                                   │                               │
                                   │ https://doh.my-dns-server.com │
                                   │ 56.33.219.60                  │
                                   └───────────────────────────────┘

Installing DNS proxy

Windows

scoop install dnsproxy

macOS

brew install dnsproxy

Linux

🤷‍♂️

Configuring DNS proxy

~/.config/dnsproxy-config.yaml:

---
bootstrap:
  - 192.168.1.1  # use the DNS provided by your DHCP server, or other public DNS servers listed on https://public-dns.info/
listen-addrs:
  - 127.0.0.1  # only allow localhost to use this instance of dnsproxy
upstream:
  # add here one or several DoH/DoT/DoQ resolvers. You can find some public resolvers on https://opennic.org/ or https://github.com/curl/curl/wiki/DNS-over-HTTPS
  - tls://dot.bortzmeyer.fr
  - https://doh.bortzmeyer.fr
  - https://www.morbitzer.de/dns-query
  - https://dns.furrydns.de/dns-query
  - https://www.jabber-germany.de/dns-query
  - https://dns.kawa.tf/dns-query
  - https://ns1.opennameserver.org/dns-query
  - https://ns2.opennameserver.org/dns-query
  - https://ns3.opennameserver.org/dns-query
  - https://ns4.opennameserver.org/dns-query
timeout: 2s  # override the default value of 10s
verbose: false  # set it to `true` to debug the configuration

Running DNS proxy

Windows

dnsproxy --config-path=%USERPROFILE%\.config\dnsproxy-donfig.yaml

macOS

dnsproxy --config-path=~/.config/dnsproxy-donfig.yaml

Linux

🤷‍♂️

Configuring your OS to use DNS proxy

Now, you have to tell your OS to use DNS proxy instead of the (insecure) DNS provided by your DHCP server.

To do so, just make your network interface use localhost, that is to say use 127.0.0.1.

Windows

Windows 10

  1. Open the Network & Internet status page
   ms-settings:network-status
  1. Click Properties
  2. Under IP settings, click Edit
  3. Choose Manual
  4. Enable IPv4
  5. Enter 127.0.0.1 in Preferred DNS, and leave every other field empty
  6. Click Save

Windows 11

🤷‍♂️

macOS

🤷‍♂️

Linux

🤷‍♂️

Conclusion

From now on, you should have a running secure DNS resolver on your machine. To go further, you can encapsulate this in a service that will start automatically when your machine boots up.