Table of Contents

Intelligent Recursive Query Routing

Overview

When running recursive DNS servers these days, you need to not only keep queries nice and quick, but also route certain queries to specific DNS servers (such as for DNSbl use). This configuration is a bit complicated, but sets up multiple pools of DNS servers for different tasks. It also enables DoH support for on-the-go DNS resolving without needing to open up your DNS servers to random querying.

Order of configuration is extremely important.

Configuration Breakdown

-- Local control socket
controlSocket('127.0.0.1:5199')
-- Only allow control from the local host
setConsoleACL('127.0.0.1/32')
-- Key needed for accessing the control socket
setKey("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
-- Local IPs and ports to listen on
setLocal('100.99.99.1')
addLocal('127.0.0.2')

-- DoH IP and key configuration.
-- Keys are in standard SSL/TLS style PEM format
-- Final quoted string is the URL path for queries
addDOHLocal("xxx.xxx.xxx.xxx:5053",
        "/etc/dnsdist/xxxxxxxxxxx.pem",
        "/etc/dnsdist/xxxxxxxxxxx.key.pem",
        "/dns-query",
        { doTCP=true, reusePort=true }
        )

-- Local IP and port to listen on for the web monitoring page.
-- First option is usename, second is password
webserver('10.11.10.1:8083', 'xxxxxxx', 'xxxxxxxxx')


-- DOH general configuration
doh_ips=newNMG()
-- Allow from anywhere IPv4 or IPv6.  Change and add more addMask lines if
-- you want to lock down further.
doh_ips:addMask('0.0.0.0/0')
doh_ips:addMask('::/0')
-- If you change the port or pool names, you need to change the following here too.
-- By default, uses standard 'recursive' pool for DoH clients
addAction(AndRule({NetmaskGroupRule(doh_ips, true), DSTPortRule(5053)}), PoolAction('recursive'))


-- Recursive ACLs - allow recursive queries from these addresses
recursiveACLs={"127.0.0.0/8", "::1/128", "fe80::/10", "10.0.0.0/8",
        "100.99.99.0/24", "172.18.0.0/16"
        }

-- Routes DNSbl queries for these specific domains to 'dnsbl' pool
addAction(AndRule({makeRule({"uribl.com.", "abuseat.org.", "sorbs.net.", "spamhaus.org.", "mailspike.net.", "dnswl.org."}), makeRule(recursiveACLs), RDRule()}), PoolAction("dnsbl"))

-- Allow resolving from recursiveACLs list
addAction(AndRule({makeRule(recursiveACLs), RDRule()}), PoolAction("recursive"))

-- 'recursive' pool
-- Each newServer defines a specific server in this pool.
-- 127.0.0.2:8053 is a local recursive PowerDNS server set up on same system
newServer({address="127.0.0.2:8053", pool="recursive"})
newServer({address="8.8.8.8:53", pool="recursive"})
newServer({address="205.171.2.65:53", pool="recursive"})
newServer({address="205.171.3.65:53", pool="recursive"})
newServer({address="[2001:4860:4860::8888]:53", pool="recursive"})
newServer({address="[2001:4860:4860::8844]:53", pool="recursive"})

-- Configures packet cache for the 'recursive' pool
recursivepc = newPacketCache(10000, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=false})
getPool("recursive"):setCache(recursivepc)


-- 'dnsbl pool'
-- These servers are only used for DNSbl queries so they don't go to public servers
-- with the potential to fail or not return correct results.
newServer({address="127.0.0.2:8053", pool="dnsbl"})

-- Configures packet cache for 'dnsbl' pool
dnsblpc = newPacketCache(10000, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=false})
getPool("dnsbl"):setCache(dnsblpc)

-- Generic allow which does nothing unless caught by above rules.
-- Although it seems like this would allow anyone to query,
-- it doesn't.  Access control is provided by above rules.
setACL({'::/0','0.0.0.0/0'})