#include "base/stream.hpp"
#include "base/tlsutility.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/stream.hpp>
namespace icinga
{
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 */
#include "base/context.hpp"
#include "base/statsfunction.hpp"
#include "base/exception.hpp"
+#include <boost/asio/buffer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ip/v6_only.hpp>
#include <boost/asio/spawn.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_mode.hpp>
+#include <boost/system/error_code.hpp>
#include <climits>
#include <fstream>
#include <memory>
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 ssl = asio::ssl;
- using asio::ip::tcp;
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 (;;) {
try {
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);
}
}
}
}
-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 {
NewClientHandlerInternal(yc, client, hostname, role);
*
* @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;
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) {
#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<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;
Endpoint::Ptr endpoint;
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)
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/ssl/context.hpp>
-#include <boost/asio/ssl/stream.hpp>
#include <set>
namespace icinga
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<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<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<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);
static ThreadPool& GetTP();