unbound: dnscrypt/dnscrypt.c File Reference

unbound 0.1

Data Structures | Macros | Functions
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.

## 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.
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.
static struct lruhash_entry * | dnsc_shared_secrets_lookup (struct slabhash *cache, uint8_t key[DNSCRYPT_SHARED_SECRET_KEY_LENGTH], uint32_t hash)
| Lookup a record in shared_secrets_cache.
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.
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.
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)
| Lookup a record in nonces_cache.
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.
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.
uint64_t | dnscrypt_hrtime (void)
static void | add_server_nonce (uint8_t *nonce)
| Add the server nonce part to once.
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.
static int | dnsc_read_from_file (char *fname, char *buf, size_t count)
| Read the content of fname into buf.
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.
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.
void | dnsc_key_to_fingerprint (char fingerprint[80U], const uint8_t *const key)
| Helper function to convert a binary key into a printable fingerprint.
static const dnsccert * | dnsc_find_cert (struct dnsc_env *dnscenv, struct sldns_buffer *buffer)
| Find the cert matching a DNSCrypt query.
static int | dnsc_load_local_data (struct dnsc_env *dnscenv, struct config_file *cfg)
| Insert local-zone and local-data into configuration.
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.
int | dnsc_handle_curved_request (struct dnsc_env *dnscenv, struct comm_reply *repinfo)
| ######################################################### ############# Publicly accessible functions ############# #########################################################
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))
| ######################################################### ############# Shared secrets cache functions ############ #########################################################
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))
| ######################################################### ############### Nonces cache functions ################## #########################################################
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

Referenced by dnsc_shared_secret_cache_insert(), dnsc_shared_secrets_cache_key(), dnsc_shared_secrets_lookup(), and dnscrypt_server_uncurve().

## Function Documentation

## ◆ dnsc_shared_secrets_cache_key()

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] | key | a uint8_t pointer of size DNSCRYPT_SHARED_SECRET_KEY_LENGTH
  [in] | esversion | The es version least significant byte.
  [in] | pk | The public key of the client. uint8_t pointer of size crypto_box_PUBLICKEYBYTES.
  [in] | sk | The 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, and lruhash_entry::key.

Referenced by dnscrypt_server_uncurve().

## ◆ dnsc_shared_secret_cache_insert()

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] | cache | the slabhash in which to look for the key.
  [in] | key | a uint8_t pointer of size DNSCRYPT_SHARED_SECRET_KEY_LENGTH which contains the key of the shared secret.
  [in] | hash | the hash of the key.
  [in] | nmkey | a 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, lruhash_entry::key, shared_secret_cache_key::key, lruhash_entry::lock, and slabhash_insert().

Referenced by dnscrypt_server_uncurve().

## ◆ dnsc_shared_secrets_lookup()

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] | cache | a pointer to shared_secrets_cache slabhash.
  [in] | key | a uint8_t pointer of size DNSCRYPT_SHARED_SECRET_KEY_LENGTH containing the key to look for.
  [in] | hash | a hash of the key.

Returns
  a pointer to the locked cache entry or NULL on failure.

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

Referenced by dnscrypt_server_uncurve().

## ◆ dnsc_nonce_cache_key_hash()

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] | nonce | a uint8_t pointer of size crypto_box_HALF_NONCEBYTES
  [in] | magic_query | a uint8_t pointer of size DNSCRYPT_MAGIC_HEADER_LEN
  [in] | pk | The public key of the client. uint8_t pointer of size crypto_box_PUBLICKEYBYTES.

Returns
  the hash of the key.

Referenced by dnscrypt_server_uncurve().

## ◆ dnsc_nonce_cache_insert()

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] | cache | the slabhash in which to look for the key.
  [in] | nonce | a uint8_t pointer of size crypto_box_HALF_NONCEBYTES
  [in] | magic_query | a uint8_t pointer of size DNSCRYPT_MAGIC_HEADER_LEN
  [in] | pk | The public key of the client. uint8_t pointer of size crypto_box_PUBLICKEYBYTES.
  [in] | hash | the 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()

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] | cache | the slabhash in which to look for the key.
  [in] | nonce | a uint8_t pointer of size crypto_box_HALF_NONCEBYTES
  [in] | magic_query | a uint8_t pointer of size DNSCRYPT_MAGIC_HEADER_LEN
  [in] | pk | The public key of the client. uint8_t pointer of size crypto_box_PUBLICKEYBYTES.
  [in] | hash | the 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()

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] | env | the dnscrypt environment.
  [in] | cert | the cert that matches this encrypted query.
  [in] | client_nonce | where the client nonce will be stored.
  [in] | nmkey | where the shared secret key will be written.
  [in] | buffer | the 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_at(), sldns_buffer_begin(), sldns_buffer_limit(), sldns_buffer_set_limit(), and sldns_buffer_set_position().

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

  buf | a buffer
  len | the initial size of the buffer
  max_len | the maximum size
  nonce | a nonce, made of the client nonce repeated twice
  secretkey |

Returns
  the new size, after padding

Referenced by dnscrypt_server_curve().

## ◆ add_server_nonce()

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] | nonce | a uint8_t* of size crypto_box_NONCEBYTES

Referenced by dnscrypt_server_curve().

## ◆ dnscrypt_server_curve()

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] | cert | the dnsccert that matches this encrypted query.
  [in] | client_nonce | client nonce used during the query
  [in] | nmkey | shared secret key used during the query.
  [in] | buffer | the buffer where to encrypt the reply.
  [in] | udp | if whether or not it is a UDP query.
  [in] | max_udp_size | configured max udp size.

Returns
  0 on success.

References add_server_nonce(), dnscrypt_pad(), sldns_buffer_begin(), sldns_buffer_limit(), sldns_buffer_set_at(), sldns_buffer_set_limit(), and sldns_buffer_write_at().

## ◆ dnsc_read_from_file()

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

Read the content of fname into buf.

Parameters

  [in] | fname | name of the file to read.
  [in] | buf | the buffer in which to read the content of the file.
  [in] | count | number of bytes to read.

Returns
  0 on success.

Referenced by dnsc_parse_certs(), and dnsc_parse_keys().

## ◆ dnsc_chroot_path()

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] | cfg | the configuration.
  [in] | path | the 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()

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] | env | the dnsc_env structure to load the certs into.
  [in] | cfg | the 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, config_strlist::str, VERB_OPS, and verbose().

## ◆ 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] | fingerprint | the buffer in which to write the printable key.
  [in] | key | the key to convert.

Referenced by dnsc_parse_keys().

## ◆ dnsc_find_cert()

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

Find the cert matching a DNSCrypt query.

Parameters

  [in] | dnscenv | The DNSCrypt environment, which contains the list of certs supported by the server.
  [in] | buffer | The 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()

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()

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] | env | The dnsc_env structure which will hold the keypairs.
  [in] | cfg | The config with the secret key file paths.

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