--enable-broken-native-stub-dnssec

Still needs a little more work for wildcards and NODATA answers...
This commit is contained in:
Willem Toorop 2015-03-18 14:45:06 +01:00
parent 59c92b884c
commit fa782d1043
7 changed files with 250 additions and 28 deletions

22
configure vendored
View File

@ -754,6 +754,7 @@ with_sysroot
enable_libtool_lock enable_libtool_lock
enable_rpath enable_rpath
enable_tcp_fastopen enable_tcp_fastopen
enable_broken_native_stub_dnssec
with_libidn with_libidn
with_libldns with_libldns
with_libunbound with_libunbound
@ -1396,6 +1397,9 @@ Optional Features:
--disable-libtool-lock avoid locking (might break parallel builds) --disable-libtool-lock avoid locking (might break parallel builds)
--disable-rpath disable hardcoded rpath (default=enabled) --disable-rpath disable hardcoded rpath (default=enabled)
--enable-tcp-fastopen Enable TCP Fast Open --enable-tcp-fastopen Enable TCP Fast Open
--enable-broken-native-stub-dnssec
Enable very experimental and broken native stub
DNSSEC support
Optional Packages: Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@ -11186,6 +11190,24 @@ _ACEOF
;; ;;
esac 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;
fi
case "$enable_broken_native_stub_dnssec" in
yes)
cat >>confdefs.h <<_ACEOF
#define STUB_NATIVE_DNSSEC 1
_ACEOF
;;
no|*)
;;
esac
# search to set include and library paths right # search to set include and library paths right
# find libidn # find libidn

View File

@ -131,6 +131,16 @@ case "$enable_tcp_fastopen" in
;; ;;
esac esac
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.])
;;
no|*)
;;
esac
# search to set include and library paths right # search to set include and library paths right
# find libidn # find libidn
AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname], AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname],

View File

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

View File

