dnscrypt.c File Reference

dnscrypt functions for encrypting DNS packets. More...

#include "config.h"
#include <stdlib.h>
#include <fcntl.h>
#include <inttypes.h>
#include <sys/time.h>
#include <sys/types.h>
#include "sldns/sbuffer.h"
#include "util/config_file.h"
#include "util/net_help.h"
#include "util/netevent.h"
#include "util/log.h"
#include "util/storage/slabhash.h"
#include "util/storage/lookup3.h"
#include "dnscrypt/cert.h"
#include "dnscrypt/dnscrypt.h"
#include "dnscrypt/dnscrypt_config.h"
#include <ctype.h>

Data Structures

struct  shared_secret_cache_key
 
struct  nonce_cache_key
 

Macros

#define DNSCRYPT_QUERY_BOX_OFFSET
 
#define DNSCRYPT_REPLY_BOX_OFFSET
 
#define DNSCRYPT_SHARED_SECRET_KEY_LENGTH    (1 + crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES)
 Shared secret cache key length. More...
 

Functions

static uint32_t dnsc_shared_secrets_cache_key (uint8_t *key, uint8_t esversion, uint8_t *pk, uint8_t *sk)
 Generate a key suitable to find shared secret in slabhash. More...
 
static void dnsc_shared_secret_cache_insert (struct slabhash *cache, uint8_t key[DNSCRYPT_SHARED_SECRET_KEY_LENGTH], uint32_t hash, uint8_t nmkey[crypto_box_BEFORENMBYTES])
 Inserts a shared secret into the shared_secrets_cache slabhash. More...
 
static struct lruhash_entrydnsc_shared_secrets_lookup (struct slabhash *cache, uint8_t key[DNSCRYPT_SHARED_SECRET_KEY_LENGTH], uint32_t hash)
 Lookup a record in shared_secrets_cache. More...
 
static uint32_t dnsc_nonce_cache_key_hash (const uint8_t nonce[crypto_box_HALF_NONCEBYTES], const uint8_t magic_query[DNSCRYPT_MAGIC_HEADER_LEN], const uint8_t pk[crypto_box_PUBLICKEYBYTES])
 Generate a key hash suitable to find a nonce in slabhash. More...
 
static void dnsc_nonce_cache_insert (struct slabhash *cache, const uint8_t nonce[crypto_box_HALF_NONCEBYTES], const uint8_t magic_query[DNSCRYPT_MAGIC_HEADER_LEN], const uint8_t pk[crypto_box_PUBLICKEYBYTES], uint32_t hash)
 Inserts a nonce, magic_query, pk tuple into the nonces_cache slabhash. More...
 
static struct lruhash_entrydnsc_nonces_lookup (struct slabhash *cache, const uint8_t nonce[crypto_box_HALF_NONCEBYTES], const uint8_t magic_query[DNSCRYPT_MAGIC_HEADER_LEN], const uint8_t pk[crypto_box_PUBLICKEYBYTES], uint32_t hash)
 Lookup a record in nonces_cache. More...
 
static int dnscrypt_server_uncurve (struct dnsc_env *env, const dnsccert *cert, uint8_t client_nonce[crypto_box_HALF_NONCEBYTES], uint8_t nmkey[crypto_box_BEFORENMBYTES], struct sldns_buffer *buffer)
 Decrypt a query using the dnsccert that was found using dnsc_find_cert. More...
 
size_t dnscrypt_pad (uint8_t *buf, const size_t len, const size_t max_len, const uint8_t *nonce, const uint8_t *secretkey)
 Add random padding to a buffer, according to a client nonce. More...
 
uint64_t dnscrypt_hrtime (void)
 
static void add_server_nonce (uint8_t *nonce)
 Add the server nonce part to once. More...
 
static int dnscrypt_server_curve (const dnsccert *cert, uint8_t client_nonce[crypto_box_HALF_NONCEBYTES], uint8_t nmkey[crypto_box_BEFORENMBYTES], struct sldns_buffer *buffer, uint8_t udp, size_t max_udp_size)
 Encrypt a reply using the dnsccert that was used with the query. More...
 
