Skip to content
szemley edited this page Dec 30, 2020 · 22 revisions

Anonymized DNS

[List of public Anonymized DNS relays]

DNS encryption was a huge step towards making DNS more secure, preventing intermediaries from recording and tampering with DNS traffic.

However, one still has to trust non-logging DNS servers for actually doing what they pretend to do. They obviously see the decrypted traffic, but also client IP addresses.

In order to prevent this, using DNS over Tor or over proxies (HTTP, SOCKS) has become quite common. However, this is slow and unreliable as these mechanisms were not designed to relay DNS traffic.

Anonymized DNS prevents servers from learning anything about client IP addresses, by using intermediate relays dedicated to forwarding encrypted DNS data.

How does it work?

Instead of directly reaching a server, an Anonymized DNS client encrypts the query for the final server, but sends it to a relay.

The relay doesn't know the secret key, and cannot learn anything about the content of the query. It can only blindly forward the query to the actual DNS server, the only server that can decrypt it.

The DNS server itself receives a connection from the relay, not from the actual client. So the only IP address it knows about is the IP of the relay, making it impossible to map queries to clients

Anonymized DNSCrypt

Anonymized DNS can be implemented on top of all existing encrypted protocols, but DNSCrypt is by far the simplest and most efficient instantiation.

It only adds a header with a constant sequence followed by routing information (server IP+port) to unmodified DNSCrypt queries. Implementing it on top of an existing DNSCrypt implementation is trivial.

The overhead is minimal. Unlike DoH where headers may still reveal a lot of information about the client's identity, Anonymized DNSCrypt, by design, doesn't allow passing any information at all besides the strict minimum required for routing.

For relay operators, Anonymized DNSCrypt is less of a commitment than running a Tor node. Queries can only be relayed over UDP, they need to match a very strict format, amplification is impossible, and loops are prevented. Relays can essentially be only used for encrypted DNS traffic.

Configuring anoymized DNS in dnscrypt-proxy

This requires a fairly recent version of dnscrypt-proxy. Support for Anonymized DNSCrypt was introduced in version 2.0.29.

Anonymization only works with DNSCrypt servers. If you need to use DoH servers, you still have to use Tor, or SOCKS proxies instead.

Enabling both DoH and DNSCrypt servers in your configuration is totally fine, but DoH traffic will not be anonymized.

The configuration file includes an [anonymized_dns] defining a set of "routes". A route describes how to reach a server via a relay.

[anonymized_dns]
routes = [
    { server_name='example-server-1', via=['anon-example-1', 'anon-example-2'] }
]

The snippet above defines a route. It tells the proxy that instead of connecting to example-server-1 directly, it should connect to either anon-example-1 or anon-example-2 instead, and these will securely forward the queries to example-server-1.

example-server-1 will only see the IP addresses of anon-example-1 or anon-example-2. Your own IP address cannot be transmitted to example-server-1. And anon-example-1 and anon-example-2 will only see encrypted content, that they can't decrypt, because only example-server-1 knows the decryption key.

But what is example-server-1 exactly?

example-server-1 is the name of any DNSCrypt server. Likely one of the servers configured in the server_names parameters.

What are anon-example-1 and anon-example-2?

These are relays. A list of relays can be found in the relays.md file that is automatically downloaded by default along with other server lists.

So, neither the servers nor dnscrypt-proxy chooses what relays will be used to reach a server. You are in control.

You probably want relays and the servers they relay to to be operated by different entities. If you want to minimized latency, choose relays and servers that are close from a network perspective. If you feel paranoid, choose relays and servers in different countries. You decide.

As many routes as needed can be defined. And each server can use a different set of relays:

[anonymized_dns]
routes = [
    { server_name='example-server-1', via=['anon-example-1', 'anon-example-2'] },
    { server_name='example-server-2', via=['anon-example-3'] },
    { server_name='example-server-3', via=['anon-example-1'] }
]

