dnscrypt-proxy Revisited: Configuring on Debian / Raspbian Jessie

In the last part, we installed dnscrypt-proxy on Raspbian Jessie in a more Debian-ish way by using the Stretch repositories.

The Stretch build of dnscrypt-proxy installs three systemd units. Let’s take a look at them:

> ls -1 /lib/systemd/system/dnscrypt-*
/lib/systemd/system/dnscrypt-proxy-resolvconf.service
/lib/systemd/system/dnscrypt-proxy.service
/lib/systemd/system/dnscrypt-proxy.socket
[Unit]
Description=DNSCrypt proxy resolvconf support
Documentation=man:dnscrypt-proxy(8)
After=dnscrypt-proxy.socket
Requires=dnscrypt-proxy.socket
ConditionFileIsExecutable=/sbin/resolvconf

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/sh -c 'systemctl show dnscrypt-proxy.socket \
                    | grep ListenDatagram \
                    | cut -d "=" -f 2 \
                    | cut -d ":" -f 1 \
                    | awk \'{ print "nameserver " $1 }\' \
                    | /sbin/resolvconf -a lo.dnscrypt-proxy'
ExecStop=/sbin/resolvconf -d lo.dnscrypt-proxy

[Install]
WantedBy=multi-user.target
Also=dnscrypt-proxy.socket

[Unit]
Description=DNSCrypt client proxy
Documentation=man:dnscrypt-proxy(8)
Requires=dnscrypt-proxy.socket
After=network.target
Before=nss-lookup.target

[Install]
Also=dnscrypt-proxy.socket
WantedBy=multi-user.target

[Service]
Type=notify
NonBlocking=true
User=_dnscrypt-proxy
ExecStart=/usr/sbin/dnscrypt-proxy /etc/dnscrypt-proxy/dnscrypt-proxy.conf
Restart=always
ProtectSystem=strict
ProtectHome=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
MemoryDenyWriteExecute=true
RestrictRealtime=true
[Unit]
Description=dnscrypt-proxy listening socket
Documentation=man:dnscrypt-proxy(8)
Wants=dnscrypt-proxy-resolvconf.service

[Socket]
ListenStream=127.0.2.1:53
ListenDatagram=127.0.2.1:53

[Install]
WantedBy=sockets.target

The first unit dnscrypt-proxy-resolvconf.service updates resolvconf with the listening IP address of dnscrypt-proxy, presumably so Linux can use it directly as a DNS resolver. This isn’t something we necessarily want. In my case I want all direct DNS queries on my network to go to BIND9 running on my Raspberry Pis. BIND9 is what I want to forward to dnscrypt-proxy.

The second unit is the dnscrypt service itself. Here we can see that it is specifically passed /etc/dnscrypt-proxy/dnscrypt-proxy.conf as a configuration file.

The third unit is the socket. This version of dnscrypt-proxy uses systemd’s sockets-based activation. That’s a reasonable topic that you can read more about that elsewhere, but as far as we’re concerned, it means that you tell systemd the ports (TCP and UDP 53), which it passes to dnscrypt-proxy whenever it starts the service.

Indeed dnscrypt-proxy.conf denounces having any control over the port if systemd is used:

# A more comprehensive example config can be found in
# /usr/share/doc/dnscrypt-proxy/examples/dnscrypt-proxy.conf

ResolverName fvz-anyone
Daemonize no

# LocalAddress only applies to users of the init script. systemd users must
# change the dnscrypt-proxy.socket file.
LocalAddress 127.0.2.1:53

Now in my situation:

  1. I don’t want resolv.conf modified to include the dnscrypt-proxy resolver.
  2. As before I want two dnscrypt-proxy instances running using two different upstream resolvers.
  3. I want them running on different ports to port 53.

First, let’s make sure that the units shipped with the package are never invoked.

> sudo systemctl stop dnscrypt-proxy.service dnscrypt-proxy.socket dnscrypt-proxy-resolvconf.service
> sudo systemctl disable dnscrypt-proxy dnscrypt-proxy-resolvconf
Removed symlink /etc/systemd/system/multi-user.target.wants/dnscrypt-proxy-resolvconf.service.
> sudo systemctl mask dnscrypt-proxy.service dnscrypt-proxy.socket dnscrypt-proxy-resolvconf.service
Created symlink from /etc/systemd/system/dnscrypt-proxy.service to /dev/null.
Created symlink from /etc/systemd/system/dnscrypt-proxy.socket to /dev/null.
Created symlink from /etc/systemd/system/dnscrypt-proxy-resolvconf.service to /dev/null.

Now let’s make copies of those original unit files and make some changes.

