Replacing dnsmasq DNS with knot-resolver on OpenWRT
OpenWRT uses dnsmasq for DHCP and DNS services, and the DNS service caused some problems for me:
- Latency when forwarding DNS requests is often higher than direct lookup.
- Does not support DNS-over-TLS (DoT).
- Forwarding to stubby adds DoT support but frequently has very high latency, and sometimes just fails completely.
Installing knot-resolver fixes these issues, but it has to be installed manually and I can't replace dnsmasq since I need the DHCP service so some configuration is needed.
Installation
First update the package index. In LUCI go to System -> Software
and press Update lists
, or in a terminal:
opkg update
Search for and install the knot-resolver
package in LUCI, or:
opkg install knot-resolver
Stop and disable the service until the configuration is in place. In LUCI go to System -> Startup
and stop and disable the kresd
service, or:
service kresd stop
service kresd disable
Configuration
First disable DNS on dnsmasq. In LUCI go to Network -> DHCP and DNS -> Advanced Settings
and set the DNS server port
to 0. Press Save & Apply
and check that nothing is listening on port 53 anymore:
netstat -tlnu
Next create a kresd
configuration file in /etc/knot-resolver/kresd.conf
:
log_target('syslog')
modules = {
'policy',
'hints > iterate',
'serve_stale < cache',
'workarounds < iterate',
'stats',
'predict'
}
net.ipv6 = false
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' })
cache.open(50 * MB, 'lmdb:///tmp/kresd/cache')
hints.add_hosts('/etc/knot-resolver/hosts.custom')
policy.add(policy.all(policy.TLS_FORWARD({
{ '1.1.1.1', hostname='cloudflare-dns.com' },
{ '1.0.0.1', hostname='cloudflare-dns.com' }
})))
predict.config({ window = 30, period = 48 })
Let's go through the settings. For details refer to the documentation.
log_target('syslog')
: The default logging target is stdout, but I want messages to appear in the syslog together with the rest of the services.modules
: All the imported modules necessary to enable the settings used.net.ipv6 = false
: I don't need IPv6 support and the default is true. Remove this if you need to add IPv6 addresses.net.listen(...)
: All the interfaces and ports to listen for DNS requests on. Replace the address with whatever the LAN address of your router is.cache.open(...)
: Use a relatively small cache on non-persistent storage. Best-practice is to mount a dedicatedtmpfs
if you want non-persistence, but since/tmp
is already mounted usingtmpfs
and has plenty of space I simply use that.hints.add_hosts(...)
: A regular hosts file with all the static mappings on the network. If your system uses/etc/hosts
it could point to that. Delete this line if you don't need static mappings.policy.TLS_FORWARD(...)
: This is where DNS forwarding using TLS is enabled for all lookups. The example uses Cloudflare servers but any DNS server supporting DoT can be used.predict.config(...)
: The prediction module is entirely optional. It refreshes cache entries based on usage patterns, time, or both depending on configuration.
Service configuration hack
The knot-resolver
package doesn't integrate with uci
and I didn't have time to create a clean solution, so I just edited the /etc/init.d/kresd
script directly to use the custom configuration and disable the autogenerated configuration file:
- Edit
CONFIGFILE
to point to/etc/knot-resolver/kresd.conf
. - Comment out
init_header
,init_rootkey
and any-a
parameter lines in thestart_service()
function.
Remember that if you upgrade the package you might have to reapply these changes.
Now all that remains is to enable and start the service, and check that it is listening on all configured interfaces and ports:
service kresd enable
service kresd start
netstat -tlnu
Check that DNS works from a computer on the network:
dig example.com @10.0.0.1
Since DNS is disabled in dnsmasq it doesn't advertise any DNS server through DHCP anymore. Remedy that by adding a custom DHCP setting. In LUCI go to Network -> Interfaces
and edit the interface for your LAN. Then go to DHCP Server -> Advanced Settings
and add the option 6,10.0.0.1
to DHCP-Options
. Save and apply and everything should work exactly as before, with all DNS lookups being encrypted and done by knot-resolver instead of dnsmasq.
You can test if TLS is used here: