Merge pull request #351 from getdnsapi/devel/dnssec_maintenance

Devel/dnssec maintenance
This commit is contained in:
wtoorop 2017-11-03 11:11:23 +01:00 committed by GitHub
commit e078f3c51a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 16 deletions

View File

@ -1,4 +1,10 @@
* 2017-1?-??: Version 1.2.1 * 2017-1?-??: Version 1.2.1
* Bugfix: Tolerate unsigned and unused RRsets in the authority section.
Fixes DNSSEC with BIND upstream.
* Bugfix: DNSSEC validation without support records
* Bugfix: Validation of full recursive DNSKEY lookups
* Bugfix: Retry to validate full recursion BOGUS replies with zero
configuration DNSSEC only when DNSSEC was actually requested
* Bugfix #348: Fix a linking issue in stubby when libbsd is present * Bugfix #348: Fix a linking issue in stubby when libbsd is present
Thanks Remi Gacogne Thanks Remi Gacogne
* More robust scheduling; Eliminating a segfault with long running * More robust scheduling; Eliminating a segfault with long running

View File

@ -802,11 +802,14 @@ static void add_pkt2val_chain(struct mem_funcs *mf,
if (is_synthesized_cname(rrset)) if (is_synthesized_cname(rrset))
continue; continue;
if (!(rrsig = _getdns_rrsig_iter_init(&rrsig_spc, rrset))
&& _getdns_rr_iter_section(&i->rr_i) != SECTION_ANSWER)
continue; /* No sigs in authority section is okayish */
if (!(head = add_rrset2val_chain(mf, chain_p, rrset, netreq))) if (!(head = add_rrset2val_chain(mf, chain_p, rrset, netreq)))
continue; continue;
for ( rrsig = _getdns_rrsig_iter_init(&rrsig_spc, rrset), n_rrsigs = 0 for ( n_rrsigs = 0; rrsig
; rrsig
; rrsig = _getdns_rrsig_iter_next(rrsig), n_rrsigs++) { ; rrsig = _getdns_rrsig_iter_next(rrsig), n_rrsigs++) {
/* Signature, so lookup DS/DNSKEY at signer's name */ /* Signature, so lookup DS/DNSKEY at signer's name */
@ -934,6 +937,17 @@ static void val_chain_sched_soa(chain_head *head, const uint8_t *dname)
val_chain_sched_soa_node(node); val_chain_sched_soa_node(node);
} }
static chain_head *_dnskey_query(const chain_node *node)
{
chain_head *head;
for (head = node->chains; head; head = head->next)
if (head->rrset.rr_type == GETDNS_RRTYPE_DNSKEY &&
head->parent == node)
return head;
return NULL;
}
static void val_chain_node_cb(getdns_dns_req *dnsreq); static void val_chain_node_cb(getdns_dns_req *dnsreq);
static void val_chain_sched_node(chain_node *node) static void val_chain_sched_node(chain_node *node)
{ {
@ -951,13 +965,27 @@ static void val_chain_sched_node(chain_node *node)
DEBUG_SEC("schedule DS & DNSKEY lookup for %s\n", name); DEBUG_SEC("schedule DS & DNSKEY lookup for %s\n", name);
node->lock++; node->lock++;
if (! node->dnskey_req /* not scheduled */ && if (! node->dnskey_req) {
_getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DNSKEY, chain_head *head;
CD_extension(node->chains->netreq->owner),
node, &node->dnskey_req, NULL, val_chain_node_cb))
node->dnskey_req = NULL; /* Reuse the DNSKEY query if this node is scheduled in the
* context of validating a DNSKEY query, because libunbound
* does not callback from a callback for the same query.
*/
if ((head = _dnskey_query(node))) {
DEBUG_SEC("Found DNSKEY head: %p\n", (void *)head);
node->dnskey_req = head->netreq;
node->dnskey.pkt = head->netreq->response;
node->dnskey.pkt_len = head->netreq->response_len;
} else if (_getdns_general_loop(
context, loop, name, GETDNS_RRTYPE_DNSKEY,
CD_extension(node->chains->netreq->owner),
node, &node->dnskey_req, NULL, val_chain_node_cb))
node->dnskey_req = NULL;
}
if (! node->ds_req && node->parent /* not root */ && if (! node->ds_req && node->parent /* not root */ &&
_getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DS, _getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DS,
CD_extension(node->chains->netreq->owner), CD_extension(node->chains->netreq->owner),
@ -2523,6 +2551,11 @@ static int chain_node_get_trusted_keys(
node->dnskey_signer = keytag; node->dnskey_signer = keytag;
return GETDNS_DNSSEC_SECURE; return GETDNS_DNSSEC_SECURE;
} }
/* ta is the DNSKEY for this name? */
if (_dname_equal(ta->name, node->dnskey.name)) {
*keys = ta;
return GETDNS_DNSSEC_SECURE;
}
/* ta is parent's ZSK */ /* ta is parent's ZSK */
if ((keytag = key_proves_nonexistance( if ((keytag = key_proves_nonexistance(
mf, now, skew, ta, &node->ds, NULL))) { mf, now, skew, ta, &node->ds, NULL))) {
@ -2938,6 +2971,26 @@ static void append_rrset2val_chain_list(
_getdns_list_append_this_dict(val_chain_list, rr_dict)) _getdns_list_append_this_dict(val_chain_list, rr_dict))
getdns_dict_destroy(rr_dict); getdns_dict_destroy(rr_dict);
/* Append the other RRSIGs, which were not used for validation too,
* because other validators might not have the same algorithm support.
*/
for ( rrsig = _getdns_rrsig_iter_init(&rrsig_spc, rrset)
; rrsig
; rrsig = _getdns_rrsig_iter_next(rrsig)) {
if (rrsig->rr_i.nxt < rrsig->rr_i.rr_type + 28)
continue;
if (gldns_read_uint16(rrsig->rr_i.rr_type + 26)
== (signer & 0xFFFF))
continue;
orig_ttl = gldns_read_uint32(rrsig->rr_i.rr_type + 14);
if ((rr_dict = _getdns_rr_iter2rr_dict_canonical(
&val_chain_list->mf, &rrsig->rr_i, &orig_ttl)) &&
_getdns_list_append_this_dict(val_chain_list, rr_dict))
getdns_dict_destroy(rr_dict);
}
if (val_rrset != val_rrset_spc) if (val_rrset != val_rrset_spc)
GETDNS_FREE(val_chain_list->mf, val_rrset); GETDNS_FREE(val_chain_list->mf, val_rrset);
} }
@ -3341,7 +3394,7 @@ void _getdns_validation_chain_timeout(getdns_dns_req *dnsreq)
void _getdns_cancel_validation_chain(getdns_dns_req *dnsreq) void _getdns_cancel_validation_chain(getdns_dns_req *dnsreq)
{ {
chain_head *head = dnsreq->chain, *next; chain_head *head = dnsreq->chain, *next, *dnskey_head;
chain_node *node; chain_node *node;
size_t node_count; size_t node_count;
@ -3353,7 +3406,10 @@ void _getdns_cancel_validation_chain(getdns_dns_req *dnsreq)
; node_count ; node_count
; node_count--, node = node->parent ) { ; node_count--, node = node->parent ) {
if (node->dnskey_req) if (node->dnskey_req &&
!( (dnskey_head = _dnskey_query(node))
&& dnskey_head->netreq == node->dnskey_req))
_getdns_context_cancel_request( _getdns_context_cancel_request(
node->dnskey_req->owner); node->dnskey_req->owner);
@ -3537,13 +3593,17 @@ getdns_validate_dnssec2(getdns_list *records_to_validate,
fflush(stdout); fflush(stdout);
#endif #endif
if (!records_to_validate || !support_records || !trust_anchors) if (!records_to_validate || !trust_anchors)
return GETDNS_RETURN_INVALID_PARAMETER; return GETDNS_RETURN_INVALID_PARAMETER;
mf = &records_to_validate->mf; mf = &records_to_validate->mf;
/* First convert everything to wire format /* First convert everything to wire format
*/ */
if (!(support = _getdns_list2wire(support_records,
if (!support_records)
(void) memset((support = support_buf), 0, GLDNS_HEADER_SIZE);
else if (!(support = _getdns_list2wire(support_records,
support_buf, &support_len, mf))) support_buf, &support_len, mf)))
return GETDNS_RETURN_MEMORY_ERROR; return GETDNS_RETURN_MEMORY_ERROR;

View File

@ -221,7 +221,10 @@ _getdns_check_dns_req_complete(getdns_dns_req *dns_req)
dns_req->dnssec_return_all_statuses dns_req->dnssec_return_all_statuses
)) ))
#endif #endif
|| ( dns_req->context->resolution_type == GETDNS_RESOLUTION_RECURSING || ( dns_req->context->resolution_type == GETDNS_RESOLUTION_RECURSING
&& (dns_req->dnssec_return_status ||
dns_req->dnssec_return_only_secure ||
dns_req->dnssec_return_all_statuses)
&& _getdns_bogus(dns_req)) && _getdns_bogus(dns_req))
)) { )) {
/* Reschedule timeout for this DNS request /* Reschedule timeout for this DNS request
@ -446,14 +449,12 @@ _getdns_submit_netreq(getdns_network_req *netreq, uint64_t *now_ms)
if (_getdns_ub_loop_enabled(&context->ub_loop)) if (_getdns_ub_loop_enabled(&context->ub_loop))
ub_resolve_r = ub_resolve_event(context->unbound_ctx, ub_resolve_r = ub_resolve_event(context->unbound_ctx,
name, netreq->request_type, dns_req->request_class, name, netreq->request_type, dns_req->request_class,
netreq, ub_resolve_event_callback, &(netreq->unbound_id)) ? netreq, ub_resolve_event_callback, &(netreq->unbound_id));
GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
else else
#endif #endif
ub_resolve_r = ub_resolve_async(context->unbound_ctx, ub_resolve_r = ub_resolve_async(context->unbound_ctx,
name, netreq->request_type, dns_req->request_class, name, netreq->request_type, dns_req->request_class,
netreq, ub_resolve_callback, &(netreq->unbound_id)) ? netreq, ub_resolve_callback, &(netreq->unbound_id));
GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
if (dnsreq_freed) if (dnsreq_freed)
return DNS_REQ_FINISHED; return DNS_REQ_FINISHED;
dns_req->freed = NULL; dns_req->freed = NULL;