
Implementation details
======================

Cryptographic library
---------------------

- We didn't reinvent the wheel.

- The crypto code is provided by NaCl: http://nacl.cr.yp.to/

- Why NaCl? Unbloated, blazing fast, and less error-prone that other libraries.
  See http://cr.yp.to/highspeed/coolnacl-20111201.pdf

- Faster, but CPU-specific implementations have been removed, though,
  so that portable packages can be built. CPU-specific implementations are
  used server-side.

- crypto_box_curve25519xsalsa20poly1305_*() for authenticating/encrypting
  queries and replies, crypto_sign_ed25519_*() for signing certificates, and
  crypto_stream_salsa20() as a PRNG.

  See the NaCl documentation for details.

Event-notification library
--------------------------

- Uses libevent. Unbound's boilerplate is also excellent, but it hasn't been
  packaged as a standalone library yet.

- Because it is totally awesome for writing portable software.

- Bundled with dnscrypt, for now, because it's a modified version (so
  that evdns can cope with TXT records) and because some distributions
  are still shipping dead old versions.

Certificates
------------

The following information has to be provided to the proxy:

- The provider name (defaults to 2.dnscrypt-cert.opendns.com.)
- The provider public key (defaults to the current one for OpenDNS).
- The resolver IP address (defaults to 208.67.220.220).

At startup and every 60 minute, the proxy directly connects to the specified
resolver IP address and issues a TXT query for the provider name. The
first component of the provider name indicates the latest protocol version,
or the version range, supported by the client.

One or more TXT records are returned, each containing a signed certificate.
The provider public key is only used to verify a certificate, never for
authenticating/encrypting queries.

Certificates have the following header:
- 4 byte magic header DNSC
- 2 byte major version
- 2 byte minor version

Followed by signed content (the signature adds 512 bits to the payload):
- server 256-bit public key
- 8 byte magic header to use for queries using this specific key
- 4 byte serial number
- 4 + 4 byte validity period (two timestamps)

The proxy drops invalid certificates for the current date, and picks the one
with the highest serial number.

More than one certificate may be returned when keys rollovers or
function changes are performed.

Resolvers are never signing certificates themselves, they are just providing
pre-signed certificates.

Queries
-------

Queries and replies are basically using djb's dnscurve protocol:
http://www.dnscurve.org/

The proxy always generates a new, in-memory only key pair at startup.

Random padding is added to queries and replies, using a 64 byte block size.

Encrypted queries are prefixed with the following header structure:

- 8 byte magic header (provided by the chosen certificate)
- A 256 bit client public key
- A 96 bit client nonce (64 bit monotically increasing timestamp +
  32 random bits)
- A 128 bit Poly1305-AES MAC

Replies are prefixed with the following header structure:

- 8 byte static magic header r6fnvWJ8
- A 192 bit nonce: the 96 bit client-supplied nonce + a 96 bit server
nonce extension.
- A 128 bit Poly1305-AES MAC.

The proxy immediately discards replies to queries made more than 10
second ago and replies that don't match the client-supplied nonce.

Miscellaneous
-------------

If you need extra monitoring/profiling, the proxy provides a bunch of
DTrace probes on OSX, as the dnscrypt-proxy provider.
See src/dnscrypt-proxy/probes_dnscrypt_proxy.d

The proxy doesn't cache replies. Neither does it perform any DNSSEC
validation yet.

This is better handled by a separate process or by linking libunbound.

The proxy does alter queries, though, in order to:

- immediately reply with a "reply truncated" message to a UDP query when
the --tcp-port switch has been turned on.

- add an empty OPT section in order to advertise a payload size unless
an EDNS section was already present or unless --payload-size with a
< 512 bytes size has been specified.

OSX Mountain Lion, OpenBSD/amd64 and Dragonfly BSD/amd64 are the primary
development platforms, but the code has been designed to be as
portable as possible, and patches to support other operating systems
and architectures are more than welcome.
