Merge branch 'features/native-stub-dnssec' into develop

Conflicts:
	configure.ac
	src/stub.c
This commit is contained in:
Willem Toorop 2015-07-02 10:27:27 +02:00
commit f066d5ef73
22 changed files with 2457 additions and 1108 deletions

4
aclocal.m4 vendored
View File

@ -1,6 +1,6 @@
# generated automatically by aclocal 1.15 -*- Autoconf -*-
# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,

21
configure vendored
View File

@ -760,7 +760,7 @@ with_sysroot
enable_libtool_lock
enable_rpath
enable_tcp_fastopen
enable_broken_native_stub_dnssec
enable_native_stub_dnssec
with_ssl
enable_draft_edns_cookies
with_libidn
@ -1406,9 +1406,8 @@ Optional Features:
--disable-libtool-lock avoid locking (might break parallel builds)
--disable-rpath disable hardcoded rpath (default=enabled)
--enable-tcp-fastopen Enable TCP Fast Open
--enable-broken-native-stub-dnssec
Enable very experimental and broken native stub
DNSSEC support
--disable-native-stub-dnssec
Disable native stub DNSSEC support
--enable-draft-edns-cookies
Enable experimental edns cookies
@ -11738,20 +11737,20 @@ _ACEOF
;;
esac
# Check whether --enable-broken-native-stub-dnssec was given.
if test "${enable_broken_native_stub_dnssec+set}" = set; then :
enableval=$enable_broken_native_stub_dnssec;
# Check whether --enable-native-stub-dnssec was given.
if test "${enable_native_stub_dnssec+set}" = set; then :
enableval=$enable_native_stub_dnssec;
fi
case "$enable_broken_native_stub_dnssec" in
yes)
case "$enable_native_stub_dnssec" in
no)
;;
yes|*)
cat >>confdefs.h <<_ACEOF
#define STUB_NATIVE_DNSSEC 1
_ACEOF
;;
no|*)
;;
esac

View File

@ -144,12 +144,12 @@ esac
# ])
# fi
AC_ARG_ENABLE(broken-native-stub-dnssec, AC_HELP_STRING([--enable-broken-native-stub-dnssec], [Enable very experimental and broken native stub DNSSEC support]))
case "$enable_broken_native_stub_dnssec" in
yes)
AC_DEFINE_UNQUOTED([STUB_NATIVE_DNSSEC], [1], [Define this to enable the very experimental and broken native stub DNSSEC support.])
AC_ARG_ENABLE(native-stub-dnssec, AC_HELP_STRING([--disable-native-stub-dnssec], [Disable native stub DNSSEC support]))
case "$enable_native_stub_dnssec" in
no)
;;
no|*)
yes|*)
AC_DEFINE_UNQUOTED([STUB_NATIVE_DNSSEC], [1], [Define this to enable native stub DNSSEC support.])
;;
esac

View File

@ -192,8 +192,7 @@
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define this to enable the very experimental and broken native stub DNSSEC
support. */
/* Define this to enable native stub DNSSEC support. */
#undef STUB_NATIVE_DNSSEC
/* System configuration dir */

View File