> sudo cp /lib/systemd/system/dnscrypt-proxy.socket /etc/systemd/system/dnscrypt-proxy1.socket
> sudo nano /etc/systemd/system/dnscrypt-proxy1.socket
> sudo cp /lib/systemd/system/dnscrypt-proxy.service /etc/systemd/system/dnscrypt-proxy1.service
> sudo nano /etc/systemd/system/dnscrypt-proxy1.service

In the socket, we remove the desired prerequisite of dnscrypt-proxy-resolvconf.service. We also modify the Listen directives to the standard localhost IP with the custom port.

[Unit]
Description=dnscrypt-proxy1 listening socket
Documentation=man:dnscrypt-proxy(8)
#Wants=dnscrypt-proxy-resolvconf.service

[Socket]
ListenStream=127.0.0.1:40053
ListenDatagram=127.0.0.1:40053

[Install]
WantedBy=sockets.target

In the service, we update references of dnscrypt-proxy.socket to dnscrypt-proxy1.socket, and we change the configuration filename used.

[Unit]
Description=DNSCrypt client proxy1
Documentation=man:dnscrypt-proxy(8)
Requires=dnscrypt-proxy1.socket
After=network.target
Before=nss-lookup.target

[Install]
Also=dnscrypt-proxy1.socket
WantedBy=multi-user.target

[Service]
Type=notify
NonBlocking=true
User=_dnscrypt-proxy
ExecStart=/usr/sbin/dnscrypt-proxy /etc/dnscrypt-proxy/dnscrypt-proxy1.conf
Restart=always
ProtectSystem=strict
ProtectHome=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
MemoryDenyWriteExecute=true
RestrictRealtime=true

Now we create a custom dnscrypt-proxy configuration file, specifying our resolver and any other options we desire.

> sudo nano /etc/dnscrypt-proxy/dnscrypt-proxy1.conf
ResolverName dnscrypt.eu-dk
EphemeralKeys on

We can now load these units and test that dnscrypt-proxy is working.

> sudo systemctl daemon-reload
> sudo systemctl enable dnscrypt-proxy1
> sudo systemctl start dnscrypt-proxy1
> nslookup -port=40053 google.com
Server:         127.0.0.1
Address:        127.0.0.1#40053

Non-authoritative answer:
Name:   google.com
Address: 172.217.17.142

For the second resolver, we simply repeat the above but with some small changes:

  • Replace dnscrypt-proxy1 with dnscrypt-proxy2
  • Choose a different port (e.g. 40054)
  • Choose a different resolver in dnscrypt-proxy2.conf

And that’s it – those two dnscrypt-proxy resolvers are now ready for a caching DNS server such as BIND or dnsmasqd to forward to.

2 Comments

  1. Bryan

    Hi, thanks for this guide. But I’m not getting this to work. At first it says the proxy service is running. As soon as I want to enable it again after the resolver change it keeps saying: Start-limit as an description for why its not loading.

    Can you also post or help me out configuring dnsmasq as a forwarder working alongside dnscrypt-proxy? Thanks.

    Reply
    1. Ryan Milne (Post author)

      Thanks for reading. I can try to help, though it may take me some time to get back to you between replies.

      I’m not sure what you mean by making the resolver change; can you clarify?

      Can you please reply with a pastebin ( https://pastebin.com/ ) of all of the commands and output you are running, errors you’re getting, etc., as well as the output of the following commands:

      1. sudo dnscrypt-proxy –version
      2. sudo systemctl status dnscrypt-proxy.service
      3. sudo systemctl status dnscrypt-proxy1.service -l
      4. cat /etc/systemd/system/dnscrypt-proxy1.socket
      5. cat /etc/systemd/system/dnscrypt-proxy1.service
      6. cat /etc/dnscrypt-proxy/dnscrypt-proxy1.conf

      (I assume you are either having issues with both dnscrypt-proxy1 and dnscrypt-proxy2, or got stuck with dnscrypt-proxy1 and stopped there. Either way let’s just focus on dnscrypt-proxy1).

      It’s been a while since I tried it with dnsmasq, but you literally just need a line in your dnsmasq config (or a dnsmasq.d fragment) for each dnscrypt-proxy service you are running. You specify the port with the hash symbol. For example I have done the following in the past.

      # ...
      server=127.0.0.1#40053
      server=127.0.0.1#40054
      # ...
      

      This page on the ArchWiki also has a small amount of information.

      Let me know if you get stuck with that and I might be able to make a post – though let’s sort out the errors you are getting first.

      Thanks

      Reply

Leave a Reply to Ryan Milne Cancel reply

Your email address will not be published. Required fields are marked *