diff --git a/doc/09-object-types.md b/doc/09-object-types.md
index fffad0000..6dda8c91d 100644
--- a/doc/09-object-types.md
+++ b/doc/09-object-types.md
@@ -64,6 +64,7 @@ Configuration Attributes:
max\_anonymous\_clients | Number | **Optional.** Limit the number of anonymous client connections (not configured endpoints and signing requests).
cipher\_list | String | **Optional.** Cipher list that is allowed. For a list of available ciphers run `openssl ciphers`. Defaults to `ALL:!LOW:!WEAK:!MEDIUM:!EXP:!NULL`.
tls\_protocolmin | String | **Optional.** Minimum TLS protocol version. Must be one of `TLSv1`, `TLSv1.1` or `TLSv1.2`. Defaults to `TLSv1`.
+ tls\_handshake\_timeout | Number | **Optional.** TLS Handshake timeout. Defaults to `10s`.
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/doc/16-upgrading-icinga-2.md b/doc/16-upgrading-icinga-2.md
index 8bf58bc13..83b4bd3ec 100644
--- a/doc/16-upgrading-icinga-2.md
+++ b/doc/16-upgrading-icinga-2.md
@@ -57,6 +57,10 @@ The corresponding REST API results from `/v1/status/ApiListener` in `json_rpc` h
from `clients` to `anonymous_clients` to better reflect their purpose. Authenticated clients
are counted as connected endpoints. A similar change is there for the performance data metrics.
+The TLS handshake timeout defaults to 10 seconds since v2.8.2. This can now be configured
+with the configuration attribute `tls_handshake_timeout`. Beware of performance issues
+with setting a too high value.
+
### API: schedule-downtime Action
The attribute `child_options` was previously accepting 0,1,2 for specific child downtime settings.
diff --git a/lib/base/configuration.cpp b/lib/base/configuration.cpp
index 31f691265..10d33645a 100644
--- a/lib/base/configuration.cpp
+++ b/lib/base/configuration.cpp
@@ -49,6 +49,7 @@ String Configuration::RunAsGroup;
String Configuration::RunAsUser;
String Configuration::SpoolDir;
String Configuration::StatePath;
+double Configuration::TlsHandshakeTimeout{10};
String Configuration::VarsPath;
String Configuration::ZonesDir;
@@ -309,6 +310,16 @@ void Configuration::SetStatePath(const String& val, bool suppress_events, const
HandleUserWrite("StatePath", &Configuration::StatePath, val, m_ReadOnly);
}
+double Configuration::GetTlsHandshakeTimeout() const
+{
+ return Configuration::TlsHandshakeTimeout;
+}
+
+void Configuration::SetTlsHandshakeTimeout(double val, bool suppress_events, const Value& cookie)
+{
+ HandleUserWrite("TlsHandshakeTimeout", &Configuration::TlsHandshakeTimeout, val, m_ReadOnly);
+}
+
String Configuration::GetVarsPath() const
{
return Configuration::VarsPath;
diff --git a/lib/base/configuration.hpp b/lib/base/configuration.hpp
index 02a516b87..2a57bbbd8 100644
--- a/lib/base/configuration.hpp
+++ b/lib/base/configuration.hpp
@@ -108,6 +108,9 @@ public:
String GetStatePath() const override;
void SetStatePath(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
+ double GetTlsHandshakeTimeout() const override;
+ void SetTlsHandshakeTimeout(double value, bool suppress_events = false, const Value& cookie = Empty) override;
+
String GetVarsPath() const override;
void SetVarsPath(const String& value, bool suppress_events = false, const Value& cookie = Empty) override;
@@ -151,6 +154,7 @@ public:
static String RunAsUser;
static String SpoolDir;
static String StatePath;
+ static double TlsHandshakeTimeout;
static String VarsPath;
static String ZonesDir;
diff --git a/lib/base/configuration.ti b/lib/base/configuration.ti
index abcba7d55..b15d5b21e 100644
--- a/lib/base/configuration.ti
+++ b/lib/base/configuration.ti
@@ -146,6 +146,11 @@ abstract class Configuration
set;
};
+ [config, no_storage, virtual] double TlsHandshakeTimeout {
+ get;
+ set;
+ };
+
[config, no_storage, virtual] String VarsPath {
get;
set;
diff --git a/lib/base/tlsstream.cpp b/lib/base/tlsstream.cpp
index 33d72d465..afb46b781 100644
--- a/lib/base/tlsstream.cpp
+++ b/lib/base/tlsstream.cpp
@@ -21,6 +21,8 @@
#include "base/utility.hpp"
#include "base/exception.hpp"
#include "base/logger.hpp"
+#include "base/configuration.hpp"
+#include "base/convert.hpp"
#include
#ifndef _WIN32
@@ -315,14 +317,13 @@ void TlsStream::Handshake()
m_CurrentAction = TlsActionHandshake;
ChangeEvents(POLLOUT);
- boost::system_time const timeout = boost::get_system_time() + boost::posix_time::seconds(TLS_TIMEOUT_SECONDS);
+ boost::system_time const timeout = boost::get_system_time() + boost::posix_time::milliseconds(long(Configuration::TlsHandshakeTimeout * 1000));
while (!m_HandshakeOK && !m_ErrorOccurred && !m_Eof && timeout > boost::get_system_time())
m_CV.timed_wait(lock, timeout);
- // We should _NOT_ (underline, bold, itallic and wordart) throw an exception for a timeout.
if (timeout < boost::get_system_time())
- BOOST_THROW_EXCEPTION(std::runtime_error("Timeout during handshake."));
+ BOOST_THROW_EXCEPTION(std::runtime_error("Timeout was reached (" + Convert::ToString(Configuration::TlsHandshakeTimeout) + ") during TLS handshake."));
if (m_Eof)
BOOST_THROW_EXCEPTION(std::runtime_error("Socket was closed during TLS handshake."));
diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp
index c9cbd3867..4605df364 100644
--- a/lib/remote/apilistener.cpp
+++ b/lib/remote/apilistener.cpp
@@ -89,6 +89,16 @@ String ApiListener::GetDefaultCaPath()
return GetCertsDir() + "/ca.crt";
}
+double ApiListener::GetTlsHandshakeTimeout() const
+{
+ return Configuration::TlsHandshakeTimeout;
+}
+
+void ApiListener::SetTlsHandshakeTimeout(double value, bool suppress_events, const Value& cookie)
+{
+ Configuration::TlsHandshakeTimeout = value;
+}
+
void ApiListener::CopyCertificateFile(const String& oldCertPath, const String& newCertPath)
{
struct stat st1, st2;
@@ -1453,6 +1463,14 @@ void ApiListener::ValidateTlsProtocolmin(const Lazy& lvalue, const Valid
}
}
+void ApiListener::ValidateTlsHandshakeTimeout(const Lazy& lvalue, const ValidationUtils& utils)
+{
+ ObjectImpl::ValidateTlsHandshakeTimeout(lvalue, utils);
+
+ if (lvalue() <= 0)
+ BOOST_THROW_EXCEPTION(ValidationError(this, { "tls_handshake_timeout" }, "Value must be greater than 0."));
+}
+
bool ApiListener::IsHACluster()
{
Zone::Ptr zone = Zone::GetLocalZone();
diff --git a/lib/remote/apilistener.hpp b/lib/remote/apilistener.hpp
index 27d236eaa..7868352d4 100644
--- a/lib/remote/apilistener.hpp
+++ b/lib/remote/apilistener.hpp
@@ -108,6 +108,9 @@ public:
static String GetDefaultKeyPath();
static String GetDefaultCaPath();
+ double GetTlsHandshakeTimeout() const override;
+ void SetTlsHandshakeTimeout(double value, bool suppress_events, const Value& cookie) override;
+
protected:
void OnConfigLoaded() override;
void OnAllConfigLoaded() override;
@@ -115,6 +118,7 @@ protected:
void Stop(bool runtimeDeleted) override;
void ValidateTlsProtocolmin(const Lazy& lvalue, const ValidationUtils& utils) override;
+ void ValidateTlsHandshakeTimeout(const Lazy& lvalue, const ValidationUtils& utils) override;
private:
std::shared_ptr m_SSLContext;
diff --git a/lib/remote/apilistener.ti b/lib/remote/apilistener.ti
index b98dae1cb..7d0b018d5 100644
--- a/lib/remote/apilistener.ti
+++ b/lib/remote/apilistener.ti
@@ -54,6 +54,12 @@ class ApiListener : ConfigObject
default {{{ return -1; }}}
};
+ [config] double tls_handshake_timeout {
+ get;
+ set;
+ default {{{ return Configuration::TlsHandshakeTimeout; }}}
+ };
+
[config] String ticket_salt;
[config] Array::Ptr access_control_allow_origin;