@ -43,6 +43,7 @@
#include <unbound.h>
#include <assert.h>
#include <netdb.h>
#include <ctype.h>
#include "config.h"
#include "gldns/str2wire.h"
@ -815,6 +816,7 @@ getdns_context_create_with_extended_memory_functions(
getdns_return_t r;
struct getdns_context *result = NULL;
mf_union mf;
gldns_buffer gbuf;
if (!context || !malloc || !realloc || !free)
return GETDNS_RETURN_INVALID_PARAMETER;
@ -860,7 +862,30 @@ getdns_context_create_with_extended_memory_functions(
result->append_name = GETDNS_APPEND_NAME_ALWAYS;
result->suffix = NULL;
result->dnssec_trust_anchors = NULL;
gldns_buffer_init_frm_data(&gbuf, result->trust_anchors_spc
, sizeof(result->trust_anchors_spc));
if (!_getdns_parse_ta_file(NULL, &gbuf)) {
result->trust_anchors = NULL;
result->trust_anchors_len = 0;
} else if ((result->trust_anchors_len = gldns_buffer_position(&gbuf))
> sizeof(result->trust_anchors_spc)) {
if ((result->trust_anchors = GETDNS_XMALLOC(
result->mf, uint8_t, result->trust_anchors_len))) {
gldns_buffer_init_frm_data(&gbuf
, result->trust_anchors
, result->trust_anchors_len);
if (!_getdns_parse_ta_file(NULL, &gbuf)) {
result->trust_anchors = NULL;
result->trust_anchors_len = 0;
}
}
} else
result->trust_anchors = result->trust_anchors_spc;
result->upstreams = NULL;
result->edns_extended_rcode = 0;
@ -873,7 +898,7 @@ getdns_context_create_with_extended_memory_functions(
goto error;
result->fchg_resolvconf = NULL;
result->fchg_hosts = NULL;
result->fchg_hosts = NULL;
if (set_from_os && (r = set_os_defaults(result)))
goto error;
@ -883,12 +908,12 @@ getdns_context_create_with_extended_memory_functions(
if ((r = create_default_dns_transports(result)))
goto error;
result->limit_outstanding_queries = 0;
result->has_ta = priv_getdns_parse_ta_file(NULL, NULL);
result->return_dnssec_status = GETDNS_EXTENSION_FALSE;
/* unbound context is initialized here */
/* Unbound needs SSL to be init'ed this early when TLS is used. However we
* don't know that till later so we will have to do this every time. */
SSL_library_init();
result->unbound_ctx = NULL;
if ((r = rebuild_ub_ctx(result)))
@ -985,7 +1010,10 @@ getdns_context_destroy(struct getdns_context *context)
getdns_list_destroy(context->dns_root_servers);
getdns_list_destroy(context->suffix);
getdns_list_destroy(context->dnssec_trust_anchors);
if (context->trust_anchors &&
context->trust_anchors != context->trust_anchors_spc)
GETDNS_FREE(context->mf, context->trust_anchors);
/* destroy the contexts */
if (context->unbound_ctx)
@ -1116,7 +1144,7 @@ rebuild_ub_ctx(struct getdns_context* context) {
set_ub_dns_transport(context);
/* Set default trust anchor */
if (context->has_ta) {
if (context->trust_anchors) {
(void) ub_ctx_add_ta_file(
context->unbound_ctx, TRUST_ANCHOR_FILE);
}
@ -1563,23 +1591,26 @@ getdns_context_set_suffix(struct getdns_context *context, struct getdns_list * v
*
*/
getdns_return_t
getdns_context_set_dnssec_trust_anchors(struct getdns_context *context,
struct getdns_list * value)
getdns_context_set_dnssec_trust_anchors(
getdns_context *context, getdns_list *value)
{
struct getdns_list *copy = NULL;
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
if (value != NULL) {
if (getdns_list_copy(value, &copy) != GETDNS_RETURN_GOOD) {
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
}
value = copy;
}
getdns_list_destroy(context->dnssec_trust_anchors);
context->dnssec_trust_anchors = value;
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
dispatch_updated(context, GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS);
if (context->trust_anchors &&
context->trust_anchors != context->trust_anchors_spc)
GETDNS_FREE(context->mf, context->trust_anchors);
return GETDNS_RETURN_GOOD;
if (value) {
context->trust_anchors_len = sizeof(context->trust_anchors_spc);
context->trust_anchors = _getdns_list2wire(value,
context->trust_anchors_spc, &context->trust_anchors_len,
&context->mf);
} else {
context->trust_anchors = NULL;
context->trust_anchors_len = 0;
}
dispatch_updated(context, GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS);
return GETDNS_RETURN_GOOD;
} /* getdns_context_set_dnssec_trust_anchors */
static void
@ -2432,8 +2463,6 @@ getdns_context_local_namespace_resolve(
{
getdns_context *context = dnsreq->context;
host_name_addrs *hnas;
uint8_t query_name[256];
size_t query_name_len = sizeof(query_name);
uint8_t lookup[256];
getdns_list empty_list = { 0 };
getdns_bindata bindata;
@ -2451,10 +2480,7 @@ getdns_context_local_namespace_resolve(
return GETDNS_RETURN_GENERIC_ERROR;
/*Do the lookup*/
if (gldns_str2wire_dname_buf(dnsreq->name,query_name,&query_name_len))
return GETDNS_RETURN_GENERIC_ERROR;
(void)memcpy(lookup, query_name, query_name_len);
(void)memcpy(lookup, dnsreq->name, dnsreq->name_len);
canonicalize_dname(lookup);
if (!(hnas = (host_name_addrs *)
@ -2470,8 +2496,8 @@ getdns_context_local_namespace_resolve(
if (!(*response = getdns_dict_create_with_context(context)))
return GETDNS_RETURN_GENERIC_ERROR;
bindata.size = query_name_len;
bindata.data = query_name;
bindata.size = dnsreq->name_len;
bindata.data = dnsreq->name;
if (getdns_dict_set_bindata(*response, "canonical_name", &bindata))
goto error;
@ -2673,15 +2699,23 @@ getdns_context_get_suffix(getdns_context *context, getdns_list **value) {
}
getdns_return_t
getdns_context_get_dnssec_trust_anchors(getdns_context *context,
getdns_list **value) {
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER);
*value = NULL;
if (context->dnssec_trust_anchors) {
return getdns_list_copy(context->dnssec_trust_anchors, value);
}
return GETDNS_RETURN_GOOD;
getdns_context_get_dnssec_trust_anchors(
getdns_context *context, getdns_list **value)
{
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER);
if (context->trust_anchors) {
if ((*value = getdns_list_create_with_context(context)))
_getdns_wire2list( context->trust_anchors
, context->trust_anchors_len
, *value);
else
return GETDNS_RETURN_MEMORY_ERROR;
} else
*value = NULL;
return GETDNS_RETURN_GOOD;
}
getdns_return_t

View File

@ -138,7 +138,8 @@ struct getdns_context {
struct getdns_list *dns_root_servers;
getdns_append_name_t append_name;
struct getdns_list *suffix;
struct getdns_list *dnssec_trust_anchors;
uint8_t *trust_anchors;
size_t trust_anchors_len;
getdns_upstreams *upstreams;
uint16_t limit_outstanding_queries;
uint32_t dnssec_allowed_skew;
@ -168,7 +169,7 @@ struct getdns_context {
/* A tree to hold local host information*/
getdns_rbtree_t local_hosts;
int has_ta; /* No DNSSEC without trust anchor */
int return_dnssec_status;
/* which resolution type the contexts are configured for
@ -194,6 +195,8 @@ struct getdns_context {
struct filechg *fchg_resolvconf;
struct filechg *fchg_hosts;
uint8_t trust_anchors_spc[1024];
}; /* getdns_context */
/** internal functions **/

View File

@ -70,6 +70,10 @@ struct getdns_dict
struct mem_funcs mf;
};
inline struct getdns_dict *_getdns_dict_create_with_mf(struct mem_funcs *mf)
{ return getdns_dict_create_with_extended_memory_functions(
mf->mf_arg, mf->mf.ext.malloc, mf->mf.ext.realloc, mf->mf.ext.free); }
#endif
/* dict.h */

File diff suppressed because it is too large Load Diff

View File

@ -39,12 +39,14 @@
#define DNSSEC_H_
#include "getdns/getdns.h"
#include "config.h"
#include "gldns/gbuffer.h"
#include "types-internal.h"
/* Do some additional requests to fetch the complete validation chain */
void priv_getdns_get_validation_chain(getdns_dns_req *dns_req);
int priv_getdns_parse_ta_file(time_t *ta_mtime, getdns_list *ta_rrs);
uint16_t _getdns_parse_ta_file(time_t *ta_mtime, gldns_buffer *gbuf);
#endif

View File

@ -38,8 +38,8 @@
#include <stdio.h>
#include <string.h>
#include <unbound.h>
#include <ldns/ldns.h>
#include "config.h"
#include "gldns/wire2str.h"
#include "context.h"
#include "types-internal.h"
#include "util-internal.h"
@ -137,6 +137,7 @@ submit_network_request(getdns_network_req *netreq)
{
getdns_return_t r;
getdns_dns_req *dns_req = netreq->owner;
char name[1024];
if (dns_req->context->resolution_type == GETDNS_RESOLUTION_RECURSING
/* TODO: Until DNSSEC with the new async stub resolver is finished,
@ -160,9 +161,11 @@ submit_network_request(getdns_network_req *netreq)
dns_req->context->timeout, &dns_req->timeout)))
return r;
}
(void) gldns_wire2str_dname_buf(dns_req->name,
dns_req->name_len, name, sizeof(name));
return ub_resolve_async(dns_req->context->unbound_ctx,
dns_req->name, netreq->request_type, netreq->request_class,
name, netreq->request_type, netreq->request_class,
netreq, ub_resolve_callback, &(netreq->unbound_id)) ?
GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
}
@ -173,7 +176,7 @@ submit_network_request(getdns_network_req *netreq)
static getdns_return_t
getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, getdns_dict *extensions,
void *userarg, getdns_transaction_t *transaction_id,
void *userarg, getdns_dns_req **dnsreq_p,
getdns_callback_t callbackfn, internal_cb_t internal_cb, int usenamespaces)
{
getdns_return_t r = GETDNS_RETURN_GOOD;
@ -185,10 +188,10 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
if (!context || !name || (!callbackfn && !internal_cb))
return GETDNS_RETURN_INVALID_PARAMETER;
if ((r = validate_dname(name)))
if ((r = priv_getdns_validate_dname(name)))
return r;
if (extensions && (r = validate_extensions(extensions)))
if (extensions && (r = priv_getdns_validate_extensions(extensions)))
return r;
/* Set up the context assuming we won't use the specified namespaces.
@ -204,8 +207,8 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
req->user_callback = callbackfn;
req->internal_cb = internal_cb;
if (transaction_id)
*transaction_id = req->trans_id;
if (dnsreq_p)
*dnsreq_p = req;
getdns_context_track_outbound_request(req);
@ -254,12 +257,12 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
getdns_return_t
priv_getdns_general_loop(getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, getdns_dict *extensions,
void *userarg, getdns_transaction_t *transaction_id,
void *userarg, getdns_dns_req **dnsreq_p,
getdns_callback_t callback, internal_cb_t internal_cb)
{
return getdns_general_ns(context, loop,
name, request_type, extensions,
userarg, transaction_id, callback, internal_cb, 0);
userarg, dnsreq_p, callback, internal_cb, 0);
} /* getdns_general_loop */
@ -271,6 +274,7 @@ priv_getdns_address_loop(getdns_context *context, getdns_eventloop *loop,
getdns_dict *my_extensions = extensions;
getdns_return_t r;
uint32_t value;
getdns_dns_req *dnsreq = NULL;
if (!my_extensions) {
if (!(my_extensions=getdns_dict_create_with_context(context)))
@ -286,7 +290,9 @@ priv_getdns_address_loop(getdns_context *context, getdns_eventloop *loop,
r = getdns_general_ns(context, loop,
name, GETDNS_RRTYPE_AAAA, my_extensions,
userarg, transaction_id, callback, NULL, 1);
userarg, &dnsreq, callback, NULL, 1);
if (dnsreq && transaction_id)
*transaction_id = dnsreq->trans_id;
if (my_extensions != extensions)
getdns_dict_destroy(my_extensions);
@ -304,6 +310,7 @@ priv_getdns_hostname_loop(getdns_context *context, getdns_eventloop *loop,
uint16_t req_type;
char name[1024];
getdns_return_t retval;
getdns_dns_req *dnsreq = NULL;
if ((retval =
getdns_dict_get_bindata(address, "address_data",
@ -377,7 +384,9 @@ priv_getdns_hostname_loop(getdns_context *context, getdns_eventloop *loop,
return GETDNS_RETURN_INVALID_PARAMETER;
}
retval = priv_getdns_general_loop(context, loop, name, req_type,
extensions, userarg, transaction_id, callback, NULL);
extensions, userarg, &dnsreq, callback, NULL);
if (dnsreq && transaction_id)
*transaction_id = dnsreq->trans_id;
return retval;
} /* getdns_hostname_loop */
@ -386,8 +395,13 @@ priv_getdns_service_loop(getdns_context *context, getdns_eventloop *loop,
const char *name, getdns_dict *extensions, void *userarg,
getdns_transaction_t * transaction_id, getdns_callback_t callback)
{
return getdns_general_ns(context, loop, name, GETDNS_RRTYPE_SRV,
extensions, userarg, transaction_id, callback, NULL, 1);
getdns_return_t r;
getdns_dns_req *dnsreq = NULL;
r = getdns_general_ns(context, loop, name, GETDNS_RRTYPE_SRV,
extensions, userarg, &dnsreq, callback, NULL, 1);
if (dnsreq && transaction_id)
*transaction_id = dnsreq->trans_id;
return r;
} /* getdns_service_loop */
/**
@ -399,11 +413,16 @@ getdns_general(getdns_context *context,
void *userarg, getdns_transaction_t * transaction_id,
getdns_callback_t callback)
{
if (!context) return GETDNS_RETURN_INVALID_PARAMETER;
return priv_getdns_general_loop(context, context->extension,
name, request_type, extensions,
userarg, transaction_id, callback, NULL);
getdns_return_t r;
getdns_dns_req *dnsreq = NULL;
if (!context) return GETDNS_RETURN_INVALID_PARAMETER;
r = priv_getdns_general_loop(context, context->extension,
name, request_type, extensions,
userarg, &dnsreq, callback, NULL);
if (dnsreq && transaction_id)
*transaction_id = dnsreq->trans_id;
return r;
} /* getdns_general */
/*

View File

@ -42,13 +42,13 @@
/* private inner helper used by sync and async */
void priv_getdns_call_user_callback(getdns_dns_req *, struct getdns_dict *);
void priv_getdns_call_user_callback(getdns_dns_req *, getdns_dict *);
void priv_getdns_check_dns_req_complete(getdns_dns_req *dns_req);
getdns_return_t
priv_getdns_general_loop(getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, getdns_dict *extensions,
void *userarg, getdns_transaction_t *transaction_id,
void *userarg, getdns_dns_req **dnsreq,
getdns_callback_t callbackfn, internal_cb_t internal_cb);
getdns_return_t

View File

@ -74,6 +74,10 @@ struct getdns_list
struct mem_funcs mf;
};
inline struct getdns_list *_getdns_list_create_with_mf(struct mem_funcs *mf)
{ return getdns_list_create_with_extended_memory_functions(
mf->mf_arg, mf->mf.ext.malloc, mf->mf.ext.realloc, mf->mf.ext.free); }
#endif
/* list.h */

View File

@ -40,6 +40,13 @@
#include "gldns/str2wire.h"
#include "gldns/gbuffer.h"
#include "gldns/pkthdr.h"
#include "dict.h"
getdns_dict dnssec_ok_checking_disabled_spc = {
{ RBTREE_NULL, 0, (int (*)(const void *, const void *)) strcmp },
{ 0 }
};
getdns_dict *dnssec_ok_checking_disabled = &dnssec_ok_checking_disabled_spc;
static int
is_extension_set(getdns_dict *extensions, const char *extension)
@ -49,6 +56,8 @@ is_extension_set(getdns_dict *extensions, const char *extension)
if (! extensions)
return 0;
else if (extensions == dnssec_ok_checking_disabled)
return 0;
r = getdns_dict_get_int(extensions, extension, &value);
return r == GETDNS_RETURN_GOOD && value == GETDNS_EXTENSION_TRUE;
@ -87,6 +96,8 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
net_req->state = NET_REQ_NOT_SENT;
net_req->owner = owner;
net_req->dnssec_status = GETDNS_DNSSEC_INDETERMINATE;
net_req->upstream = NULL;
net_req->fd = -1;
net_req->transport_count = owner->context->dns_transport_count;
@ -193,8 +204,6 @@ dns_req_free(getdns_dns_req * req)
req->timeout.timeout_cb = NULL;
}
/* free strduped name */
GETDNS_FREE(req->my_mf, req->name);
GETDNS_FREE(req->my_mf, req);
}
@ -210,14 +219,12 @@ dns_req_new(getdns_context *context, getdns_eventloop *loop,
= is_extension_set(extensions, "dnssec_return_only_secure");
int dnssec_return_validation_chain
= is_extension_set(extensions, "dnssec_return_validation_chain");
int dnssec_ok_checking_disabled
= is_extension_set(extensions, "dnssec_ok_checking_disabled");
int edns_cookies
= is_extension_set(extensions, "edns_cookies");
int dnssec_extension_set = dnssec_return_status
|| dnssec_return_only_secure || dnssec_return_validation_chain
|| dnssec_ok_checking_disabled;;
|| (extensions == dnssec_ok_checking_disabled);
uint32_t edns_do_bit;
int edns_maximum_udp_payload_size;
@ -252,6 +259,9 @@ dns_req_new(getdns_context *context, getdns_eventloop *loop,
size_t max_query_sz, max_response_sz, netreq_sz, dnsreq_base_sz;
uint8_t *region;
if (extensions == dnssec_ok_checking_disabled)
extensions = NULL;
have_add_opt_parameters = getdns_dict_get_dict(extensions,
"add_opt_parameters", &add_opt_parameters) == GETDNS_RETURN_GOOD;
@ -347,7 +357,12 @@ dns_req_new(getdns_context *context, getdns_eventloop *loop,
result->netreqs[1] = NULL;
result->my_mf = context->mf;
result->name = getdns_strdup(&(result->my_mf), name);
result->name_len = sizeof(result->name);
if (gldns_str2wire_dname_buf(name, result->name, &result->name_len)) {
GETDNS_FREE(result->my_mf, result);
return NULL;
}
result->context = context;
result->loop = loop;
result->canceled = 0;

View File

@ -255,9 +255,9 @@ static priv_getdns_rdata_def soa_rdata[] = {
{ "rname" , GETDNS_RDF_N_C },
{ "serial" , GETDNS_RDF_I4 },
{ "refresh" , GETDNS_RDF_I4 },
{ "refresh" , GETDNS_RDF_I4 },
{ "retry" , GETDNS_RDF_I4 },
{ "expire" , GETDNS_RDF_I4 }};
{ "expire" , GETDNS_RDF_I4 },
{ "minimum" , GETDNS_RDF_I4 }};
static priv_getdns_rdata_def mg_rdata[] = {
{ "mgmname" , GETDNS_RDF_N_C }};
static priv_getdns_rdata_def mr_rdata[] = {
@ -737,192 +737,95 @@ priv_getdns_rr_type_name(int rr_type)
return priv_getdns_rr_def_lookup(rr_type)->name;
}
static getdns_return_t priv_getdns_construct_wire_rdata_from_rdata(
struct getdns_dict *rdata, uint32_t rr_type,
uint8_t **wire, size_t *wire_size)
{
getdns_return_t r = GETDNS_RETURN_GOOD;
const ldns_rr_descriptor *rr_descript;
const priv_getdns_rr_def *def;
size_t i, size;
struct getdns_bindata *bindata;
uint32_t value;
uint8_t *ptr;
assert(rdata);
assert(wire);
assert(wire_size);
def = priv_getdns_rr_def_lookup(rr_type);
rr_descript = ldns_rr_descript(rr_type);
/* First calculate needed size */
size = 0;
for (i = 0; !r && i < def->n_rdata_fields; i++) {
if (def->rdata[i].type & GETDNS_RDF_BINDATA)
if ((r = getdns_dict_get_bindata(rdata,
def->rdata[i].name, &bindata)))
break;
else {
size += bindata->size;
continue;
}
else if (!(def->rdata[i].type & GETDNS_RDF_INTEGER)) {
r = GETDNS_RETURN_GENERIC_ERROR;
break;
}
switch (ldns_rr_descriptor_field_type(rr_descript, i)) {
case LDNS_RDF_TYPE_CLASS:
case LDNS_RDF_TYPE_ALG :
case LDNS_RDF_TYPE_INT8 : size += 1;
break;
case LDNS_RDF_TYPE_TYPE :
case LDNS_RDF_TYPE_CERT_ALG:
case LDNS_RDF_TYPE_INT16: size += 2;
break;
case LDNS_RDF_TYPE_TIME :
case LDNS_RDF_TYPE_PERIOD:
case LDNS_RDF_TYPE_INT32: size += 4;
break;
default: r = GETDNS_RETURN_GENERIC_ERROR;
break;
}
}
*wire_size = size + 2;
*wire = ptr = GETDNS_XMALLOC(rdata->mf, uint8_t, size + 2);
if (! ptr)
return GETDNS_RETURN_MEMORY_ERROR;
ptr[0] = (uint8_t) (size >> 8) & 0xff;
ptr[1] = (uint8_t) size & 0xff;
ptr += 2;
for (i = 0; !r && i < def->n_rdata_fields; i++) {
if (def->rdata[i].type & GETDNS_RDF_BINDATA)
if ((r = getdns_dict_get_bindata(rdata,
def->rdata[i].name, &bindata)))
break;
else {
(void) memcpy(ptr, bindata->data,
bindata->size);
ptr += bindata->size;
continue;
}
else if (!(def->rdata[i].type & GETDNS_RDF_INTEGER)) {
r = GETDNS_RETURN_GENERIC_ERROR;
break;
}
if ((r = getdns_dict_get_int(
rdata, def->rdata[i].name, &value)))
break;
switch (ldns_rr_descriptor_field_type(rr_descript, i)) {
case LDNS_RDF_TYPE_CLASS:
case LDNS_RDF_TYPE_ALG :
case LDNS_RDF_TYPE_INT8 : ptr[0] = (uint8_t) value & 0xff;
ptr += 1;
break;
case LDNS_RDF_TYPE_TYPE :
case LDNS_RDF_TYPE_CERT_ALG:
case LDNS_RDF_TYPE_INT16: ptr[0] = (uint8_t)(value>> 8) & 0xff;
ptr[1] = (uint8_t) value & 0xff;
ptr += 2;
break;
case LDNS_RDF_TYPE_TIME :
case LDNS_RDF_TYPE_PERIOD:
case LDNS_RDF_TYPE_INT32: ptr[0] = (uint8_t)(value>>24) & 0xff;
ptr[1] = (uint8_t)(value>>16) & 0xff;
ptr[2] = (uint8_t)(value>>8 ) & 0xff;
ptr[3] = (uint8_t) value & 0xff;
ptr += 4;
break;
default: r = GETDNS_RETURN_GENERIC_ERROR;
break;
}
}
if (r)
GETDNS_FREE(rdata->mf, ptr);
return r;
}
static getdns_return_t
priv_getdns_dict_get_raw_rdata(struct getdns_dict *rdata,
uint8_t **wire, size_t *wire_size)
{
getdns_return_t r;
struct getdns_bindata *bindata;
if ((r = getdns_dict_get_bindata(rdata, "rdata_raw", &bindata)))
return r;
*wire_size = bindata->size + 2;
*wire = GETDNS_XMALLOC(rdata->mf, uint8_t, *wire_size);
if (! *wire)
return GETDNS_RETURN_MEMORY_ERROR;
(*wire)[0] = (uint8_t) (bindata->size >> 8) & 0xff;
(*wire)[1] = (uint8_t) bindata->size & 0xff;
(void) memcpy(*wire + 2, bindata->data, bindata->size);
return GETDNS_RETURN_GOOD;
}
getdns_return_t
priv_getdns_create_rr_from_dict(struct getdns_dict *rr_dict, ldns_rr **rr)
priv_getdns_rr_dict2wire(getdns_dict *rr_dict, gldns_buffer *buf)
{
getdns_return_t r = GETDNS_RETURN_GOOD;
struct getdns_bindata *name;
struct getdns_bindata *rdata_raw;
struct getdns_bindata *bindata;
struct getdns_dict *rdata;
uint32_t rr_type;
ldns_rdf *owner;
ldns_status s;
size_t pos;
uint8_t *wire;
size_t wire_size;
uint32_t rr_class = GETDNS_RRCLASS_IN;
uint32_t rr_ttl = 0;
uint32_t value;
const priv_getdns_rr_def *rr_def;
const priv_getdns_rdata_def *rd_def;
int n_rdata_fields;
size_t j, rdata_size_mark;
assert(rr_dict);
assert(rr);
assert(buf);
*rr = ldns_rr_new();
if (! *rr)
return GETDNS_RETURN_MEMORY_ERROR;
do {
r = getdns_dict_get_bindata(rr_dict, "name", &name);
if (r != GETDNS_RETURN_GOOD)
break;
owner = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_DNAME, name->size, name->data);
if (! owner) {
r = GETDNS_RETURN_MEMORY_ERROR;
if ((r = getdns_dict_get_bindata(rr_dict, "name", &name)))
goto error;
gldns_buffer_write(buf, name->data, name->size);
if ((r = getdns_dict_get_int(rr_dict, "type", &rr_type)))
goto error;
gldns_buffer_write_u16(buf, (uint16_t)rr_type);
(void) getdns_dict_get_int(rr_dict, "class", &rr_class);
gldns_buffer_write_u16(buf, (uint16_t)rr_class);
(void) getdns_dict_get_int(rr_dict, "ttl", &rr_ttl);
gldns_buffer_write_u32(buf, rr_ttl);
/* Does rdata contain compressed names?
* Because rdata_raw is unusable then.
*/
rr_def = priv_getdns_rr_def_lookup(rr_type);
for ( rd_def = rr_def->rdata
, n_rdata_fields = rr_def->n_rdata_fields
; n_rdata_fields ; n_rdata_fields-- , rd_def++ ) {
if (rd_def->type & GETDNS_RDF_COMPRESSED)
break;
}
if ((r = getdns_dict_get_dict(rr_dict, "rdata", &rdata)))
goto error;
if (n_rdata_fields == 0 && GETDNS_RETURN_GOOD ==
(r = getdns_dict_get_bindata(rdata, "rdata_raw", &rdata_raw))) {
gldns_buffer_write_u16(buf, (uint16_t)rdata_raw->size);
gldns_buffer_write(buf, rdata_raw->data, rdata_raw->size);
} else if (n_rdata_fields || r == GETDNS_RETURN_NO_SUCH_DICT_NAME) {
rdata_size_mark = gldns_buffer_position(buf);
gldns_buffer_skip(buf, 2);
for ( rd_def = rr_def->rdata
, n_rdata_fields = rr_def->n_rdata_fields
; n_rdata_fields ; n_rdata_fields-- , rd_def++ ) {
if (rd_def->type & GETDNS_RDF_BINDATA) {
if ((r = getdns_dict_get_bindata(rdata,
rd_def->name, &bindata)))
break;
gldns_buffer_write(buf, bindata->data
, bindata->size );
continue;
}
if (!(rd_def->type & GETDNS_RDF_INTEGER)) {
r = GETDNS_RETURN_GENERIC_ERROR;
break;
}
if ((r = getdns_dict_get_int(
rdata, rd_def->name, &value)))
break;
for (j = rd_def->type & GETDNS_RDF_FIXEDSZ; j; j--)
gldns_buffer_write_u8(buf,
(uint8_t)(value >> (8 * (j - 1))) & 0xff);
}
ldns_rr_set_owner(*rr, owner);
r = getdns_dict_get_int(rr_dict, "type", &rr_type);
if (r != GETDNS_RETURN_GOOD)
break;
ldns_rr_set_type(*rr, rr_type);
r = getdns_dict_get_dict(rr_dict, "rdata", &rdata);
if (r != GETDNS_RETURN_GOOD)
break;
r = priv_getdns_dict_get_raw_rdata(rdata, &wire, &wire_size);
if (r == GETDNS_RETURN_NO_SUCH_DICT_NAME) {
r = priv_getdns_construct_wire_rdata_from_rdata(
rdata, rr_type, &wire, &wire_size);
}
if (r != GETDNS_RETURN_GOOD)
break;
pos = 0;
s = ldns_wire2rdf(*rr, wire, wire_size, &pos);
GETDNS_FREE(rr_dict->mf, wire);
if (s == LDNS_STATUS_OK)
return r;
r = GETDNS_RETURN_GENERIC_ERROR;
} while (0);
ldns_rr_free(*rr);
gldns_buffer_write_u16_at(buf, rdata_size_mark,
(uint16_t)(gldns_buffer_position(buf)-rdata_size_mark-2));
}
error:
return r;
}

View File

@ -32,8 +32,9 @@
#ifndef RR_DICT_H_
#define RR_DICT_H_
#include <ldns/ldns.h>
#include "config.h"
#include "getdns/getdns.h"
#include "gldns/gbuffer.h"
typedef uint8_t *(*priv_getdns_rdf_end_t)(
uint8_t *pkt, uint8_t *pkt_end, uint8_t *rdf);
@ -51,56 +52,57 @@ typedef struct priv_getdns_rdf_special {
/* draft-levine-dnsextlang'ish type rr and rdata definitions */
#define GETDNS_RDF_INTEGER 0x010000
#define GETDNS_RDF_BINDATA 0x020000
#define GETDNS_RDF_DNAME 0x060000
#define GETDNS_RDF_REPEAT 0x100000
#define GETDNS_RDF_INTEGER 0x010000
#define GETDNS_RDF_BINDATA 0x020000
#define GETDNS_RDF_DNAME 0x060000
#define GETDNS_RDF_COMPRESSED 0x080000
#define GETDNS_RDF_REPEAT 0x100000
#define GETDNS_RDF_FIXEDSZ 0x0000FF
#define GETDNS_RDF_LEN_VAL 0x00FF00
#define GETDNS_RDF_FIXEDSZ 0x0000FF
#define GETDNS_RDF_LEN_VAL 0x00FF00
typedef enum priv_getdns_rdf_wf_type {
GETDNS_RDF_N = 0x060000, /* N */
GETDNS_RDF_N_A = GETDNS_RDF_N, /* N[A] */
GETDNS_RDF_N_A_C = GETDNS_RDF_N, /* N[A,C] */
GETDNS_RDF_N_C = GETDNS_RDF_N, /* N[C] */
GETDNS_RDF_N_M = 0x160000, /* N[M] */
GETDNS_RDF_N = 0x060000, /* N */
GETDNS_RDF_N_A = 0x060000, /* N[A] */
GETDNS_RDF_N_C = 0x0E0000, /* N[C] */
GETDNS_RDF_N_A_C = 0x0E0000, /* N[A,C] */
GETDNS_RDF_N_M = 0x160000, /* N[M] */
GETDNS_RDF_I1 = 0x010001, /* I1 */
GETDNS_RDF_I2 = 0x010002, /* I2 */
GETDNS_RDF_I4 = 0x010004, /* I4 */
GETDNS_RDF_I1 = 0x010001, /* I1 */
GETDNS_RDF_I2 = 0x010002, /* I2 */
GETDNS_RDF_I4 = 0x010004, /* I4 */
GETDNS_RDF_T = 0x010004, /* T */
GETDNS_RDF_T = 0x010004, /* T */
/* Time values using ring arithmetics
* (rfc1982) for TKEY['inception'],
* TKEY['expiration'],
* RRSIG['inception'] and
* RRSIG['expiration']
*/
GETDNS_RDF_T6 = 0x020006, /* T6 */
GETDNS_RDF_T6 = 0x020006, /* T6 */
/* Absolute time values (since epoch)
* for TSIG['time_signed']
*/
GETDNS_RDF_A = 0x020004, /* A */
GETDNS_RDF_AA = 0x020008, /* AA */
GETDNS_RDF_AAAA = 0x020010, /* AAAA */
GETDNS_RDF_A = 0x020004, /* A */
GETDNS_RDF_AA = 0x020008, /* AA */
GETDNS_RDF_AAAA = 0x020010, /* AAAA */
GETDNS_RDF_S = 0x020100, /* S */
GETDNS_RDF_S_L = 0x020000, /* S[L] */
GETDNS_RDF_S_M = 0x120100, /* S[M] */
GETDNS_RDF_S = 0x020100, /* S */
GETDNS_RDF_S_L = 0x020000, /* S[L] */
GETDNS_RDF_S_M = 0x120100, /* S[M] */
GETDNS_RDF_B = 0x020000, /* B */
GETDNS_RDF_B_C = 0x020100, /* B[C] */
GETDNS_RDF_B = 0x020000, /* B */
GETDNS_RDF_B_C = 0x020100, /* B[C] */
GETDNS_RDF_B32_C = 0x020100, /* B32[C] */
GETDNS_RDF_B32_C = 0x020100, /* B32[C] */
GETDNS_RDF_X = 0x020000, /* X */
GETDNS_RDF_X_C = 0x020100, /* X[C] */
GETDNS_RDF_X = 0x020000, /* X */
GETDNS_RDF_X_C = 0x020100, /* X[C] */
/* for NSEC3['salt'] and
* NSEC3PARAM['salt'].
*/
GETDNS_RDF_X_S = 0x020200, /* X[S] */
GETDNS_RDF_X_S = 0x020200, /* X[S] */
/* for OPT['option_data'],
* TKEY['key_data'],
* TKEY['other_data'],
@ -109,12 +111,12 @@ typedef enum priv_getdns_rdf_wf_type {
* Although those do not have an
* official presentation format.
*/
GETDNS_RDF_X6 = 0x020006,
GETDNS_RDF_X8 = 0x020008,
GETDNS_RDF_X6 = 0x020006,
GETDNS_RDF_X8 = 0x020008,
GETDNS_RDF_R = 0x100000, /* Repeat */
GETDNS_RDF_R = 0x100000, /* Repeat */
GETDNS_RDF_SPECIAL = 0x800000,
GETDNS_RDF_SPECIAL = 0x800000,
} priv_getdns_rdf_type;
typedef struct priv_getdns_rdata_def {
@ -131,8 +133,8 @@ typedef struct priv_getdns_rr_def {
const priv_getdns_rr_def *priv_getdns_rr_def_lookup(uint16_t rr_type);
getdns_return_t priv_getdns_create_rr_from_dict(
struct getdns_dict *rr_dict, ldns_rr **rr);
getdns_return_t priv_getdns_rr_dict2wire(
getdns_dict *rr_dict, gldns_buffer *buf);
const char *priv_getdns_rr_type_name(int rr_type);

View File

@ -98,6 +98,13 @@ priv_getdns_rr_iter_init(priv_getdns_rr_iter *i, uint8_t *pkt, size_t pkt_len)
return find_rrtype(i);
}
priv_getdns_rr_iter *
priv_getdns_rr_iter_rewind(priv_getdns_rr_iter *i)
{
assert(i);
return priv_getdns_rr_iter_init(i, i->pkt, i->pkt_end - i->pkt);
}
priv_getdns_rr_iter *
priv_getdns_rr_iter_next(priv_getdns_rr_iter *i)

View File

@ -62,6 +62,8 @@ typedef struct priv_getdns_rr_iter {
priv_getdns_rr_iter *priv_getdns_rr_iter_init(priv_getdns_rr_iter *i,
uint8_t *pkt, size_t pkt_len);
priv_getdns_rr_iter *priv_getdns_rr_iter_rewind(priv_getdns_rr_iter *i);
priv_getdns_rr_iter *priv_getdns_rr_iter_next(priv_getdns_rr_iter *i);
uint8_t *priv_getdns_owner_if_or_as_decompressed(

View File

@ -31,6 +31,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <openssl/err.h>
#include "config.h"
#include <fcntl.h>
#include "stub.h"
@ -40,7 +41,6 @@
#include "gldns/str2wire.h"
#include "rr-iter.h"
#include "context.h"
#include <ldns/util.h>
#include "util-internal.h"
#include "general.h"
@ -273,21 +273,6 @@ create_starttls_request(getdns_dns_req *dnsreq, getdns_upstream *upstream,
return 1;
}
static int
dname_equal(uint8_t *s1, uint8_t *s2)
{
uint8_t i;
for (;;) {
if (*s1 != *s2)
return 0;
else if (!*s1)
return 1;
for (i = *s1++, s2++; i > 0; i--, s1++, s2++)
if ((*s1 & 0xDF) != (*s2 & 0xDF))
return 0;
}
}
static int
is_starttls_response(getdns_network_req *netreq)
{
@ -295,10 +280,10 @@ is_starttls_response(getdns_network_req *netreq)
priv_getdns_rdf_iter rdf_iter_storage, *rdf_iter;
uint16_t rr_type;
gldns_pkt_section section;
uint8_t starttls_name_space[256],
*starttls_name = starttls_name_space;
uint8_t starttls_name_space[256], *starttls_name;
uint8_t owner_name_space[256], *owner_name;
size_t starttls_name_len = 256, owner_name_len;
size_t starttls_name_len = sizeof(starttls_name_space);
size_t owner_name_len = sizeof(owner_name_space);;
/* Servers that are not STARTTLS aware will refuse the CH query*/
if (GLDNS_RCODE_NOERROR != GLDNS_RCODE_WIRE(netreq->response))
@ -307,9 +292,6 @@ is_starttls_response(getdns_network_req *netreq)
if (GLDNS_ANCOUNT(netreq->response) != 1)
return 0;
(void) gldns_str2wire_dname_buf(
netreq->owner->name, starttls_name_space, &starttls_name_len);
for ( rr_iter = priv_getdns_rr_iter_init(&rr_iter_storage
, netreq->response
, netreq->response_len)
@ -318,25 +300,25 @@ is_starttls_response(getdns_network_req *netreq)
section = priv_getdns_rr_iter_section(rr_iter);
rr_type = gldns_read_uint16(rr_iter->rr_type);
if (section != GLDNS_SECTION_ANSWER || rr_type != GETDNS_RRTYPE_TXT)
if (section != GLDNS_SECTION_ANSWER
|| rr_type != GETDNS_RRTYPE_TXT)
continue;
owner_name = priv_getdns_owner_if_or_as_decompressed(
rr_iter, owner_name_space, &owner_name_len);
if (!dname_equal(starttls_name, owner_name))
if (!priv_getdns_dname_equal(netreq->owner->name, owner_name))
continue;
if (!(rdf_iter = priv_getdns_rdf_iter_init(
&rdf_iter_storage, rr_iter)))
continue;
/* re-use the starttls_name for the response dname*/
starttls_name = priv_getdns_rdf_if_or_as_decompressed(
rdf_iter,starttls_name_space,&starttls_name_len);
if (dname_equal(starttls_name, owner_name))
if ((starttls_name = priv_getdns_rdf_if_or_as_decompressed(
rdf_iter, starttls_name_space, &starttls_name_len)) &&
priv_getdns_dname_equal(starttls_name, owner_name))
return 1;
else
return 0;
continue;
return 0;
}
return 0;
}
@ -1144,10 +1126,6 @@ stub_udp_read_cb(void *userarg)
}
netreq->response_len = read;
dnsreq->upstreams->current = 0;
/* TODO: DNSSEC */
netreq->secure = 0;
netreq->bogus = 0;
done:
netreq->state = NET_REQ_FINISHED;
priv_getdns_check_dns_req_complete(dnsreq);
@ -1227,10 +1205,6 @@ stub_tcp_read_cb(void *userarg)
netreq->tcp.read_buf = NULL;
dnsreq->upstreams->current = 0;
/* TODO: DNSSEC */
netreq->secure = 0;
netreq->bogus = 0;
stub_cleanup(netreq);
close(netreq->fd);
priv_getdns_check_dns_req_complete(dnsreq);
@ -1317,10 +1291,6 @@ upstream_read_cb(void *userarg)
* on a working connection until we hit a problem.*/
upstream->upstreams->current = 0;
/* TODO: DNSSEC */
netreq->secure = 0;
netreq->bogus = 0;
if (netreq->owner == upstream->starttls_req) {
dnsreq = netreq->owner;
if (is_starttls_response(netreq)) {

View File

@ -166,6 +166,90 @@ print_usage(FILE *out, const char *progname)
fprintf(out, "\t-q\tQuiet mode - don't print response\n");
}
static getdns_return_t validate_chain(getdns_dict *response)
{
getdns_return_t r;
getdns_list *validation_chain;
getdns_list *replies_tree;
getdns_dict *reply;
getdns_list *to_validate;
getdns_list *trust_anchor;
size_t i;
int s;
if (!(to_validate = getdns_list_create()))
return GETDNS_RETURN_MEMORY_ERROR;
if (!(trust_anchor = getdns_root_trust_anchor(NULL)))
return GETDNS_RETURN_GENERIC_ERROR;
if ((r = getdns_dict_get_list(
response, "validation_chain", &validation_chain)))
return r;
if ((r = getdns_dict_get_list(
response, "replies_tree", &replies_tree)))
return r;
fprintf(stdout, "replies_tree %zu, dnssec_status: ", i);
switch ((s = getdns_validate_dnssec(
replies_tree, validation_chain, trust_anchor))) {
case GETDNS_DNSSEC_SECURE:
fprintf(stdout, "GETDNS_DNSSEC_SECURE\n");
break;
case GETDNS_DNSSEC_BOGUS:
fprintf(stdout, "GETDNS_DNSSEC_BOGUS\n");
break;
case GETDNS_DNSSEC_INDETERMINATE:
fprintf(stdout, "GETDNS_DNSSEC_INDETERMINATE\n");
break;
case GETDNS_DNSSEC_INSECURE:
fprintf(stdout, "GETDNS_DNSSEC_INSECURE\n");
break;
case GETDNS_DNSSEC_NOT_PERFORMED:
fprintf(stdout, "GETDNS_DNSSEC_NOT_PERFORMED\n");
break;
default:
fprintf(stdout, "%d\n", (int)s);
}
i = 0;
while (!(r = getdns_list_get_dict(replies_tree, i++, &reply))) {
if ((r = getdns_list_set_dict(to_validate, 0, reply)))
return r;
fprintf( stdout
, "reply %zu, dnssec_status: ", i);
switch ((s = getdns_validate_dnssec(
to_validate, validation_chain, trust_anchor))) {
case GETDNS_DNSSEC_SECURE:
fprintf(stdout, "GETDNS_DNSSEC_SECURE\n");
break;
case GETDNS_DNSSEC_BOGUS:
fprintf(stdout, "GETDNS_DNSSEC_BOGUS\n");
break;
case GETDNS_DNSSEC_INDETERMINATE:
fprintf(stdout, "GETDNS_DNSSEC_INDETERMINATE\n");
break;
case GETDNS_DNSSEC_INSECURE:
fprintf(stdout, "GETDNS_DNSSEC_INSECURE\n");
break;
case GETDNS_DNSSEC_NOT_PERFORMED:
fprintf(stdout, "GETDNS_DNSSEC_NOT_PERFORMED\n");
break;
default:
fprintf(stdout, "%d\n", (int)s);
}
}
if (r != GETDNS_RETURN_NO_SUCH_LIST_ITEM)
return r;
return GETDNS_RETURN_GOOD;
}
void callback(getdns_context *context, getdns_callback_type_t callback_type,
getdns_dict *response, void *userarg, getdns_transaction_t trans_id)
{
@ -178,6 +262,7 @@ void callback(getdns_context *context, getdns_callback_type_t callback_type,
: getdns_pretty_print_dict(response))) {
fprintf(stdout, "ASYNC response:\n%s\n", response_str);
validate_chain(response);
free(response_str);
}
fprintf(stdout,
@ -617,6 +702,7 @@ main(int argc, char **argv)
fprintf( stdout, "SYNC response:\n%s\n"
, response_str);
validate_chain(response);
free(response_str);
} else {
r = GETDNS_RETURN_MEMORY_ERROR;

View File

@ -189,9 +189,8 @@ typedef struct getdns_network_req
/* request class */
uint16_t request_class;
/* result */
int secure;
int bogus;
/* dnssec status */
int dnssec_status;
/* For stub resolving */
struct getdns_upstream *upstream;
@ -232,7 +231,8 @@ typedef struct getdns_dns_req {
getdns_rbnode_t node;
/* name */
char *name;
uint8_t name[256];
size_t name_len;
/* canceled flag */
int canceled;
@ -319,6 +319,8 @@ typedef struct getdns_dns_req {
/* utility methods */
extern getdns_dict *dnssec_ok_checking_disabled;
/* dns request utils */
getdns_dns_req *dns_req_new(getdns_context *context, getdns_eventloop *loop,
const char *name, uint16_t request_type, getdns_dict *extensions);

View File

@ -37,6 +37,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
#include <unbound.h>
#include "getdns/getdns.h"
#include "dict.h"
@ -60,7 +61,6 @@
static getdns_extension_format extformats[] = {
{"add_opt_parameters", t_dict},
{"add_warning_for_bad_dns", t_int},
{"dnssec_ok_checking_disabled", t_int},
{"dnssec_return_only_secure", t_int},
{"dnssec_return_status", t_int},
{"dnssec_return_validation_chain", t_int},
@ -179,7 +179,7 @@ sockaddr_to_dict(struct getdns_context *context, struct sockaddr_storage *addres
}
getdns_dict *
priv_getdns_rr_iter2rr_dict(getdns_context *context, priv_getdns_rr_iter *i)
priv_getdns_rr_iter2rr_dict(struct mem_funcs *mf, priv_getdns_rr_iter *i)
{
getdns_dict *rr_dict, *rdata_dict;
getdns_bindata bindata;
@ -192,7 +192,7 @@ priv_getdns_rr_iter2rr_dict(getdns_context *context, priv_getdns_rr_iter *i)
uint16_t rr_type;
assert(i);
if (!(rr_dict = getdns_dict_create_with_context(context)))
if (!(rr_dict = _getdns_dict_create_with_mf(mf)))
return NULL;
bindata.data = priv_getdns_owner_if_or_as_decompressed(
@ -248,8 +248,8 @@ priv_getdns_rr_iter2rr_dict(getdns_context *context, priv_getdns_rr_iter *i)
goto error;
}
if (!(rdata_dict = getdns_dict_create_with_context(context)))
goto error;
if (!(rdata_dict = _getdns_dict_create_with_mf(mf)))
return NULL;
if (i->rr_type + 10 <= i->nxt) {
bindata.size = i->nxt - (i->rr_type + 10);
@ -330,7 +330,8 @@ priv_getdns_rr_iter2rr_dict(getdns_context *context, priv_getdns_rr_iter *i)
/* list with rdf values */
if (! repeat_list && !(repeat_list =
getdns_list_create_with_context(context)))
_getdns_list_create_with_mf(mf)))
goto rdata_error;
switch (val_type) {
@ -357,7 +358,7 @@ priv_getdns_rr_iter2rr_dict(getdns_context *context, priv_getdns_rr_iter *i)
if (repeat_dict) {
if (! repeat_list && !(repeat_list =
getdns_list_create_with_context(context)))
_getdns_list_create_with_mf(mf)))
goto rdata_error;
if (getdns_list_append_dict(
@ -368,7 +369,7 @@ priv_getdns_rr_iter2rr_dict(getdns_context *context, priv_getdns_rr_iter *i)
repeat_dict = NULL;
}
if (!(repeat_dict =
getdns_dict_create_with_context(context)))
_getdns_dict_create_with_mf(mf)))
goto rdata_error;
}
assert(repeat_dict);
@ -393,7 +394,7 @@ priv_getdns_rr_iter2rr_dict(getdns_context *context, priv_getdns_rr_iter *i)
}
if (repeat_dict) {
if (!repeat_list && !(repeat_list =
getdns_list_create_with_context(context)))
_getdns_list_create_with_mf(mf)))
goto rdata_error;
if (getdns_list_append_dict(repeat_list, repeat_dict))
goto rdata_error;
@ -422,8 +423,8 @@ error:
return NULL;
}
static int
dname_equal(uint8_t *s1, uint8_t *s2)
int
priv_getdns_dname_equal(const uint8_t *s1, const uint8_t *s2)
{
uint8_t i;
for (;;) {
@ -432,7 +433,8 @@ dname_equal(uint8_t *s1, uint8_t *s2)
else if (!*s1)
return 1;
for (i = *s1++, s2++; i > 0; i--, s1++, s2++)
if ((*s1 & 0xDF) != (*s2 & 0xDF))
if (*s1 != *s2 && tolower((unsigned char)*s1)
!= tolower((unsigned char)*s2))
return 0;
}
}
@ -543,8 +545,7 @@ priv_getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
if ((r = getdns_dict_set_dict(result, "header", header)))
goto error;
(void) gldns_str2wire_dname_buf(
req->owner->name, canonical_name_space, &canonical_name_len);
canonical_name = req->owner->name;
for ( rr_iter = priv_getdns_rr_iter_init(&rr_iter_storage
, req->response
@ -553,7 +554,7 @@ priv_getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
; rr_iter = priv_getdns_rr_iter_next(rr_iter)) {
if (!set_dict(&rr_dict,
priv_getdns_rr_iter2rr_dict(context, rr_iter)))
priv_getdns_rr_iter2rr_dict(&context->mf, rr_iter)))
continue;
section = priv_getdns_rr_iter_section(rr_iter);
@ -580,7 +581,7 @@ priv_getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
owner_name = priv_getdns_owner_if_or_as_decompressed(
rr_iter, owner_name_space, &owner_name_len);
if (!dname_equal(canonical_name, owner_name))
if (!priv_getdns_dname_equal(canonical_name, owner_name))
continue;
if (!(rdf_iter = priv_getdns_rdf_iter_init(
@ -653,7 +654,7 @@ priv_getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
owner_name = priv_getdns_owner_if_or_as_decompressed(
rr_iter, owner_name_space, &owner_name_len);
if (!dname_equal(canonical_name, owner_name))
if (!priv_getdns_dname_equal(canonical_name, owner_name))
continue;
if (!(rdf_iter = priv_getdns_rdf_iter_init(
@ -733,21 +734,22 @@ create_getdns_response(getdns_dns_req *completed_request)
continue;
nreplies++;
if (netreq->secure)
if (netreq->dnssec_status == GETDNS_DNSSEC_SECURE)
nsecure++;
else if (! netreq->bogus)
else if (! netreq->dnssec_status != GETDNS_DNSSEC_BOGUS)
ninsecure++;
if (dnssec_return_status && netreq->bogus)
if (dnssec_return_status &&
netreq->dnssec_status == GETDNS_DNSSEC_BOGUS)
nbogus++;
else if (GLDNS_RCODE_NOERROR ==
GLDNS_RCODE_WIRE(netreq->response))
nanswers++;
if (! completed_request->dnssec_return_validation_chain) {
if (dnssec_return_status && netreq->bogus)
if (dnssec_return_status &&
netreq->dnssec_status == GETDNS_DNSSEC_BOGUS)
continue;
else if (completed_request->dnssec_return_only_secure
&& ! netreq->secure)
&& netreq->dnssec_status != GETDNS_DNSSEC_SECURE)
continue;
}
if (!(reply = priv_getdns_create_reply_dict(context,
@ -762,15 +764,18 @@ create_getdns_response(getdns_dns_req *completed_request)
result, "canonical_name", canonical_name))
goto error;
}
/* TODO: Check instead if canonical_name for request_type
* is in the answer section.
*/
if (GLDNS_RCODE_NOERROR ==
GLDNS_RCODE_WIRE(netreq->response))
nanswers++;
if (dnssec_return_status ||
completed_request->dnssec_return_validation_chain) {
if (getdns_dict_set_int(reply, "dnssec_status",
( netreq->secure ? GETDNS_DNSSEC_SECURE
: netreq->bogus ? GETDNS_DNSSEC_BOGUS
: rrsigs_in_answer &&
context->has_ta ? GETDNS_DNSSEC_INDETERMINATE
: GETDNS_DNSSEC_INSECURE )))
netreq->dnssec_status))
goto error;
}
@ -830,7 +835,7 @@ extformatcmp(const void *a, const void *b)
/*---------------------------------------- validate_extensions */
getdns_return_t
validate_extensions(struct getdns_dict * extensions)
priv_getdns_validate_extensions(struct getdns_dict * extensions)
{
struct getdns_dict_item *item;
getdns_extension_format *extformat;
@ -852,16 +857,18 @@ validate_extensions(struct getdns_dict * extensions)
return GETDNS_RETURN_EXTENSION_MISFORMAT;
}
return GETDNS_RETURN_GOOD;
} /* validate_extensions */
} /* priv_getdns_validate_extensions */
getdns_return_t
getdns_apply_network_result(getdns_network_req* netreq,
struct ub_result* ub_res)
{
size_t dname_len;
netreq->secure = ub_res->secure;
netreq->bogus = ub_res->bogus;
if (ub_res->bogus)
netreq->dnssec_status = GETDNS_DNSSEC_BOGUS;
else if (ub_res->secure)
netreq->dnssec_status = GETDNS_DNSSEC_SECURE;
else if (netreq->owner->context->trust_anchors)
netreq->dnssec_status = GETDNS_DNSSEC_INSECURE;
if (ub_res == NULL) /* Timeout */
return GETDNS_RETURN_GOOD;
@ -900,24 +907,24 @@ getdns_apply_network_result(getdns_network_req* netreq,
GLDNS_RA_SET(netreq->response);
GLDNS_RCODE_SET(netreq->response, ub_res->rcode);
dname_len = netreq->max_udp_payload_size - GLDNS_HEADER_SIZE;
if (gldns_str2wire_dname_buf(netreq->owner->name,
netreq->response + GLDNS_HEADER_SIZE, &dname_len))
return GETDNS_RETURN_GENERIC_ERROR;
(void) memcpy( netreq->response + GLDNS_HEADER_SIZE
, netreq->owner->name, netreq->owner->name_len);
gldns_write_uint16( netreq->response + GLDNS_HEADER_SIZE + dname_len
gldns_write_uint16( netreq->response + GLDNS_HEADER_SIZE
+ netreq->owner->name_len
, netreq->request_type);
gldns_write_uint16( netreq->response + GLDNS_HEADER_SIZE + dname_len + 2
gldns_write_uint16( netreq->response + GLDNS_HEADER_SIZE
+ netreq->owner->name_len + 2
, netreq->request_class);
netreq->response_len = GLDNS_HEADER_SIZE + dname_len + 4;
netreq->response_len = GLDNS_HEADER_SIZE + netreq->owner->name_len + 4;
return GETDNS_RETURN_GOOD;
}
getdns_return_t
validate_dname(const char* dname) {
priv_getdns_validate_dname(const char* dname) {
int len;
int label_len;
const char* s;
@ -980,7 +987,150 @@ validate_dname(const char* dname) {
return GETDNS_RETURN_BAD_DOMAIN_NAME;
}
return GETDNS_RETURN_GOOD;
} /* validate_dname */
} /* priv_getdns_validate_dname */
static void _getdns_list2wire_buf(gldns_buffer *buf, getdns_list *l)
{
getdns_dict *rr_dict, *q_dict;
getdns_list *section;
getdns_return_t r;
size_t i, j, pkt_start, ancount, qdcount;
uint32_t qtype, qclass;
getdns_bindata *qname;
pkt_start = gldns_buffer_position(buf);
/* Empty header */
gldns_buffer_write_u32(buf, 0);
gldns_buffer_write_u32(buf, 0);
gldns_buffer_write_u32(buf, 0);
for ( i = 0, qdcount = 0
; (r = getdns_list_get_dict(l, i, &rr_dict))
!= GETDNS_RETURN_NO_SUCH_LIST_ITEM
; i++ ) {
if (r) {
if (r == GETDNS_RETURN_WRONG_TYPE_REQUESTED)
continue;
else
break;
}
if (getdns_dict_get_dict(rr_dict, "question", &q_dict)
== GETDNS_RETURN_GOOD) {
/* rr_dict was actually a reply
* with a question section/rr_dict
*/
rr_dict = q_dict;
}
if (getdns_dict_get_int(rr_dict, "qtype", &qtype) ||
getdns_dict_get_bindata(rr_dict, "qname", &qname))
continue;
(void) getdns_dict_get_int(rr_dict, "qclass", &qclass);
gldns_buffer_write(buf, qname->data, qname->size);
gldns_buffer_write_u16(buf, (uint16_t)qtype);
gldns_buffer_write_u16(buf, (uint16_t)qclass);
qdcount++;
}
gldns_buffer_write_u16_at(buf, pkt_start+GLDNS_QDCOUNT_OFF, qdcount);
for ( i = 0, ancount = 0
; (r = getdns_list_get_dict(l, i, &rr_dict))
!= GETDNS_RETURN_NO_SUCH_LIST_ITEM
; i++ ) {
if (r) {
if (r == GETDNS_RETURN_WRONG_TYPE_REQUESTED)
continue;
else
break;
}
if (priv_getdns_rr_dict2wire(rr_dict, buf)
== GETDNS_RETURN_GOOD) {
ancount++;
continue;
}
if (getdns_dict_get_list(rr_dict, "answer", &section)
== GETDNS_RETURN_GOOD) {
for ( j = 0
; (r = getdns_list_get_dict(section, j, &q_dict))
!= GETDNS_RETURN_NO_SUCH_LIST_ITEM
; j++ ) {
if (r) {
if (r ==
GETDNS_RETURN_WRONG_TYPE_REQUESTED)
continue;
else
break;
}
if (priv_getdns_rr_dict2wire(q_dict, buf)
== GETDNS_RETURN_GOOD)
ancount++;
}
}
if (getdns_dict_get_list(rr_dict, "authority", &section)
== GETDNS_RETURN_GOOD) {
for ( j = 0
; (r = getdns_list_get_dict(section, j, &q_dict))
!= GETDNS_RETURN_NO_SUCH_LIST_ITEM
; j++ ) {
if (r) {
if (r ==
GETDNS_RETURN_WRONG_TYPE_REQUESTED)
continue;
else
break;
}
if (priv_getdns_rr_dict2wire(q_dict, buf)
== GETDNS_RETURN_GOOD)
ancount++;
}
}
}
gldns_buffer_write_u16_at(buf, pkt_start+GLDNS_ANCOUNT_OFF, ancount);
}
uint8_t *_getdns_list2wire(
getdns_list *l, uint8_t *buf, size_t *buf_len, struct mem_funcs *mf)
{
gldns_buffer gbuf;
size_t sz;
gldns_buffer_init_frm_data(&gbuf, buf, *buf_len);
_getdns_list2wire_buf(&gbuf, l);
if ((sz = gldns_buffer_position(&gbuf)) <= *buf_len)
return buf;
if (!(buf = GETDNS_XMALLOC(*mf, uint8_t, (*buf_len = sz))))
return NULL;
gldns_buffer_init_frm_data(&gbuf, buf, sz);
_getdns_list2wire_buf(&gbuf, l);
return buf;
}
void _getdns_wire2list(uint8_t *pkt, size_t pkt_len, getdns_list *l)
{
priv_getdns_rr_iter rr_spc, *rr;
getdns_dict *rr_dict;
for ( rr = priv_getdns_rr_iter_init(&rr_spc, pkt, pkt_len)
; rr ; rr = priv_getdns_rr_iter_next(rr)) {
if (!(rr_dict = priv_getdns_rr_iter2rr_dict(&l->mf, rr)))
continue;
(void)getdns_list_append_dict(l, rr_dict);
getdns_dict_destroy(rr_dict);
}
}
/* util-internal.c */

View File

@ -44,6 +44,7 @@
#define SCHED_DEBUG 0
#define WIRE_DEBUG 0
#define STUB_DEBUG 0
#define SEC_DEBUG 1
#ifdef S_SPLINT_S
# define INLINE
@ -122,7 +123,7 @@ getdns_return_t sockaddr_to_dict(struct getdns_context *context,
struct sockaddr_storage *sockaddr, struct getdns_dict ** output);
getdns_dict *
priv_getdns_rr_iter2rr_dict(getdns_context *context, priv_getdns_rr_iter *i);
priv_getdns_rr_iter2rr_dict(struct mem_funcs *mf, priv_getdns_rr_iter *i);
struct getdns_dns_req;
struct getdns_dict *create_getdns_response(struct getdns_dns_req *completed_request);
@ -130,7 +131,15 @@ struct getdns_dict *create_getdns_response(struct getdns_dns_req *completed_requ
getdns_dict *priv_getdns_create_reply_dict(getdns_context *context,
getdns_network_req *req, getdns_list *just_addrs, int *rrsigs_in_answer);
getdns_return_t validate_dname(const char* dname);
getdns_return_t priv_getdns_validate_dname(const char* dname);
int priv_getdns_dname_equal(const uint8_t *s1, const uint8_t *s2);
uint8_t *_getdns_list2wire(
getdns_list *l, uint8_t *buf, size_t *buf_len, struct mem_funcs *mf);
void _getdns_wire2list(uint8_t *pkt, size_t pkt_len, getdns_list *l);
/**
* detect unrecognized extension strings or invalid extension formats
@ -140,7 +149,7 @@ getdns_return_t validate_dname(const char* dname);
* @return GETDNS_RETURN_NO_SUCH_EXTENSION A name in the extensions dict is not a valid extension.
* @return GETDNS_RETURN_EXTENSION_MISFORMAT One or more of the extensions has a bad format.
*/
getdns_return_t validate_extensions(struct getdns_dict * extensions);
getdns_return_t priv_getdns_validate_extensions(struct getdns_dict * extensions);
#define DEBUG_ON(...) do { \
struct timeval tv; \
@ -170,6 +179,13 @@ getdns_return_t validate_extensions(struct getdns_dict * extensions);
#define DEBUG_STUB(...) DEBUG_OFF(__VA_ARGS__)
#endif
#if defined(SEC_DEBUG) && SEC_DEBUG
#include <time.h>
#define DEBUG_SEC(...) DEBUG_ON(__VA_ARGS__)
#else
#define DEBUG_SEC(...) DEBUG_OFF(__VA_ARGS__)
#endif
INLINE getdns_eventloop_event *getdns_eventloop_event_init(
getdns_eventloop_event *ev,void *userarg, getdns_eventloop_callback read_cb,
getdns_eventloop_callback write_cb, getdns_eventloop_callback timeout_cb)