mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-16 18:24:31 +02:00
ApiListener: detect protocol
This commit is contained in:
parent
539855bac1
commit
e21956e26e
@ -9,7 +9,12 @@
|
|||||||
#include "base/stream.hpp"
|
#include "base/stream.hpp"
|
||||||
#include "base/tlsutility.hpp"
|
#include "base/tlsutility.hpp"
|
||||||
#include "base/fifo.hpp"
|
#include "base/fifo.hpp"
|
||||||
|
#include <utility>
|
||||||
|
#include <boost/asio/buffered_stream.hpp>
|
||||||
|
#include <boost/asio/io_service.hpp>
|
||||||
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
#include <boost/asio/ssl/context.hpp>
|
#include <boost/asio/ssl/context.hpp>
|
||||||
|
#include <boost/asio/ssl/stream.hpp>
|
||||||
|
|
||||||
namespace icinga
|
namespace icinga
|
||||||
{
|
{
|
||||||
@ -94,6 +99,33 @@ private:
|
|||||||
void CloseInternal(bool inDestructor);
|
void CloseInternal(bool inDestructor);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AsioTlsStreamHack : public boost::asio::ssl::stream<boost::asio::ip::tcp::socket>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline
|
||||||
|
AsioTlsStreamHack(std::pair<boost::asio::io_service*, boost::asio::ssl::context*>& init)
|
||||||
|
: stream(*init.first, *init.second)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsioTlsStream : public boost::asio::buffered_stream<AsioTlsStreamHack>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline
|
||||||
|
AsioTlsStream(boost::asio::io_service& ioService, boost::asio::ssl::context& sslContext)
|
||||||
|
: AsioTlsStream(std::make_pair(&ioService, &sslContext))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline
|
||||||
|
AsioTlsStream(std::pair<boost::asio::io_service*, boost::asio::ssl::context*> init)
|
||||||
|
: buffered_stream(init)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* TLSSTREAM_H */
|
#endif /* TLSSTREAM_H */
|
||||||
|
@ -19,13 +19,14 @@
|
|||||||
#include "base/context.hpp"
|
#include "base/context.hpp"
|
||||||
#include "base/statsfunction.hpp"
|
#include "base/statsfunction.hpp"
|
||||||
#include "base/exception.hpp"
|
#include "base/exception.hpp"
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/asio/ip/tcp.hpp>
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
#include <boost/asio/ip/v6_only.hpp>
|
#include <boost/asio/ip/v6_only.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/asio/ssl/stream.hpp>
|
|
||||||
#include <boost/asio/ssl/verify_context.hpp>
|
#include <boost/asio/ssl/verify_context.hpp>
|
||||||
#include <boost/asio/ssl/verify_mode.hpp>
|
#include <boost/asio/ssl/verify_mode.hpp>
|
||||||
|
#include <boost/system/error_code.hpp>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -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<boost::asio::ip::tcp::acceptor>& server, const std::shared_ptr<boost::asio::ssl::context>& sslContext)
|
void ApiListener::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)
|
||||||
{
|
{
|
||||||
namespace asio = boost::asio;
|
namespace asio = boost::asio;
|
||||||
namespace ssl = asio::ssl;
|
|
||||||
using asio::ip::tcp;
|
|
||||||
|
|
||||||
auto& io (server->get_io_service());
|
auto& io (server->get_io_service());
|
||||||
auto sslConn (std::make_shared<ssl::stream<tcp::socket>>(io, *sslContext));
|
auto sslConn (std::make_shared<AsioTlsStream>(io, *sslContext));
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
try {
|
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); });
|
asio::spawn(io, [this, sslConn](asio::yield_context yc) { NewClientHandler(yc, sslConn, String(), RoleServer); });
|
||||||
|
|
||||||
sslConn = std::make_shared<ssl::stream<tcp::socket>>(io, *sslContext);
|
sslConn = std::make_shared<AsioTlsStream>(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<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>& client, const String& hostname, ConnectionRole role)
|
void ApiListener::NewClientHandler(boost::asio::yield_context yc, const std::shared_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole role)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
NewClientHandlerInternal(yc, client, hostname, role);
|
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.
|
* @param client The new client.
|
||||||
*/
|
*/
|
||||||
void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>& client, const String& hostname, ConnectionRole role)
|
void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const std::shared_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole role)
|
||||||
{
|
{
|
||||||
namespace ssl = boost::asio::ssl;
|
namespace asio = boost::asio;
|
||||||
|
namespace ssl = asio::ssl;
|
||||||
|
|
||||||
String conninfo;
|
String conninfo;
|
||||||
|
|
||||||
@ -669,12 +669,14 @@ void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const
|
|||||||
conninfo = conninfo_.str();
|
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;
|
bool verify_ok = false;
|
||||||
String verifyError;
|
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;
|
verify_ok = preverified;
|
||||||
|
|
||||||
if (!preverified) {
|
if (!preverified) {
|
||||||
@ -697,20 +699,20 @@ void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const
|
|||||||
|
|
||||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||||
if (!hostname.IsEmpty()) {
|
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 */
|
#endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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) {
|
} catch (const std::exception& ex) {
|
||||||
Log(LogCritical, "ApiListener")
|
Log(LogCritical, "ApiListener")
|
||||||
<< "Client TLS handshake failed (" << conninfo << "): " << DiagnosticInformation(ex, false);
|
<< "Client TLS handshake failed (" << conninfo << "): " << DiagnosticInformation(ex, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<X509> cert (SSL_get_peer_certificate(client->native_handle()), X509_free);
|
std::shared_ptr<X509> cert (SSL_get_peer_certificate(sslConn.native_handle()), X509_free);
|
||||||
String identity;
|
String identity;
|
||||||
Endpoint::Ptr endpoint;
|
Endpoint::Ptr endpoint;
|
||||||
|
|
||||||
@ -753,6 +755,41 @@ void ApiListener::NewClientHandlerInternal(boost::asio::yield_context yc, const
|
|||||||
Log(LogInformation, "ApiListener")
|
Log(LogInformation, "ApiListener")
|
||||||
<< "New client connection " << conninfo << " (no client certificate)";
|
<< "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)
|
void ApiListener::SyncClient(const JsonRpcConnection::Ptr& aclient, const Endpoint::Ptr& endpoint, bool needSync)
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#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/asio/ssl/stream.hpp>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
namespace icinga
|
namespace icinga
|
||||||
@ -134,8 +133,8 @@ private:
|
|||||||
void NewClientHandler(const Socket::Ptr& client, const String& hostname, ConnectionRole role);
|
void NewClientHandler(const Socket::Ptr& client, const String& hostname, ConnectionRole role);
|
||||||
void NewClientHandlerInternal(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<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>& client, const String& hostname, ConnectionRole role);
|
void NewClientHandler(boost::asio::yield_context yc, const std::shared_ptr<AsioTlsStream>& client, const String& hostname, ConnectionRole role);
|
||||||
void NewClientHandlerInternal(boost::asio::yield_context yc, const std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>& client, const String& hostname, ConnectionRole role);
|
void NewClientHandlerInternal(boost::asio::yield_context yc, 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);
|
||||||
|
|
||||||
static ThreadPool& GetTP();
|
static ThreadPool& GetTP();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user