diff --git a/src/context.c b/src/context.c index 87f309de..a62020cd 100644 --- a/src/context.c +++ b/src/context.c @@ -1467,6 +1467,9 @@ getdns_context_create_with_extended_memory_functions( result->return_call_reporting = 0; result->specify_class = GETDNS_RRCLASS_IN; + result->sys_ctxt = NULL; + result->ta_notify = NULL; + /* state data used to detect changes to the system config files */ result->fchg_resolvconf = NULL; @@ -1596,6 +1599,10 @@ getdns_context_destroy(struct getdns_context *context) return; context->destroying = 1; + + if (context->sys_ctxt) + getdns_context_destroy(context->sys_ctxt); + /* cancel all outstanding requests */ cancel_outstanding_requests(context); diff --git a/src/context.h b/src/context.h index ae2315f1..fc95a21d 100644 --- a/src/context.h +++ b/src/context.h @@ -95,7 +95,8 @@ typedef enum getdns_conn_state { typedef enum getdns_tasrc { GETDNS_TASRC_NONE, GETDNS_TASRC_ZONE, - GETDNS_TASRC_XML + GETDNS_TASRC_XML, + GETDNS_TASRC_FAILED } getdns_tasrc; typedef enum getdns_tsig_algo { @@ -371,6 +372,18 @@ struct getdns_context { unsigned return_call_reporting : 1; uint16_t specify_class; + /* + * Context for doing system queries. + * For example to resolve data.iana.org or to resolver the addresses + * of upstreams without specified addresses. + */ + getdns_context *sys_ctxt; + + /* List of dnsreqs that want to be notified when we have fetched a + * trust anchor from data.iana.org. + */ + getdns_dns_req *ta_notify; + /* * state data used to detect changes to the system config files */ diff --git a/src/dnssec.c b/src/dnssec.c index fbbc966d..4b60fbc5 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -2980,6 +2980,14 @@ static void append_empty_ds2val_chain_list( getdns_dict_destroy(rr_dict); } +static void data_iana_org_a(getdns_dns_req *dnsreq) +{ + getdns_dns_req *orig_dnsreq = (getdns_dns_req *)dnsreq->user_pointer; + DEBUG_SEC("Address for data.iana.org. found\n"); + _getdns_context_cancel_request(dnsreq); + check_chain_complete(orig_dnsreq->chain); +} + static void check_chain_complete(chain_head *chain) { getdns_dns_req *dnsreq; @@ -2999,6 +3007,70 @@ static void check_chain_complete(chain_head *chain) dnsreq = chain->netreq->owner; context = dnsreq->context; + if (dnsreq->waiting_for_ta) { + getdns_dns_req **d; + + for (d = &context->ta_notify; *d; d = &(*d)->ta_notify) { + if (*d == dnsreq) { + *d = dnsreq->ta_notify; + dnsreq->ta_notify = NULL; + dnsreq->waiting_for_ta = 0; + break; + } + } + + } else if (context->trust_anchors_source == GETDNS_TASRC_NONE) { + DEBUG_SEC("Need to fetch a trust anchor\n"); + + dnsreq->waiting_for_ta = 1; + dnsreq->ta_notify = context->ta_notify; + context->ta_notify = dnsreq; + + if (dnsreq->ta_notify) + return; /* Wait for the notify callback */ + + else if (!context->sys_ctxt) { + if (getdns_context_create_with_extended_memory_functions( + &context->sys_ctxt, 1, + context->mf.mf_arg, + context->mf.mf.ext.malloc, + context->mf.mf.ext.realloc, + context->mf.mf.ext.free)) { + DEBUG_SEC("TA fetch: Error creating system context\n"); + + } else if (getdns_context_set_eventloop( + context->sys_ctxt, context->extension) || + getdns_context_set_resolution_type( + context->sys_ctxt, GETDNS_RESOLUTION_STUB) + ) { + DEBUG_SEC("TA fetch: Error configuring system context\n"); + + getdns_context_destroy(context->sys_ctxt); + context->sys_ctxt = NULL; + } + } + if (context->sys_ctxt) { + DEBUG_SEC("Start of fetching of root-anchors.xml\n"); + if (!_getdns_general_loop(context->sys_ctxt, + dnsreq->loop, "data.iana.org.", GETDNS_RRTYPE_A, + NULL, dnsreq, NULL, NULL, data_iana_org_a) +#if 0 + || !_getdns_general_loop(context->sys_ctxt, + dnsreq->loop, "data.iana.org.", GETDNS_RRTYPE_AAAA, + NULL, context, NULL, data_iana_org_aaaa) +#endif + ) + return; + + DEBUG_SEC("Scheduling of lookup for \"data.iana.org.\" failed\n"); + + getdns_context_destroy(context->sys_ctxt); + context->sys_ctxt = NULL; + } + dnsreq->waiting_for_ta = 0; + context->ta_notify = dnsreq->ta_notify; + dnsreq->ta_notify = NULL; + } #ifdef STUB_NATIVE_DNSSEC /* Perform validation only on GETDNS_RESOLUTION_STUB (unbound_id == -1) * Or when asked for the validation chain (to identify the RRSIGs that diff --git a/src/request-internal.c b/src/request-internal.c index 15f97179..32f6611a 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -940,8 +940,10 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, result->upstreams->referenced++; result->finished_next = NULL; + result->ta_notify = NULL; result->freed = NULL; result->validating = 0; + result->waiting_for_ta = 0; result->is_dns_request = 1; result->request_timed_out = 0; result->chain = NULL; diff --git a/src/types-internal.h b/src/types-internal.h index 7834fc32..9b50fc91 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -324,6 +324,7 @@ typedef struct getdns_dns_req { * freed is touched by _getdns_submit_netreq only */ unsigned validating : 1; + unsigned waiting_for_ta : 1; int *freed; /* Validation chain to be canceled when this request is canceled */ @@ -365,6 +366,11 @@ typedef struct getdns_dns_req { */ struct getdns_dns_req *finished_next; + /* Linked list pointer for dns requests, which need to validate DNSSEC + * and are waiting for the root trust-anchors fetch. + */ + struct getdns_dns_req *ta_notify; + /* network requests for this dns request. * The array is terminated with NULL. *