From e21956e26e7edc20d0b75c331f79405cd980867e Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 12 Feb 2019 14:56:47 +0100 Subject: [PATCH] ApiListener: detect protocol --- lib/base/tlsstream.hpp | 32 +++++++++++++++++++ lib/remote/apilistener.cpp | 63 ++++++++++++++++++++++++++++++-------- lib/remote/apilistener.hpp | 5 ++- 3 files changed, 84 insertions(+), 16 deletions(-) diff --git a/lib/base/tlsstream.hpp b/lib/base/tlsstream.hpp index cd3d0abfa..cca8cb286 100644 --- a/lib/base/tlsstream.hpp +++ b/lib/base/tlsstream.hpp @@ -9,7 +9,12 @@ #include "base/stream.hpp" #include "base/tlsutility.hpp" #include "base/fifo.hpp" +#include +#include +#include +#include #include +#include namespace icinga { @@ -94,6 +99,33 @@ private: void CloseInternal(bool inDestructor); }; +class AsioTlsStreamHack : public boost::asio::ssl::stream +{ +public: + inline + AsioTlsStreamHack(std::pair& init) + : stream(*init.first, *init.second) + { + } +}; + +class AsioTlsStream : public boost::asio::buffered_stream +{ +public: + inline + AsioTlsStream(boost::asio::io_service& ioService, boost::asio::ssl::context& sslContext) + : AsioTlsStream(std::make_pair(&ioService, &sslContext)) + { + } + +private: + inline + AsioTlsStream(std::pair init) + : buffered_stream(init) + { + } +}; + } #endif /* TLSSTREAM_H */ diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp index 4adb9035b..3f882a3d1 100644 --- a/lib/remote/apilistener.cpp +++ b/lib/remote/apilistener.cpp @@ -19,13 +19,14 @@ #include "base/context.hpp" #include "base/statsfunction.hpp" #include "base/exception.hpp" +#include #include #include #include #include -#include #include #include +#include #include #include #include @@ -390,11 +391,9 @@ bool ApiListener::AddListener(const String& node, const String& service) void ApiListener::ListenerCoroutineProc(boost::asio::yield_context yc, const std::shared_ptr& server, const std::shared_ptr& sslContext) { namespace asio = boost::asio; - namespace ssl = asio::ssl; - using asio::ip::tcp; auto& io (server->get_io_service()); - auto sslConn (std::make_shared>(io, *sslContext)); + auto sslConn (std::make_shared(io, *sslContext)); for (;;) { try { @@ -406,7 +405,7 @@ void ApiListener::ListenerCoroutineProc(boost::asio::yield_context yc, const std asio::spawn(io, [this, sslConn](asio::yield_context yc) { NewClientHandler(yc, sslConn, String(), RoleServer); }); - sslConn = std::make_shared>(io, *sslContext); + sslConn = std::make_shared(io, *sslContext); } } @@ -629,7 +628,7 @@ void ApiListener::NewClientHandlerInternal(const Socket::Ptr& client, const Stri } } -void ApiListener::NewClientHandler(boost::asio::yield_context yc, const std::shared_ptr>& client, const String& hostname, ConnectionRole role) +void ApiListener::NewClientHandler(boost::asio::yield_context yc, const std::shared_ptr& client, const String& hostname, ConnectionRole role) { try { NewClientHandlerInternal(yc, client, hostname, role); @@ -647,9 +646,10 @@ void ApiListener::NewClientHandler(boost::asio::yield_context yc, const std::sha * * @param client The new client. */ -void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const std::shared_ptr>& client, const String& hostname, ConnectionRole role) +void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const std::shared_ptr& client, const String& hostname, ConnectionRole role) { - namespace ssl = boost::asio::ssl; + namespace asio = boost::asio; + namespace ssl = asio::ssl; String conninfo; @@ -669,12 +669,14 @@ void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const conninfo = conninfo_.str(); } - client->set_verify_mode(ssl::verify_peer | ssl::verify_client_once); + auto& sslConn (client->next_layer()); + + sslConn.set_verify_mode(ssl::verify_peer | ssl::verify_client_once); bool verify_ok = false; String verifyError; - client->set_verify_callback([&verify_ok, &verifyError](bool preverified, ssl::verify_context& ctx) { + sslConn.set_verify_callback([&verify_ok, &verifyError](bool preverified, ssl::verify_context& ctx) { verify_ok = preverified; if (!preverified) { @@ -697,20 +699,20 @@ void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if (!hostname.IsEmpty()) { - SSL_set_tlsext_host_name(client->native_handle(), serverName.CStr()); + SSL_set_tlsext_host_name(sslConn.native_handle(), serverName.CStr()); } #endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */ } try { - client->async_handshake(role == RoleClient ? client->client : client->server, yc); + sslConn.async_handshake(role == RoleClient ? sslConn.client : sslConn.server, yc); } catch (const std::exception& ex) { Log(LogCritical, "ApiListener") << "Client TLS handshake failed (" << conninfo << "): " << DiagnosticInformation(ex, false); return; } - std::shared_ptr cert (SSL_get_peer_certificate(client->native_handle()), X509_free); + std::shared_ptr cert (SSL_get_peer_certificate(sslConn.native_handle()), X509_free); String identity; Endpoint::Ptr endpoint; @@ -753,6 +755,41 @@ void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const Log(LogInformation, "ApiListener") << "New client connection " << conninfo << " (no client certificate)"; } + + ClientType ctype; + + if (role != RoleClient) { + { + boost::system::error_code ec; + + if (client->async_fill(yc[ec]) == 0u) { + if (identity.IsEmpty()) { + Log(LogInformation, "ApiListener") + << "No data received on new API connection. " + << "Ensure that the remote endpoints are properly configured in a cluster setup."; + } else { + Log(LogWarning, "ApiListener") + << "No data received on new API connection for identity '" << identity << "'. " + << "Ensure that the remote endpoints are properly configured in a cluster setup."; + } + + return; + } + } + + char firstByte = 0; + + { + asio::mutable_buffer firstByteBuf (&firstByte, 1); + client->peek(firstByteBuf); + } + + if (firstByte >= '0' && firstByte <= '9') { + ctype = ClientJsonRpc; + } else { + ctype = ClientHttp; + } + } } void ApiListener::SyncClient(const JsonRpcConnection::Ptr& aclient, const Endpoint::Ptr& endpoint, bool needSync) diff --git a/lib/remote/apilistener.hpp b/lib/remote/apilistener.hpp index e8b578aba..093837493 100644 --- a/lib/remote/apilistener.hpp +++ b/lib/remote/apilistener.hpp @@ -17,7 +17,6 @@ #include #include #include -#include #include namespace icinga @@ -134,8 +133,8 @@ private: void NewClientHandler(const Socket::Ptr& client, const String& hostname, ConnectionRole role); void NewClientHandlerInternal(const Socket::Ptr& client, const String& hostname, ConnectionRole role); - void NewClientHandler(boost::asio::yield_context yc, const std::shared_ptr>& client, const String& hostname, ConnectionRole role); - void NewClientHandlerInternal(boost::asio::yield_context yc, const std::shared_ptr>& client, const String& hostname, ConnectionRole role); + void NewClientHandler(boost::asio::yield_context yc, const std::shared_ptr& client, const String& hostname, ConnectionRole role); + void NewClientHandlerInternal(boost::asio::yield_context yc, const std::shared_ptr& client, const String& hostname, ConnectionRole role); void ListenerCoroutineProc(boost::asio::yield_context yc, const std::shared_ptr& server, const std::shared_ptr& sslContext); static ThreadPool& GetTP();