Return to Level1Techs.com

Infrastructure Series -- Taking DNS One Step Further - Full DNS Server infrastructure

table of contents

Introduction

So we are all familiar with my other post: Infrastructure Series -- Recursive DNS and Adblocking DNS over TLS w/NGINX

Obligatory shill of blog stream post: Phaselockedloopable- PLL’s continued exploration of networking, self-hosting and decoupling from big tech

As always check for updates in the second post :wink:

DoT is great but it can be messed with or blocked by denying port 853. So what can we do to get around this and what are our options.

Well lets make a full set of architecture. Lets do DoH and normal DNS via our NGINX server! Why not right? We already have the setup and the backbone.

Standard DNS

A standard DNS server is easy to host given our DoT setup. It really is as simple as created a entry for port 53 and TCP streaming it via the stream block. (please refer to DoT post)

   # Standard DNS Server
server {
   listen 53;
   listen [::]:53;
   error_log  /var/log/nginx/dns53.log info;
   proxy_pass dns;
}

Open the port on your node and DNS will be functioning when you point at its addresses after you restart nginx. It really is that simple.

BUT you will get DDOSd so here is the mitigation

Mitigating port 53 attacks.

If you want your linode to proxy 53 dns you need to TCP dump where the floods are coming from…

Establish throttling:

iptables -A INPUT -p udp -m hashlimit --hashlimit-srcmask 24 --hashlimit-mode srcip --hashlimit-upto 120/m --hashlimit-burst 30 --hashlimit-name DNSTHROTTLE --dport 53 -j ACCEPT
iptables -A INPUT -p udp -m udp --dport 53 -j DROP

Protect against string patterns that are actively flooding your server which are usually ICP and RIPE:

iptables -A INPUT -p udp -m string --hex-string "|00000000000103697363036f726700|" --algo bm --to 65535 --dport 53 -j DROP
iptables -A INPUT -p udp -m string --hex-string "|0000000000010472697065036e6574|" --algo bm --to 65535 --dport 53 -j DROP 

Limit Any queries and throttle to 120 per minute. If someone is pulling an ANY query more than a few times a minute they are fucking with you. its rarely needed

iptables -A INPUT -p udp --dport 53 -m string --from 50 --algo bm --hex-string '|0000FF0001|' -m recent --set --name dnsanyquery
iptables -A INPUT -p udp --dport 53 -m string --from 50 --algo bm --hex-string '|0000FF0001|' -m recent --name dnsanyquery --rcheck --seconds 60 --hitcount 4 -j DROP

New Pizza SEO Attacks

iptables -I INPUT 1 -d DNS_SERVER_IP_ADDRESS -p udp -m udp --dport 53 -m string --string "pizzaseo" --algo kmp --from 41 --to 48 -j NFLOG --nflog-prefix  "DROP PizzaSEO DDoS ATTACK Requests"
iptables -I OUTPUT 1 -s DNS_SERVER_IP_ADDRESS -p udp -m udp --sport 53 -m u32 --u32 "0x0>>0x16&[email protected]&0x8005=0x8005" -j NFLOG --nflog-prefix  "DROP OUTBOUND DNS Query Refused Response"

Disclaimer: *You should always apply to INPUT before FORWARD or OUTPUT

DoH + DoQ

We are going to use the DoH-Proxy software written in rust. Its well supported, fast, mature and secure.

I extracted this into /opt/doh-proxy/ and then I symlinked via sudo cp -s /opt/doh-proxy/doh-proxy /usr/bin/doh-proxy

chmod +x 'd the file to make sure it was executable and made a systemd process to start it

your systemd process shoud look like:

[Unit]
Description=This DoH-Proxy unit will start after internet connection
After=network.target
Wants=network-online.target
[Service]
Restart=on-failure
Type=simple
ExecStart=/usr/bin/doh-proxy -l 0.0.0.0:<listenport> -c 65534 -C 65534 -u IPofYOURDNSSERVER:53
KillSignal=SIGKILL
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=true
Restart=on-failure
RestartSec=30s
StartLimitBurst=3
StartLimitIntervalSec=0

[Install]
WantedBy=multi-user.target 

Bingo enable it, start it, check its status. It should be running

I created a configuration file called 98-dnsDoH.conf in the conf.d folder (sometimes called http.d)

# DoH Port 80
server {
    if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
        return 501;
    }
    listen 80;
    listen [::]:80;
    server_name dns.utangard.net;
    return 301 https://$server_name$request_uri;
}
# DoH Port 443
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    include /etc/nginx/headers.d/98-dnsDoHHeaders.conf; # Security headers   
    server_name dns.utangard.net;
    location /dns-query {
         proxy_set_header Host $http_host;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_redirect off;
         proxy_buffering off;
         proxy_pass http://dohproxy_backend;
    }
}

We want to return a 501/502 for any method that isnt explicitly after DNS to prevent anything useful from being extracted. Given that my server is listening on ipv6 primarily it is permissable to have the flag ipv6 only. You dont need my level of logging. I like to have it as insurance and helpful dianostics. so you can exclude error_log entries.

We want a location called /dns-query and we want the entries you see above. the proxy pass will point to a socket you have created and its name. In my case we see it below

    upstream dohproxy_backend {
       server localhost:<listenport_you_defined_in_systemd_process>;
    }

That pretty much covers it. Then just point all DoH resolvers towards the URL you defined it as. In my case
https://dns.utangard.net/dns-query