static int dnsc_read_from_file (char *fname, char *buf, size_t count)
 Read the content of fname into buf. More...
 
static char * dnsc_chroot_path (struct config_file *cfg, char *path)
 Given an absolute path on the original root, returns the absolute path within the chroot. More...
 
static int dnsc_parse_certs (struct dnsc_env *env, struct config_file *cfg)
 Parse certificates files provided by the configuration and load them into dnsc_env. More...
 
void dnsc_key_to_fingerprint (char fingerprint[80U], const uint8_t *const key)
 Helper function to convert a binary key into a printable fingerprint. More...
 
static const dnsccert * dnsc_find_cert (struct dnsc_env *dnscenv, struct sldns_buffer *buffer)
 Find the cert matching a DNSCrypt query. More...
 
static int dnsc_load_local_data (struct dnsc_env *dnscenv, struct config_file *cfg)
 Insert local-zone and local-data into configuration. More...
 
static const char * key_get_es_version (uint8_t version[2])
 
static int dnsc_parse_keys (struct dnsc_env *env, struct config_file *cfg)
 Parse the secret key files from dnscrypt-secret-key config and populates a list of dnsccert with es_version, magic number and secret/public keys supported by dnscrypt listener. More...
 
int dnsc_handle_curved_request (struct dnsc_env *dnscenv, struct comm_reply *repinfo)
 
int dnsc_handle_uncurved_request (struct comm_reply *repinfo)
 
struct dnsc_env * dnsc_create (void)
 
int dnsc_apply_cfg (struct dnsc_env *env, struct config_file *cfg)
 
void dnsc_delete (struct dnsc_env *env)
 
size_t dnsc_shared_secrets_sizefunc (void *k, void *ATTR_UNUSED(d))
 
int dnsc_shared_secrets_compfunc (void *m1, void *m2)
 
void dnsc_shared_secrets_delkeyfunc (void *k, void *ATTR_UNUSED(arg))
 
void dnsc_shared_secrets_deldatafunc (void *d, void *ATTR_UNUSED(arg))
 
size_t dnsc_nonces_sizefunc (void *k, void *ATTR_UNUSED(d))
 
int dnsc_nonces_compfunc (void *m1, void *m2)
 
void dnsc_nonces_delkeyfunc (void *k, void *ATTR_UNUSED(arg))
 
void dnsc_nonces_deldatafunc (void *ATTR_UNUSED(d), void *ATTR_UNUSED(arg))
 

Detailed Description

dnscrypt functions for encrypting DNS packets.

Macro Definition Documentation

◆ DNSCRYPT_QUERY_BOX_OFFSET

#define DNSCRYPT_QUERY_BOX_OFFSET
Value:
(DNSCRYPT_MAGIC_HEADER_LEN + crypto_box_PUBLICKEYBYTES + \
crypto_box_HALF_NONCEBYTES)

◆ DNSCRYPT_REPLY_BOX_OFFSET

#define DNSCRYPT_REPLY_BOX_OFFSET
Value:
(DNSCRYPT_MAGIC_HEADER_LEN + crypto_box_HALF_NONCEBYTES + \
crypto_box_HALF_NONCEBYTES)

◆ DNSCRYPT_SHARED_SECRET_KEY_LENGTH

#define DNSCRYPT_SHARED_SECRET_KEY_LENGTH    (1 + crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES)

Shared secret cache key length.

secret key. 1 byte: ES_VERSION[1] 32 bytes: client crypto_box_PUBLICKEYBYTES 32 bytes: server crypto_box_SECRETKEYBYTES

Function Documentation

◆ dnsc_shared_secrets_cache_key()

static uint32_t dnsc_shared_secrets_cache_key ( uint8_t *  key,
uint8_t  esversion,
uint8_t *  pk,
uint8_t *  sk 
)
static

Generate a key suitable to find shared secret in slabhash.

Parameters
[in]keya uint8_t pointer of size DNSCRYPT_SHARED_SECRET_KEY_LENGTH
[in]esversionThe es version least significant byte.
[in]pkThe public key of the client. uint8_t pointer of size crypto_box_PUBLICKEYBYTES.
[in]skThe secret key of the server matching the magic query number. uint8_t pointer of size crypto_box_SECRETKEYBYTES.
Returns
the hash of the key.

