mirror of https://github.com/getdnsapi/getdns.git
Merge branch 'features/tsig' into develop
This commit is contained in:
commit
ee2a1fbfe6
|
@ -206,7 +206,7 @@ else
|
|||
fi
|
||||
AC_CHECK_HEADERS([openssl/conf.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode])
|
||||
AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode])
|
||||
AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [
|
||||
AC_INCLUDES_DEFAULT
|
||||
#ifdef HAVE_OPENSSL_ERR_H
|
||||
|
|
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) {
|
||||
|
@ -598,6 +599,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)
|
||||
|
@ -634,6 +693,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);
|
||||
|
@ -1701,15 +1764,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;
|
||||
|
||||
|
@ -1746,6 +1815,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;
|
||||
|
@ -1783,6 +1909,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);
|
||||
}
|
||||
|
@ -2527,9 +2672,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;
|
||||
}
|
||||
|
@ -2547,34 +2695,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);
|
||||
|
@ -2935,43 +3057,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++;
|
||||
}
|
||||
|
@ -992,6 +995,7 @@ getdns_pp_dict(gldns_buffer * buf, size_t indent,
|
|||
if (!json &&
|
||||
(strcmp(item->node.key, "answer_type") == 0 ||
|
||||
strcmp(item->node.key, "dnssec_status") == 0 ||
|
||||
strcmp(item->node.key, "tsig_status") == 0 ||
|
||||
strcmp(item->node.key, "status") == 0 ||
|
||||
strcmp(item->node.key, "append_name") == 0 ||
|
||||
strcmp(item->node.key, "follow_redirects") == 0 ||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -87,6 +87,19 @@ gldns_write_uint32(void *dst, uint32_t data)
|
|||
}
|
||||
|
||||
|
||||
INLINE void
|
||||
gldns_write_uint48(void *dst, uint64_t data)
|
||||
{
|
||||
uint8_t *p = (uint8_t *) dst;
|
||||
p[0] = (uint8_t) ((data >> 40) & 0xff);
|
||||
p[1] = (uint8_t) ((data >> 32) & 0xff);
|
||||
p[2] = (uint8_t) ((data >> 24) & 0xff);
|
||||
p[3] = (uint8_t) ((data >> 16) & 0xff);
|
||||
p[4] = (uint8_t) ((data >> 8) & 0xff);
|
||||
p[5] = (uint8_t) (data & 0xff);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \file gbuffer.h
|
||||
*
|
||||
|
@ -534,6 +547,20 @@ gldns_buffer_write_u32_at(gldns_buffer *buffer, size_t at, uint32_t data)
|
|||
gldns_write_uint32(buffer->_data + at, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* writes the given 6 byte integer at the given position in the buffer
|
||||
* \param[in] buffer the buffer
|
||||
* \param[in] at the position in the buffer
|
||||
* \param[in] data the (lower) 48 bits to write
|
||||
*/
|
||||
INLINE void
|
||||
gldns_buffer_write_u48_at(gldns_buffer *buffer, size_t at, uint64_t data)
|
||||
{
|
||||
if (buffer->_fixed && at + 6 > buffer->_limit) return;
|
||||
assert(gldns_buffer_available_at(buffer, at, 6));
|
||||
gldns_write_uint48(buffer->_data + at, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* writes the given 4 byte integer at the current position in the buffer
|
||||
* \param[in] buffer the buffer
|
||||
|
@ -546,6 +573,18 @@ gldns_buffer_write_u32(gldns_buffer *buffer, uint32_t data)
|
|||
buffer->_position += sizeof(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* writes the given 6 byte integer at the current position in the buffer
|
||||
* \param[in] buffer the buffer
|
||||
* \param[in] data the 48 bits to write
|
||||
*/
|
||||
INLINE void
|
||||
gldns_buffer_write_u48(gldns_buffer *buffer, uint64_t data)
|
||||
{
|
||||
gldns_buffer_write_u48_at(buffer, buffer->_position, data);
|
||||
buffer->_position += 6;
|
||||
}
|
||||
|
||||
/**
|
||||
* copies count bytes of data at the given position to the given data-array
|
||||
* \param[in] buffer the buffer
|
||||
|
|
|
@ -41,6 +41,26 @@
|
|||
#include "gldns/gbuffer.h"
|
||||
#include "gldns/pkthdr.h"
|
||||
#include "dict.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* MAXIMUM_TSIG_SPACE = TSIG name (dname) : 256
|
||||
* TSIG type (uint16_t) : 2
|
||||
* TSIG class (uint16_t) : 2
|
||||
* TSIG TTL (uint32_t) : 4
|
||||
* RdLen (uint16_t) : 2
|
||||
* Algorithm name (dname) : 256
|
||||
* Time Signed (uint48_t) : 6
|
||||
* Fudge (uint16_t) : 2
|
||||
* Mac Size (uint16_t) : 2
|
||||
* Mac (variable) : EVP_MAX_MD_SIZE
|
||||
* Original Id (uint16_t) : 2
|
||||
* Error (uint16_t) : 2
|
||||
* Other Len (uint16_t) : 2
|
||||
* Other Data (nothing) : 0
|
||||
* ---- +
|
||||
* 538 + EVP_MAX_MD_SIZE
|
||||
*/
|
||||
#define MAXIMUM_TSIG_SPACE (538 + EVP_MAX_MD_SIZE)
|
||||
|
||||
getdns_dict dnssec_ok_checking_disabled_spc = {
|
||||
{ RBTREE_NULL, 0, (int (*)(const void *, const void *)) strcmp },
|
||||
|
@ -114,6 +134,7 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
|
|||
net_req->owner = owner;
|
||||
|
||||
net_req->dnssec_status = GETDNS_DNSSEC_INDETERMINATE;
|
||||
net_req->tsig_status = GETDNS_DNSSEC_INDETERMINATE;
|
||||
|
||||
net_req->upstream = NULL;
|
||||
net_req->fd = -1;
|
||||
|
@ -250,7 +271,7 @@ _getdns_network_req_add_upstream_option(getdns_network_req * req, uint16_t code,
|
|||
|
||||
/* no overflow allowed for OPT size either (maybe this is overkill
|
||||
given the above check?) */
|
||||
oldlen = gldns_read_uint16(req->opt + 9);
|
||||
oldlen = gldns_read_uint16(req->opt + 9);
|
||||
newlen = oldlen + 4 + sz;
|
||||
if (newlen > UINT16_MAX)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
@ -278,6 +299,267 @@ _getdns_network_req_add_upstream_option(getdns_network_req * req, uint16_t code,
|
|||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
||||
size_t
|
||||
_getdns_network_req_add_tsig(getdns_network_req *req)
|
||||
{
|
||||
getdns_upstream *upstream = req->upstream;
|
||||
gldns_buffer gbuf;
|
||||
uint16_t arcount;
|
||||
const getdns_tsig_info *tsig_info;
|
||||
uint8_t md_buf[EVP_MAX_MD_SIZE];
|
||||
unsigned int md_len = EVP_MAX_MD_SIZE;
|
||||
const EVP_MD *digester;
|
||||
|
||||
/* Should only be called when in stub mode */
|
||||
assert(req->query);
|
||||
|
||||
if (upstream->tsig_alg == GETDNS_NO_TSIG || !upstream->tsig_dname_len)
|
||||
return req->response - req->query;
|
||||
|
||||
arcount = gldns_read_uint16(req->query + 10);
|
||||
|
||||
#if defined(STUB_DEBUG) && STUB_DEBUG
|
||||
/* TSIG should not have been written yet. */
|
||||
if (req->opt) {
|
||||
assert(arcount == 1);
|
||||
assert(req->opt + 11 + gldns_read_uint16(req->opt + 9)
|
||||
== req->response);
|
||||
} else
|
||||
assert(arcount == 0);
|
||||
#endif
|
||||
tsig_info = _getdns_get_tsig_info(upstream->tsig_alg);
|
||||
|
||||
gldns_buffer_init_frm_data(&gbuf, req->response, MAXIMUM_TSIG_SPACE);
|
||||
gldns_buffer_write(&gbuf,
|
||||
upstream->tsig_dname, upstream->tsig_dname_len); /* Name */
|
||||
gldns_buffer_write_u16(&gbuf, GETDNS_RRCLASS_ANY); /* Class */
|
||||
gldns_buffer_write_u32(&gbuf, 0); /* TTL */
|
||||
gldns_buffer_write(&gbuf,
|
||||
tsig_info->dname, tsig_info->dname_len); /* Algorithm Name */
|
||||
gldns_buffer_write_u48(&gbuf, time(NULL)); /* Time Signed */
|
||||
gldns_buffer_write_u16(&gbuf, 300); /* Fudge */
|
||||
gldns_buffer_write_u16(&gbuf, 0); /* Error */
|
||||
gldns_buffer_write_u16(&gbuf, 0); /* Other len */
|
||||
|
||||
switch (upstream->tsig_alg) {
|
||||
#ifdef HAVE_EVP_MD5
|
||||
case GETDNS_HMAC_MD5 : digester = EVP_md5() ; break;
|
||||
#endif
|
||||
#ifdef HAVE_EVP_SHA1
|
||||
case GETDNS_HMAC_SHA1 : digester = EVP_sha1() ; break;
|
||||
#endif
|
||||
#ifdef HAVE_EVP_SHA224
|
||||
case GETDNS_HMAC_SHA224: digester = EVP_sha224(); break;
|
||||
#endif
|
||||
#ifdef HAVE_EVP_SHA256
|
||||
case GETDNS_HMAC_SHA256: digester = EVP_sha256(); break;
|
||||
#endif
|
||||
#ifdef HAVE_EVP_SHA384
|
||||
case GETDNS_HMAC_SHA384: digester = EVP_sha384(); break;
|
||||
#endif
|
||||
#ifdef HAVE_EVP_SHA512
|
||||
case GETDNS_HMAC_SHA512: digester = EVP_sha512(); break;
|
||||
#endif
|
||||
default : return req->response - req->query;
|
||||
}
|
||||
|
||||
(void) HMAC(digester, upstream->tsig_key, upstream->tsig_size,
|
||||
(void *)req->query, gldns_buffer_current(&gbuf) - req->query,
|
||||
md_buf, &md_len);
|
||||
|
||||
gldns_buffer_rewind(&gbuf);
|
||||
gldns_buffer_write(&gbuf,
|
||||
upstream->tsig_dname, upstream->tsig_dname_len); /* Name */
|
||||
gldns_buffer_write_u16(&gbuf, GETDNS_RRTYPE_TSIG); /* Type*/
|
||||
gldns_buffer_write_u16(&gbuf, GETDNS_RRCLASS_ANY); /* Class */
|
||||
gldns_buffer_write_u32(&gbuf, 0); /* TTL */
|
||||
gldns_buffer_write_u16(&gbuf,
|
||||
tsig_info->dname_len + 10 + md_len + 6); /* RdLen */
|
||||
gldns_buffer_write(&gbuf,
|
||||
tsig_info->dname, tsig_info->dname_len); /* Algorithm Name */
|
||||
gldns_buffer_write_u48(&gbuf, time(NULL)); /* Time Signed */
|
||||
gldns_buffer_write_u16(&gbuf, 300); /* Fudge */
|
||||
gldns_buffer_write_u16(&gbuf, md_len); /* MAC Size */
|
||||
gldns_buffer_write(&gbuf, md_buf, md_len); /* MAC*/
|
||||
gldns_buffer_write(&gbuf, req->query, 2); /* Original ID */
|
||||
gldns_buffer_write_u16(&gbuf, 0); /* Error */
|
||||
gldns_buffer_write_u16(&gbuf, 0); /* Other len */
|
||||
|
||||
if (gldns_buffer_position(&gbuf) > gldns_buffer_limit(&gbuf))
|
||||
return req->response - req->query;
|
||||
|
||||
DEBUG_STUB("Sending with TSIG, mac length: %d\n", (int)md_len);
|
||||
req->tsig_status = GETDNS_DNSSEC_INSECURE;
|
||||
gldns_write_uint16(req->query + 10, arcount + 1);
|
||||
req->response = gldns_buffer_current(&gbuf);
|
||||
return req->response - req->query;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
_getdns_network_validate_tsig(getdns_network_req *req)
|
||||
{
|
||||
_getdns_rr_iter rr_spc, *rr;
|
||||
_getdns_rdf_iter rdf_spc, *rdf;
|
||||
uint8_t *request_mac;
|
||||
uint16_t request_mac_len;
|
||||
uint8_t tsig_vars[MAXIMUM_TSIG_SPACE];
|
||||
gldns_buffer gbuf;
|
||||
uint8_t *dname;
|
||||
size_t dname_len;
|
||||
uint8_t *response_mac;
|
||||
uint16_t response_mac_len;
|
||||
uint8_t other_len;
|
||||
uint8_t result_mac[EVP_MAX_MD_SIZE];
|
||||
unsigned int result_mac_len = EVP_MAX_MD_SIZE;
|
||||
uint16_t original_id;
|
||||
const EVP_MD *digester;
|
||||
HMAC_CTX ctx;
|
||||
|
||||
DEBUG_STUB("Validate TSIG\n");
|
||||
for ( rr = _getdns_rr_iter_init(&rr_spc, req->query,
|
||||
(req->response - req->query))
|
||||
; rr
|
||||
; rr = _getdns_rr_iter_next(rr)) {
|
||||
|
||||
if (_getdns_rr_iter_section(rr) == GLDNS_SECTION_ADDITIONAL &&
|
||||
gldns_read_uint16(rr->rr_type) == GETDNS_RRTYPE_TSIG)
|
||||
break;
|
||||
}
|
||||
if (!rr || !(rdf = _getdns_rdf_iter_init_at(&rdf_spc, rr, 3)))
|
||||
return; /* No good TSIG sent, so nothing expected on reply */
|
||||
|
||||
request_mac_len = gldns_read_uint16(rdf->pos);
|
||||
if (request_mac_len != rdf->nxt - rdf->pos - 2)
|
||||
return;
|
||||
DEBUG_STUB("Request MAC found length: %d\n", (int)(request_mac_len));
|
||||
request_mac = rdf->pos + 2;
|
||||
|
||||
/* Now we expect a TSIG on the response! */
|
||||
req->tsig_status = GETDNS_DNSSEC_BOGUS;
|
||||
|
||||
for ( rr = _getdns_rr_iter_init(
|
||||
&rr_spc, req->response, req->response_len)
|
||||
; rr
|
||||
; rr = _getdns_rr_iter_next(rr)) {
|
||||
|
||||
if (_getdns_rr_iter_section(rr) == GLDNS_SECTION_ADDITIONAL &&
|
||||
gldns_read_uint16(rr->rr_type) == GETDNS_RRTYPE_TSIG)
|
||||
break;
|
||||
}
|
||||
if (!rr || !(rdf = _getdns_rdf_iter_init(&rdf_spc, rr)))
|
||||
return;
|
||||
gldns_buffer_init_frm_data(&gbuf, tsig_vars, MAXIMUM_TSIG_SPACE);
|
||||
|
||||
dname_len = gldns_buffer_remaining(&gbuf);
|
||||
if (!(dname = _getdns_owner_if_or_as_decompressed(
|
||||
rr, gldns_buffer_current(&gbuf), &dname_len)))
|
||||
return;
|
||||
if (dname == gldns_buffer_current(&gbuf))
|
||||
gldns_buffer_skip(&gbuf, dname_len);
|
||||
else
|
||||
gldns_buffer_write(&gbuf, dname, dname_len);
|
||||
|
||||
gldns_buffer_write(&gbuf, rr->rr_type + 2, 2); /* Class */
|
||||
gldns_buffer_write(&gbuf, rr->rr_type + 4, 4); /* TTL */
|
||||
|
||||
dname_len = gldns_buffer_remaining(&gbuf);
|
||||
if (!(dname = _getdns_rdf_if_or_as_decompressed(
|
||||
rdf, gldns_buffer_current(&gbuf), &dname_len)))
|
||||
return;
|
||||
if (dname == gldns_buffer_current(&gbuf))
|
||||
gldns_buffer_skip(&gbuf, dname_len);
|
||||
else
|
||||
gldns_buffer_write(&gbuf, dname, dname_len);
|
||||
|
||||
if (!(rdf = _getdns_rdf_iter_next(rdf)) ||
|
||||
rdf->nxt - rdf->pos != 6)
|
||||
return;
|
||||
gldns_buffer_write(&gbuf, rdf->pos, 6); /* Time Signed */
|
||||
|
||||
if (!(rdf = _getdns_rdf_iter_next(rdf)) ||
|
||||
rdf->nxt - rdf->pos != 2)
|
||||
return;
|
||||
gldns_buffer_write(&gbuf, rdf->pos, 2); /* Fudge */
|
||||
|
||||
if (!(rdf = _getdns_rdf_iter_next(rdf))) /* mac */
|
||||
return;
|
||||
response_mac_len = gldns_read_uint16(rdf->pos);
|
||||
if (response_mac_len != rdf->nxt - rdf->pos - 2)
|
||||
return;
|
||||
DEBUG_STUB("Response MAC found length: %d\n", (int)(response_mac_len));
|
||||
response_mac = rdf->pos + 2;
|
||||
|
||||
if (!(rdf = _getdns_rdf_iter_next(rdf)) ||
|
||||
rdf->nxt -rdf->pos != 2) /* Original ID */
|
||||
return;
|
||||
original_id = gldns_read_uint16(rdf->pos);
|
||||
|
||||
if (!(rdf = _getdns_rdf_iter_next(rdf)) ||
|
||||
rdf->nxt - rdf->pos != 2)
|
||||
return;
|
||||
gldns_buffer_write(&gbuf, rdf->pos, 2); /* Error */
|
||||
|
||||
if (!(rdf = _getdns_rdf_iter_next(rdf))) /* Other */
|
||||
return;
|
||||
|
||||
gldns_buffer_write_u16(&gbuf, 0); /* Other len */
|
||||
other_len = gldns_read_uint16(rdf->pos);
|
||||
if (other_len != rdf->nxt - rdf->pos - 2)
|
||||
return;
|
||||
if (other_len)
|
||||
gldns_buffer_write(&gbuf, rdf->pos, other_len);
|
||||
|
||||
/* TSIG found */
|
||||
DEBUG_STUB("TSIG found, original ID: %d\n", (int)original_id);
|
||||
|
||||
gldns_write_uint16(req->response + 10,
|
||||
gldns_read_uint16(req->response + 10) - 1);
|
||||
gldns_write_uint16(req->response, original_id);
|
||||
|
||||
switch (req->upstream->tsig_alg) {
|
||||
#ifdef HAVE_EVP_MD5
|
||||
case GETDNS_HMAC_MD5 : digester = EVP_md5() ; break;
|
||||
#endif
|
||||
#ifdef HAVE_EVP_SHA1
|
||||
case GETDNS_HMAC_SHA1 : digester = EVP_sha1() ; break;
|
||||
#endif
|
||||
#ifdef HAVE_EVP_SHA224
|
||||
case GETDNS_HMAC_SHA224: digester = EVP_sha224(); break;
|
||||
#endif
|
||||
#ifdef HAVE_EVP_SHA256
|
||||
case GETDNS_HMAC_SHA256: digester = EVP_sha256(); break;
|
||||
#endif
|
||||
#ifdef HAVE_EVP_SHA384
|
||||
case GETDNS_HMAC_SHA384: digester = EVP_sha384(); break;
|
||||
#endif
|
||||
#ifdef HAVE_EVP_SHA512
|
||||
case GETDNS_HMAC_SHA512: digester = EVP_sha512(); break;
|
||||
#endif
|
||||
default : return;
|
||||
}
|
||||
|
||||
HMAC_CTX_init(&ctx);
|
||||
(void) HMAC_Init_ex(&ctx, req->upstream->tsig_key,
|
||||
req->upstream->tsig_size, digester, NULL);
|
||||
(void) HMAC_Update(&ctx, request_mac - 2, request_mac_len + 2);
|
||||
(void) HMAC_Update(&ctx, req->response, rr->pos - req->response);
|
||||
(void) HMAC_Update(&ctx, tsig_vars, gldns_buffer_position(&gbuf));
|
||||
HMAC_Final(&ctx, result_mac, &result_mac_len);
|
||||
|
||||
DEBUG_STUB("Result MAC length: %d\n", (int)(result_mac_len));
|
||||
if (result_mac_len == response_mac_len &&
|
||||
memcmp(result_mac, response_mac, result_mac_len) == 0)
|
||||
req->tsig_status = GETDNS_DNSSEC_SECURE;
|
||||
|
||||
HMAC_CTX_cleanup(&ctx);
|
||||
|
||||
gldns_write_uint16(req->response, gldns_read_uint16(req->query));
|
||||
gldns_write_uint16(req->response + 10,
|
||||
gldns_read_uint16(req->response + 10) + 1);
|
||||
}
|
||||
|
||||
void
|
||||
_getdns_dns_req_free(getdns_dns_req * req)
|
||||
{
|
||||
|
@ -440,7 +722,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop,
|
|||
+ strlen(name) + 1 + 4 /* dname always smaller then strlen(name) + 1 */
|
||||
+ 12 + opt_options_size /* space needed for OPT (if needed) */
|
||||
+ MAXIMUM_UPSTREAM_OPTION_SPACE
|
||||
/* TODO: TSIG */
|
||||
+ MAXIMUM_TSIG_SPACE
|
||||
+ 7) / 8 * 8;
|
||||
}
|
||||
max_response_sz = (( edns_maximum_udp_payload_size != -1
|
||||
|
|
|
@ -728,7 +728,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
|||
netreq->keepalive_sent = 1;
|
||||
}
|
||||
}
|
||||
pkt_len = netreq->response - netreq->query;
|
||||
pkt_len = _getdns_network_req_add_tsig(netreq);
|
||||
/* We have an initialized packet buffer.
|
||||
* Lets see how much of it we can write
|
||||
*/
|
||||
|
@ -1207,7 +1207,7 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp,
|
|||
}
|
||||
}
|
||||
|
||||
pkt_len = netreq->response - netreq->query;
|
||||
pkt_len = _getdns_network_req_add_tsig(netreq);
|
||||
/* We have an initialized packet buffer.
|
||||
* Lets see how much of it we can write */
|
||||
|
||||
|
@ -1332,7 +1332,7 @@ stub_udp_write_cb(void *userarg)
|
|||
if (attach_edns_client_subnet_private(netreq))
|
||||
return; /* too many upstream options */
|
||||
}
|
||||
pkt_len = netreq->response - netreq->query;
|
||||
pkt_len = _getdns_network_req_add_tsig(netreq);
|
||||
if ((ssize_t)pkt_len != sendto(netreq->fd, netreq->query, pkt_len, 0,
|
||||
(struct sockaddr *)&netreq->upstream->addr,
|
||||
netreq->upstream->addr_len)) {
|
||||
|
|
|
@ -267,6 +267,66 @@ static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL;
|
|||
|
||||
int get_rrtype(const char *t);
|
||||
|
||||
int gqldns_b64_pton(char const *src, uint8_t *target, size_t targsize)
|
||||
{
|
||||
const uint8_t pad64 = 64; /* is 64th in the b64 array */
|
||||
const char* s = src;
|
||||
uint8_t in[4];
|
||||
size_t o = 0, incount = 0;
|
||||
|
||||
while(*s) {
|
||||
/* skip any character that is not base64 */
|
||||
/* conceptually we do:
|
||||
const char* b64 = pad'=' is appended to array
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
const char* d = strchr(b64, *s++);
|
||||
and use d-b64;
|
||||
*/
|
||||
char d = *s++;
|
||||
if(d <= 'Z' && d >= 'A')
|
||||
d -= 'A';
|
||||
else if(d <= 'z' && d >= 'a')
|
||||
d = d - 'a' + 26;
|
||||
else if(d <= '9' && d >= '0')
|
||||
d = d - '0' + 52;
|
||||
else if(d == '+')
|
||||
d = 62;
|
||||
else if(d == '/')
|
||||
d = 63;
|
||||
else if(d == '=')
|
||||
d = 64;
|
||||
else continue;
|
||||
in[incount++] = (uint8_t)d;
|
||||
if(incount != 4)
|
||||
continue;
|
||||
/* process whole block of 4 characters into 3 output bytes */
|
||||
if(in[3] == pad64 && in[2] == pad64) { /* A B = = */
|
||||
if(o+1 > targsize)
|
||||
return -1;
|
||||
target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
|
||||
o += 1;
|
||||
break; /* we are done */
|
||||
} else if(in[3] == pad64) { /* A B C = */
|
||||
if(o+2 > targsize)
|
||||
return -1;
|
||||
target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
|
||||
target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2);
|
||||
o += 2;
|
||||
break; /* we are done */
|
||||
} else {
|
||||
if(o+3 > targsize)
|
||||
return -1;
|
||||
/* write xxxxxxyy yyyyzzzz zzwwwwww */
|
||||
target[o] = (in[0]<<2) | ((in[1]&0x30)>>4);
|
||||
target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2);
|
||||
target[o+2]= ((in[2]&0x03)<<6) | in[3];
|
||||
o += 3;
|
||||
}
|
||||
incount = 0;
|
||||
}
|
||||
return (int)o;
|
||||
}
|
||||
|
||||
getdns_dict *
|
||||
ipaddr_dict(getdns_context *context, char *ipstr)
|
||||
{
|
||||
|
@ -275,6 +335,13 @@ ipaddr_dict(getdns_context *context, char *ipstr)
|
|||
char *p = strchr(ipstr, '@'), *portstr = "";
|
||||
char *t = strchr(ipstr, '#'), *tls_portstr = "";
|
||||
char *n = strchr(ipstr, '~'), *tls_namestr = "";
|
||||
/* ^[alg:]name:key */
|
||||
char *T = strchr(ipstr, '^'), *tsig_name_str = ""
|
||||
, *tsig_secret_str = ""
|
||||
, *tsig_algorithm_str = "";
|
||||
int tsig_secret_size;
|
||||
uint8_t tsig_secret_buf[256]; /* 4 times SHA512 */
|
||||
getdns_bindata tsig_secret;
|
||||
uint8_t buf[sizeof(struct in6_addr)];
|
||||
getdns_bindata addr;
|
||||
|
||||
|
@ -297,6 +364,22 @@ ipaddr_dict(getdns_context *context, char *ipstr)
|
|||
*n = 0;
|
||||
tls_namestr = n + 1;
|
||||
}
|
||||
if (T) {
|
||||
*T = 0;
|
||||
tsig_name_str = T + 1;
|
||||
if ((T = strchr(tsig_name_str, ':'))) {
|
||||
*T = 0;
|
||||
tsig_secret_str = T + 1;
|
||||
if ((T = strchr(tsig_secret_str, ':'))) {
|
||||
*T = 0;
|
||||
tsig_algorithm_str = tsig_name_str;
|
||||
tsig_name_str = tsig_secret_str;
|
||||
tsig_secret_str = T + 1;
|
||||
}
|
||||
} else {
|
||||
tsig_name_str = "";
|
||||
}
|
||||
}
|
||||
if (strchr(ipstr, ':')) {
|
||||
getdns_dict_util_set_string(r, "address_type", "IPv6");
|
||||
addr.size = 16;
|
||||
|
@ -322,7 +405,19 @@ ipaddr_dict(getdns_context *context, char *ipstr)
|
|||
}
|
||||
if (*scope_id_str)
|
||||
getdns_dict_util_set_string(r, "scope_id", scope_id_str);
|
||||
|
||||
if (*tsig_name_str)
|
||||
getdns_dict_util_set_string(r, "tsig_name", tsig_name_str);
|
||||
if (*tsig_algorithm_str)
|
||||
getdns_dict_util_set_string(r, "tsig_algorithm", tsig_name_str);
|
||||
if (*tsig_secret_str) {
|
||||
tsig_secret_size = gqldns_b64_pton(
|
||||
tsig_secret_str, tsig_secret_buf, sizeof(tsig_secret_buf));
|
||||
if (tsig_secret_size > 0) {
|
||||
tsig_secret.size = tsig_secret_size;
|
||||
tsig_secret.data = tsig_secret_buf;
|
||||
getdns_dict_set_bindata(r, "tsig_secret", &tsig_secret);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -209,6 +209,14 @@ typedef struct getdns_network_req
|
|||
/* dnssec status */
|
||||
int dnssec_status;
|
||||
|
||||
/* tsig status:
|
||||
* GETDNS_DNSSEC_INDETERMINATE means "No TSIG processing"
|
||||
* GETDNS_DNSSEC_INSECURE means "TSIG sent, validate reply"
|
||||
* GETDNS_DNSSEC_SECURE means "Validated"
|
||||
* GETDNS_DNSSEC_BOGUS means "Validation failed"
|
||||
*/
|
||||
int tsig_status;
|
||||
|
||||
/* For stub resolving */
|
||||
struct getdns_upstream *upstream;
|
||||
int fd;
|
||||
|
@ -381,5 +389,10 @@ getdns_return_t _getdns_network_req_add_upstream_option(getdns_network_req * req
|
|||
uint16_t code, uint16_t sz, const void* data);
|
||||
void _getdns_network_req_clear_upstream_options(getdns_network_req * req);
|
||||
|
||||
/* Adds TSIG signature (if needed) and returns query length */
|
||||
size_t _getdns_network_req_add_tsig(getdns_network_req *req);
|
||||
|
||||
void _getdns_network_validate_tsig(getdns_network_req *req);
|
||||
|
||||
#endif
|
||||
/* types-internal.h */
|
||||
|
|
|
@ -819,6 +819,9 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request)
|
|||
if (! netreq->response_len)
|
||||
continue;
|
||||
|
||||
if (netreq->tsig_status == GETDNS_DNSSEC_INSECURE)
|
||||
_getdns_network_validate_tsig(netreq);
|
||||
|
||||
nreplies++;
|
||||
if (netreq->dnssec_status == GETDNS_DNSSEC_SECURE)
|
||||
nsecure++;
|
||||
|
@ -837,6 +840,8 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request)
|
|||
else if (completed_request->dnssec_return_only_secure
|
||||
&& netreq->dnssec_status != GETDNS_DNSSEC_SECURE)
|
||||
continue;
|
||||
else if (netreq->tsig_status == GETDNS_DNSSEC_BOGUS)
|
||||
continue;
|
||||
}
|
||||
if (!(reply = _getdns_create_reply_dict(context,
|
||||
netreq, just_addrs, &rrsigs_in_answer)))
|
||||
|
@ -864,7 +869,11 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request)
|
|||
netreq->dnssec_status))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (netreq->tsig_status != GETDNS_DNSSEC_INDETERMINATE) {
|
||||
if (getdns_dict_set_int(reply, "tsig_status",
|
||||
netreq->tsig_status))
|
||||
goto error;
|
||||
}
|
||||
if (_getdns_list_append_dict(replies_tree, reply)) {
|
||||
getdns_dict_destroy(reply);
|
||||
goto error;
|
||||
|
|
Loading…
Reference in New Issue