From 2131318c48146be135fc3832dda7af98651b2d1d Mon Sep 17 00:00:00 2001 From: Julian Brost Date: Wed, 19 May 2021 16:40:49 +0200 Subject: [PATCH] Add timeout for all new connections This commit adds a timeout for both establishing new outgoing and incoming connections. This timeout applies to everything until the connection is in a state where either JsonRpcConnection or HttpServerConnection takes over. --- doc/09-object-types.md | 1 + lib/remote/apilistener.cpp | 28 +++++++++++++++++++++++++++- lib/remote/apilistener.ti | 4 ++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/doc/09-object-types.md b/doc/09-object-types.md index 6111ec0aa..cad9afc54 100644 --- a/doc/09-object-types.md +++ b/doc/09-object-types.md @@ -1094,6 +1094,7 @@ Configuration Attributes: cipher\_list | String | **Optional.** Cipher list that is allowed. For a list of available ciphers run `openssl ciphers`. Defaults to `ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:AES256-GCM-SHA384:AES128-GCM-SHA256`. tls\_protocolmin | String | **Optional.** Minimum TLS protocol version. Since v2.11, only `TLSv1.2` is supported. Defaults to `TLSv1.2`. tls\_handshake\_timeout | Number | **Optional.** TLS Handshake timeout. Defaults to `10s`. + connect\_timeout | Number | **Optional.** Timeout for establishing new connections. Affects both incoming and outgoing connections. Within this time, the TCP and TLS handshakes must complete and either a HTTP request or an Icinga cluster connection must be initiated. Defaults to `15s`. access\_control\_allow\_origin | Array | **Optional.** Specifies an array of origin URLs that may access the API. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Origin) access\_control\_allow\_credentials | Boolean | **Deprecated.** Indicates whether or not the actual request can be made using credentials. Defaults to `true`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Credentials) access\_control\_allow\_headers | String | **Deprecated.** Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request. Defaults to `Authorization`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Headers) diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp index 2e7d75bd5..61643220f 100644 --- a/lib/remote/apilistener.cpp +++ b/lib/remote/apilistener.cpp @@ -440,7 +440,21 @@ void ApiListener::ListenerCoroutineProc(boost::asio::yield_context yc, const std auto strand (Shared::Make(io)); - IoEngine::SpawnCoroutine(*strand, [this, strand, sslConn](asio::yield_context yc) { NewClientHandler(yc, strand, sslConn, String(), RoleServer); }); + IoEngine::SpawnCoroutine(*strand, [this, strand, sslConn](asio::yield_context yc) { + Timeout::Ptr timeout(new Timeout(strand->context(), *strand, boost::posix_time::microseconds(int64_t(GetConnectTimeout() * 1e6)), + [sslConn](asio::yield_context yc) { + Log(LogWarning, "ApiListener") + << "Timeout while processing incoming connection from " + << sslConn->lowest_layer().remote_endpoint(); + + boost::system::error_code ec; + sslConn->lowest_layer().cancel(ec); + } + )); + Defer cancelTimeout([timeout]() { timeout->Cancel(); }); + + NewClientHandler(yc, strand, sslConn, String(), RoleServer); + }); } catch (const std::exception& ex) { Log(LogCritical, "ApiListener") << "Cannot accept new connection: " << ex.what(); @@ -478,6 +492,18 @@ void ApiListener::AddConnection(const Endpoint::Ptr& endpoint) try { auto sslConn (std::make_shared(io, *sslContext, endpoint->GetName())); + Timeout::Ptr timeout(new Timeout(strand->context(), *strand, boost::posix_time::microseconds(int64_t(GetConnectTimeout() * 1e6)), + [sslConn, endpoint, host, port](asio::yield_context yc) { + Log(LogCritical, "ApiListener") + << "Timeout while reconnecting to endpoint '" << endpoint->GetName() << "' via host '" << host + << "' and port '" << port << "', cancelling attempt"; + + boost::system::error_code ec; + sslConn->lowest_layer().cancel(ec); + } + )); + Defer cancelTimeout([&timeout]() { timeout->Cancel(); }); + Connect(sslConn->lowest_layer(), host, port, yc); NewClientHandler(yc, strand, sslConn, endpoint->GetName(), RoleClient); diff --git a/lib/remote/apilistener.ti b/lib/remote/apilistener.ti index ede50b606..671618213 100644 --- a/lib/remote/apilistener.ti +++ b/lib/remote/apilistener.ti @@ -43,6 +43,10 @@ class ApiListener : ConfigObject default {{{ return Configuration::TlsHandshakeTimeout; }}} }; + [config] double connect_timeout { + default {{{ return 15.0; }}} + }; + [config] String ticket_salt; [config] Array::Ptr access_control_allow_origin;