Collect validation chains for RRs without sigs

This commit is contained in:
Willem Toorop 2015-06-17 14:46:44 +02:00
parent 39639a86c4
commit 129e340e8e
3 changed files with 204 additions and 24 deletions

View File

@ -76,7 +76,7 @@ struct chain_link {
}; };
static void launch_chain_link_lookup(struct validation_chain *chain, static void launch_chain_link_lookup(struct validation_chain *chain,
priv_getdns_rdf_iter *rdf_dname); uint8_t *dname);
static void destroy_chain(struct validation_chain *chain); static void destroy_chain(struct validation_chain *chain);
#ifdef STUB_NATIVE_DNSSEC #ifdef STUB_NATIVE_DNSSEC
@ -170,10 +170,11 @@ static void callback_on_complete_chain(struct validation_chain *chain)
} }
RBTREE_FOR(link, struct chain_link *, RBTREE_FOR(link, struct chain_link *,
(getdns_rbtree_t *)&(chain->root)) { (getdns_rbtree_t *)&(chain->root)) {
for (i = 0; !getdns_list_get_dict( link->DNSKEY.result for (i = 0; !getdns_list_get_dict( link->DS.result
, i, &rr_dict); i++) , i, &rr_dict); i++)
(void) getdns_list_append_dict(keys, rr_dict); (void) getdns_list_append_dict(keys, rr_dict);
for (i = 0; !getdns_list_get_dict( link->DS.result
for (i = 0; !getdns_list_get_dict( link->DNSKEY.result
, i, &rr_dict); i++) , i, &rr_dict); i++)
(void) getdns_list_append_dict(keys, rr_dict); (void) getdns_list_append_dict(keys, rr_dict);
} }
@ -205,6 +206,8 @@ chain_response_callback(struct getdns_dns_req *dns_req)
getdns_list *keys; getdns_list *keys;
size_t nkeys; size_t nkeys;
getdns_return_t r; getdns_return_t r;
uint8_t sign_name_space[256], *sign_name;
size_t sign_name_len = sizeof(sign_name_space);
response->dns_req = dns_req; response->dns_req = dns_req;
if (!(keys = getdns_list_create_with_context(context))) if (!(keys = getdns_list_create_with_context(context)))
@ -218,13 +221,16 @@ chain_response_callback(struct getdns_dns_req *dns_req)
; rr_iter = priv_getdns_rr_iter_next(rr_iter) ; rr_iter = priv_getdns_rr_iter_next(rr_iter)
) { ) {
section = priv_getdns_rr_iter_section(rr_iter); section = priv_getdns_rr_iter_section(rr_iter);
if (section != GLDNS_SECTION_ANSWER) if (section != GLDNS_SECTION_ANSWER &&
section != GLDNS_SECTION_AUTHORITY)
continue; continue;
rr_type = gldns_read_uint16(rr_iter->rr_type); rr_type = gldns_read_uint16(rr_iter->rr_type);
if (rr_type == GETDNS_RRTYPE_DS || if (rr_type == GETDNS_RRTYPE_DS ||
rr_type == GETDNS_RRTYPE_DNSKEY) { rr_type == GETDNS_RRTYPE_DNSKEY ||
rr_type == GETDNS_RRTYPE_NSEC ||
rr_type == GETDNS_RRTYPE_NSEC3) {
if (!(rr_dict = priv_getdns_rr_iter2rr_dict( if (!(rr_dict = priv_getdns_rr_iter2rr_dict(
context, rr_iter))) context, rr_iter)))
continue; continue;
@ -240,11 +246,17 @@ chain_response_callback(struct getdns_dns_req *dns_req)
continue; continue;
type_covered = gldns_read_uint16(rdf->pos); type_covered = gldns_read_uint16(rdf->pos);
if (type_covered == GETDNS_RRTYPE_DS) { if (type_covered == GETDNS_RRTYPE_DS ||
type_covered == GETDNS_RRTYPE_NSEC ||
type_covered == GETDNS_RRTYPE_NSEC3) {
if ((rdf = priv_getdns_rdf_iter_init_at( if ((rdf = priv_getdns_rdf_iter_init_at(
&rdf_storage, rr_iter, 7))) &rdf_storage, rr_iter, 7)) &&
(sign_name = priv_getdns_rdf_if_or_as_decompressed(
rdf, sign_name_space, &sign_name_len)))
launch_chain_link_lookup( launch_chain_link_lookup(
response->chain, rdf); response->chain, sign_name);
} else if (type_covered != GETDNS_RRTYPE_DNSKEY) } else if (type_covered != GETDNS_RRTYPE_DNSKEY)
continue; continue;
@ -302,23 +314,86 @@ resolve(char* name, int rrtype, struct chain_response *response)
return r; return r;
} }
static void
find_delegation_point_callback(struct getdns_dns_req *dns_req)
{
struct validation_chain *chain =
(struct validation_chain *) dns_req->user_pointer;
getdns_context *context = dns_req->context;
getdns_network_req **netreq_p, *netreq;
priv_getdns_rr_iter rr_iter_storage, *rr_iter;
priv_getdns_rdf_iter rdf_storage, *rdf;
gldns_pkt_section section;
uint16_t rr_type;
uint8_t rr_name_space[256], *rr_name;
size_t rr_name_len = sizeof(rr_name_space);
for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++) {
for ( rr_iter = priv_getdns_rr_iter_init(&rr_iter_storage
, netreq->response
, netreq->response_len)
; rr_iter
; rr_iter = priv_getdns_rr_iter_next(rr_iter)
) {
section = priv_getdns_rr_iter_section(rr_iter);
if (section != GLDNS_SECTION_ANSWER &&
section != GLDNS_SECTION_AUTHORITY)
continue;
rr_type = gldns_read_uint16(rr_iter->rr_type);
if (rr_type != GETDNS_RRTYPE_SOA)
continue;
if (!(rr_name = priv_getdns_owner_if_or_as_decompressed(
rr_iter, rr_name_space, &rr_name_len)))
continue;
launch_chain_link_lookup(chain, rr_name);
}
}
chain->lock--;
getdns_context_clear_outbound_request(dns_req);
dns_req_free(dns_req);
callback_on_complete_chain(chain);
}
static int
find_delegation_point(struct validation_chain *chain, uint8_t *dname)
{
getdns_return_t r;
getdns_dict *extensions;
char name[1024];
if (!gldns_wire2str_dname_buf(dname, 256, name, sizeof(name)))
return GETDNS_RETURN_GENERIC_ERROR;
if (!(extensions = getdns_dict_create_with_context(
chain->dns_req->context)))
return GETDNS_RETURN_MEMORY_ERROR;
chain->lock++;
if (!(r = getdns_dict_set_int(extensions,
"dnssec_ok_checking_disabled", GETDNS_EXTENSION_TRUE)))
r = priv_getdns_general_loop(chain->dns_req->context,
chain->dns_req->loop, name, GETDNS_RRTYPE_SOA, extensions,
chain, NULL, NULL, find_delegation_point_callback);
getdns_dict_destroy(extensions);
if (r)
chain->lock--;
return r;
}
static void static void
launch_chain_link_lookup( launch_chain_link_lookup(
struct validation_chain *chain, priv_getdns_rdf_iter *rdf_dname) struct validation_chain *chain, uint8_t *dname)
{ {
int r; int r;
struct chain_link *link; struct chain_link *link;
uint8_t dname_spc[256], *dname;
char name[1024]; char name[1024];
size_t dname_spc_sz = sizeof(dname_spc);
if (!(dname = priv_getdns_rdf_if_or_as_decompressed( if (!gldns_wire2str_dname_buf(dname, 256, name, sizeof(name)))
rdf_dname, dname_spc, &dname_spc_sz)))
return;
if (!gldns_wire2str_dname_buf(dname, (dname == dname_spc ?
sizeof(dname_spc) : rdf_dname->nxt - rdf_dname->pos),
name, sizeof(name)))
return; return;
if ((link = (struct chain_link *) if ((link = (struct chain_link *)
@ -393,6 +468,18 @@ static void destroy_chain(struct validation_chain *chain)
GETDNS_FREE(chain->mf, chain); GETDNS_FREE(chain->mf, chain);
} }
static int priv_getdns_dname_is_subdomain(
const uint8_t *subdomain, const uint8_t *domain)
{
while (*domain) {
if (priv_getdns_dname_equal(subdomain, domain))
return 1;
domain += *domain + 1;
}
return *subdomain == 0;
}
/* Do some additional requests to fetch the complete validation chain */ /* Do some additional requests to fetch the complete validation chain */
static void static void
getdns_get_validation_chain(getdns_dns_req *dns_req, uint64_t *timeout) getdns_get_validation_chain(getdns_dns_req *dns_req, uint64_t *timeout)
@ -403,12 +490,21 @@ getdns_get_validation_chain(getdns_dns_req *dns_req, uint64_t *timeout)
priv_getdns_rdf_iter rdf_storage, *rdf; priv_getdns_rdf_iter rdf_storage, *rdf;
gldns_pkt_section section; gldns_pkt_section section;
uint16_t rr_type; uint16_t rr_type;
priv_getdns_rr_iter rrsig_iter_storage, *rrsig_iter;
uint8_t rr_name_space[256], *rr_name;
uint8_t rrsig_name_space[256], *rrsig_name;
uint8_t sign_name_space[256], *sign_name;
size_t rr_name_len = sizeof(rr_name_space);
size_t rrsig_name_len = sizeof(rrsig_name_space);
size_t sign_name_len = sizeof(sign_name_space);
int rrsigs_found;
if (! chain) { if (! chain) {
priv_getdns_call_user_callback( priv_getdns_call_user_callback(
dns_req, create_getdns_response(dns_req)); dns_req, create_getdns_response(dns_req));
return; return;
} }
chain->lock++;
for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++) { for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++) {
for ( rr_iter = priv_getdns_rr_iter_init(&rr_iter_storage for ( rr_iter = priv_getdns_rr_iter_init(&rr_iter_storage
@ -422,17 +518,66 @@ getdns_get_validation_chain(getdns_dns_req *dns_req, uint64_t *timeout)
section != GLDNS_SECTION_AUTHORITY) section != GLDNS_SECTION_AUTHORITY)
continue; continue;
/* Skip RRSIGs because we do only lookups for RRSIGS
* that have an rrset in the record too.
*/
rr_type = gldns_read_uint16(rr_iter->rr_type); rr_type = gldns_read_uint16(rr_iter->rr_type);
if (rr_type != GETDNS_RRTYPE_RRSIG) if (rr_type == GETDNS_RRTYPE_RRSIG)
continue; continue;
if (!(rdf = priv_getdns_rdf_iter_init_at( if (!(rr_name = priv_getdns_owner_if_or_as_decompressed(
&rdf_storage , rr_iter, 7))) rr_iter, rr_name_space, &rr_name_len)))
continue; continue;
launch_chain_link_lookup(chain, rdf); rrsigs_found = 0;
for ( rrsig_iter = priv_getdns_rr_iter_init(&rrsig_iter_storage
, netreq->response
, netreq->response_len )
; rrsig_iter
; rrsig_iter = priv_getdns_rr_iter_next(rrsig_iter)
) {
section = priv_getdns_rr_iter_section(rrsig_iter);
if (section != GLDNS_SECTION_ANSWER &&
section != GLDNS_SECTION_AUTHORITY)
continue;
if (GETDNS_RRTYPE_RRSIG !=
gldns_read_uint16(rrsig_iter->rr_type))
continue;
rdf = priv_getdns_rdf_iter_init(&rdf_storage
, rrsig_iter);
if (!rdf || gldns_read_uint16(rdf->pos) != rr_type)
continue;
if (!(rrsig_name = priv_getdns_owner_if_or_as_decompressed(
rrsig_iter, rrsig_name_space, &rrsig_name_len)))
continue;
if (!priv_getdns_dname_equal(rr_name, rrsig_name))
continue;
if (!(rdf = priv_getdns_rdf_iter_init_at(
&rdf_storage , rrsig_iter, 7)))
continue;
if (!(sign_name = priv_getdns_rdf_if_or_as_decompressed(
rdf, sign_name_space, &sign_name_len)))
continue;
if (!priv_getdns_dname_is_subdomain(sign_name, rr_name))
continue;
rrsigs_found++;
launch_chain_link_lookup(chain, sign_name);
}
if (rrsigs_found)
continue;
find_delegation_point(chain, rr_name);
} }
} }
chain->lock--;
callback_on_complete_chain(chain); callback_on_complete_chain(chain);
} }
@ -789,6 +934,41 @@ done_free_verifying_keys:
return s; return s;
} }
typedef struct getdns_rrset getdns_rrset;
struct getdns_rrset {
getdns_bindata *name;
uint16_t rr_type;
uint16_t rr_class;
uint32_t ttl;
getdns_list *rrs;
getdns_list *sigs;
};
typedef struct getdns_delpath_elem getdns_delpath_elem;
struct getdns_delpath_elem {
getdns_delpath_elem *e; /* self or canonical element
* (with overlapping paths)
*/
unsigned int is_zonecut : 1;
unsigned int ds_nxdomain: 1;
getdns_rrset ds;
getdns_rrset dnskey;
getdns_dict *ds_nsec;
getdns_list *ds_nsec_sigs;
getdns_dict *ds_nsec_wc; /* wildcard */
getdns_list *ds_nsec_wc_sigs;
getdns_dict *ds_nsec_ce; /* closest encloser */
getdns_list *ds_nsec_ce_sigs;
};
typedef struct getdns_delpath getdns_delpath;
struct getdns_delpath {
getdns_delpath *next; /* In a ring */
getdns_rrset rrset;
size_t nlabels;
getdns_delpath_elem elems[];
};
/* /*
* getdns_validate_dnssec * getdns_validate_dnssec
* *

View File

@ -424,7 +424,7 @@ error:
} }
int int
priv_getdns_dname_equal(uint8_t *s1, uint8_t *s2) priv_getdns_dname_equal(const uint8_t *s1, const uint8_t *s2)
{ {
uint8_t i; uint8_t i;
for (;;) { for (;;) {

View File

@ -132,7 +132,7 @@ getdns_dict *priv_getdns_create_reply_dict(getdns_context *context,
getdns_return_t priv_getdns_validate_dname(const char* dname); getdns_return_t priv_getdns_validate_dname(const char* dname);
int priv_getdns_dname_equal(uint8_t *s1, uint8_t *s2); int priv_getdns_dname_equal(const uint8_t *s1, const uint8_t *s2);