From 1ba2e5bf4de515c7f02c679cce692fe5364b117a Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Sun, 20 Nov 2016 11:19:08 +0000 Subject: [PATCH 1/4] Add stubby to readme. Add transport to stubby log. --- README.md | 21 +++++++++++++++++++-- src/context.c | 11 +++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1b5a4807..c1a8bae4 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ Traditional access to DNS data from applications has several limitations: * Sophisticated uses of the DNS (things like IDNA and DNSSEC validation) require considerable application work, possibly by application developers with little experience with the vagaries of DNS. +getdns also provides a prototype DNS Privacy enabled client called 'stubby' - see below for more details. + ## Motivation for providing the API The developers are of the opinion that DNSSEC offers a unique global infrastructure for establishing and enhancing cryptographic trust relations. With the development of this API we intend to offer application developers a modern and flexible interface that enables end-to-end trust in the DNS architecture, and which will inspire application developers to implement innovative security solutions in their applications. @@ -73,9 +75,13 @@ If you want to make use of the configuration files that utilise a JSON-like form before building. -If you want to use the getdns_query command line wrapper script for testing or to enable getdns as a daemon then you must build it using +As well as building the getdns library 2 other tools are installed by default by the above process: + +* getdns_query: a command line test script wrapper for getdns +* stubby: a DNS Privacy enabled client + +Note: If you only want to build stubby, then use the `--enable-stub-only` and `--without-libidn` options when running 'configure'. - # make getdns_query ## Minimizing dependencies @@ -91,6 +97,17 @@ The implementation works with a variety of event loops, each built as a separate * [libuv](https://github.com/joyent/libuv) * [libev](http://software.schmorp.de/pkg/libev.html) +## Stubby + +* Stubby is a prototype implementation of a DNS Privacy enabled stub resolver. Feedback is welcome! +* A default configuration file is available here uses a 'Strict' privacy usage profile using some of the available test DNS Privacy servers to resolve queries. Note these servers are test servers that offer no service guarantees. An alternative file can be specified with the '-C' flag +* If you would like minimal logging output from Stubby (which servers are used and connection level statistics) then also use the '--enable-debug-daemon' flag when running 'configure'. + +To use stubby +* Start stubby from the command line +* Test it by doing, for example, 'dig @127.0.0.1 www.example.com' +* Alter the default DNS resolvers on your system to point at localhost (127.0.0.1, ::1) + ## Regression Tests A suite of regression tests are included with the library, if you make changes or just diff --git a/src/context.c b/src/context.c index 121c536a..1d9a046b 100644 --- a/src/context.c +++ b/src/context.c @@ -720,16 +720,15 @@ _getdns_upstream_shutdown(getdns_upstream *upstream) STUB_DEBUG_DAEMON, upstream->addr_str, (int)upstream->responses_received, (int)upstream->responses_timeouts, getdns_auth_str_array[upstream->tls_auth_state], (int)upstream->keepalive_timeout); - DEBUG_DAEMON("%s %s : Upstream stats - Resp=%d,Timeouts=%d,Best_auth=%s,Conns=%d\n", + DEBUG_DAEMON("%s %s : Upstream stats - Resp=%d,Timeouts=%d,Transport=%s,Best_auth=%s\n", STUB_DEBUG_DAEMON, upstream->addr_str, (int)upstream->total_responses, (int)upstream->total_timeouts, - getdns_auth_str_array[upstream->best_tls_auth_state], - (int)upstream->conn_completed); - DEBUG_DAEMON("%s %s : Upstream stats - Conn_fails=%d,Conn_shutdowns=%d,Backoffs=%d\n", + (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "UDP/TCP"), + getdns_auth_str_array[upstream->best_tls_auth_state]); + DEBUG_DAEMON("%s %s : Upstream stats - Conns=%d,Conn_fails=%d,Conn_shutdowns=%d,Backoffs=%d\n", STUB_DEBUG_DAEMON, upstream->addr_str, - (int)upstream->conn_setup_failed, + (int)upstream->conn_completed, (int)upstream->conn_setup_failed, (int)upstream->conn_shutdowns, (int)upstream->conn_backoffs); - #endif /* Back off connections that never got up service at all (probably no From 576e38977f746fc5aa8af2127d37ce12e7a419db Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Mon, 5 Dec 2016 18:05:04 +0000 Subject: [PATCH 2/4] More logging changes to stubby to correctly report profile, transport and stats for TCP and UDP when used as fallbacks. Reporting UDP stats every 100 responses or timeouts to give user some indication UDP is being used. --- src/context.c | 12 ++++++++---- src/context.h | 2 ++ src/stub.c | 24 ++++++++++++++++++++---- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/context.c b/src/context.c index 1d9a046b..8b8413f8 100644 --- a/src/context.c +++ b/src/context.c @@ -716,17 +716,19 @@ _getdns_upstream_shutdown(getdns_upstream *upstream) if (upstream->tls_auth_state > upstream->best_tls_auth_state) upstream->best_tls_auth_state = upstream->tls_auth_state; #if defined(DAEMON_DEBUG) && DAEMON_DEBUG - DEBUG_DAEMON("%s %s : Conn closed: Conn stats - Resp=%d,Timeouts=%d,Auth=%s,Keepalive(ms)=%d\n", + DEBUG_DAEMON("%s %s : Conn closed : Transport=%s - Resp=%d,Timeouts=%d,Auth=%s,Keepalive(ms)=%d\n", STUB_DEBUG_DAEMON, upstream->addr_str, + (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP"), (int)upstream->responses_received, (int)upstream->responses_timeouts, getdns_auth_str_array[upstream->tls_auth_state], (int)upstream->keepalive_timeout); - DEBUG_DAEMON("%s %s : Upstream stats - Resp=%d,Timeouts=%d,Transport=%s,Best_auth=%s\n", + DEBUG_DAEMON("%s %s : Upstream stats: Transport=%s - Resp=%d,Timeouts=%d,Best_auth=%s\n", STUB_DEBUG_DAEMON, upstream->addr_str, + (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP"), (int)upstream->total_responses, (int)upstream->total_timeouts, - (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "UDP/TCP"), getdns_auth_str_array[upstream->best_tls_auth_state]); - DEBUG_DAEMON("%s %s : Upstream stats - Conns=%d,Conn_fails=%d,Conn_shutdowns=%d,Backoffs=%d\n", + DEBUG_DAEMON("%s %s : Upstream stats: Transport=%s - Conns=%d,Conn_fails=%d,Conn_shutdowns=%d,Backoffs=%d\n", STUB_DEBUG_DAEMON, upstream->addr_str, + (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP"), (int)upstream->conn_completed, (int)upstream->conn_setup_failed, (int)upstream->conn_shutdowns, (int)upstream->conn_backoffs); #endif @@ -903,6 +905,8 @@ upstream_init(getdns_upstream *upstream, /* How is this upstream doing on UDP? */ upstream->to_retry = 2; upstream->back_off = 1; + upstream->udp_responses = 0; + upstream->udp_timeouts = 0; /* For sharing a socket to this upstream with TCP */ upstream->fd = -1; diff --git a/src/context.h b/src/context.h index 41e7a830..fdf8066e 100644 --- a/src/context.h +++ b/src/context.h @@ -131,6 +131,8 @@ typedef struct getdns_upstream { /* How is this upstream doing over UDP? */ int to_retry; int back_off; + size_t udp_responses; + size_t udp_timeouts; /* For stateful upstreams, need to share the connection and track the activity on the connection */ diff --git a/src/stub.c b/src/stub.c index 2527ed61..83ab992c 100644 --- a/src/stub.c +++ b/src/stub.c @@ -571,6 +571,13 @@ stub_timeout_cb(void *userarg) /* Handle upstream*/ if (netreq->fd >= 0) { close(netreq->fd); + netreq->upstream->udp_timeouts++; +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + if (netreq->upstream->udp_timeouts % 100 == 0) + DEBUG_DAEMON("%s %s : Upstream stats: Transport=UDP - Resp=%d,Timeouts=%d\n", + STUB_DEBUG_DAEMON, netreq->upstream->addr_str, + (int)netreq->upstream->udp_responses, (int)netreq->upstream->udp_timeouts); +#endif stub_next_upstream(netreq); } else { netreq->upstream->responses_timeouts++; @@ -1305,6 +1312,13 @@ stub_udp_read_cb(void *userarg) dnsreq->upstreams->current_udp = 0; netreq->debug_end_time = _getdns_get_time_as_uintt64(); netreq->state = NET_REQ_FINISHED; + upstream->udp_responses++; +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + if (upstream->udp_responses % 100 == 0) + DEBUG_DAEMON("%s %s : Upstream stats: Transport=UDP - Resp=%d,Timeouts=%d\n", + STUB_DEBUG_DAEMON, upstream->addr_str, + (int)upstream->udp_responses, (int)upstream->udp_timeouts); +#endif _getdns_check_dns_req_complete(dnsreq); } @@ -1767,15 +1781,16 @@ upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport, upstream->tls_hs_state = GETDNS_HS_WRITE; } upstream->conn_state = GETDNS_CONN_SETUP; +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + DEBUG_DAEMON("%s %s : Conn init : Transport= %s - Profile=%s\n", STUB_DEBUG_DAEMON, + upstream->addr_str, transport == GETDNS_TRANSPORT_TLS ? "TLS":"TCP", + dnsreq->context->tls_auth_min == GETDNS_AUTHENTICATION_NONE ? "Opportunistic":"Strict"); +#endif break; default: return -1; /* Nothing to do*/ } -#if defined(DAEMON_DEBUG) && DAEMON_DEBUG - DEBUG_DAEMON("%s %s : Conn init\n", - STUB_DEBUG_DAEMON, upstream->addr_str); -#endif return fd; } @@ -1841,6 +1856,7 @@ fallback_on_write(getdns_network_req *netreq) /* Deal with UDP one day*/ DEBUG_STUB("%s %-35s: MSG: %p FALLING BACK \n", STUB_DEBUG_SCHEDULE, __FUNCTION__, netreq); + DEBUG_DAEMON("%s Falling back...\n", STUB_DEBUG_DAEMON); /* Try to find a fallback transport*/ getdns_return_t result = _getdns_submit_stub_request(netreq); From 471e8725e2611031e2a53dd30c7fda65e793f359 Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Tue, 6 Dec 2016 14:44:40 +0000 Subject: [PATCH 3/4] Change the default profile for Stubby to use TLS then UDP/TCP - this will only try over TLS a few times before backing off to clear text - but makes the default for Stubby opportunistic privacy (Willem - WDYT?) Also use padding and ECS privacy by default for Stubby. More debugging to help users when there are failures or fallbacks. Also remove a few help options from Stubby that don't apply Add -v to output version on getdns_query/stubby --- src/context.c | 2 +- src/stub.c | 11 +++++++--- src/tools/getdns_query.c | 46 ++++++++++++++++++++++++++++------------ 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/context.c b/src/context.c index 8b8413f8..d0fb6b39 100644 --- a/src/context.c +++ b/src/context.c @@ -755,7 +755,7 @@ _getdns_upstream_shutdown(getdns_upstream *upstream) upstream->conn_shutdowns = 0; upstream->conn_backoffs++; #if defined(DAEMON_DEBUG) && DAEMON_DEBUG - DEBUG_DAEMON("%s %s : !Backing off this upstream - will retry as new upstream at %s\n", + DEBUG_DAEMON("%s %s : !Backing off this upstream - Will retry as new upstream at %s", STUB_DEBUG_DAEMON, upstream->addr_str, asctime(gmtime(&upstream->conn_retry_time))); #endif diff --git a/src/stub.c b/src/stub.c index 83ab992c..ef74beb8 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1314,7 +1314,8 @@ stub_udp_read_cb(void *userarg) netreq->state = NET_REQ_FINISHED; upstream->udp_responses++; #if defined(DAEMON_DEBUG) && DAEMON_DEBUG - if (upstream->udp_responses % 100 == 0) + if (upstream->udp_responses == 1 || + upstream->udp_responses % 100 == 0) DEBUG_DAEMON("%s %s : Upstream stats: Transport=UDP - Resp=%d,Timeouts=%d\n", STUB_DEBUG_DAEMON, upstream->addr_str, (int)upstream->udp_responses, (int)upstream->udp_timeouts); @@ -1545,6 +1546,9 @@ upstream_write_cb(void *userarg) case STUB_NO_AUTH: /* Cleaning up after connection or auth check failure. Need to fallback. */ stub_cleanup(netreq); + DEBUG_DAEMON("%s %s : Conn closed : Transport=%s - *Failure*\n", + STUB_DEBUG_DAEMON, upstream->addr_str, + (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP")); if (fallback_on_write(netreq) == STUB_TCP_ERROR) { /* TODO: Need new state to report transport unavailable*/ netreq->state = NET_REQ_FINISHED; @@ -1782,7 +1786,7 @@ upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport, } upstream->conn_state = GETDNS_CONN_SETUP; #if defined(DAEMON_DEBUG) && DAEMON_DEBUG - DEBUG_DAEMON("%s %s : Conn init : Transport= %s - Profile=%s\n", STUB_DEBUG_DAEMON, + DEBUG_DAEMON("%s %s : Conn init : Transport=%s - Profile=%s\n", STUB_DEBUG_DAEMON, upstream->addr_str, transport == GETDNS_TRANSPORT_TLS ? "TLS":"TCP", dnsreq->context->tls_auth_min == GETDNS_AUTHENTICATION_NONE ? "Opportunistic":"Strict"); #endif @@ -1843,6 +1847,8 @@ upstream_find_for_netreq(getdns_network_req *netreq) } /* Handle better, will give generic error*/ DEBUG_STUB("%s %-35s: MSG: %p No valid upstream! \n", STUB_DEBUG_SCHEDULE, __FUNCTION__, netreq); + DEBUG_DAEMON("%s *FAILURE* no valid transports or upstreams available!\n", + STUB_DEBUG_DAEMON); return -1; } @@ -1856,7 +1862,6 @@ fallback_on_write(getdns_network_req *netreq) /* Deal with UDP one day*/ DEBUG_STUB("%s %-35s: MSG: %p FALLING BACK \n", STUB_DEBUG_SCHEDULE, __FUNCTION__, netreq); - DEBUG_DAEMON("%s Falling back...\n", STUB_DEBUG_DAEMON); /* Try to find a fallback transport*/ getdns_return_t result = _getdns_submit_stub_request(netreq); diff --git a/src/tools/getdns_query.c b/src/tools/getdns_query.c index 92a27337..089f005e 100644 --- a/src/tools/getdns_query.c +++ b/src/tools/getdns_query.c @@ -51,8 +51,11 @@ typedef unsigned short in_port_t; static int i_am_stubby = 0; static const char *default_stubby_config = "{ resolution_type: GETDNS_RESOLUTION_STUB" +", dns_transport_list: [ GETDNS_TRANSPORT_TLS, GETDNS_TRANSPORT_UDP, GETDNS_TRANSPORT_TCP ]" ", idle_timeout: 10000" ", listen_addresses: [ 127.0.0.1@53, 0::1@53 ]" +", tls_query_padding_blocksize: 256" +", edns_client_subnet_private : 1" "}"; static int clear_listen_list_on_arg = 0; #ifndef GETDNS_ON_WINDOWS @@ -161,13 +164,19 @@ print_usage(FILE *out, const char *progname) { fprintf(out, "usage: %s [