Merge pull request #8224 from Icinga/bugfix/handshake-timeout-7805-2.11.6

Close connections w/o sucessful TLS handshakes during 10s
This commit is contained in:
Alexander Aleksandrovič Klimov 2020-09-11 11:29:24 +02:00 committed by GitHub
commit 1bbef11196
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 9 deletions

View File

@ -24,11 +24,14 @@
#include "base/exception.hpp" #include "base/exception.hpp"
#include "base/tcpsocket.hpp" #include "base/tcpsocket.hpp"
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/asio/io_context_strand.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp> #include <boost/asio/spawn.hpp>
#include <boost/asio/ssl/context.hpp> #include <boost/asio/ssl/context.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <climits> #include <climits>
#include <cstdint>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <openssl/ssl.h> #include <openssl/ssl.h>
@ -435,7 +438,9 @@ void ApiListener::ListenerCoroutineProc(boost::asio::yield_context yc, const std
server->async_accept(sslConn->lowest_layer(), yc); server->async_accept(sslConn->lowest_layer(), yc);
IoEngine::SpawnCoroutine(io, [this, sslConn](asio::yield_context yc) { NewClientHandler(yc, sslConn, String(), RoleServer); }); auto strand (Shared<asio::io_context::strand>::Make(io));
IoEngine::SpawnCoroutine(*strand, [this, strand, sslConn](asio::yield_context yc) { NewClientHandler(yc, strand, sslConn, String(), RoleServer); });
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
Log(LogCritical, "ApiListener") Log(LogCritical, "ApiListener")
<< "Cannot accept new connection: " << ex.what(); << "Cannot accept new connection: " << ex.what();
@ -461,8 +466,9 @@ void ApiListener::AddConnection(const Endpoint::Ptr& endpoint)
} }
auto& io (IoEngine::Get().GetIoContext()); auto& io (IoEngine::Get().GetIoContext());
auto strand (Shared<asio::io_context::strand>::Make(io));
IoEngine::SpawnCoroutine(io, [this, endpoint, &io, sslContext](asio::yield_context yc) { IoEngine::SpawnCoroutine(*strand, [this, strand, endpoint, &io, sslContext](asio::yield_context yc) {
String host = endpoint->GetHost(); String host = endpoint->GetHost();
String port = endpoint->GetPort(); String port = endpoint->GetPort();
@ -474,7 +480,7 @@ void ApiListener::AddConnection(const Endpoint::Ptr& endpoint)
Connect(sslConn->lowest_layer(), host, port, yc); Connect(sslConn->lowest_layer(), host, port, yc);
NewClientHandler(yc, sslConn, endpoint->GetName(), RoleClient); NewClientHandler(yc, strand, sslConn, endpoint->GetName(), RoleClient);
endpoint->SetConnecting(false); endpoint->SetConnecting(false);
Log(LogInformation, "ApiListener") Log(LogInformation, "ApiListener")
@ -488,10 +494,13 @@ void ApiListener::AddConnection(const Endpoint::Ptr& endpoint)
}); });
} }
void ApiListener::NewClientHandler(boost::asio::yield_context yc, const std::shared_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole role) void ApiListener::NewClientHandler(
boost::asio::yield_context yc, const Shared<boost::asio::io_context::strand>::Ptr& strand,
const std::shared_ptr<AsioTlsStream>&client, const String& hostname, ConnectionRole role
)
{ {
try { try {
NewClientHandlerInternal(yc, client, hostname, role); NewClientHandlerInternal(yc, strand, client, hostname, role);
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
Log(LogCritical, "ApiListener") Log(LogCritical, "ApiListener")
<< "Exception while handling new API client connection: " << DiagnosticInformation(ex, false); << "Exception while handling new API client connection: " << DiagnosticInformation(ex, false);
@ -506,7 +515,10 @@ void ApiListener::NewClientHandler(boost::asio::yield_context yc, const std::sha
* *
* @param client The new client. * @param client The new client.
*/ */
void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const std::shared_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole role) void ApiListener::NewClientHandlerInternal(
boost::asio::yield_context yc, const Shared<boost::asio::io_context::strand>::Ptr& strand,
const std::shared_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole role
)
{ {
namespace asio = boost::asio; namespace asio = boost::asio;
namespace ssl = asio::ssl; namespace ssl = asio::ssl;
@ -533,7 +545,34 @@ void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const
boost::system::error_code ec; boost::system::error_code ec;
sslConn.async_handshake(role == RoleClient ? sslConn.client : sslConn.server, yc[ec]); {
struct DoneHandshake
{
bool Done = false;
};
auto doneHandshake (Shared<DoneHandshake>::Make());
IoEngine::SpawnCoroutine(*strand, [strand, client, doneHandshake](asio::yield_context yc) {
namespace sys = boost::system;
{
boost::asio::deadline_timer timer (strand->context());
timer.expires_from_now(boost::posix_time::microseconds(intmax_t(Configuration::TlsHandshakeTimeout * 1000000)));
sys::error_code ec;
timer.async_wait(yc[ec]);
}
if (!doneHandshake->Done) {
sys::error_code ec;
client->lowest_layer().cancel(ec);
}
});
sslConn.async_handshake(role == RoleClient ? sslConn.client : sslConn.server, yc[ec]);
doneHandshake->Done = true;
}
if (ec) { if (ec) {
// https://github.com/boostorg/beast/issues/915 // https://github.com/boostorg/beast/issues/915

View File

@ -17,6 +17,7 @@
#include "base/tlsstream.hpp" #include "base/tlsstream.hpp"
#include "base/threadpool.hpp" #include "base/threadpool.hpp"
#include <atomic> #include <atomic>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp> #include <boost/asio/spawn.hpp>
#include <boost/asio/ssl/context.hpp> #include <boost/asio/ssl/context.hpp>
@ -152,8 +153,14 @@ private:
bool AddListener(const String& node, const String& service); bool AddListener(const String& node, const String& service);
void AddConnection(const Endpoint::Ptr& endpoint); void AddConnection(const Endpoint::Ptr& endpoint);
void NewClientHandler(boost::asio::yield_context yc, const std::shared_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole role); void NewClientHandler(
void NewClientHandlerInternal(boost::asio::yield_context yc, const std::shared_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole role); boost::asio::yield_context yc, const Shared<boost::asio::io_context::strand>::Ptr& strand,
const std::shared_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole role
);
void NewClientHandlerInternal(
boost::asio::yield_context yc, const Shared<boost::asio::io_context::strand>::Ptr& strand,
const std::shared_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole role
);
void ListenerCoroutineProc(boost::asio::yield_context yc, const std::shared_ptr<boost::asio::ip::tcp::acceptor>& server, const std::shared_ptr<boost::asio::ssl::context>& sslContext); void ListenerCoroutineProc(boost::asio::yield_context yc, const std::shared_ptr<boost::asio::ip::tcp::acceptor>& server, const std::shared_ptr<boost::asio::ssl::context>& sslContext);
WorkQueue m_RelayQueue; WorkQueue m_RelayQueue;