References DNSCRYPT_SHARED_SECRET_KEY_LENGTH, hashlittle(), and lruhash_entry::key.

Referenced by dnscrypt_server_uncurve().

◆ dnsc_shared_secret_cache_insert()

static void dnsc_shared_secret_cache_insert ( struct slabhash cache,
uint8_t  key[DNSCRYPT_SHARED_SECRET_KEY_LENGTH],
uint32_t  hash,
uint8_t  nmkey[crypto_box_BEFORENMBYTES] 
)
static

Inserts a shared secret into the shared_secrets_cache slabhash.

The shared secret is copied so the caller can use it freely without caring about the cache entry being evicted or not.

Parameters
[in]cachethe slabhash in which to look for the key.
[in]keya uint8_t pointer of size DNSCRYPT_SHARED_SECRET_KEY_LENGTH which contains the key of the shared secret.
[in]hashthe hash of the key.
[in]nmkeya uint8_t pointer of size crypto_box_BEFORENMBYTES which contains the shared secret.

References lruhash_entry::data, DNSCRYPT_SHARED_SECRET_KEY_LENGTH, shared_secret_cache_key::entry, lruhash_entry::hash, shared_secret_cache_key::key, lruhash_entry::key, lruhash_entry::lock, and slabhash_insert().

Referenced by dnscrypt_server_uncurve().

◆ dnsc_shared_secrets_lookup()

static struct lruhash_entry* dnsc_shared_secrets_lookup ( struct slabhash cache,
uint8_t  key[DNSCRYPT_SHARED_SECRET_KEY_LENGTH],
uint32_t  hash 
)
static

Lookup a record in shared_secrets_cache.

Parameters
[in]cachea pointer to shared_secrets_cache slabhash.
[in]keya uint8_t pointer of size DNSCRYPT_SHARED_SECRET_KEY_LENGTH containing the key to look for.
[in]hasha hash of the key.
Returns
a pointer to the locked cache entry or NULL on failure.

References lruhash_entry::hash, lruhash_entry::key, and slabhash_lookup().

Referenced by dnscrypt_server_uncurve().

◆ dnsc_nonce_cache_key_hash()

static uint32_t dnsc_nonce_cache_key_hash ( const uint8_t  nonce[crypto_box_HALF_NONCEBYTES],
const uint8_t  magic_query[DNSCRYPT_MAGIC_HEADER_LEN],
const uint8_t  pk[crypto_box_PUBLICKEYBYTES] 
)
static

Generate a key hash suitable to find a nonce in slabhash.

Parameters
[in]noncea uint8_t pointer of size crypto_box_HALF_NONCEBYTES
[in]magic_querya uint8_t pointer of size DNSCRYPT_MAGIC_HEADER_LEN
[in]pkThe public key of the client. uint8_t pointer of size crypto_box_PUBLICKEYBYTES.
Returns
the hash of the key.

References hashlittle().

Referenced by dnscrypt_server_uncurve().

◆ dnsc_nonce_cache_insert()

static void dnsc_nonce_cache_insert ( struct slabhash cache,
const uint8_t  nonce[crypto_box_HALF_NONCEBYTES],
const uint8_t  magic_query[DNSCRYPT_MAGIC_HEADER_LEN],
const uint8_t  pk[crypto_box_PUBLICKEYBYTES],
uint32_t  hash 
)
static

Inserts a nonce, magic_query, pk tuple into the nonces_cache slabhash.

Parameters
[in]cachethe slabhash in which to look for the key.
[in]noncea uint8_t pointer of size crypto_box_HALF_NONCEBYTES
[in]magic_querya uint8_t pointer of size DNSCRYPT_MAGIC_HEADER_LEN
[in]pkThe public key of the client. uint8_t pointer of size crypto_box_PUBLICKEYBYTES.
[in]hashthe hash of the key.

References nonce_cache_key::client_publickey, lruhash_entry::data, nonce_cache_key::entry, lruhash_entry::hash, lruhash_entry::key, lruhash_entry::lock, nonce_cache_key::magic_query, nonce_cache_key::nonce, and slabhash_insert().

