Skip to content

Anonymized DNS

Hoosier3 edited this page Mar 30, 2021 · 21 revisions
Clone this wiki locally

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, that is one of the public resolvers, 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 DNS recursive resolver, the only server that can decrypt it.

The DNS resolver 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 anonymized 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.

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 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:

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.

A wildcard can also be used as a relay (via=["*"]). In that case, the proxy will automatically choose the relays, selecting them by trying to avoid relays and servers to be on the same network.


Relaying is currently incompatible with cisco, as this resolver doesn't correctly implement DNSCrypt 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.


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 or couldn't be reached anonymously messages 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

Using a relay operated by the same entity as the server it relays to, would defeat the purpose of anonymization. Below, there is an explanation about how to avoid such a situation.

When using wildcards, dnscrypt-proxy tries to choose relays so that they are not on the same network as the servers they relay to. However, this is very likely to be suboptimal from a performance and privacy perspective. A manual selection is always preferred.

You may also leverage disabled_server_names to prevent servers operated by entities used by relays from being used. Here is an illustration of such configuration.

In the following example, we have two servers, cs-fr and bcn-dnscrypt, that can also act as relays. We disable them as servers, and enable them as relays.

The relevant parts of the dnscrypt-proxy.toml file would be as follows:

# Here, `server_names` is empty or commented out, so that all servers
# matching filters can be used
#server_names = ['scaleway-fr', 'google', 'yandex', 'cloudflare']

# Server names to disable, because we use them as relays
disabled_server_names = ['cs-fr', 'bcn-dnscrypt']

# Filters
dnscrypt_servers = true
doh_servers = false

# Anonymized DNS section.
# -----------------------

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

skip_incompatible = true

With the above configuration, there is no possibility to use a server and a relay operated by the same entities, which is very important from a privacy point of view. Also, the skip_incompatible option skips resolvers incompatible with anonymization instead of using them directly (cf. the example-dnscrypt-proxy.toml file) when set to true.

After applying above changes, restart the dnscrypt-proxy service and check the logs and/or status - there should be the following information:

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