From d7099f6e3015e5e3560e0797add3ae1057cf30bc Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Fri, 21 Feb 2020 14:17:00 +0100 Subject: [PATCH] Deal with DoT servers that take long to connect to (because they might be under attack) --- src/context.c | 1 + src/context.h | 5 ++++- src/stub.c | 26 +++++++++++++++++++++----- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/context.c b/src/context.c index 57686f0a6..6264ae995 100644 --- a/src/context.c +++ b/src/context.c @@ -925,6 +925,7 @@ upstream_init(getdns_upstream *upstream, /* For sharing a socket to this upstream with TCP */ upstream->fd = -1; + upstream->expires = 0; upstream->tls_obj = NULL; upstream->tls_session = NULL; upstream->tls_cipher_list = NULL; diff --git a/src/context.h b/src/context.h index eb42382fe..f97884d30 100644 --- a/src/context.h +++ b/src/context.h @@ -209,7 +209,10 @@ typedef struct getdns_upstream { _getdns_tls_session* tls_session; getdns_tls_hs_state_t tls_hs_state; getdns_auth_state_t tls_auth_state; - + uint64_t expires; /* Expire time of waiting netreqs. + * This is how long a handshake may + * take. + */ /* TLS settings */ char *tls_cipher_list; char *tls_ciphersuites; diff --git a/src/stub.c b/src/stub.c index e647fdaf5..5f52b8669 100644 --- a/src/stub.c +++ b/src/stub.c @@ -68,7 +68,8 @@ #define STUB_TCP_ERROR -2 /* Don't currently have access to the context whilst doing handshake */ -#define TIMEOUT_TLS 2500 +#define MIN_TLS_HS_TIMEOUT 2500 +#define MAX_TLS_HS_TIMEOUT 7500 /* Arbritray number of message for EDNS keepalive resend*/ #define EDNS_KEEPALIVE_RESEND 5 @@ -981,13 +982,23 @@ tls_do_handshake(getdns_upstream *upstream) int r; while ((r = _getdns_tls_connection_do_handshake(upstream->tls_obj)) != GETDNS_RETURN_GOOD) { + uint64_t timeout_tls = _getdns_ms_until_expiry(upstream->expires); + + if (timeout_tls < MIN_TLS_HS_TIMEOUT) + timeout_tls = MIN_TLS_HS_TIMEOUT; + else if (timeout_tls > MAX_TLS_HS_TIMEOUT) + timeout_tls = MAX_TLS_HS_TIMEOUT; + + DEBUG_STUB("%s %-35s: FD: %d, do_handshake -> %d (timeout: %d)\n", + STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, r, (int)timeout_tls); + switch (r) { case GETDNS_RETURN_TLS_WANT_READ: GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.read_cb = upstream_read_cb; upstream->event.write_cb = NULL; GETDNS_SCHEDULE_EVENT(upstream->loop, - upstream->fd, TIMEOUT_TLS, &upstream->event); + upstream->fd, timeout_tls, &upstream->event); upstream->tls_hs_state = GETDNS_HS_READ; return STUB_TCP_RETRY; case GETDNS_RETURN_TLS_WANT_WRITE: @@ -995,7 +1006,7 @@ tls_do_handshake(getdns_upstream *upstream) upstream->event.read_cb = NULL; upstream->event.write_cb = upstream_write_cb; GETDNS_SCHEDULE_EVENT(upstream->loop, - upstream->fd, TIMEOUT_TLS, &upstream->event); + upstream->fd, timeout_tls, &upstream->event); upstream->tls_hs_state = GETDNS_HS_WRITE; return STUB_TCP_RETRY; default: @@ -1199,7 +1210,12 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, _getdns_tls_connection* tls_obj = upstream->tls_obj; uint16_t padding_sz; - int q = tls_connected(upstream); + int q; + + if (netreq->owner->expires > upstream->expires) + upstream->expires = netreq->owner->expires; + + q = tls_connected(upstream); if (q != 0) return q; /* This is the case where the upstream is connected but it isn't an authenticated @@ -2226,7 +2242,7 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq) /* Set a timeout on the upstream so we can catch failed setup*/ upstream->event.timeout_cb = upstream_setup_timeout_cb; GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, - _getdns_ms_until_expiry(netreq->owner->expires)/2, + _getdns_ms_until_expiry(netreq->owner->expires)/5*4, &upstream->event); #if defined(HAVE_DECL_TCP_FASTOPEN) && HAVE_DECL_TCP_FASTOPEN \ && !(defined(HAVE_DECL_TCP_FASTOPEN_CONNECT) && HAVE_DECL_TCP_FASTOPEN_CONNECT) \