DNSCrypt - ArchWiki

# DNSCrypt

DNSCrypt encrypts and authenticates DNS traffic between user and DNS resolver. While IP traffic itself is unchanged, it prevents local spoofing of DNS queries, ensuring DNS responses are sent by the server of choice. [1]

## Installation

Install the dnscrypt-proxy package.

## Configuration

Tip: An example configuration file, `/etc/dnscrypt-proxy.conf.example` is provided, but note that systemd overrides the `LocalAddress` option with a socket file.

To configure dnscrypt-proxy, perform the following steps:

### Select resolver

Select a resolver from `/usr/share/dnscrypt-proxy/dnscrypt-resolvers.csv` and edit `/etc/dnscrypt-proxy.conf`, using a short name from the csv file's first column, `Name`. For example, to select dnscrypt.eu-nl as the resolver:

    ResolverName dnscrypt.eu-nl

Tip:

- A potentially more up-to-date list is available directly on the upstream page.
- At this stage you may also wish to add an unprivileged user to run dnscrypt. See #dnscrypt runs with root privileges.

### Modify resolv.conf

After selecting a dnscrypt resolver, modify the resolv.conf file and replace the current set of resolver addresses with address for localhost:

    nameserver 127.0.0.1

Other programs may overwrite this setting; see resolv.conf#Preserve DNS settings for details.

### Start systemd service

Finally, start and enable the `dnscrypt-proxy.service`.

## Tips and tricks

### Local DNS cache configuration

It is recommended to run DNSCrypt as a forwarder for a local DNS cache, otherwise every single query will make a round-trip to the upstream resolver. Any local DNS caching program should work. In addition to setting up dnscrypt-proxy, you must setup your local DNS cache program.

#### Change port

Note: Changing the IP address or port in `/etc/dnscrypt-proxy.conf` does not work when using the provided systemd unit and must be changed in the provided systemd socket as follows.

In order to forward to a local DNS cache, dnscrypt-proxy should listen on a port different from the default `53`, since the DNS cache itself needs to listen on `53` and query dnscrypt-proxy on a different port. Port number `5353` is used as an example in this section. In this example, the port number is larger than 1024 so dnscrypt-proxy is not required to be run by root. Edit `dnscrypt-proxy.socket` with the following contents:

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

#### Example local DNS cache configurations

The following configurations should work with dnscrypt-proxy and assume that it is listening on port `5353`.

##### Unbound

