Want to setup OpenWRT to query specific DNSCrypt server depending on domain name to resolve? Read on.
It is assumed that you know what DNSCrypt is. Long story short, it is a protocol for encrypting DNS lookup traffic.
I installed dnscrypt-proxy 1.4.3-1
from OpenWRT package repository. The proxy serves to receive incoming DNS requests then it makes an outbound request to DNSCrypt servers. It could load one proxy just fine but it could not initiate multiple instances until I applied a patch (more details below).
You may ask why do I need multiple when a single Anycast DNS server can give you the closest server? Sometimes the closest server does not have the content that you want; one way of geo-blocking by content providers. Solution is to use a UK DNS server to lookup a UK address, a US DNS server for US address, etc.
Install dnscrypt-proxy
if you have not already. As mentioned earlier, the version I have at time of writing is 1.4.3-1
.
Stop the service:
/etc/init.d/dnscrypt-proxy stop
This version needs to be patched to support multiple instances. Patch the file at /etc/init.d/dnscrypt-proxy
with the following, copied from here:
#!/bin/sh /etc/rc.common
# dnscrypt-proxy init-script utilizing procd to support multiple instances at once
START=50
USE_PROCD=1
dnscrypt_instance() {
config_get address "$1" 'address'
config_get port "$1" 'port'
config_get resolver "$1" 'resolver'
config_get resolvers_list "$1" 'resolvers_list'
procd_open_instance
procd_set_param command "/usr/sbin/dnscrypt-proxy"
procd_append_param command -a "${address}:${port}"
procd_append_param command -u nobody
procd_append_param command -L "${resolvers_list:-'/usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv'}"
procd_append_param command -R "${resolver:-'opendns'}"
procd_close_instance
}
start_service () {
config_load dnscrypt-proxy
config_foreach dnscrypt_instance dnscrypt-proxy
}
service_triggers() {
procd_add_reload_trigger "dnscrypt-proxy"
}
Overwrite /usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv
with a newer version from GitHub. This is to give us more DNSCrypt servers to choose from.
Next, edit /etc/config/dnscrypt-proxy
to configure the instances. Below is a sample with 2 instances; one with Anycast support listening on port 5353, another without located in the UK listening on port 5354:
config dnscrypt-proxy
option address '127.0.0.1'
option port '5353'
option resolver 'cisco'
option resolvers_list '/usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv'
config dnscrypt-proxy
option address '127.0.0.1'
option port '5354'
option resolver 'fvz-rec-gb-lon-01'
option resolvers_list '/usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv'
Start DNSCrypt:
/etc/init.d/dnscrypt-proxy start
Install bind-tools
so that we can use dig
command to lookup DNS information:
opkg update
opkg install bind-tools
Lookup DNS record of www.google.com using:
dig 127.0.0.1 -p [port] www.google.com
Substitute [port] with whatever that you have defined in /etc/config/dnscrypt-proxy
. Below is an example of the output from UK DNS server:
...
;; QUESTION SECTION:
;www.google.com. IN A
;; ANSWER SECTION:
www.google.com. 144 IN A 216.58.213.164
...
As shown above, the IP address of www.google.com is 216.58.213.164
whereas if I lookup against an Anycast DNS server, the response I get is 172.217.24.196
, somewhere much closer to me than the former.
Edit /etc/config/dhcp
. The gist is list server ...
lines.
config dnsmasq
...
option noresolv '1'
list server '/[UK server host name]/127.0.0.1#5354'
list server '127.0.0.1#5353'
list server '/pool.ntp.org/8.8.8.8'
noresolv '1'
is to prevent using any upstream DNS server other than those specified in this file. Substitute [UK server host name]
with a real one of course. You may add multiple lines. Just keep them above the list server '127.0.0.1#5353'
line.
IMPORTANT: Note that DNSCrypt requires time to be synchronised. Time synchronisation is performed against a host name but your DNS server is unavailable to perform lookups. This presents a chicken and egg problem. To mitigate this problem, a bypass is required for pool.ntp.org
(assuming this is the NTP server configured in your OpenWRT) such that the lookup will be performed by a public DNS server i.e. 8.8.8.8
, a Google DNS server. Rules are parsed top-down so subsequent lookups of pool.ntp.org
will not reach Google DNS.
This is very likely due to Internet connection not available yet at time of starting DNSCrypt. In such a case, the workaround is to wait for Internet connection to be available before restarting DNSCrypt. Add the following lines into /etc/rc.local
:
# Wait until Internet connection is available
for i in {1..60}; do ping -c1 -W1 8.8.8.8 &> /dev/null && break; done
# Restart DNSCrypt proxy as it requires a successful time sync for its encryption to work
/etc/init.d/dnscrypt-proxy restart
I am using ping
to test whether Internet connection is available. This is not the best option but I did not want to invest too much time on this. Others have suggested using sleep
command. If you know a better way, please share that as a comment below.