diff --git a/README.md b/README.md index e866d47d..c6426c29 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ Note: If you only want to build stubby, then use the `--enable-stub-only` and `- ## Extensions and Event loop dependencies -The implementation works with a variety of event loops, each built as a separate shared library. See [the wiki](https://github.com/getdnsapi/getdns/wiki/Asynchronous-Support#wiki-included-event-loop-integrations) for more details. +The implementation works with a variety of event loops, each built as a separate shared library. See [this Doxygen page](https://getdnsapi.net/doxygen/group__eventloops.html) and [this man page](https://getdnsapi.net/documentation/manpages/#ASYNCHRONOUS USE) for more details. * [libevent](http://libevent.org). Note: the examples *require* this and should work with either libevent 1.x or 2.x. 2.x is preferred. * [libuv](https://github.com/joyent/libuv) @@ -170,8 +170,8 @@ Non-goals (things we will not be doing at least initially) include: ## Language Bindings In parallel, the team is actively developing bindings for various languages. -For more information, visit the -[wiki](https://github.com/getdnsapi/getdns/wiki/Language-Bindings). +For more information, visit this +[webpage](https://getdnsapi.net/bindings/). ## Unsupported getDNS Features @@ -187,10 +187,10 @@ The following minor implementation omissions are noted: Recursive mode does not support: * TLS as a transport * Non-zero connection idle timeouts or query pipelining +* Anything other than query_type and resolution_type in the return_call_reporting extension Stub mode does not support: * Non zero idle timeouts for synchronous calls -* Limit on number of outstanding queries # Known Issues @@ -264,7 +264,7 @@ build the packages; this is simply the one we chose to use. If you're using [Homebrew](http://brew.sh/), you may run `brew install getdns`. By default, this will only build the core library without any 3rd party event loop support. -To install the [event loop integration libraries](https://github.com/getdnsapi/getdns/wiki/Asynchronous-Support) that enable support for libevent, libuv, and libev, run: `brew install getdns --with-libevent --with-libuv --with-libev`. All switches are optional. +To install the [event loop integration libraries](https://getdnsapi.net/doxygen/group__eventloops.html) that enable support for libevent, libuv, and libev, run: `brew install getdns --with-libevent --with-libuv --with-libev`. All switches are optional. Note that in order to compile the examples, the `--with-libevent` switch is required. diff --git a/spec/index.html b/spec/index.html index a0432b4c..6888489f 100644 --- a/spec/index.html +++ b/spec/index.html @@ -875,7 +875,7 @@ names:

  • query_name (a bindata) is the name that was sent
  • query_type (an int) is the type that was queried for
  • query_to (a bindata) is the address to which the query was sent
  • -
  • run_time (a bindata) is the difference between the time the successful +
  • run_time/ms (a bindata) is the difference between the time the successful query started and ended in milliseconds, represented as a uint32_t (this does not include time taken for connection set up or transport fallback)
  • diff --git a/src/dnssec.c b/src/dnssec.c index fbbc966d..e9962852 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -550,11 +550,26 @@ static chain_head *add_rrset2val_chain(struct mem_funcs *mf, /* Also, try to prevent adding double rrsets */ if ( rrset->rr_class == head->rrset.rr_class && rrset->rr_type == head->rrset.rr_type - && rrset->pkt == head->rrset.pkt - && rrset->pkt_len == head->rrset.pkt_len - && _dname_equal(rrset->name, head->rrset.name)) - return NULL; + && _dname_equal(rrset->name, head->rrset.name)) { + if (rrset->pkt == head->rrset.pkt && + rrset->pkt_len == head->rrset.pkt_len) + return NULL; + else { + /* Anticipate resubmissions due to + * roadblock avoidance */ + head->rrset.pkt = rrset->pkt; + head->rrset.pkt_len = rrset->pkt_len; + return head; + } + } + + if ( rrset->rr_class == head->rrset.rr_class + && rrset->rr_type == head->rrset.rr_type + && rrset->pkt != head->rrset.pkt + && _dname_equal(rrset->name, head->rrset.name)) { + return NULL; + } for (label = labels; label < last_label; label++) { if (! _dname_is_parent(*label, head->rrset.name)) break; @@ -2416,6 +2431,7 @@ static int key_proves_nonexistance( * ========================+ * First find the closest encloser. */ + if (*rrset->name) for ( nc_name = rrset->name, ce_name = rrset->name + *rrset->name + 1 ; *ce_name ; nc_name = ce_name, ce_name += *ce_name + 1) { @@ -3029,19 +3045,50 @@ static void check_chain_complete(chain_head *chain) && !dnsreq->avoid_dnssec_roadblocks && dnsreq->netreqs[0]->dnssec_status == GETDNS_DNSSEC_BOGUS) { - int r = GETDNS_RETURN_GOOD; getdns_network_req **netreq_p, *netreq; uint64_t now_ms = 0; dnsreq->avoid_dnssec_roadblocks = 1; + dnsreq->chain->lock += 1; for ( netreq_p = dnsreq->netreqs - ; !r && (netreq = *netreq_p) + ; (netreq = *netreq_p) ; netreq_p++) { _getdns_netreq_change_state(netreq, NET_REQ_NOT_SENT); + netreq->dnssec_status = + GETDNS_DNSSEC_INDETERMINATE; netreq->owner = dnsreq; - r = _getdns_submit_netreq(netreq, &now_ms); + (void) _getdns_submit_netreq(netreq, &now_ms); + } + if (!dnsreq->dnssec_return_validation_chain) + return; + + for ( head = chain; head ; head = next ) { + next = head->next; + for ( node_count = head->node_count + , node = head->parent + ; node_count + ; node_count--, node = node->parent ) { + + if (node->dnskey_req) { + _getdns_netreq_change_state( + node->dnskey_req, + NET_REQ_NOT_SENT); + node->dnskey_req->owner-> + avoid_dnssec_roadblocks = 1; + (void) _getdns_submit_netreq( + node->dnskey_req, &now_ms); + } + if (node->ds_req) { + _getdns_netreq_change_state( + node->ds_req, NET_REQ_NOT_SENT); + node->ds_req->owner-> + avoid_dnssec_roadblocks = 1; + (void) _getdns_submit_netreq( + node->ds_req, &now_ms); + } + } } return; } @@ -3185,11 +3232,16 @@ void _getdns_get_validation_chain(getdns_dns_req *dnsreq) getdns_network_req *netreq, **netreq_p; chain_head *chain = NULL, *chain_p; - if (dnsreq->validating) + if (dnsreq->avoid_dnssec_roadblocks) { + chain = dnsreq->chain; + + } else if (dnsreq->validating) return; dnsreq->validating = 1; - for (netreq_p = dnsreq->netreqs; (netreq = *netreq_p) ; netreq_p++) { + if (dnsreq->avoid_dnssec_roadblocks && chain->lock == 0) + ; /* pass */ + else for (netreq_p = dnsreq->netreqs; (netreq = *netreq_p) ; netreq_p++) { if (! netreq->response || netreq->response_len < GLDNS_HEADER_SIZE || ( GLDNS_RCODE_WIRE(netreq->response) @@ -3217,6 +3269,9 @@ void _getdns_get_validation_chain(getdns_dns_req *dnsreq) if (chain_p->lock) chain_p->lock--; } dnsreq->chain = chain; + if (dnsreq->avoid_dnssec_roadblocks && chain->lock) + chain->lock -= 1; + check_chain_complete(chain); } else { dnsreq->validating = 0; diff --git a/src/general.c b/src/general.c index 280df08d..2420a47c 100644 --- a/src/general.c +++ b/src/general.c @@ -59,6 +59,9 @@ void _getdns_call_user_callback(getdns_dns_req *dnsreq, getdns_dict *response) { _getdns_context_clear_outbound_request(dnsreq); +#if defined(REQ_DEBUG) && REQ_DEBUG + debug_req(__FUNC__, *dnsreq->netreqs); +#endif if (dnsreq->user_callback) { dnsreq->context->processing = 1; dnsreq->user_callback(dnsreq->context, @@ -211,6 +214,7 @@ _getdns_check_dns_req_complete(getdns_dns_req *dns_req) #ifdef STUB_NATIVE_DNSSEC || (dns_req->context->resolution_type == GETDNS_RESOLUTION_STUB + && !dns_req->avoid_dnssec_roadblocks && (dns_req->dnssec_return_status || dns_req->dnssec_return_only_secure || dns_req->dnssec_return_all_statuses @@ -228,6 +232,9 @@ _getdns_check_dns_req_complete(getdns_dns_req *dns_req) NULL, NULL, (getdns_eventloop_callback) _getdns_validation_chain_timeout)); +#if defined(REQ_DEBUG) && REQ_DEBUG + debug_req("getting validation chain for ", *dns_req->netreqs); +#endif _getdns_get_validation_chain(dns_req); } else _getdns_call_user_callback( diff --git a/src/getdns/getdns.h.in b/src/getdns/getdns.h.in index b483c7ea..feba62a1 100644 --- a/src/getdns/getdns.h.in +++ b/src/getdns/getdns.h.in @@ -1101,7 +1101,6 @@ getdns_service(getdns_context *context, * (e.g. CRYPTO_THREADID_set_call) depending on the library version used. * @param context context that can be used immediately with other API calls * @param set_from_os set to 1 to initialize the context with os defaults - * the second bit set (2) prevents OpenSSL library initialization. * @return GETDNS_RETURN_GOOD on success */ getdns_return_t @@ -1114,7 +1113,6 @@ getdns_context_create(getdns_context ** context, int set_from_os); * (e.g. CRYPTO_THREADID_set_call) depending on the library version used. * @param context context that can be used immediately with other API calls * @param set_from_os set to 1 to initialize the context with os defaults - * the second bit set (2) prevents OpenSSL library initialization. * @param malloc custom malloc function * @param realloc custom realloc function * @param free custom free function @@ -1136,7 +1134,6 @@ getdns_context_create_with_memory_functions( * (e.g. CRYPTO_THREADID_set_call) depending on the library version used. * @param context context that can be used immediately with other API calls * @param set_from_os set to 1 to initialize the context with os defaults - * the second bit set (2) prevents OpenSSL library initialization. * @param userarg parameter passed to the custom malloc, realloc and free functions * @param malloc custom malloc function * @param realloc custom realloc function diff --git a/src/stub.c b/src/stub.c index c6f25c79..b8ac6710 100644 --- a/src/stub.c +++ b/src/stub.c @@ -588,6 +588,7 @@ _getdns_cancel_stub_request(getdns_network_req *netreq) #else close(netreq->fd); #endif + netreq->fd = -1; } } @@ -606,6 +607,7 @@ stub_timeout_cb(void *userarg) #else close(netreq->fd); #endif + netreq->fd = -1; netreq->upstream->udp_timeouts++; if (netreq->upstream->udp_timeouts % 100 == 0) _getdns_upstream_log(netreq->upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG, @@ -1413,6 +1415,7 @@ stub_udp_read_cb(void *userarg) #else close(netreq->fd); #endif + netreq->fd = -1; stub_next_upstream(netreq); } netreq->debug_end_time = _getdns_get_time_as_uintt64(); @@ -1435,8 +1438,8 @@ stub_udp_read_cb(void *userarg) closesocket(netreq->fd); #else close(netreq->fd); - netreq->fd = -1; #endif + netreq->fd = -1; while (GLDNS_TC_WIRE(netreq->response)) { DEBUG_STUB("%s %-35s: MSG: %p TC bit set in response \n", STUB_DEBUG_READ, __FUNC__, (void*)netreq); @@ -1533,6 +1536,7 @@ stub_udp_write_cb(void *userarg) #else close(netreq->fd); #endif + netreq->fd = -1; stub_next_upstream(netreq); } netreq->debug_end_time = _getdns_get_time_as_uintt64(); @@ -1958,7 +1962,7 @@ upstream_select(getdns_network_req *netreq) return &upstreams->upstreams[i]; } i+=GETDNS_UPSTREAM_TRANSPORTS; - if (i > upstreams->count) + if (i >= upstreams->count) i = 0; } while (i != upstreams->current_udp); diff --git a/src/tools/Dockerfile b/src/tools/Dockerfile index 9ae731a3..20bde4c5 100644 --- a/src/tools/Dockerfile +++ b/src/tools/Dockerfile @@ -24,7 +24,7 @@ RUN set -ex \ && cd /usr/src \ && git clone https://github.com/getdnsapi/getdns.git \ && cd /usr/src/getdns \ - && git checkout release/1.1.1 \ + && git checkout master \ && git submodule update --init \ && libtoolize -ci \ && autoreconf -fi \ @@ -35,7 +35,7 @@ RUN set -ex \ && cp src/tools/stubby.conf /etc \ && mkdir -p /etc/unbound \ && cd /etc/unbound \ - && wget http://www.nomountain.net/getdns-root.key + && unbound-anchor -a /etc/unbound/getdns-root.key || : EXPOSE 53 diff --git a/src/tools/getdns_query.c b/src/tools/getdns_query.c index 58fb70c6..f237585c 100644 --- a/src/tools/getdns_query.c +++ b/src/tools/getdns_query.c @@ -81,6 +81,8 @@ static uint16_t request_type = GETDNS_RRTYPE_NS; static int timeout, edns0_size, padding_blocksize; static int async = 0, interactive = 0; static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL; +static int bogus_answers = 0; +static int check_dnssec = 0; static int get_rrtype(const char *t) { @@ -317,6 +319,7 @@ static getdns_return_t validate_chain(getdns_dict *response) break; case GETDNS_DNSSEC_BOGUS: if (verbosity) fprintf(stdout, "GETDNS_DNSSEC_BOGUS\n"); + bogus_answers += 1; break; case GETDNS_DNSSEC_INDETERMINATE: if (verbosity) fprintf(stdout, "GETDNS_DNSSEC_INDETERMINATE\n"); @@ -346,6 +349,7 @@ static getdns_return_t validate_chain(getdns_dict *response) break; case GETDNS_DNSSEC_BOGUS: if (verbosity) fprintf(stdout, "GETDNS_DNSSEC_BOGUS\n"); + bogus_answers += 1; break; case GETDNS_DNSSEC_INDETERMINATE: if (verbosity) fprintf(stdout, "GETDNS_DNSSEC_INDETERMINATE\n"); @@ -389,6 +393,14 @@ void callback(getdns_context *context, getdns_callback_type_t callback_type, if (callback_type == GETDNS_CALLBACK_COMPLETE) { if (verbosity) printf("Response code was: GOOD. Status was: Callback with ID %"PRIu64" was successful.\n", trans_id); + if (check_dnssec) { + uint32_t dnssec_status = GETDNS_DNSSEC_SECURE; + + (void )getdns_dict_get_int(response, + "/replies_tree/0/dnssec_status", &dnssec_status); + if (dnssec_status == GETDNS_DNSSEC_BOGUS) + bogus_answers += 1; + } } else if (callback_type == GETDNS_CALLBACK_CANCEL) fprintf(stderr, @@ -403,7 +415,6 @@ void callback(getdns_context *context, getdns_callback_type_t callback_type, getdns_get_errorstr_by_id(callback_type)); } getdns_dict_destroy(response); - response = NULL; } #define CONTINUE ((getdns_return_t)-2) @@ -578,6 +589,9 @@ getdns_return_t parse_args(int argc, char **argv) continue; } else if (arg[0] == '+') { + if (strncmp(arg+1, "dnssec_", 7) == 0) + check_dnssec = 1; + if (arg[1] == 's' && arg[2] == 'i' && arg[3] == 't' && (arg[4] == '=' || arg[4] == '\0')) { if ((r = set_cookie(extensions, arg+4))) { @@ -1196,6 +1210,7 @@ getdns_return_t do_the_call(void) fprintf( stdout, "%s\n", response_str); if (verbosity) fprintf( stdout, "SYNC call completed.\n"); + validate_chain(response); free(response_str); } else { @@ -1208,8 +1223,18 @@ getdns_return_t do_the_call(void) if (verbosity) fprintf(stdout, "Response code was: GOOD. Status was: %s\n", getdns_get_errorstr_by_id(status)); - if (response) + if (response) { + if (check_dnssec) { + uint32_t dnssec_status = GETDNS_DNSSEC_SECURE; + + (void )getdns_dict_get_int(response, + "/replies_tree/0/dnssec_status", + &dnssec_status); + if (dnssec_status == GETDNS_DNSSEC_BOGUS) + bogus_answers += 1; + } getdns_dict_destroy(response); + } } getdns_dict_destroy(address); return r; @@ -1790,5 +1815,7 @@ done_destroy_context: if (!i_am_stubby && verbosity) fprintf(stdout, "\nAll done.\n"); - return r; + return r ? r + : bogus_answers ? GETDNS_DNSSEC_BOGUS + : GETDNS_RETURN_GOOD; }