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
* 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
Thanks Remi Gacogne
* 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))
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)))
continue;
for ( rrsig = _getdns_rrsig_iter_init(&rrsig_spc, rrset), n_rrsigs = 0
; rrsig
for ( n_rrsigs = 0; rrsig
; rrsig = _getdns_rrsig_iter_next(rrsig), n_rrsigs++) {
/* 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);
}
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_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);
node->lock++;
if (! node->dnskey_req /* not scheduled */ &&
_getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DNSKEY,
CD_extension(node->chains->netreq->owner),
node, &node->dnskey_req, NULL, val_chain_node_cb))
if (! node->dnskey_req) {
chain_head *head;
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 */ &&
_getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DS,
CD_extension(node->chains->netreq->owner),
@ -2523,6 +2551,11 @@ static int chain_node_get_trusted_keys(
node->dnskey_signer = keytag;
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 */
if ((keytag = key_proves_nonexistance(
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_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)
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)
{
chain_head *head = dnsreq->chain, *next;
chain_head *head = dnsreq->chain, *next, *dnskey_head;
chain_node *node;
size_t node_count;
@ -3353,7 +3406,10 @@ void _getdns_cancel_validation_chain(getdns_dns_req *dnsreq)
; node_count
; 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(
node->dnskey_req->owner);
@ -3537,13 +3593,17 @@ getdns_validate_dnssec2(getdns_list *records_to_validate,
fflush(stdout);
#endif
if (!records_to_validate || !support_records || !trust_anchors)
if (!records_to_validate || !trust_anchors)
return GETDNS_RETURN_INVALID_PARAMETER;
mf = &records_to_validate->mf;
/* 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)))
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
))
#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))
)) {
/* 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))
ub_resolve_r = ub_resolve_event(context->unbound_ctx,
name, netreq->request_type, dns_req->request_class,
netreq, ub_resolve_event_callback, &(netreq->unbound_id)) ?
GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
netreq, ub_resolve_event_callback, &(netreq->unbound_id));
else
#endif
ub_resolve_r = ub_resolve_async(context->unbound_ctx,
name, netreq->request_type, dns_req->request_class,
netreq, ub_resolve_callback, &(netreq->unbound_id)) ?
GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
netreq, ub_resolve_callback, &(netreq->unbound_id));
if (dnsreq_freed)
return DNS_REQ_FINISHED;
dns_req->freed = NULL;