Relay names can also be replaced with DNS stamps (sdns://...), IPs and ports (ip:port) or hostnames and ports ('host:port). If a resolver also acts as a relay, it's possible to use its regular stamp instead of the relay stamp.

A wildcard (*) can be used instead of a server name in order to apply a set of relays to all servers. Only use this if you have server_names defined, with a small set of servers that don't overlap with relays.

Caveats

Relaying is currently incompatible with cisco, as this resolver doesn't implement DNSCrypt v2 yet, and doesn't support large queries.

For each server, a random relay from the set is chosen when the proxy starts, and the same relay will be used until the proxy is restarted. Relay randomization and failover will be implemented in future versions.

Protocol

The Anonymized DNSCrypt extension was designed to only relay encrypted DNS data. As a result, its overhead is very low, including on relays that don't need to perform any additional encryption.

Like DNSCrypt, this is an open specification: Anonymized DNSCrypt specification

Encrypted DNS Server can be used to quickly set up a relay on a Linux or BSD machine.

All combinations seem to be "incompatible with anonymization"

Anonymization requires the ability to send large (fragmented) UDP packets.

If you are seeing the incompatible with anonymization message even with compatible resolvers, it is likely that your router was mistakenly configured to block UDP fragments. You need to disable this option, that breaks the UDP protocol without any security benefits.

Using servers and relays operated by different entities

When using all available DNSCrypt servers (by default server_names option is commented out) with anonymization ("DNS Anonymization is only compatible with servers supporting the DNSCrypt protocol"), it may happen that the server will use its own relay (e.g. bcn-dnscrypt server and anon-bcn relay) when - for example - User will choose such relay. That's what should be avoided.

There is an important statement made above: "You probably want relays and the servers they relay to, to be operated by different entities (...)" (please see "Configuring anoymized DNS in dnscrypt-proxy" subsection). It's a key information for a privacy oriented Users. So, how above goal can be achieved using Anonymized DNS?

It's relatively simple, because of disabled_server_names option, found in dnscrypt-proxy.toml file and used to define, declare server names to avoid, even if they match all criteria (vide require_{dnssec,log,nofilter} options).

CONFIGURATION

At the beginning, User has to choose - for example - two servers, which also offer anonymized relays. Let's take for example: 'cs-fr and bcn-dnscrypt servers. Because both servers will be avoided - they will be added to the disabled_server_names option, these Anonymized DNS relays can be used to reach servers: anon-cs-fr and anon-bcn. (NOTE: if it's about relays number, it seems, that two is a good choice; probably three is the biggest, suggested value).

Below is an example configuration with exceptions from dnscrypt-proxy.toml file. Please note, that DoH protocol is disabled so only DNSCrypt servers will be used.

# Servers from the "public-resolvers" source.
# (NOTE: this option must be commented out!)
# --------------------------------------------
#server_names = ['scaleway-fr', 'google', 'yandex', 'cloudflare']

# Server names to avoid
# even if they match all criteria.
# ---------------------------------
disabled_server_names = ['cs-fr', 'bcn-dnscrypt']

# Server type to use.
# --------------------
dnscrypt_servers = true
doh_servers = false

# Randomly choose server.
# ------------------------
lb_strategy = 'random'

# Anonymized DNS section.
# ------------------------
skip_incompatible = true

[anonymized_dns]

routes = [
   { server_name='*', via=['anon-cs-fr', 'anon-bcn'] }
]

The important thing is that, with above configuration, there is no possibility to use server and relay operated by the same entities, which is very important from a privacy point of view. For even greater privacy, skip_incompatible option responsible for: "skip resolvers incompatible with anonymization instead of using them directly" (please see example-dnscrypt-proxy.toml file) is set to true.

Additionaly, load balancing strategy (see lb_strategy option) has been set to random - by default, it is commented out (DNSCrypt-Proxy ver. 2.0.44). It's a good solution, due to the large number of DNSCrypt servers available and because they will be choosed randomly etc. So, it also improves privacy, because DNS queries are spread across multiple providers/servers (which may provide additional protection).

After applying above changes and restarting DNSCrypt-Proxy service, log and/or status should contain the following information:

[NOTICE] Anonymized DNS: routing everything via [anon-cs-fr anon-bcn]

Of course, there are some doubts. For example, User has to decide whether it's better to spread DNS queries between multiple different servers, however often with no informations about its DNS traffic situation etc. If such traffic is relative small, then it's harder to, let say, "hide". Summarizing: with a resolver, that doesn't get a lot of traffic, Users can lost a lot of anonymity, privacy etc.

Generally, such providers may provide smaller privacy/protection, because of less traffic to "hide in". If, for example, User is the only user of such a server then DNS queries are practically obvious. On the other hand, using multiple providers means that no single provider can see all User DNS traffic etc.

The situation is completely different in the case of DNS servers, such as Google, CloudFlare or Quad9 where User can "hide" more "preciselly". But now, here comes the question of trust. Anyway, there are so many aspects but this is not the content of this post.

The described configuration has been tested and verified.

Clone this wiki locally