Referenced by dnscrypt_server_uncurve().

◆ dnsc_nonces_lookup()

static struct lruhash_entry* dnsc_nonces_lookup ( struct slabhash cache,
const uint8_t  nonce[crypto_box_HALF_NONCEBYTES],
const uint8_t  magic_query[DNSCRYPT_MAGIC_HEADER_LEN],
const uint8_t  pk[crypto_box_PUBLICKEYBYTES],
uint32_t  hash 
)
static

Lookup a record in nonces_cache.

Parameters
[in]cachethe slabhash in which to look for the key.
[in]noncea uint8_t pointer of size crypto_box_HALF_NONCEBYTES
[in]magic_querya uint8_t pointer of size DNSCRYPT_MAGIC_HEADER_LEN
[in]pkThe public key of the client. uint8_t pointer of size crypto_box_PUBLICKEYBYTES.
[in]hashthe hash of the key.
Returns
a pointer to the locked cache entry or NULL on failure.

References nonce_cache_key::client_publickey, nonce_cache_key::entry, lruhash_entry::hash, nonce_cache_key::magic_query, nonce_cache_key::nonce, and slabhash_lookup().

Referenced by dnscrypt_server_uncurve().

◆ dnscrypt_server_uncurve()

static int dnscrypt_server_uncurve ( struct dnsc_env *  env,
const dnsccert *  cert,
uint8_t  client_nonce[crypto_box_HALF_NONCEBYTES],
uint8_t  nmkey[crypto_box_BEFORENMBYTES],
struct sldns_buffer buffer 
)
static

Decrypt a query using the dnsccert that was found using dnsc_find_cert.

The client nonce will be extracted from the encrypted query and stored in client_nonce, a shared secret will be computed and stored in nmkey and the buffer will be decrypted inplace.

Parameters
[in]envthe dnscrypt environment.
[in]certthe cert that matches this encrypted query.
[in]client_noncewhere the client nonce will be stored.
[in]nmkeywhere the shared secret key will be written.
[in]bufferthe encrypted buffer.
Returns
0 on success.

References dnsc_nonce_cache_insert(), dnsc_nonce_cache_key_hash(), dnsc_nonces_lookup(), dnsc_shared_secret_cache_insert(), dnsc_shared_secrets_cache_key(), dnsc_shared_secrets_lookup(), DNSCRYPT_SHARED_SECRET_KEY_LENGTH, lruhash_entry::hash, nonce_cache_key::nonce, sldns_buffer_begin(), and sldns_buffer_limit().

Referenced by dnsc_handle_curved_request().

◆ dnscrypt_pad()

size_t dnscrypt_pad ( uint8_t *  buf,
const size_t  len,
const size_t  max_len,
const uint8_t *  nonce,
const uint8_t *  secretkey 
)

Add random padding to a buffer, according to a client nonce.

The length has to depend on the query in order to avoid reply attacks.

Parameters
bufa buffer
lenthe initial size of the buffer
max_lenthe maximum size
noncea nonce, made of the client nonce repeated twice
secretkey
Returns
the new size, after padding

◆ add_server_nonce()

static void add_server_nonce ( uint8_t *  nonce)
static

Add the server nonce part to once.

The nonce is made half of client nonce and the second half of the server nonce, both of them of size crypto_box_HALF_NONCEBYTES.

Parameters
[in]noncea uint8_t* of size crypto_box_NONCEBYTES

◆ dnscrypt_server_curve()

static int dnscrypt_server_curve ( const dnsccert *  cert,
uint8_t  client_nonce[crypto_box_HALF_NONCEBYTES],
uint8_t  nmkey[crypto_box_BEFORENMBYTES],
struct sldns_buffer buffer,
uint8_t  udp,
size_t  max_udp_size 
)
static

Encrypt a reply using the dnsccert that was used with the query.

The client nonce will be extracted from the encrypted query and stored in The buffer will be encrypted inplace.

Parameters
[in]certthe dnsccert that matches this encrypted query.
[in]client_nonceclient nonce used during the query
[in]nmkeyshared secret key used during the query.
[in]bufferthe buffer where to encrypt the reply.
[in]udpif whether or not it is a UDP query.
[in]max_udp_sizeconfigured max udp size.
Returns
0 on success.