@ -79,6 +79,57 @@ static void launch_chain_link_lookup(struct validation_chain *chain,
priv_getdns_rdf_iter *rdf_dname); priv_getdns_rdf_iter *rdf_dname);
static void destroy_chain(struct validation_chain *chain); static void destroy_chain(struct validation_chain *chain);
#ifdef STUB_NATIVE_DNSSEC
static void
native_stub_validate_dnssec(getdns_dns_req *dns_req, getdns_list *support)
{
getdns_network_req *netreq, **netreq_p;
getdns_list *trust_anchors;
getdns_dict *reply = NULL;
getdns_dict *header;
getdns_list *to_validate;
uint32_t rcode;
if (!(trust_anchors = getdns_root_trust_anchor(NULL)))
return;
for (netreq_p = dns_req->netreqs; (netreq = *netreq_p) ; netreq_p++) {
if (!(reply = priv_getdns_create_reply_dict(dns_req->context,
netreq, NULL, NULL)))
continue;
if (getdns_dict_get_dict(reply, "header", &header))
break;
if (getdns_dict_get_int(header, "rcode", &rcode))
break;
if (rcode == GETDNS_RCODE_NXDOMAIN) {
if (getdns_dict_get_list(
reply, "authority", &to_validate))
break;
} else if (getdns_dict_get_list(reply, "answer", &to_validate))
break;
switch ((int)getdns_validate_dnssec(
to_validate, support, trust_anchors)) {
case GETDNS_DNSSEC_SECURE:
netreq->secure = 1;
netreq->bogus = 0;
break;
case GETDNS_DNSSEC_BOGUS:
netreq->secure = 0;
netreq->bogus = 1;
break;
default:
/* GETDNS_DNSSEC_INSECURE */
netreq->secure = 0;
netreq->bogus = 0;
break;
}
getdns_dict_destroy(reply);
reply = NULL;
}
getdns_dict_destroy(reply);
}
#endif
static void callback_on_complete_chain(struct validation_chain *chain) static void callback_on_complete_chain(struct validation_chain *chain)
{ {
getdns_context *context = chain->dns_req->context; getdns_context *context = chain->dns_req->context;
@ -101,10 +152,9 @@ static void callback_on_complete_chain(struct validation_chain *chain)
if (ongoing > 0) if (ongoing > 0)
return; return;
if (!(response = create_getdns_response(chain->dns_req)) || if (!(keys = getdns_list_create_with_context(context))) {
!(keys = getdns_list_create_with_context(context))) { priv_getdns_call_user_callback(chain->dns_req,
create_getdns_response(chain->dns_req));
priv_getdns_call_user_callback(chain->dns_req, response);
destroy_chain(chain); destroy_chain(chain);
return; return;
} }
@ -117,7 +167,13 @@ static void callback_on_complete_chain(struct validation_chain *chain)
, i, &rr_dict); i++) , i, &rr_dict); i++)
(void) getdns_list_append_dict(keys, rr_dict); (void) getdns_list_append_dict(keys, rr_dict);
} }
(void) getdns_dict_set_list(response, "validation_chain", keys); #ifdef STUB_NATIVE_DNSSEC
native_stub_validate_dnssec(chain->dns_req, keys);
#endif
if ((response = create_getdns_response(chain->dns_req)) &&
chain->dns_req->dnssec_return_validation_chain) {
(void)getdns_dict_set_list(response, "validation_chain", keys);
}
getdns_list_destroy(keys); getdns_list_destroy(keys);
priv_getdns_call_user_callback(chain->dns_req, response); priv_getdns_call_user_callback(chain->dns_req, response);
destroy_chain(chain); destroy_chain(chain);
@ -385,6 +441,82 @@ priv_getdns_rr_list_from_list(struct getdns_list *list, ldns_rr_list **rr_list)
return r; return r;
} }
static int
priv_getdns_rr_dict_with_compressed_names(getdns_dict *rr_dict)
{
uint32_t rr_type;
getdns_dict *rdata;
if (getdns_dict_get_int(rr_dict, "type", &rr_type))
return 0;
if (rr_type == GETDNS_RRTYPE_RRSIG) {
if (getdns_dict_get_dict(rr_dict, "rdata", &rdata))
return 0;
if (getdns_dict_get_int(rdata, "type_covered", &rr_type))
return 0;
}
switch (rr_type) {
case GETDNS_RRTYPE_NS:
case GETDNS_RRTYPE_MD:
case GETDNS_RRTYPE_CNAME:
case GETDNS_RRTYPE_SOA:
case GETDNS_RRTYPE_MG:
case GETDNS_RRTYPE_MR:
case GETDNS_RRTYPE_PTR:
case GETDNS_RRTYPE_MINFO:
case GETDNS_RRTYPE_MX:
return 1;
default:
return 0;
}
}
static int
ldns_dname_compare_v(const void *a, const void *b) {
return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
}
ldns_status
priv_getdns_ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
{
ldns_dnssec_name *new_name;
ldns_rbnode_t *new_node;
if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_NSEC3)
return ldns_dnssec_zone_add_rr(zone, rr);
if (!(new_name = ldns_dnssec_name_new()))
return LDNS_STATUS_MEM_ERR;
new_name->name = ldns_rdf_clone(ldns_rr_owner(rr));
new_name->hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
new_name->name_alloced = true;
if (!(new_node = LDNS_MALLOC(ldns_rbnode_t))) {
ldns_dnssec_name_free(new_name);
return LDNS_STATUS_MEM_ERR;
}
new_node->key = new_name->name;
new_node->data = new_name;
if (!zone->names)
zone->names = ldns_rbtree_create(ldns_dname_compare_v);
(void)ldns_rbtree_insert(zone->names, new_node);
if (!(new_node = LDNS_MALLOC(ldns_rbnode_t))) {
ldns_dnssec_name_free(new_name);
return LDNS_STATUS_MEM_ERR;
}
new_node->key = new_name->hashed_name;
new_node->data = new_name;
if (!zone->hashed_names) {
zone->_nsec3params = rr;
zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v);
}
(void)ldns_rbtree_insert(zone->hashed_names, new_node);
return ldns_dnssec_zone_add_rr(zone, rr);
}
static getdns_return_t static getdns_return_t
priv_getdns_dnssec_zone_from_list(struct getdns_list *list, priv_getdns_dnssec_zone_from_list(struct getdns_list *list,
ldns_dnssec_zone **zone) ldns_dnssec_zone **zone)
@ -405,10 +537,13 @@ priv_getdns_dnssec_zone_from_list(struct getdns_list *list,
if ((r = getdns_list_get_dict(list, i, &rr_dict))) if ((r = getdns_list_get_dict(list, i, &rr_dict)))
break; break;
if (priv_getdns_rr_dict_with_compressed_names(rr_dict))
continue;
if ((r = priv_getdns_create_rr_from_dict(rr_dict, &rr))) if ((r = priv_getdns_create_rr_from_dict(rr_dict, &rr)))
break; break;
if ((s = ldns_dnssec_zone_add_rr(*zone, rr))) { if ((s = priv_getdns_ldns_dnssec_zone_add_rr(*zone, rr))) {
ldns_rr_free(rr); ldns_rr_free(rr);
r = GETDNS_RETURN_GENERIC_ERROR; r = GETDNS_RETURN_GENERIC_ERROR;
break; break;
@ -423,19 +558,41 @@ typedef struct zone_iter {
ldns_dnssec_zone *zone; ldns_dnssec_zone *zone;
ldns_rbnode_t *cur_node; ldns_rbnode_t *cur_node;
ldns_dnssec_rrsets *cur_rrset; ldns_dnssec_rrsets *cur_rrset;
ldns_dnssec_rrsets nsec_rrset;
ldns_dnssec_rrs nsec_rrs;
} zone_iter; } zone_iter;
static void static void
rrset_iter_init_zone(zone_iter *i, ldns_dnssec_zone *zone) rrset_iter_init_zone(zone_iter *i, ldns_dnssec_zone *zone)
{ {
ldns_dnssec_name *name;
assert(i); assert(i);
i->zone = zone; i->zone = zone;
i->cur_node = zone->names ? ldns_rbtree_first(zone->names) if ((i->cur_node = zone->names
: LDNS_RBTREE_NULL; ? ldns_rbtree_first(zone->names)
i->cur_rrset = i->cur_node != LDNS_RBTREE_NULL : LDNS_RBTREE_NULL) == LDNS_RBTREE_NULL) {
? ((ldns_dnssec_name *)i->cur_node->data)->rrsets
: NULL; i->cur_rrset = NULL;
return;
}
i->cur_rrset = ((ldns_dnssec_name *)i->cur_node->data)->rrsets;
if (!i->cur_rrset) {
name = ((ldns_dnssec_name *)i->cur_node->data);
if (name->nsec && name->nsec_signatures) {
i->cur_rrset = &i->nsec_rrset;
i->nsec_rrset.rrs = &i->nsec_rrs;
i->nsec_rrs.rr = name->nsec;
i->nsec_rrs.next = NULL;
i->nsec_rrset.type = ldns_rr_get_type(name->nsec);
i->nsec_rrset.signatures =
name->nsec_signatures;
i->nsec_rrset.next = NULL;
return;
}
}
} }
static ldns_dnssec_rrsets * static ldns_dnssec_rrsets *
@ -449,12 +606,30 @@ rrset_iter_value(zone_iter *i)
static void static void
rrset_iter_next(zone_iter *i) rrset_iter_next(zone_iter *i)
{ {
int was_nsec_rrset;
ldns_dnssec_name *name;
assert(i); assert(i);
if (! i->cur_rrset) if (! i->cur_rrset)
return; return;
was_nsec_rrset = (i->cur_rrset == &i->nsec_rrset);
if (! (i->cur_rrset = i->cur_rrset->next)) { if (! (i->cur_rrset = i->cur_rrset->next)) {
if (!was_nsec_rrset) {
name = ((ldns_dnssec_name *)i->cur_node->data);
if (name->nsec && name->nsec_signatures) {
i->cur_rrset = &i->nsec_rrset;
i->nsec_rrset.rrs = &i->nsec_rrs;
i->nsec_rrs.rr = name->nsec;
i->nsec_rrs.next = NULL;
i->nsec_rrset.type = ldns_rr_get_type(name->nsec);
i->nsec_rrset.signatures =
name->nsec_signatures;
i->nsec_rrset.next = NULL;
return;
}
}
i->cur_node = ldns_rbtree_next(i->cur_node); i->cur_node = ldns_rbtree_next(i->cur_node);
i->cur_rrset = i->cur_node != LDNS_RBTREE_NULL i->cur_rrset = i->cur_node != LDNS_RBTREE_NULL
? ((ldns_dnssec_name *)i->cur_node->data)->rrsets ? ((ldns_dnssec_name *)i->cur_node->data)->rrsets
@ -572,9 +747,9 @@ done_free_verifying_keys:
* *
*/ */
getdns_return_t getdns_return_t
getdns_validate_dnssec(struct getdns_list *records_to_validate, getdns_validate_dnssec(getdns_list *records_to_validate,
struct getdns_list *support_records, getdns_list *support_records,
struct getdns_list *trust_anchors) getdns_list *trust_anchors)
{ {
getdns_return_t r; getdns_return_t r;
ldns_rr_list *trusted; ldns_rr_list *trusted;
@ -584,7 +759,7 @@ getdns_validate_dnssec(struct getdns_list *records_to_validate,
zone_iter i; zone_iter i;
ldns_dnssec_rrsets *rrset; ldns_dnssec_rrsets *rrset;
ldns_dnssec_rrs *rrs; ldns_dnssec_rrs *rrs;
ldns_status s = LDNS_STATUS_OK; ldns_status s = LDNS_STATUS_ERR;
if ((r = priv_getdns_rr_list_from_list(trust_anchors, &trusted))) if ((r = priv_getdns_rr_list_from_list(trust_anchors, &trusted)))
return r; return r;
@ -616,8 +791,7 @@ getdns_validate_dnssec(struct getdns_list *records_to_validate,
for (rrset_iter_init_zone(&i, to_validate); for (rrset_iter_init_zone(&i, to_validate);
(rrset = rrset_iter_value(&i)); rrset_iter_next(&i)) { (rrset = rrset_iter_value(&i)); rrset_iter_next(&i)) {
s |= chase(rrset, support, support_keys, trusted); if ((s = chase(rrset, support, support_keys, trusted)))
if (s != 0)
break; break;
} }
if (s == LDNS_STATUS_CRYPTO_BOGUS) if (s == LDNS_STATUS_CRYPTO_BOGUS)

View File

@ -93,7 +93,13 @@ priv_getdns_check_dns_req_complete(getdns_dns_req *dns_req)
if (! results_found) if (! results_found)
priv_getdns_call_user_callback(dns_req, NULL); priv_getdns_call_user_callback(dns_req, NULL);
else if (dns_req->dnssec_return_validation_chain) else if (dns_req->dnssec_return_validation_chain
#ifdef STUB_NATIVE_DNSSEC
|| (dns_req->context->resolution_type == GETDNS_RESOLUTION_STUB
&& (dns_req->dnssec_return_status ||
dns_req->dnssec_return_only_secure))
#endif
)
priv_getdns_get_validation_chain(dns_req); priv_getdns_get_validation_chain(dns_req);
else else
priv_getdns_call_user_callback( priv_getdns_call_user_callback(
@ -130,13 +136,16 @@ submit_network_request(getdns_network_req *netreq)
getdns_return_t r; getdns_return_t r;
getdns_dns_req *dns_req = netreq->owner; getdns_dns_req *dns_req = netreq->owner;
if (dns_req->context->resolution_type == GETDNS_RESOLUTION_RECURSING || if (dns_req->context->resolution_type == GETDNS_RESOLUTION_RECURSING
/* TODO: Until DNSSEC with the new async stub resolver is finished, /* TODO: Until DNSSEC with the new async stub resolver is finished,
* use unbound when we need DNSSEC. * use unbound when we need DNSSEC.
*/ */
dns_req->dnssec_return_status || #ifndef STUB_NATIVE_DNSSEC
dns_req->dnssec_return_only_secure || || dns_req->dnssec_return_status
dns_req->dnssec_return_validation_chain) { || dns_req->dnssec_return_only_secure
|| dns_req->dnssec_return_validation_chain
#endif
) {
/* schedule the timeout */ /* schedule the timeout */
if (! dns_req->timeout.timeout_cb) { if (! dns_req->timeout.timeout_cb) {

View File

@ -477,8 +477,8 @@ set_dict(getdns_dict **var, getdns_dict *value)
#define SET_WIRE_CNT(X,Y) if (getdns_dict_set_int(header, #X , (int) \ #define SET_WIRE_CNT(X,Y) if (getdns_dict_set_int(header, #X , (int) \
GLDNS_ ## Y (req->response))) goto error GLDNS_ ## Y (req->response))) goto error
static getdns_dict * getdns_dict *
create_reply_dict(getdns_context *context, getdns_network_req *req, priv_getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
getdns_list *just_addrs, int *rrsigs_in_answer) getdns_list *just_addrs, int *rrsigs_in_answer)
{ {
/* turn a packet into this glorious structure /* turn a packet into this glorious structure
@ -595,7 +595,7 @@ create_reply_dict(getdns_context *context, getdns_network_req *req,
rr_type = gldns_read_uint16(rr_iter->rr_type); rr_type = gldns_read_uint16(rr_iter->rr_type);
if (section > GLDNS_SECTION_QUESTION && if (section > GLDNS_SECTION_QUESTION &&
rr_type == GETDNS_RRTYPE_RRSIG) rr_type == GETDNS_RRTYPE_RRSIG && rrsigs_in_answer)
*rrsigs_in_answer = 1; *rrsigs_in_answer = 1;
if (section != GLDNS_SECTION_ANSWER) if (section != GLDNS_SECTION_ANSWER)
@ -635,7 +635,7 @@ create_reply_dict(getdns_context *context, getdns_network_req *req,
getdns_dict_set_bindata(rr_dict,"address_data",&bindata) || getdns_dict_set_bindata(rr_dict,"address_data",&bindata) ||
getdns_list_append_dict(just_addrs, rr_dict)) { (just_addrs && getdns_list_append_dict(just_addrs, rr_dict))) {
goto error; goto error;
} }
@ -775,7 +775,7 @@ create_getdns_response(getdns_dns_req *completed_request)
&& ! netreq->secure) && ! netreq->secure)
continue; continue;
} }
if (!(reply = create_reply_dict(context, if (!(reply = priv_getdns_create_reply_dict(context,
netreq, just_addrs, &rrsigs_in_answer))) netreq, just_addrs, &rrsigs_in_answer)))
goto error; goto error;

View File

@ -43,7 +43,7 @@
#include "rr-iter.h" #include "rr-iter.h"
#define SCHED_DEBUG 0 #define SCHED_DEBUG 0
#define WIRE_DEBUG 1 #define WIRE_DEBUG 0
#ifdef S_SPLINT_S #ifdef S_SPLINT_S
# define INLINE # define INLINE
@ -127,6 +127,9 @@ priv_getdns_rr_iter2rr_dict(getdns_context *context, priv_getdns_rr_iter *i);
struct getdns_dns_req; struct getdns_dns_req;
struct getdns_dict *create_getdns_response(struct getdns_dns_req *completed_request); struct getdns_dict *create_getdns_response(struct getdns_dns_req *completed_request);
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 validate_dname(const char* dname);
/** /**