mirror of https://github.com/getdnsapi/getdns.git
Setting & getting of tsig info per upstream
This commit is contained in:
parent
bc2ec7cee3
commit
98dc4018c3
283
src/context.c
283
src/context.c
|
@ -54,6 +54,7 @@
|
|||
#include "dnssec.h"
|
||||
#include "stub.h"
|
||||
#include "list.h"
|
||||
#include "dict.h"
|
||||
|
||||
#define GETDNS_PORT_ZERO 0
|
||||
#define GETDNS_PORT_DNS 53
|
||||
|
@ -167,7 +168,7 @@ static inline void canonicalize_dname(uint8_t *dname)
|
|||
{
|
||||
uint8_t *next_label;
|
||||
|
||||
while (*dname) {
|
||||
while (*dname && !(*dname & 0xC0)) {
|
||||
next_label = dname + *dname + 1;
|
||||
dname += 1;
|
||||
while (dname < next_label) {
|
||||
|
@ -599,6 +600,64 @@ net_req_query_id_cmp(const void *id1, const void *id2)
|
|||
return (intptr_t)id1 - (intptr_t)id2;
|
||||
}
|
||||
|
||||
static getdns_tsig_info tsig_info[] = {
|
||||
{ GETDNS_NO_TSIG, NULL, 0, NULL, 0, 0, 0 }
|
||||
, { GETDNS_HMAC_MD5 , "hmac-md5.sig-alg.reg.int", 24
|
||||
, (uint8_t *)"\x08hmac-md5\x07sig-alg\x03reg\x03int", 26, 10, 16 }
|
||||
, { GETDNS_NO_TSIG, NULL, 0, NULL, 0, 0, 0 }
|
||||
, { GETDNS_HMAC_SHA1 , "hmac-sha1" , 9
|
||||
, (uint8_t *)"\x09hmac-sha1" , 11, 10, 20 }
|
||||
, { GETDNS_HMAC_SHA224, "hmac-sha224", 11
|
||||
, (uint8_t *)"\x0bhmac-sha224", 13, 14, 28 }
|
||||
, { GETDNS_HMAC_SHA224, "hmac-sha256", 11
|
||||
, (uint8_t *)"\x0bhmac-sha256", 13, 16, 32 }
|
||||
, { GETDNS_HMAC_SHA224, "hmac-sha384", 11
|
||||
, (uint8_t *)"\x0bhmac-sha383", 13, 24, 48 }
|
||||
, { GETDNS_HMAC_SHA224, "hmac-sha512", 11
|
||||
, (uint8_t *)"\x0bhmac-sha512", 13, 32, 64 }
|
||||
, { GETDNS_HMAC_MD5 , "hmac-md5" , 8
|
||||
, (uint8_t *)"\x08hmac-md5" , 10, 10, 16 }
|
||||
};
|
||||
|
||||
const getdns_tsig_info *_getdns_get_tsig_info(getdns_tsig_algo tsig_alg)
|
||||
{
|
||||
return tsig_alg > sizeof(tsig_info) - 1
|
||||
|| tsig_info[tsig_alg].alg == GETDNS_NO_TSIG ? NULL
|
||||
: &tsig_info[tsig_alg];
|
||||
}
|
||||
|
||||
static const getdns_tsig_algo _getdns_get_tsig_algo(getdns_bindata *algo)
|
||||
{
|
||||
getdns_tsig_info *i;
|
||||
|
||||
if (!algo || algo->size == 0)
|
||||
return GETDNS_NO_TSIG;
|
||||
|
||||
if (algo->data[algo->size-1] != 0) {
|
||||
/* Unterminated string */
|
||||
for (i = tsig_info; i < tsig_info + sizeof(tsig_info); i++)
|
||||
if (algo->size == i->strlen_name &&
|
||||
strncasecmp((const char *)algo->data, i->name,
|
||||
i->strlen_name) == 0)
|
||||
return i->alg;
|
||||
|
||||
} else if (!_getdns_bindata_is_dname(algo)) {
|
||||
/* Terminated string */
|
||||
for (i = tsig_info; i < tsig_info + sizeof(tsig_info); i++)
|
||||
if (algo->size - 1 == i->strlen_name &&
|
||||
strncasecmp((const char *)algo->data, i->name,
|
||||
i->strlen_name) == 0)
|
||||
return i->alg;
|
||||
|
||||
} else {
|
||||
/* fqdn, canonical_dname_compare is now safe to use! */
|
||||
for (i = tsig_info; i < tsig_info + sizeof(tsig_info); i++)
|
||||
if (canonical_dname_compare(algo->data, i->dname) == 0)
|
||||
return i->alg;
|
||||
}
|
||||
return GETDNS_NO_TSIG;
|
||||
}
|
||||
|
||||
static void
|
||||
upstream_init(getdns_upstream *upstream,
|
||||
getdns_upstreams *parent, struct addrinfo *ai)
|
||||
|
@ -635,6 +694,10 @@ upstream_init(getdns_upstream *upstream,
|
|||
upstream->has_prev_client_cookie = 0;
|
||||
upstream->has_server_cookie = 0;
|
||||
|
||||
upstream->tsig_alg = GETDNS_NO_TSIG;
|
||||
upstream->tsig_dname_len = 0;
|
||||
upstream->tsig_size = 0;
|
||||
|
||||
/* Tracking of network requests on this socket */
|
||||
_getdns_rbtree_init(&upstream->netreq_by_query_id,
|
||||
net_req_query_id_cmp);
|
||||
|
@ -1715,15 +1778,21 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
upstreams = upstreams_create(
|
||||
context, count * GETDNS_UPSTREAM_TRANSPORTS);
|
||||
for (i = 0; i < count; i++) {
|
||||
getdns_dict *dict;
|
||||
getdns_dict *dict;
|
||||
getdns_bindata *address_type;
|
||||
getdns_bindata *address_data;
|
||||
getdns_bindata *tls_auth_name;
|
||||
struct sockaddr_storage addr;
|
||||
|
||||
getdns_bindata *scope_id;
|
||||
getdns_bindata *scope_id;
|
||||
getdns_upstream *upstream;
|
||||
|
||||
getdns_bindata *tsig_alg_name, *tsig_name, *tsig_key;
|
||||
getdns_tsig_algo tsig_alg;
|
||||
char tsig_name_str[1024];
|
||||
uint8_t tsig_dname_spc[256], *tsig_dname;
|
||||
size_t tsig_dname_len;
|
||||
|
||||
if ((r = getdns_list_get_dict(upstream_list, i, &dict)))
|
||||
goto error;
|
||||
|
||||
|
@ -1760,6 +1829,63 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
eos[scope_id->size] = 0;
|
||||
}
|
||||
|
||||
tsig_alg_name = tsig_name = tsig_key = NULL;
|
||||
tsig_dname = NULL;
|
||||
tsig_dname_len = 0;
|
||||
|
||||
if (getdns_dict_get_bindata(dict,
|
||||
"tsig_algorithm", &tsig_alg_name) == GETDNS_RETURN_GOOD)
|
||||
tsig_alg = _getdns_get_tsig_algo(tsig_alg_name);
|
||||
else
|
||||
tsig_alg = GETDNS_HMAC_MD5;
|
||||
|
||||
if (getdns_dict_get_bindata(dict, "tsig_name", &tsig_name))
|
||||
tsig_alg = GETDNS_NO_TSIG; /* No name, no TSIG */
|
||||
|
||||
else if (tsig_name->size == 0)
|
||||
tsig_alg = GETDNS_NO_TSIG;
|
||||
|
||||
else if (tsig_name->data[tsig_name->size - 1] != 0) {
|
||||
/* Unterminated string */
|
||||
if (tsig_name->size >= sizeof(tsig_name_str) - 1)
|
||||
tsig_alg = GETDNS_NO_TSIG;
|
||||
else {
|
||||
(void) memcpy(tsig_name_str, tsig_name->data
|
||||
, tsig_name->size);
|
||||
tsig_name_str[tsig_name->size] = 0;
|
||||
|
||||
tsig_dname_len = sizeof(tsig_dname_spc);
|
||||
if (gldns_str2wire_dname_buf(tsig_name_str,
|
||||
tsig_dname_spc, &tsig_dname_len))
|
||||
tsig_alg = GETDNS_NO_TSIG;
|
||||
else
|
||||
tsig_dname = tsig_dname_spc;
|
||||
}
|
||||
} else if (!_getdns_bindata_is_dname(tsig_name)) {
|
||||
/* Terminated string */
|
||||
tsig_dname_len = sizeof(tsig_dname_spc);
|
||||
if (gldns_str2wire_dname_buf(tsig_name_str,
|
||||
tsig_dname_spc, &tsig_dname_len))
|
||||
tsig_alg = GETDNS_NO_TSIG;
|
||||
else
|
||||
tsig_dname = tsig_dname_spc;
|
||||
|
||||
} else if (tsig_name->size > sizeof(tsig_dname_spc))
|
||||
tsig_alg = GETDNS_NO_TSIG;
|
||||
|
||||
else {
|
||||
/* fqdn */
|
||||
tsig_dname = memcpy(tsig_dname_spc, tsig_name->data
|
||||
, tsig_name->size);
|
||||
tsig_dname_len = tsig_name->size;
|
||||
}
|
||||
if (getdns_dict_get_bindata(dict, "tsig_secret", &tsig_key))
|
||||
tsig_alg = GETDNS_NO_TSIG; /* No key, no TSIG */
|
||||
|
||||
/* Don't check TSIG length contraints here.
|
||||
* Let the upstream decide what is secure enough.
|
||||
*/
|
||||
|
||||
/* Loop to create upstreams as needed*/
|
||||
for (size_t j = 0; j < GETDNS_UPSTREAM_TRANSPORTS; j++) {
|
||||
uint32_t port;
|
||||
|
@ -1798,6 +1924,25 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
upstream->tls_auth_name[tls_auth_name->size] = '\0';
|
||||
}
|
||||
}
|
||||
if ((upstream->tsig_alg = tsig_alg)) {
|
||||
if (tsig_name) {
|
||||
(void) memcpy(upstream->tsig_dname,
|
||||
tsig_dname, tsig_dname_len);
|
||||
upstream->tsig_dname_len =
|
||||
tsig_dname_len;
|
||||
} else
|
||||
upstream->tsig_dname_len = 0;
|
||||
|
||||
if (tsig_key) {
|
||||
(void) memcpy(upstream->tsig_key,
|
||||
tsig_key->data, tsig_key->size);
|
||||
upstream->tsig_size = tsig_key->size;
|
||||
} else
|
||||
upstream->tsig_size = 0;
|
||||
} else {
|
||||
upstream->tsig_dname_len = 0;
|
||||
upstream->tsig_size = 0;
|
||||
}
|
||||
upstreams->count++;
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
|
@ -2542,9 +2687,12 @@ upstream_port(getdns_upstream *upstream)
|
|||
}
|
||||
|
||||
static getdns_dict*
|
||||
_get_context_settings(getdns_context* context) {
|
||||
_get_context_settings(getdns_context* context)
|
||||
{
|
||||
getdns_return_t r = GETDNS_RETURN_GOOD;
|
||||
getdns_dict* result = getdns_dict_create_with_context(context);
|
||||
getdns_list *upstreams;
|
||||
|
||||
if (!result) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2562,34 +2710,8 @@ _get_context_settings(getdns_context* context) {
|
|||
r |= getdns_dict_set_int(result, "append_name", context->append_name);
|
||||
/* list fields */
|
||||
if (context->suffix) r |= getdns_dict_set_list(result, "suffix", context->suffix);
|
||||
if (context->upstreams && context->upstreams->count > 0) {
|
||||
size_t i;
|
||||
getdns_upstream *upstream;
|
||||
getdns_list *upstreams =
|
||||
getdns_list_create_with_context(context);
|
||||
|
||||
for (i = 0; i < context->upstreams->count;) {
|
||||
size_t j;
|
||||
getdns_dict *d;
|
||||
upstream = &context->upstreams->upstreams[i];
|
||||
d = sockaddr_dict(context,
|
||||
(struct sockaddr *)&upstream->addr);
|
||||
for ( j = 1, i++
|
||||
; j < GETDNS_UPSTREAM_TRANSPORTS &&
|
||||
i < context->upstreams->count
|
||||
; j++, i++) {
|
||||
|
||||
upstream = &context->upstreams->upstreams[i];
|
||||
if (upstream->transport != GETDNS_TRANSPORT_TLS)
|
||||
continue;
|
||||
if (upstream_port(upstream) != getdns_port_array[j])
|
||||
continue;
|
||||
(void) getdns_dict_set_int(d, "tls_port",
|
||||
(uint32_t) upstream_port(upstream));
|
||||
}
|
||||
r |= _getdns_list_append_dict(upstreams, d);
|
||||
getdns_dict_destroy(d);
|
||||
}
|
||||
|
||||
if (!getdns_context_get_upstream_recursive_servers(context, &upstreams)) {
|
||||
r |= getdns_dict_set_list(result, "upstream_recursive_servers",
|
||||
upstreams);
|
||||
getdns_list_destroy(upstreams);
|
||||
|
@ -2956,43 +3078,88 @@ getdns_context_get_dnssec_allowed_skew(getdns_context *context,
|
|||
|
||||
getdns_return_t
|
||||
getdns_context_get_upstream_recursive_servers(getdns_context *context,
|
||||
getdns_list **upstream_list) {
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
RETURN_IF_NULL(upstream_list, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
*upstream_list = NULL;
|
||||
if (context->upstreams && context->upstreams->count > 0) {
|
||||
getdns_return_t r = GETDNS_RETURN_GOOD;
|
||||
size_t i;
|
||||
getdns_upstream *upstream;
|
||||
getdns_list *upstreams = getdns_list_create();
|
||||
for (i = 0; i < context->upstreams->count;) {
|
||||
getdns_list **upstreams_r)
|
||||
{
|
||||
size_t i;
|
||||
getdns_list *upstreams;
|
||||
getdns_return_t r;
|
||||
|
||||
if (!context || !upstreams_r)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
if (!(upstreams = getdns_list_create_with_context(context)))
|
||||
return GETDNS_RETURN_MEMORY_ERROR;
|
||||
|
||||
if (!context->upstreams || context->upstreams->count == 0) {
|
||||
*upstreams_r = upstreams;
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
r = GETDNS_RETURN_GOOD;
|
||||
i = 0;
|
||||
while (!r && i < context->upstreams->count) {
|
||||
size_t j;
|
||||
getdns_dict *d;
|
||||
upstream = &context->upstreams->upstreams[i];
|
||||
d = sockaddr_dict(context, (struct sockaddr *)&upstream->addr);
|
||||
getdns_upstream *upstream = &context->upstreams->upstreams[i];
|
||||
getdns_bindata bindata;
|
||||
const getdns_tsig_info *tsig_info;
|
||||
|
||||
if (!(d =
|
||||
sockaddr_dict(context, (struct sockaddr*)&upstream->addr))) {
|
||||
r = GETDNS_RETURN_MEMORY_ERROR;
|
||||
break;
|
||||
}
|
||||
if (upstream->tsig_alg) {
|
||||
tsig_info = _getdns_get_tsig_info(upstream->tsig_alg);
|
||||
|
||||
bindata.data = tsig_info->dname;
|
||||
bindata.size = tsig_info->dname_len;
|
||||
if ((r = getdns_dict_set_bindata(
|
||||
d, "tsig_algorithm", &bindata)))
|
||||
break;
|
||||
|
||||
if (upstream->tsig_dname_len) {
|
||||
bindata.data = upstream->tsig_dname;
|
||||
bindata.size = upstream->tsig_dname_len;
|
||||
if ((r = getdns_dict_set_bindata(
|
||||
d, "tsig_name", &bindata)))
|
||||
break;
|
||||
}
|
||||
if (upstream->tsig_size) {
|
||||
bindata.data = upstream->tsig_key;
|
||||
bindata.size = upstream->tsig_size;
|
||||
if ((r = getdns_dict_set_bindata(
|
||||
d, "tsig_secret", &bindata)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
for ( j = 1, i++
|
||||
; j < GETDNS_UPSTREAM_TRANSPORTS &&
|
||||
i < context->upstreams->count
|
||||
; j++, i++) {
|
||||
|
||||
upstream = &context->upstreams->upstreams[i];
|
||||
if (upstream->transport != GETDNS_TRANSPORT_TLS)
|
||||
continue;
|
||||
if (upstream_port(upstream) != getdns_port_array[j])
|
||||
continue;
|
||||
(void) getdns_dict_set_int(d, "tls_port",
|
||||
(uint32_t) upstream_port(upstream));
|
||||
|
||||
if (upstream->transport == GETDNS_TRANSPORT_UDP &&
|
||||
upstream_port(upstream) != getdns_port_array[j] &&
|
||||
(r = getdns_dict_set_int(d, "port",
|
||||
(uint32_t)upstream_port(upstream))))
|
||||
break;
|
||||
|
||||
if (upstream->transport == GETDNS_TRANSPORT_TLS &&
|
||||
upstream_port(upstream) != getdns_port_array[j] &&
|
||||
(r = getdns_dict_set_int(d, "tls_port",
|
||||
(uint32_t)upstream_port(upstream))))
|
||||
break;
|
||||
}
|
||||
r |= _getdns_list_append_dict(upstreams, d);
|
||||
if (!r)
|
||||
r = _getdns_list_append_dict(upstreams, d);
|
||||
getdns_dict_destroy(d);
|
||||
}
|
||||
if (r != GETDNS_RETURN_GOOD) {
|
||||
getdns_list_destroy(upstreams);
|
||||
return GETDNS_RETURN_MEMORY_ERROR;
|
||||
}
|
||||
*upstream_list = upstreams;
|
||||
}
|
||||
return GETDNS_RETURN_GOOD;
|
||||
if (r)
|
||||
getdns_list_destroy(upstreams);
|
||||
else
|
||||
*upstreams_r = upstreams;
|
||||
return r;
|
||||
}
|
||||
|
||||
getdns_return_t
|
||||
|
|
|
@ -79,6 +79,29 @@ typedef enum getdns_tls_hs_state {
|
|||
GETDNS_HS_FAILED
|
||||
} getdns_tls_hs_state_t;
|
||||
|
||||
typedef enum getdns_tsig_algo {
|
||||
GETDNS_NO_TSIG = 0, /* Do not use tsig */
|
||||
GETDNS_HMAC_MD5 = 1, /* 128 bits */
|
||||
GETDNS_GSS_TSIG = 2, /* Not supported */
|
||||
GETDNS_HMAC_SHA1 = 3, /* 160 bits */
|
||||
GETDNS_HMAC_SHA224 = 4,
|
||||
GETDNS_HMAC_SHA256 = 5,
|
||||
GETDNS_HMAC_SHA384 = 6,
|
||||
GETDNS_HMAC_SHA512 = 7
|
||||
} getdns_tsig_algo;
|
||||
|
||||
typedef struct getdns_tsig_info {
|
||||
getdns_tsig_algo alg;
|
||||
const char *name;
|
||||
size_t strlen_name;
|
||||
const uint8_t *dname;
|
||||
size_t dname_len;
|
||||
size_t min_size; /* in # octets */
|
||||
size_t max_size; /* Actual size in # octets */
|
||||
} getdns_tsig_info;
|
||||
|
||||
const getdns_tsig_info *_getdns_get_tsig_info(getdns_tsig_algo tsig_alg);
|
||||
|
||||
typedef struct getdns_upstream {
|
||||
/* backpointer to containing upstreams structure */
|
||||
struct getdns_upstreams *upstreams;
|
||||
|
@ -120,6 +143,13 @@ typedef struct getdns_upstream {
|
|||
unsigned has_server_cookie : 1;
|
||||
unsigned server_cookie_len : 5;
|
||||
|
||||
/* TSIG */
|
||||
uint8_t tsig_dname[256];
|
||||
size_t tsig_dname_len;
|
||||
size_t tsig_size;
|
||||
uint8_t tsig_key[256];
|
||||
getdns_tsig_algo tsig_alg;
|
||||
|
||||
} getdns_upstream;
|
||||
|
||||
typedef struct getdns_upstreams {
|
||||
|
|
|
@ -656,12 +656,15 @@ getdns_indent(size_t indent)
|
|||
return spaces + 80 - (indent < 80 ? indent : 0);
|
||||
} /* getdns_indent */
|
||||
|
||||
static int
|
||||
int
|
||||
_getdns_bindata_is_dname(getdns_bindata *bindata)
|
||||
{
|
||||
size_t i = 0, n_labels = 0;
|
||||
|
||||
while (i < bindata->size && bindata->data[i]) {
|
||||
if (bindata->data[i] & 0xC0) /* Compression pointer! */
|
||||
return 0;
|
||||
|
||||
i += ((size_t)bindata->data[i]) + 1;
|
||||
n_labels++;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,11 @@ getdns_return_t _getdns_dict_find(
|
|||
getdns_return_t _getdns_dict_find_and_add(
|
||||
getdns_dict *dict, const char *key, getdns_item **item);
|
||||
|
||||
/* Return 1 (true) if bindata can be interpreted as an
|
||||
* uncompressed dname.
|
||||
*/
|
||||
int _getdns_bindata_is_dname(getdns_bindata *bindata);
|
||||
|
||||
#endif
|
||||
|
||||
/* dict.h */
|
||||
|
|
Loading…
Reference in New Issue