I was considering using Knot DNS since a while. Switching to DNS over TLS for the resolver queries was the push needed. Turns out that transposing my setup with Knot DNS is very easy and fast.
Knot Resolver does not provide init scripts and suggests to use supervisor as an alternative to systemd omnipresent features. Wary with this idea, turns out that supervisor is very easy to put in place and I might use it more, replace some xinetd, in the future.
For the record, my setup is as follow: there is a local DNS server to serve the local area network HERE.ici domain and is a resolver that cache requests. All requests are sent to the resolver and this one, if he cannot answer, then ask the relevant DNS server. Nothing too fancy, even if sometimes LAN are set up the other way around, where people query the local DNS server by default and this one query the local resolver if he can’t answer.
Install require the following:
|
1
2
|
apt install knot/testingapt install knot-resolver supervisor |
DNS for the local area network
The Knot DNS server will not be queried directly but by the Knot Resolver and DHCPd. Edit /etc/knot/knot.conf by adding:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
server: # meant to be called only on loopback # by knot-resolver and dhcpd on update listen: 127.0.1.1@53acl: - id: update_acl # restrict by IP is enough, no need for a ddns key stored on the same host address: 127.0.0.1 action: updatezone: - domain: HERE.ici dnssec-signing: on acl: update_acl - domain: 10.in-addr.arpa dnssec-signing: on acl: update_acl |
Create the zones (edit serverhostname and HERE.ici according to your setup):
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
invoke-rc.d knot restartknotc zone-begin HERE.iciknotc zone-set HERE.ici @ 7200 SOA serverhostname hostmaster 1 86400 900 691200 3600knotc zone-set HERE.ici serverhostname 3600 A 10.10.10.1knotc zone-set HERE.ici @ 3600 NS serverhostnameknotc zone-set HERE.ici @ 3600 MX 10 mx.HERE.iciknotc zone-set HERE.ici jeden 3600 CNAME serverhostnameknotc zone-commit HERE.iciknotc zone-begin 10.in-addr.arpaknotc zone-set 10.in-addr.arpa @ 7200 SOA serverhostname.HERE.ici. hostmaster.HERE.ici. 1 86400 900 691200 3600knotc zone-set 10.in-addr.arpa 10.10.10.1 3600 PTR serverhostnameknotc zone-set 10.in-addr.arpa @ 3600 NS serverhostname.HERE.ici.knotc zone-commit 10.in-addr.arpa |
Zone will to be updated by the DHCP server, in this case ISC dhcpd. Edit /etc/dhcp/dhcpd.conf accordingly:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
# dynamic updateddns-updates on;ddns-update-style standard;ignore client-updates; # restrict to domain name# option definitions common to all supported networks...option domain-name "HERE.ici";option domain-search "HERE.ici";# you can add other extra name servers if you consider acceptable # direct external queries in case the resolver is deadoption domain-name-servers 10.0.0.1;option routers 10.0.0.1;default-lease-time 600;max-lease-time 6000;update-static-leases on;authoritative; [...]zone HERE.ici. { primary 127.0.1.1;}zone 10.in-addr.arpa. { primary 127.0.1.1;} |
No dynamic update keys, everything goes through the loopback. You might want erase DHCPd leases (usually in /var/lib/dhcp/) so it does not get confused.
DNS Resolver
The Knot Resolver will handle all clients queries, contacting Internet DNS over TLS if need be and caching results. Edit /etc/knot-resolver/kresd.conf to contain:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
-- Network interface configuration-- (knot dns should be using 127.0.1.1)net.listen('127.0.0.1', 53, { kind = 'dns' })net.listen('127.0.0.1', 853, { kind = 'tls' })net.listen('10.0.0.1', 53, { kind = 'dns' })net.listen('10.0.0.1', 853, { kind = 'tls' })-- drop privileges (check /var/lib/knot-resolves modes/owner)user('knot-resolver', 'knot-resolver')-- Load useful modulesmodules = { 'hints > iterate', -- Load /etc/hosts and allow custom root hints 'stats', -- Track internal statistics 'predict', -- Prefetch expiring/frequent records 'view', -- require to limit access}-- Cache sizecache.size = 500 * MB-- whitelist queries identified by subnetview:addr('127.0.0.0/24', policy.all(policy.PASS))view:addr('10.0.0.0/24', policy.all(policy.PASS))-- drop everything that hasn't matchedview:addr('0.0.0.0/0', policy.all(policy.DROP))-- Custom hints: local spoofed address and antispam/adshints.add_hosts("/etc/knot-resolver/redirect-spoof")hints.add_hosts("/etc/knot-resolver/redirect-ads")-- internal domain: use knot dns listening on loopbackinternalDomains = policy.todnames({'HERE.ici', '10.in-addr.arpa'})policy.add(policy.suffix(policy.FLAGS({'NO_CACHE'}), internalDomains))policy.add(policy.suffix(policy.STUB({'127.0.1.1@53'}), internalDomains))-- forward in TLS policy.add(policy.all(policy.TLS_FORWARD( {'208.67.222.222', hostname='dns.opendns.com'}, {'208.67.220.220', hostname='dns.opendns.com'}, {'1.1.1.1', hostname='cloudflare-dns.com'}, {'1.0.0.1', hostname='cloudflare-dns.com'},}))) |
redirect-spoof and redirect-ads at /etc/hosts format: it allows domain spoofing or ads domains filtering. It replaces conveniently the extra lua script that my setup was using with PowerDNS.
Update Feb 19 2023: Check recent files on gitlab, I know use RPZ instead of hints/hosts file to block hostile domains. No real change in principle but knot-resolver seems to handle better very long lists in this form.
Finally, the resolver need to be started by the supervisord, with a /etc/supervisor/conf.d/knot-resolver.conf as such:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
[program:knot-resolver]command=/usr/sbin/kresd -c /etc/knot-resolver/kresd.conf --noninteractivepriority=0autostart=trueautorestart=truestdout_syslog=truestderr_syslog=truedirectory=/var/lib/knot-resolver[program:knot-resolver-gc]command=/usr/sbin/kres-cache-gc -c /var/lib/knot-resolver -d 120000user=knot-resolverautostart=trueautorestart=truestdout_syslog=truestderr_syslog=truedirectory=/var/lib/knot-resolver |
Restart the supervisor, check logs. Everything should be fine. You can cleanup.
|
1
2
3
4
5
6
7
8
|
rc-update add supervisorrc-update add knotapt --purge remove pdns-*# check if there is still traffic on DNS port 53 on the public network interface (should be none)tcpdump -ni eth0 -p port 53# check if there is trafic on DNS over TLS port 853 (should be whenever there is a query outside of the cache and LAN)tcpdump -ni eth0 -p port 853 |
(My default files are my rien-host package; if you have on your network a mail server using DNS blacklist which will inevitably blocked, you might want to install knot-resolver also on this server, in recursive mode)