The PowerDNS Recursor is a high-performance DNS recursor with built-in scripting capabilities. The following guide outlines the deployment methodology and installation instructions for performing Domain Name filtering via DNS servers. The solution includes PowerDNS Recursor application deployed on Ubuntu 20.04 servers.The domain block list will be stored in SQLITE3 database which is small and fast SQL engine.
PowerDNS Recursor Installation
Configure the PowerDNS repositories. Create the file ‘/etc/apt/sources.list.d/pdns.list’ and add following content to the file:
deb [arch=amd64] http://repo.powerdns.com/ubuntu focal-rec-46 main
Change the package installation preference to the PowerDNS repository for the pdns packages. Create and add following content in the file /etc/apt/preferences.d/pdns:
Package: pdns-* Pin: origin repo.powerdns.com Pin-Priority: 600
Install the PowerDNS Recursor package. Also install sqlite3 and lua driver for sqlite3 which will be used to perform domain blocking.
$ curl https://repo.powerdns.com/FD380FBB-pub.asc | sudo apt-key add - $ sudo apt-get update $ sudo apt-get install pdns-recursor $ sudo apt install sqlite3 lua-sql-sqlite3
Make the following configuration changes to the main configuration file /etc/powerdns/recursor.conf.
allow-from-file=/etc/powerdns/allowedclients api-key=SomeApiKey config-dir=/etc/powerdns distributor-threads=2 hint-file=/usr/share/dns/root.hints include-dir=/etc/powerdns/recursor.d local-address=0.0.0.0 loglevel=6 lua-config-file=/etc/powerdns/recursor.lua lua-dns-script=/etc/powerdns/blacklistcheck.lua max-cache-entries=3000000 max-packetcache-entries=1000000 network-timeout=2000 pdns-distributes-queries=yes quiet=yes reuseport=yes setgid=pdns setuid=pdns threads=4 webserver=yes webserver-address=0.0.0.0 webserver-allow-from=127.0.0.1,192.168.10.0/27 webserver-loglevel=none webserver-password=SomePassWord
Add the clients allowed to use the recursor DNS in the file /etc/powerdns/allowedclients:
127.0.0.0/8 10.0.0.0/8 100.64.0.0/10 192.168.0.0/16 172.16.0.0/12
Create LUA script /etc/powerdns/blocklistcheck.lua which will search the SQLITE3 database for blocked domains. If a record is found it will return TRUE with a local IP against A record. If no match is found it will return FALSE which means that standard DNS resolution process will follow.
driver = require "luasql.sqlite3" local env = driver.sqlite3() function preresolve ( dq ) if dq.qtype == pdns.A then local con = env:connect('/var/lib/powerdns/blocklistdomains.sqlite3',READONLY) local sth = con:execute( string.format("SELECT 1 FROM domains WHERE name = '%s'", dq.qname ) ) if sth:fetch() then dq:addAnswer(pdns.A, "127.0.0.1", 300) sth:close() con:close() return true; end con:close() end return false; end
Create the SQLITE3 database to store the blocked domains list. The following will create the database and domains table with single column, import the blocked domain list into the table and enable INDEXING on the table for fast searching. Before adding to the domain list the domain names need to be appended with a “.” at the end because the domain name passed to the LUA filter is of the format “domain.name.com.”.
$ sed 's/$/./' inputlist > domainlist $ $ sudo mkdir /var/lib/powerdns/ $ sudo chown -R pdns:pdns /var/lib/powerdns $ sudo sqlite3 /var/lib/powerdns/blocklistdomains.sqlite3 sqlite> create table domains (name VARCHAR(255) NOT NULL COLLATE NOCASE UNIQUE); sqlite> .import domainslist domains sqlite> CREATE INDEX name_index ON domains(name);
To improve the recursor performance the ROOT DNS zone can be cached on the DNS server. Edit the file /etc/powerdns/recursor.lua and add the following file:
zoneToCache(".", "url", "https://www.internic.net/domain/root.zone", { refreshPeriod = 0 })
Start the DNS server and verify that everything is working via log files.
$ sudo systemctl restart pdns-recursor $ $ journalctl -u pdns-recursor.service -f Dec 17 09:14:37 pdnsfilter.domain.com systemd[1]: Starting PowerDNS Recursor... Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: PowerDNS Recursor 4.6.0-rc1 (C) 2001-2021 PowerDNS.COM BV Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Using 64-bits mode. Built using gcc 9.3.0 on Dec 1 2021 20:06:03 by root@2cc4b71556fc. Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: PowerDNS comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of the GPL version 2. Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: If using IPv6, please raise sysctl net.ipv6.route.max_size, currently set to 4096 which is < 16384 Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Enabling IPv4 transport for outgoing queries Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: NOT using IPv6 for outgoing queries - add an IPv6 address (like '::') to query-local-address to enable Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Done parsing 10 allow-from ranges from file '/etc/powerdns/allowedclients' - overriding 'allow-from' setting Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Will not send queries to: 127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10, 0.0.0.> Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: PowerDNS Recursor itself will distribute queries over threads Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Inserting rfc 1918 private space zones Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Not decreasing socket buffer size from 16777216 to 250000 Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Listening for UDP queries on 0.0.0.0:53 Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Enabled TCP data-ready filter for (slight) DoS protection Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Listening for TCP queries on 0.0.0.0:53 Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Not decreasing socket buffer size from 16777216 to 250000 Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Listening for UDP queries on 0.0.0.0:53 Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Enabled TCP data-ready filter for (slight) DoS protection Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Listening for TCP queries on 0.0.0.0:53 Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: msg="Getting zone by URL" subsystem="ztc" level=0 ts="1639714477.263" zone="." Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Launching 2 distributor threads Dec 17 09:14:37 pdnsfilter.domain.com pdns-recursor[38907]: Launching 4 worker threads Dec 17 09:14:37 pdnsfilter.domain.com systemd[1]: Started PowerDNS Recursor.
Updates to the DNS BlockList DB
To add domain names into the blocklist or to remove names, SQLITE3 IMPORT and DELETE functions can be used. And this does not require the DNS recursor process to restart.
To add domains the block list, create a text will with the domain names. Add a “.” at the end of each domain name.
$ sed 's/$/./' inputlist > domainlist
Create a import script file which will be passed to the SQLITE3 database.
.import /home/ubuntu/domainlist domains
Run the import command script.
$ sudo sqlite3 /var/lib/powerdns/blocklistdomains.sqlite3 < importcmd
Create a delete script which will read the domain names from the file and will delete from the database.
#!/bin/bash DBFILE="/var/lib/powerdns/blacklistdomains.sqlite3" DELETEFILE=”/home/ubuntu/deletelist” sed 's/$/./' inputlist > $DELETEFILE while read DOMAINNAME do echo "Deleting $DOMAINNAME" echo "delete from domains where name='$DOMAINNAME'; " | sqlite3 $DBFILE done < $DELETEFILE
References
https://doc.powerdns.com/recursor/
https://makoserver.net/articles/Lua-SQLite-Database-Tutorial