For the last 3 years I have been using djbdns on SmartOS and it has all been working great. Recently however, I started looking into DNSSEC and DNSCrypt, which ended up leading me to the OpenNIC Project.
I decided to change my home DNS server setup to forward OpenNIC DNS servers over an encrypted channel as opposed to using OpenDNS like I did with djbdns.
To set this up, I have a zone with
dnsmasq- listens globally on port 53 for incoming DNS requests, answers local domain DNS requests for my network, and forwards the rest to
dnscrypt-proxy- listens locally on port 5300 for incoming DNS requests from
dnsmasqand forwards them securely to an OpenNIC DNS server
To start, install
dnsmasq with the following command:
pkgin in dnsmasq
dnscrypt-proxy requires a little bit more work as it is currently
not in pkgsrc. To install it, we need to pull in some dependencies.
pkgin in go git
Now we can build
mkdir -p ~/dnscrypt-proxy cd ~/dnscrypt-proxy && wget https://github.com/jedisct1/dnscrypt-proxy/archive/2.0.16.tar.gz && tar xf 2.0.16.tar.gz && cd dnscrypt-proxy-2.0.16/dnscrypt-proxy && go get go build
We can verify it built by running it with
$ ./dnscrypt-proxy -version 2.0.16
And finally we can install it with
cp ./dnscrypt-proxy /opt/local/bin
Use the following config to configure
dnscrypt-proxy to work with OpenNIC DNS
servers. This server will listen on
127.0.0.1:5300 for plaintext requests
dnsmasq which we'll configure next.
Save this configuration file to
listen_addresses = ['127.0.0.1:5300'] ipv4_servers = true dnscrypt_servers = true doh_servers = true require_dnssec = true require_nolog = true require_nofilter = true timeout = 2500 keepalive = 30 cert_refresh_delay = 240 fallback_resolver = '18.104.22.168:53' ignore_system_dns = true cache = true cache_size = 512 cache_min_ttl = 600 cache_max_ttl = 86400 cache_neg_min_ttl = 60 cache_neg_max_ttl = 600 [sources] [sources.'opennic'] url = 'http://download.dnscrypt.info/resolvers-list/v2/opennic.md' minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3' cache_file = '/var/tmp/opennic.md' # log queries #[query_log] # format = 'tsv' # file = '/dev/stdout'
Note that I personally don't log any DNS requests on my home network for privacy reasons, but I've left the configuration lines there commented-out as turning on logging can be valuable for debugging purposes when setting up these services.
dnscrypt-proxy wasn't in pkgsrc we will have to create the SMF
<?xml version='1.0'?> <!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'> <service_bundle type='manifest' name='export'> <service name='application/dnscrypt-proxy' type='service' version='0'> <create_default_instance enabled='true'/> <dependency name='dep0' grouping='require_all' restart_on='error' type='service'> <service_fmri value='svc:/milestone/multi-user:default'/> </dependency> <exec_method name='start' type='method' exec='dnscrypt-proxy -config /opt/local/etc/dnscrypt.conf &' timeout_seconds='10'> <method_context working_directory='/var/empty'> <method_credential user='nobody' group='nobody'/> <method_environment> <envvar name='PATH' value='/opt/local/sbin:/opt/local/bin:/opt/custom/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'/> </method_environment> </method_context> </exec_method> <exec_method name='stop' type='method' exec=':kill' timeout_seconds='30'/> <template> <common_name> <loctext xml:lang='C'>dnscrypt-proxy</loctext> </common_name> </template> </service> </service_bundle>
And then run the following command to import the service and start it.
svccfg import ~/dnscrypt-proxy.xml
You can verify it's running with:
$ svcs -p dnscrypt-proxy STATE STIME FMRI online 23:02:53 svc:/application/dnscrypt-proxy:default
Or check the logs with:
$ tail "$(svcs -L dnscrypt-proxy)" [ Jul 7 03:02:53 Executing start method ("dnscrypt-proxy -config /opt/local/etc/dnscrypt.conf &"). ] [ Jul 7 03:02:53 Method "start" exited with status 0. ] [2018-07-07 03:02:53] [NOTICE] Source [/var/tmp/opennic.md] loaded [2018-07-07 03:02:53] [NOTICE] dnscrypt-proxy 2.0.16 [2018-07-07 03:02:53] [NOTICE] Now listening to 127.0.0.1:5300 [UDP] [2018-07-07 03:02:53] [NOTICE] Now listening to 127.0.0.1:5300 [TCP] [2018-07-07 03:02:53] [NOTICE] [opennic-onic] OK (crypto v1) - rtt: 32ms [2018-07-07 03:02:55] [NOTICE] [publicarray-au] TIMEOUT [2018-07-07 03:02:55] [NOTICE] Server with the lowest initial latency: opennic-onic (rtt: 32ms) [2018-07-07 03:02:55] [NOTICE] dnscrypt-proxy is ready - live servers: 1
And finally you can query the server directly with:
$ dig @127.0.0.1 -p 5300 +short daveeddy.com A 22.214.171.124
dnscrypt-proxy is setup to securely forward requests to OpenNIC DNS
servers, we can configure
dnsmasq to answer local requests and forward
Save this configuration file to
port=53 listen-address=0.0.0.0 bind-interfaces domain-needed proxy-dnssec filterwin2k no-resolv no-poll no-hosts neg-ttl=3600 # Rapture hosts domain=rapture.com local=/rapture.com/ # A records address=/host1.rapture.com/10.0.1.1 address=/host2.rapture.com/10.0.1.2 # PTR records ptr-record=126.96.36.199.in-addr.arpa,"host1.rapture.com" ptr-record=188.8.131.52.in-addr.arpa,"host2.rapture.com" # Forward everything else to dnscrypt server=127.0.0.1#5300 # log queries to stderr #log-queries #log-facility=-
rapture.com is my personal home domain - swap this out for your own personal
address lines will become local A records and the
lines will become local PTR records. Again, I personally don't log any queries
on my network but the config lines are there commented-out to help with
debugging when setting up the service initially.
Start the service with
svcadm enable dnsmasq
You can verify it's running with:
$ svcs -p dnsmasq STATE STIME FMRI online Jul_05 svc:/pkgsrc/dnsmasq:default Jul_05 39838 dnsmasq
To check that this is working, we can run the same command from configuring
dnscrypt-proxy, but this time using port 53 instead of 5300.
$ dig @127.0.0.1 -p 53 +short daveeddy.com A 184.108.40.206 $ dig @127.0.0.1 -p 53 +short host1.rapture.com A 10.0.1.1 $ dig @127.0.0.1 -p 53 +short host2.rapture.com A 10.0.1.2
With these two services in place, any server on the network can set their DNS
servers to this zone and get local records as well as public records over an
encrypted channel. I have 2 zones (on 2 different physical machines) on my
network running these DNS services, and I give out both of their IP addresses
as part of DHCP. If you want to test out these servers manually on a different
machine you'd have to edit
/etc/resolv.conf to look like:
search rapture.com domain rapture.com nameserver 10.0.1.2 nameserver 10.0.1.3
10.0.1.3 are the IP addresses of the DNS zones on the
network. With this config in place your local machine will use these zones as
their default resolvers.
Lookup local addresses
$ nslookup host1.rapture.com Server: 10.0.1.2 Address: 10.0.1.2#53 Name: host1.rapture.com Address: 10.0.1.2 $ nslookup 10.0.1.2 220.127.116.11.in-addr.arpa name = host1.rapture.com.
Lookup a bogus local address
$ nslookup foo.rapture.com Server: 10.0.1.2 Address: 10.0.1.2#53 ** server can't find foo.rapture.com: NXDOMAIN
Lookup a public address
$ nslookup daveeddy.com Server: 10.0.1.2 Address: 10.0.1.2#53 Non-authoritative answer: Name: daveeddy.com Address: 18.104.22.168
Lookup an OpenNIC specific address
$ nslookup grep.geek Server: 10.0.1.2 Address: 10.0.1.2#53 Name: grep.geek Address: 22.214.171.124 Name: grep.geek Address: 2001:470:4212:1::254