diff --git a/src/context.c b/src/context.c index ca3603cf..2af25a3f 100644 --- a/src/context.c +++ b/src/context.c @@ -691,8 +691,10 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams) while (upstream->finished_dnsreqs) { dnsreq = upstream->finished_dnsreqs; upstream->finished_dnsreqs = dnsreq->finished_next; - debug_req("Destroy ", *dnsreq->netreqs); - _getdns_context_cancel_request(dnsreq); + if (!dnsreq->internal_cb) { /* Not part of chain */ + debug_req("Destroy ", *dnsreq->netreqs); + _getdns_context_cancel_request(dnsreq); + } } if (upstream->tls_session != NULL) SSL_SESSION_free(upstream->tls_session); @@ -3088,7 +3090,10 @@ getdns_cancel_callback(getdns_context *context, NULL, dnsreq->user_pointer, dnsreq->trans_id); dnsreq->context->processing = 0; } - _getdns_context_cancel_request(dnsreq); + if (!dnsreq->internal_cb) { /* Not part of chain */ + debug_req("Destroy ", *dnsreq->netreqs); + _getdns_context_cancel_request(dnsreq); + } return GETDNS_RETURN_GOOD; } /* getdns_cancel_callback */ diff --git a/src/dnssec.c b/src/dnssec.c index b3e86bae..8c01a635 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -3113,6 +3113,43 @@ static void check_chain_complete(chain_head *chain) _getdns_call_user_callback(dnsreq, response_dict); } +void _getdns_validation_chain_timeout(getdns_dns_req *dnsreq) +{ + chain_head *head = dnsreq->chain, *next; + chain_node *node; + size_t node_count; + + while (head) { + next = head->next; + + for ( node_count = head->node_count, node = head->parent + ; node_count + ; node_count--, node = node->parent ) { + + if (!_getdns_netreq_finished(node->dnskey_req)) { + _getdns_context_cancel_request( + node->dnskey_req->owner); + node->dnskey_req = NULL; + } + + if (!_getdns_netreq_finished(node->ds_req)) { + _getdns_context_cancel_request( + node->ds_req->owner); + node->ds_req = NULL; + } + + if (!_getdns_netreq_finished(node->soa_req)) { + _getdns_context_cancel_request( + node->soa_req->owner); + node->soa_req = NULL; + } + } + head = next; + } + dnsreq->request_timed_out = 1; + check_chain_complete(dnsreq->chain); +} + void _getdns_cancel_validation_chain(getdns_dns_req *dnsreq) { chain_head *head = dnsreq->chain, *next; diff --git a/src/dnssec.h b/src/dnssec.h index b7becfe9..b0334d52 100644 --- a/src/dnssec.h +++ b/src/dnssec.h @@ -47,6 +47,7 @@ /* Do some additional requests to fetch the complete validation chain */ void _getdns_get_validation_chain(getdns_dns_req *dns_req); void _getdns_cancel_validation_chain(getdns_dns_req *dns_req); +void _getdns_validation_chain_timeout(getdns_dns_req *dns_req); uint16_t _getdns_parse_ta_file(time_t *ta_mtime, gldns_buffer *gbuf); diff --git a/src/general.c b/src/general.c index 4ac4e3f2..16a07128 100644 --- a/src/general.c +++ b/src/general.c @@ -61,8 +61,9 @@ void _getdns_call_user_callback(getdns_dns_req *dnsreq, getdns_dict *response) if (dnsreq->user_callback) { dnsreq->context->processing = 1; dnsreq->user_callback(dnsreq->context, - (response ? GETDNS_CALLBACK_COMPLETE - : GETDNS_CALLBACK_ERROR), + ( ! response ? GETDNS_CALLBACK_ERROR + : dnsreq->request_timed_out ? GETDNS_CALLBACK_TIMEOUT + : GETDNS_CALLBACK_COMPLETE ), response, dnsreq->user_pointer, dnsreq->trans_id); dnsreq->context->processing = 0; } @@ -214,9 +215,22 @@ _getdns_check_dns_req_complete(getdns_dns_req *dns_req) dns_req->dnssec_return_all_statuses )) #endif - )) + )) { + /* Reschedule timeout for this DNS request + */ + dns_req->timeout.userarg = dns_req; + dns_req->timeout.read_cb = NULL; + dns_req->timeout.write_cb = NULL; + dns_req->timeout.timeout_cb = + (getdns_eventloop_callback) + _getdns_validation_chain_timeout; + dns_req->timeout.ev = NULL; + (void) dns_req->loop->vmt->schedule(dns_req->loop, -1, + _getdns_ms_until_expiry2(dns_req->expires, &now_ms), + &dns_req->timeout); + _getdns_get_validation_chain(dns_req); - else + } else _getdns_call_user_callback( dns_req, _getdns_create_getdns_response(dns_req)); } diff --git a/src/request-internal.c b/src/request-internal.c index 1bd5475e..d91563f4 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -944,6 +944,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, result->freed = NULL; result->validating = 0; result->is_dns_request = 1; + result->request_timed_out = 0; result->chain = NULL; network_req_init(result->netreqs[0], result, diff --git a/src/stub.c b/src/stub.c index 30c08091..90b44c96 100644 --- a/src/stub.c +++ b/src/stub.c @@ -32,6 +32,12 @@ */ #include "config.h" + +/* Intercept and do not sent out COM DS queries with TLS + * For debugging purposes only. Never commit with this turned on. + */ +#define INTERCEPT_COM_DS 0 + #ifdef USE_POLL_DEFAULT_EVENTLOOP # ifdef HAVE_SYS_POLL_H # include @@ -1306,6 +1312,22 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, /* TODO[TLS]: Handle error cases, partial writes, renegotiation etc. */ ERR_clear_error(); +#if INTERCEPT_COM_DS + /* Intercept and do not sent out COM DS queries. For debugging + * purposes only. Never commit with this turned on. + */ + if (netreq->request_type == GETDNS_RRTYPE_DS && + netreq->owner->name_len == 5 && + netreq->owner->name[0] == 3 && + (netreq->owner->name[1] & 0xDF) == 'C' && + (netreq->owner->name[2] & 0xDF) == 'O' && + (netreq->owner->name[3] & 0xDF) == 'M' && + netreq->owner->name[4] == 0) { + + debug_req("Intercepting", netreq); + written = pkt_len + 2; + } else +#endif written = SSL_write(tls_obj, netreq->query - 2, pkt_len + 2); if (written <= 0) return STUB_TCP_ERROR; diff --git a/src/test/tpkg/070-coding-practice.tpkg/070-coding-practice.test b/src/test/tpkg/070-coding-practice.tpkg/070-coding-practice.test index b628a657..09473687 100644 --- a/src/test/tpkg/070-coding-practice.tpkg/070-coding-practice.test +++ b/src/test/tpkg/070-coding-practice.tpkg/070-coding-practice.test @@ -33,6 +33,19 @@ rm -f report.txt echo "" fi ) >> report.txt +( + cd ${SRCROOT}/src + if [ `grep '^#define[ ]*INTERCEPT_COM_DS[ ]*1' stub.c | wc -l` -gt 0 ] + then + echo "*** " + echo "*** The repo contained the COM DS queries interception" + echo "*** with TLS transports turned on, this should be off" + echo "*** " + grep -n '^#define[ ]INTERCEPT_COM_DS[ ]*1' stub.c + echo "" + fi +) >> report.txt + if [ -s report.txt ] then diff --git a/src/types-internal.h b/src/types-internal.h index 5e1961ac..e70d8911 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -314,6 +314,7 @@ typedef struct getdns_dns_req { unsigned dnssec_ok_checking_disabled : 1; unsigned is_sync_request : 1; unsigned is_dns_request : 1; + unsigned request_timed_out : 1; /* The validating and freed variables are used to make sure a single * code path is followed while processing a DNS request, even when diff --git a/src/util-internal.c b/src/util-internal.c index 33c31745..ddac7b51 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -1263,6 +1263,7 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) GETDNS_FREE(context->mf, srvs.rrs); } if (getdns_dict_set_int(result, GETDNS_STR_KEY_STATUS, + completed_request->request_timed_out || nreplies == 0 ? GETDNS_RESPSTATUS_ALL_TIMEOUT : completed_request->dnssec_return_only_secure && nsecure == 0 && ninsecure > 0 ? GETDNS_RESPSTATUS_NO_SECURE_ANSWERS :