- Add a new mode where for TLS (and infact TCP too) the upstream selection simply cycles over all the upstreams rather than treating them as an ordered list and always using the first open one.

- Make IP field in debug output fixed width
- Collect all the one line config options at the top of the stubby.conf file to make it easier to read
This commit is contained in:
Sara Dickinson 2017-03-16 14:51:46 +00:00
parent 5f3de12644
commit f0f3c43552
7 changed files with 116 additions and 30 deletions

View File

@ -73,6 +73,7 @@ static struct const_info consts_info[] = {
{ 619, "GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE", GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE_TEXT },
{ 620, "GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE", GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE_TEXT },
{ 621, "GETDNS_CONTEXT_CODE_PUBKEY_PINSET", GETDNS_CONTEXT_CODE_PUBKEY_PINSET_TEXT },
{ 622, "GETDNS_CONTEXT_CODE_TLS_USE_ALL_UPSTREAMS", GETDNS_CONTEXT_CODE_TLS_USE_ALL_UPSTREAMS_TEXT },
{ 700, "GETDNS_CALLBACK_COMPLETE", GETDNS_CALLBACK_COMPLETE_TEXT },
{ 701, "GETDNS_CALLBACK_CANCEL", GETDNS_CALLBACK_CANCEL_TEXT },
{ 702, "GETDNS_CALLBACK_TIMEOUT", GETDNS_CALLBACK_TIMEOUT_TEXT },
@ -161,6 +162,7 @@ static struct const_name_info consts_name_info[] = {
{ "GETDNS_CONTEXT_CODE_TIMEOUT", 616 },
{ "GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION", 618 },
{ "GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE", 620 },
{ "GETDNS_CONTEXT_CODE_TLS_USE_ALL_UPSTREAMS", 622 },
{ "GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS", 603 },
{ "GETDNS_DNSSEC_BOGUS", 401 },
{ "GETDNS_DNSSEC_INDETERMINATE", 402 },

View File

@ -647,6 +647,7 @@ upstreams_create(getdns_context *context, size_t size)
r->referenced = 1;
r->count = 0;
r->current_udp = 0;
r->current_stateful = 0;
return r;
}
@ -721,17 +722,17 @@ _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 : Transport=%s - Resp=%d,Timeouts=%d,Auth=%s,Keepalive(ms)=%d\n",
DEBUG_DAEMON("%s %-40s : 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(upstream->tls_auth_state), (int)upstream->keepalive_timeout);
DEBUG_DAEMON("%s %s : Upstream stats: Transport=%s - Resp=%d,Timeouts=%d,Best_auth=%s\n",
DEBUG_DAEMON("%s %-40s : 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,
_getdns_auth_str(upstream->best_tls_auth_state));
DEBUG_DAEMON("%s %s : Upstream stats: Transport=%s - Conns=%d,Conn_fails=%d,Conn_shutdowns=%d,Backoffs=%d\n",
DEBUG_DAEMON("%s %-40s : 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,
@ -760,7 +761,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",
DEBUG_DAEMON("%s %-40s : !Backing off this upstream - Will retry as new upstream at %s",
STUB_DEBUG_DAEMON, upstream->addr_str,
asctime(gmtime(&upstream->conn_retry_time)));
#endif
@ -1428,6 +1429,7 @@ getdns_context_create_with_extended_memory_functions(
goto error;
result->tls_auth = GETDNS_AUTHENTICATION_NONE;
result->tls_auth_min = GETDNS_AUTHENTICATION_NONE;
result->tls_use_all_upstreams = 0;
result->limit_outstanding_queries = 0;
/* unbound context is initialized here */
@ -2031,6 +2033,27 @@ getdns_context_set_tls_authentication(getdns_context *context,
return GETDNS_RETURN_GOOD;
} /* getdns_context_set_tls_authentication_list */
/*
* getdns_context_set_tls_use_all_upstreams
*
*/
getdns_return_t
getdns_context_set_tls_use_all_upstreams(getdns_context *context, uint8_t value)
{
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
/* only allow 0 or 1 */
if (value != 0 && value != 1) {
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
}
context->tls_use_all_upstreams = value;
dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_USE_ALL_UPSTREAMS);
return GETDNS_RETURN_GOOD;
} /* getdns_context_set_tls_use_all_upstreams */
#ifdef HAVE_LIBUNBOUND
static void
set_ub_limit_outstanding_queries(getdns_context* context, uint16_t value) {
@ -3467,7 +3490,9 @@ _get_context_settings(getdns_context* context)
|| getdns_dict_set_int(result, "append_name",
context->append_name)
|| getdns_dict_set_int(result, "tls_authentication",
context->tls_auth))
context->tls_auth)
|| getdns_dict_set_int(result, "tls_use_all_upstreams",
context->tls_use_all_upstreams))
goto error;
/* list fields */
@ -3763,6 +3788,15 @@ getdns_context_get_tls_authentication(getdns_context *context,
return GETDNS_RETURN_GOOD;
}
getdns_return_t
getdns_context_get_tls_use_all_upstreams(getdns_context *context,
uint8_t* value) {
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER);
*value = context->tls_use_all_upstreams;
return GETDNS_RETURN_GOOD;
}
getdns_return_t
getdns_context_get_limit_outstanding_queries(getdns_context *context,
uint16_t* value) {
@ -4158,6 +4192,7 @@ _getdns_context_config_setting(getdns_context *context,
CONTEXT_SETTING_INT(edns_client_subnet_private)
CONTEXT_SETTING_INT(tls_authentication)
CONTEXT_SETTING_INT(tls_use_all_upstreams)
CONTEXT_SETTING_INT(tls_query_padding_blocksize)
/**************************************/

View File

@ -217,6 +217,7 @@ typedef struct getdns_upstreams {
size_t referenced;
size_t count;
size_t current_udp;
size_t current_stateful;
getdns_upstream upstreams[];
} getdns_upstreams;
@ -248,6 +249,7 @@ struct getdns_context {
uint32_t dnssec_allowed_skew;
getdns_tls_authentication_t tls_auth; /* What user requested for TLS*/
getdns_tls_authentication_t tls_auth_min; /* Derived minimum auth allowed*/
uint8_t tls_use_all_upstreams;
getdns_transport_list_t *dns_transports;
size_t dns_transport_count;

View File

@ -76,6 +76,8 @@ extern "C" {
#define GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE_TEXT "Change related to getdns_context_set_tls_query_padding_blocksize"
#define GETDNS_CONTEXT_CODE_PUBKEY_PINSET 621
#define GETDNS_CONTEXT_CODE_PUBKEY_PINSET_TEXT "Change related to getdns_context_set_pubkey_pinset"
#define GETDNS_CONTEXT_CODE_TLS_USE_ALL_UPSTREAMS 622
#define GETDNS_CONTEXT_CODE_TLS_USE_ALL_UPSTREAMS_TEXT "Change related to getdns_context_set_pubkey_pinset"
/** @}
*/
@ -265,6 +267,9 @@ getdns_return_t
getdns_context_set_tls_authentication(
getdns_context *context, getdns_tls_authentication_t value);
getdns_return_t
getdns_context_set_tls_use_all_upstreams(getdns_context *context, uint8_t value);
getdns_return_t
getdns_context_set_edns_client_subnet_private(getdns_context *context, uint8_t value);
@ -356,6 +361,10 @@ getdns_return_t
getdns_context_get_tls_authentication(getdns_context *context,
getdns_tls_authentication_t* value);
getdns_return_t
getdns_context_get_tls_use_all_upstreams(getdns_context *context,
uint8_t* value);
/**
* Get the currently registered callback function and user defined argument
* for context changes.

View File

@ -30,6 +30,7 @@ getdns_context_get_suffix
getdns_context_get_timeout
getdns_context_get_tls_authentication
getdns_context_get_tls_query_padding_blocksize
getdns_context_get_tls_use_all_upstreams
getdns_context_get_update_callback
getdns_context_get_upstream_recursive_servers
getdns_context_process_async
@ -60,6 +61,7 @@ getdns_context_set_suffix
getdns_context_set_timeout
getdns_context_set_tls_authentication
getdns_context_set_tls_query_padding_blocksize
getdns_context_get_tls_use_all_upstreams
getdns_context_set_update_callback
getdns_context_set_upstream_recursive_servers
getdns_context_set_use_threads

View File

@ -591,7 +591,7 @@ stub_timeout_cb(void *userarg)
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",
DEBUG_DAEMON("%s %-40s : 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
@ -907,7 +907,7 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd);
#if defined(DAEMON_DEBUG) && DAEMON_DEBUG
else
DEBUG_DAEMON("%s %s : Conn failed : Transport=TLS - *Failure* - Pinset validation failure\n",
DEBUG_DAEMON("%s %-40s : Conn failed : Transport=TLS - *Failure* - Pinset validation failure\n",
STUB_DEBUG_DAEMON, upstream->addr_str);
#endif
} else {
@ -1373,7 +1373,7 @@ stub_udp_read_cb(void *userarg)
#if defined(DAEMON_DEBUG) && DAEMON_DEBUG
if (upstream->udp_responses == 1 ||
upstream->udp_responses % 100 == 0)
DEBUG_DAEMON("%s %s : Upstream stats: Transport=UDP - Resp=%d,Timeouts=%d\n",
DEBUG_DAEMON("%s %-40s : Upstream stats: Transport=UDP - Resp=%d,Timeouts=%d\n",
STUB_DEBUG_DAEMON, upstream->addr_str,
(int)upstream->udp_responses, (int)upstream->udp_timeouts);
#endif
@ -1608,7 +1608,7 @@ upstream_write_cb(void *userarg)
/* Cleaning up after connection or auth check failure. Need to fallback. */
stub_cleanup(netreq);
#if defined(DAEMON_DEBUG) && DAEMON_DEBUG
DEBUG_DAEMON("%s %s : Conn closed : Transport=%s - *Failure*\n",
DEBUG_DAEMON("%s %-40s : Conn closed : Transport=%s - *Failure*\n",
STUB_DEBUG_DAEMON, upstream->addr_str,
(upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP"));
#endif
@ -1672,6 +1672,17 @@ upstream_active(getdns_upstream *upstream)
return 0;
}
static int
upstream_usable(getdns_upstream *upstream)
{
if ((upstream->conn_state == GETDNS_CONN_CLOSED ||
upstream->conn_state == GETDNS_CONN_SETUP ||
upstream->conn_state == GETDNS_CONN_OPEN) &&
upstream->keepalive_shutdown == 0)
return 1;
return 0;
}
static int
upstream_auth_status_ok(getdns_upstream *upstream, getdns_network_req *netreq) {
if (netreq->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED)
@ -1692,10 +1703,16 @@ upstream_valid(getdns_upstream *upstream,
getdns_transport_list_t transport,
getdns_network_req *netreq)
{
if (upstream->transport != transport || upstream->conn_state != GETDNS_CONN_CLOSED)
if (upstream->transport != transport && upstream_usable(upstream))
return 0;
if (transport == GETDNS_TRANSPORT_TCP)
return 1;
if (upstream->conn_state == GETDNS_CONN_OPEN) {
if (!upstream_auth_status_ok(upstream, netreq))
return 0;
else
return 1;
}
/* We need to check past authentication history to see if this is usable for TLS.*/
if (netreq->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED)
return 1;
@ -1728,7 +1745,7 @@ upstream_select_stateful(getdns_network_req *netreq, getdns_transport_list_t tra
getdns_upstreams *upstreams = netreq->owner->upstreams;
size_t i;
time_t now = time(NULL);
if (!upstreams->count)
return NULL;
@ -1738,37 +1755,55 @@ upstream_select_stateful(getdns_network_req *netreq, getdns_transport_list_t tra
upstreams->upstreams[i].conn_retry_time < now) {
upstreams->upstreams[i].conn_state = GETDNS_CONN_CLOSED;
#if defined(DAEMON_DEBUG) && DAEMON_DEBUG
DEBUG_DAEMON("%s %s : Re-instating upstream\n",
DEBUG_DAEMON("%s %-40s : Re-instating upstream\n",
STUB_DEBUG_DAEMON, upstreams->upstreams[i].addr_str);
#endif
}
}
/* First find if an open upstream has the correct properties and use that*/
for (i = 0; i < upstreams->count; i++) {
if (upstream_valid_and_open(&upstreams->upstreams[i], transport, netreq))
return &upstreams->upstreams[i];
if (netreq->owner->context->tls_use_all_upstreams == 0) {
/* First find if an open upstream has the correct properties and use that*/
for (i = 0; i < upstreams->count; i++) {
if (upstream_valid_and_open(&upstreams->upstreams[i], transport, netreq))
return &upstreams->upstreams[i];
}
}
/* OK - we will have to open one. Choose the first one that has the best stats
and the right properties, but because we completely back off failed
/* OK - Find the next one to use. First check we have at least one valid
upstream because we completely back off failed
upstreams we may have no valid upstream at all (in contrast to UDP). This
will be better communicated to the user when we have better error codes*/
for (i = 0; i < upstreams->count; i++) {
i = upstreams->current_stateful;
do {
DEBUG_STUB("%s %-35s: Testing upstreams %d %d\n", STUB_DEBUG_SETUP,
__FUNC__, (int)i, (int)upstreams->upstreams[i].conn_state);
if (upstream_valid(&upstreams->upstreams[i], transport, netreq)) {
upstream = &upstreams->upstreams[i];
break;
}
}
i++;
if (i >= upstreams->count)
i = 0;
} while (i != upstreams->current_stateful);
if (!upstream)
return NULL;
for (i++; i < upstreams->count; i++) {
if (upstream_valid(&upstreams->upstreams[i], transport, netreq) &&
upstream_stats(&upstreams->upstreams[i]) > upstream_stats(upstream))
upstream = &upstreams->upstreams[i];
/* Now select the specific upstream */
if (netreq->owner->context->tls_use_all_upstreams == 0) {
/* Base the decision on the stats, noting we will have started from 0*/
for (i++; i < upstreams->count; i++) {
if (upstream_valid(&upstreams->upstreams[i], transport, netreq) &&
upstream_stats(&upstreams->upstreams[i]) > upstream_stats(upstream))
upstream = &upstreams->upstreams[i];
}
} else {
/* Simplistic, but always just pick the first one, incrementing the current.
Note we are not distinguishing TCP/TLS here....*/
upstreams->current_stateful+=GETDNS_UPSTREAM_TRANSPORTS;
if (upstreams->current_stateful >= upstreams->count)
upstreams->current_stateful = 0;
}
return upstream;
}
@ -1853,7 +1888,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 %-40s : 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

View File

@ -1,5 +1,11 @@
{ resolution_type: GETDNS_RESOLUTION_STUB
, dns_transport_list: [ GETDNS_TRANSPORT_TLS ]
, tls_authentication: GETDNS_AUTHENTICATION_REQUIRED
, tls_query_padding_blocksize: 256
, edns_client_subnet_private : 1
, listen_addresses: [ 127.0.0.1, 0::1 ]
, idle_timeout: 10000
, tls_use_all_upstreams: 1
, upstream_recursive_servers:
[ { address_data: 145.100.185.15
, tls_auth_name: "dnsovertls.sinodun.com"
@ -56,9 +62,4 @@
} ]
}
]
, tls_authentication: GETDNS_AUTHENTICATION_REQUIRED
, tls_query_padding_blocksize: 256
, edns_client_subnet_private : 1
, listen_addresses: [ 127.0.0.1, 0::1 ]
, idle_timeout: 10000
}