Which by the way if you visit in a browers it should error 40x out :wink:

Im prepared for DoQ but fedora’s nginx version doesnt support it yet. When they upgrade to 1.19 I will add to any HTTP2 a HTTP/3 optional svc block as you can see is commented out. Eventually though I will and it will be sweet to have QUIC support.

I like being ready to deply as soon as possible thats my philosophy its OKAY to not agree with it and be different.

Enabling it on devices

Im going to focus on enabling where its easy and relevant not so much every single combination of stuff

Windows

  1. On connections, open Settings > Network & Internet > Status.
  2. Click Properties and Select Edit IP assignment or Edit DNS server assignment.
  3. Enter the DNS server via the URL or IP of the server. Done. “Once encryption is enabled, you can confirm it’s working by looking at the applied DNS servers in the network properties and see them labelled as ‘(Encrypted)’ servers,” Which they will show as. I confirmed this works on the latest build of windows 10.

Apple devices

Anyone who would like to expand this via the following links please do. I dont support apple devices in anyway shape or form nor do I use them. So somebody will have to figure this out and add it :slight_smile:
First hits on google:

Happy hunting

Any OS/Desktop/Laptop (OS agnostic Browser Dependent)

Chrome (and subsequently anything chromium based):

Youll find this in the Privacy and security. Just use your server as custom

Firefox

On the desktop its in network settings. Firefox gets rather difficult on the mobile side. We will get to that. Use your URL as I mentioned before and it should work. Im not using it on this internal system but you could.

Android (Various Browsers)

Chrome/Chromium Based:
Easy peasy just go to privacy and security and they make it easy. LISTEN UP MOZILLA YOU NEED TO BE THIS GOD DAMN EASY.
Brave browser used for example: (its the same as chrome)


Thats all you need to do and it will utilize it.

Firefox: and OBLIGATORY RANT:

So mozilla seems to have the most unique talent of making everything possible a complete pain in the ass. I wont lie they are terrible about how they do things but I will show how to do this regardless. It works on ios and android BUT ONLY in the beta version or higher because for some god awful and quite dumb set of decision making they made it so you cannot access about:config on the normal release or the normal fdroid release. Honestly stop mozilla. Just stop being so crappy to your user base. It is any wonder why you have 6% market share. You suck. (at the time of writing this guide) Mozilla and DoH is always fun on mobile I guess.

Procedure:
Now once you have signed in and done your thing into Firefox beta. You will need to go to the about config page and I will screen shot the values you need. Use the search term network.trr first to limit the scope.

We want to set clean up and the bootstrap address. The bootstrap address is the IP you choose to use to bootstrap the trusted resolver to. In my case I chose 4 despite all my infrastructure being 6 as this will be most compatible with all setups.

setting network.trr.mode will set to always using DoH regardless. (2 is best effort)

The next stage is to set the URL to navigate to and to make sure we dont skip IPv6 lookups since mozillas detection of “when not supported” is COMPLETELY broke.

Firefox has one unique feature I give them credit for. Encrypted SNI. Enable it by setting this value to true or creating it

Then restart the browser and it should work. Firefox can be a total pain.

And bingo just like that we have a full DNS server

Conclusion to what we have

A DNS Server that has implemented the following:
Standard port 53 lookups anywhere via a publicly addressable server
A hardened DoT Server for port 853 DNS over TLS lookups
A hardened DoH Server to use DNS in the application layer to avoid blocking and censorship
DoQ optionally when its arrives for DNS over HTTPS via NGINX implementation

Now you have a server accessible via any method you want. This is currently what I have

Disclaimer:

Dont use my server because I wont whitelist a site for you. Make your own or expect breakage :wink:

Any services discovered in this guide are pursuant to the following Policy: Flame

Links to Infrastructure Series and Other Resources

Blog: Phaselockedloopable- PLL’s continued exploration of networking, self-hosting and decoupling from big tech

Phaselockedloopable- PLL’s continued exploration of networking, self-hosting and decoupling from big tech

Series 1: Native Dual Stack IP4+IP6

Infrastructure Series – Native Dual Stack IP4+IP6

Series 2: Wireguard Site to Site Tunnel

Infrastructure Series – Wireguard Site to Site Tunnel

Series 3: Recursive DNS and Adblocking DNS over TLS w/NGINX

Infrastructure Series – Recursive DNS and Adblocking DNS over TLS w/NGINX

Series 4: NGINX Reverse Proxy and Hardening SSL

Infrastructure Series – NGINX Reverse Proxy and Hardening SSL

Series 5: Taking DNS One Step Further - Full DNS Server infrastructure

Infrastructure Series – Taking DNS One Step Further - Full DNS Server infrastructure

Series 6: HTTP(S) Security Headers! You should use them!

Infrastructure Series – HTTP(S) Security Headers! You should use them! [NGINX]

Series 7: Use NGINX to inject CSS themes

Infrastructure Series – Use NGINX to inject CSS themes

ONE KEY TO RULE THEM ALL

Setting up a YubiKey Properly – One Key to rule them ALL!

Series 9: Infrastructure Series: BIND9 Authoritative DNS Guide “Please See Me Edition”

Infrastructure Series: BIND9 Authoritative DNS Guide “Please See Me Edition”

Buy me a crypto-beer

If you found this guide helpful you can donate Monero or Bitcoin to me at the following address in my User Card Profile

3 Likes

Reserved

UPDATED 2021-11-21T07:00:00Z

New DoH backend

1 Like