References sldns_buffer_begin(), and sldns_buffer_limit().

◆ dnsc_read_from_file()

static int dnsc_read_from_file ( char *  fname,
char *  buf,
size_t  count 
)
static

Read the content of fname into buf.

Parameters
[in]fnamename of the file to read.
[in]bufthe buffer in which to read the content of the file.
[in]countnumber of bytes to read.
Returns
0 on success.

Referenced by dnsc_parse_certs(), and dnsc_parse_keys().

◆ dnsc_chroot_path()

static char* dnsc_chroot_path ( struct config_file cfg,
char *  path 
)
static

Given an absolute path on the original root, returns the absolute path within the chroot.

If chroot is disabled, the path is not modified. No char * is malloced so there is no need to free this.

Parameters
[in]cfgthe configuration.
[in]paththe path from the original root.
Returns
the path from inside the chroot.

References config_file::chrootdir.

Referenced by dnsc_parse_certs(), and dnsc_parse_keys().

◆ dnsc_parse_certs()

static int dnsc_parse_certs ( struct dnsc_env *  env,
struct config_file cfg 
)
static

Parse certificates files provided by the configuration and load them into dnsc_env.

Parameters
[in]envthe dnsc_env structure to load the certs into.
[in]cfgthe configuration.
Returns
the number of certificates loaded.

References dnsc_chroot_path(), dnsc_read_from_file(), config_file::dnscrypt_provider_cert, config_file::dnscrypt_provider_cert_rotated, config_strlist::next, and config_strlist::str.

◆ dnsc_key_to_fingerprint()

void dnsc_key_to_fingerprint ( char  fingerprint[80U],
const uint8_t *const  key 
)

Helper function to convert a binary key into a printable fingerprint.

Parameters
[in]fingerprintthe buffer in which to write the printable key.
[in]keythe key to convert.

◆ dnsc_find_cert()

static const dnsccert* dnsc_find_cert ( struct dnsc_env *  dnscenv,
struct sldns_buffer buffer 
)
static

Find the cert matching a DNSCrypt query.

Parameters
[in]dnscenvThe DNSCrypt environment, which contains the list of certs supported by the server.
[in]bufferThe encrypted DNS query.
Returns
a dnsccert * if we found a cert matching the magic_number of the query, NULL otherwise.

References sldns_buffer_begin(), and sldns_buffer_limit().

Referenced by dnsc_handle_curved_request().

◆ dnsc_load_local_data()

static int dnsc_load_local_data ( struct dnsc_env *  dnscenv,
struct config_file cfg 
)
static

Insert local-zone and local-data into configuration.

In order to be able to serve certs over TXT, we can reuse the local-zone and local-data config option. The zone and qname are inferred from the provider_name and the content of the TXT record from the certificate content. returns the number of certificate TXT record that were loaded. < 0 in case of error.

References cfg_str2list_insert(), cfg_strlist_insert(), config_file::local_data, config_file::local_zones, log_err(), VERB_OPS, and verbose().

◆ dnsc_parse_keys()

static int dnsc_parse_keys ( struct dnsc_env *  env,
struct config_file cfg 
)
static

Parse the secret key files from dnscrypt-secret-key config and populates a list of dnsccert with es_version, magic number and secret/public keys supported by dnscrypt listener.

Parameters
[in]envThe dnsc_env structure which will hold the keypairs.
[in]cfgThe config with the secret key file paths.

References dnsc_chroot_path(), dnsc_read_from_file(), config_file::dnscrypt_secret_key, config_strlist::next, and config_strlist::str.

◆ dnsc_handle_curved_request()

int dnsc_handle_curved_request ( struct dnsc_env *  dnscenv,
struct comm_reply repinfo 
)

◆ dnsc_shared_secrets_sizefunc()

size_t dnsc_shared_secrets_sizefunc ( void *  k,
void *  ATTR_UNUSED
)
####### Shared secrets cache functions

◆ dnsc_nonces_sizefunc()

size_t dnsc_nonces_sizefunc ( void *  k,
void *  ATTR_UNUSED
)
######### Nonces cache functions