Configure Unbound to your liking (in particular, see Unbound#Local DNS server) and add the following lines to the end of the `server` section in `/etc/unbound/unbound.conf`:

    do-not-query-localhost: no
    forward-zone:
      name: "."
      forward-addr: 127.0.0.1@5353

Tip: If you are setting up a server, add `interface: 0.0.0.0@53` and `access-control: your-network/subnet-mask allow` inside the `server:` section so that the other computers can connect to the server. A client must be configured with `nameserver address-of-your-server` in `/etc/resolv.conf`.

Restart `unbound.service` to apply the changes.

##### dnsmasq

Configure dnsmasq as a local DNS cache. The basic configuration to work with DNSCrypt:

    /etc/dnsmasq.conf

    no-resolv
    server=127.0.0.1#5353
    listen-address=127.0.0.1

If you configured DNSCrypt to use a resolver with enabled DNSSEC validation, make sure to enable it also in dnsmasq:

    /etc/dnsmasq.conf

    proxy-dnssec

Restart `dnsmasq.service` to apply the changes.

##### pdnsd

Install pdnsd. A basic configuration to work with DNSCrypt is:

    /etc/pdnsd.conf

    global {
        perm_cache = 1024;
        cache_dir = "/var/cache/pdnsd";
        run_as = "pdnsd";
        server_ip = 127.0.0.1;
        status_ctl = on;
        query_method = udp_tcp;
        min_ttl = 15m;       # Retain cached entries at least 15 minutes.
        max_ttl = 1w;        # One week.
        timeout = 10;        # Global timeout option (10 seconds).
        neg_domain_pol = on;
        udpbufsize = 1024;   # Upper limit on the size of UDP messages.
    }

    server {
        label = "dnscrypt-proxy";
        ip = 127.0.0.1;
        port = 5353;
        timeout = 4;
        proxy_only = on;
    }

    source {
        owner = localhost;
        file = "/etc/hosts";
    }

Restart `pdnsd.service` to apply the changes.

### Sandboxing

Edit `dnscrypt-proxy.service` to include the following lines:

    [Service]
    CapabilityBoundingSet=CAP_IPC_LOCK CAP_SETGID CAP_SETUID
    ProtectSystem=strict
    ProtectHome=true
    ProtectKernelTunables=true
    ProtectKernelModules=true
    ProtectControlGroups=true
    PrivateTmp=true
    PrivateDevices=true
    MemoryDenyWriteExecute=true
    NoNewPrivileges=true
    RestrictRealtime=true
    RestrictAddressFamilies=AF_INET
    SystemCallArchitectures=native
    SystemCallFilter=~@clock @cpu-emulation @debug @keyring @ipc @module @mount @obsolete @raw-io

See systemd.exec(5) and Systemd#Sandboxing application environments for more information. Additionally see upstream comments.

This can be combined with the additions in #dnscrypt runs with root privileges.

### Enable EDNS0

Extension Mechanisms for DNS that, among other things, allows a client to specify how large a reply over UDP can be.

Add the following line to your `/etc/resolv.conf`:

    options edns0

You may also wish to append the following to `/etc/dnscrypt-proxy.conf`:

    EDNSPayloadSize <bytes>

Where <bytes> is a number, the default size being 1252, with values up to 4096 bytes being purportedly safe. A value below or equal to 512 bytes will disable this mechanism, unless a client sends a packet with an OPT section providing a payload size.

#### Test EDNS0

Make use of the DNS Reply Size Test Server, use the dig command line tool from the bind-tools package to issue a TXT query for the name rs.dns-oarc.net:

    $ dig +short rs.dns-oarc.net TXT

With EDNS0 supported, the output should look similar to this:

    rst.x3827.rs.dns-oarc.net.
    rst.x4049.x3827.rs.dns-oarc.net.
    rst.x4055.x4049.x3827.rs.dns-oarc.net.
    "2a00:d880:3:1::a6c1:2e89 DNS reply size limit is at least 4055 bytes"
    "2a00:d880:3:1::a6c1:2e89 sent EDNS buffer size 4096"

### Redundant DNSCrypt providers

To use several different dnscrypt providers, you may simply copy the original `dnscrypt-proxy.service` and `dnscrypt-proxy.socket`. Then in your new copy of the service change the command line parameters, either pointing to a new configuration file or naming a different resolver directly. From there change the port in the new copy of the socket. Lastly, update your local DNS cache program to point to new service's port. For example, with unbound the configuration file would look like if using ports `5353` for the original socket and `5354` for the new socket.

    /etc/unbound/unbound.conf

     do-not-query-localhost: no
     forward-zone:
       name: "."
       forward-addr: 127.0.0.1@5353
       forward-addr: 127.0.0.1@5354

#### Create instanced systemd service

An alternative option to copying the systemd service is to used an instanced service.

##### Create systemd file

First, create `/etc/systemd/system/dnscrypt-proxy@.service` containing:

    [Unit]
    Description=DNSCrypt client proxy
    Documentation=man:dnscrypt-proxy(8)
    Requires=dnscrypt-proxy@%i.socket

    [Service]
    Type=notify
    NonBlocking=true
    ExecStart=/usr/bin/dnscrypt-proxy \
        --resolver-name=%i
    Restart=always

This specifies an instanced systemd service that starts a dnscrypt-proxy using the service name specified after the @ symbol of a corresponding .socket file.

##### Add dnscrypt-sockets

To create multiple dnscrypt-proxy sockets, copy `/usr/lib/systemd/system/dnscrypt-proxy.socket` to a new file, `/etc/systemd/system/dnscrypt-proxy@short-name.here.socket`, replacing the socket instance name with one of the short names listed in `dnscrypt-resolvers.csv` and change the port. Use a different port for each instance (5353, 5354, and so forth).

##### Apply new systemd configuration

Now we need to reload the systemd configuration.

    # systemctl daemon-reload

Since we are replacing the default service with a different name, we need to explicitly stop and disable `dnscrypt-proxy.service` and `dnscrypt-proxy.socket`.

Now start/enable the new service(s), e.g., `dnscrypt-proxy@dnscrypt.eu-nl`, etc.

Finally restart `unbound.service`.

## Troubleshooting

### dnscrypt runs with root privileges

See FS#49881 for more information. To work around this, create an unprivileged user manually.

Create the user as follows:

    # useradd -r -d /var/dnscrypt -m -s /sbin/nologin dnscrypt

Two possible solutions Edit `/etc/dnscrypt-proxy.conf`, appending the new user:

    User dnscrypt

Alternatively, you should use `User=` in in the `dnscrypt-proxy.service` systemd unit:

    [Service]
    User=dnscrypt
    CapabilityBoundingSet=CAP_NET_BIND_SERVICE

This second option is useful when using a caching server like unbound and is preferred, since the unit is not exec'ed as root in the first place. If you changed the port to an unprivileged one (e.g. 5353), then `CapabilityBoundingSet=CAP_NET_BIND_SERVICE` is not needed. This method can be combined with #Sandboxing.

Categories:

- Domain Name System
- Encryption