diff --git a/include/opendht/dht_proxy_client.h b/include/opendht/dht_proxy_client.h index a482d13695922e4fc8575d36d30def9f07a1ce96..1dc9f8708fd7834683d4a6b69dd25e587f5f019c 100644 --- a/include/opendht/dht_proxy_client.h +++ b/include/opendht/dht_proxy_client.h @@ -54,9 +54,7 @@ public: DhtProxyClient(); explicit DhtProxyClient( -#ifdef OPENDHT_PROXY_OPENSSL std::shared_ptr<dht::crypto::Certificate> certificate, -#endif std::function<void()> loopSignal, const std::string& serverHost, const std::string& pushClientId = "", std::shared_ptr<dht::Logger> logger = {}); @@ -331,9 +329,7 @@ private: */ void cancelAllOperations(); -#ifdef OPENDHT_PROXY_OPENSSL std::shared_ptr<dht::crypto::Certificate> serverCertificate_; -#endif std::pair<std::string, std::string> serverHostService_; std::string pushClientId_; diff --git a/include/opendht/dht_proxy_server.h b/include/opendht/dht_proxy_server.h index a345528fdb1f2d27adcec5e7e35718c74f70f3af..65d2b198d8df5112a9bcee0bfc16faadf8fdb838 100644 --- a/include/opendht/dht_proxy_server.h +++ b/include/opendht/dht_proxy_server.h @@ -33,9 +33,7 @@ #include <mutex> #include <restinio/all.hpp> -#ifdef OPENDHT_PROXY_OPENSSL #include <restinio/tls.hpp> -#endif #include "http.h" #ifdef OPENDHT_JSONCPP @@ -96,9 +94,7 @@ public: * it will fails silently */ DhtProxyServer( -#ifdef OPENDHT_PROXY_OPENSSL - dht::crypto::Identity& identity, -#endif + std::shared_ptr<dht::crypto::Identity> identity, std::shared_ptr<DhtRunner> dht, in_port_t port = 8000, const std::string& pushServer = "", std::shared_ptr<dht::Logger> logger = {}); @@ -340,22 +336,21 @@ private: using time_point = clock::time_point; std::shared_ptr<DhtRunner> dht_; - std::shared_ptr<dht::Logger> logger_; Json::StreamWriterBuilder jsonBuilder_; // http server std::thread httpServerThread_; std::unique_ptr<restinio::http_server_t<RestRouterTraits>> httpServer_; -#ifdef OPENDHT_PROXY_OPENSSL std::unique_ptr<asio::const_buffer> pk_; std::unique_ptr<asio::const_buffer> cc_; - std::shared_ptr<dht::crypto::Certificate> serverCertificate_; -#endif + std::shared_ptr<dht::crypto::Identity> serverIdentity_; // http client std::pair<std::string, std::string> pushHostPort_; std::map<unsigned int /*id*/, std::shared_ptr<http::Request>> requests_; + std::shared_ptr<dht::Logger> logger_; + mutable std::mutex statsMutex_; mutable ServerStats stats_; mutable NodeInfo nodeInfo_ {}; diff --git a/include/opendht/http.h b/include/opendht/http.h index bbfea71aa12b3e7eff8cc05b032419d38fe03136..9aceb39f2fb5273d7572a118db06f2e50e9e9cc2 100644 --- a/include/opendht/http.h +++ b/include/opendht/http.h @@ -51,10 +51,10 @@ public: unsigned int id(); bool is_open(); bool is_v6(); + bool is_ssl(); void set_endpoint(const asio::ip::tcp::endpoint& endpoint, - const asio::ssl::verify_mode verify_mode = asio::ssl::verify_none - ); + const asio::ssl::verify_mode verify_mode = asio::ssl::verify_none); asio::streambuf& input(); asio::streambuf& data(); @@ -143,6 +143,8 @@ public: ~Resolver(); + std::string get_service() const; + void add_callback(ResolverCb cb); private: @@ -151,6 +153,7 @@ private: std::mutex mutex_; asio::error_code ec_; + std::string service_; asio::ip::tcp::resolver resolver_; std::vector<asio::ip::tcp::endpoint> endpoints_; @@ -277,9 +280,7 @@ private: std::unique_ptr<Callbacks> cbs_; State state_; -#ifdef OPENDHT_PROXY_OPENSSL std::shared_ptr<dht::crypto::Certificate> certificate_; -#endif std::string service_; std::string host_; diff --git a/src/dht_proxy_client.cpp b/src/dht_proxy_client.cpp index 0e382e0faba4e4d8ba0071b37b48d638a4e28eec..a27c6e237cfa0abbb5cc06fc016dffb7b5d18597 100644 --- a/src/dht_proxy_client.cpp +++ b/src/dht_proxy_client.cpp @@ -70,21 +70,20 @@ struct DhtProxyClient::ProxySearch { DhtProxyClient::DhtProxyClient() {} DhtProxyClient::DhtProxyClient( -#ifdef OPENDHT_PROXY_OPENSSL - std::shared_ptr<dht::crypto::Certificate> certificate, -#endif + std::shared_ptr<dht::crypto::Certificate> certificate, std::function<void()> signal, const std::string& serverHost, const std::string& pushClientId, std::shared_ptr<dht::Logger> logger) : -#ifdef OPENDHT_PROXY_OPENSSL serverCertificate_(certificate), -#endif pushClientId_(pushClientId), loopSignal_(signal), logger_(logger) { // build http client serverHostService_ = splitPort(serverHost); serverHostService_.second = serverHostService_.second.empty() ? "80" : serverHostService_.second; + if (serverCertificate_ and logger_) + logger_->d("[proxy:client] using server certificate for ssl:\n%s", + serverCertificate_->toString(false/*chain*/).c_str()); // resolve once resolver_ = std::make_shared<http::Resolver>(httpContext_, serverHostService_.first, serverHostService_.second, logger_); @@ -345,9 +344,9 @@ DhtProxyClient::get(const InfoHash& key, GetCallback cb, DoneCallback donecb, Va requests_.erase(reqid); } }); -#ifdef OPENDHT_PROXY_OPENSSL + if (serverCertificate_) + request->set_certificate(serverCertificate_); request->set_certificate(serverCertificate_); -#endif request->send(); requests_[reqid] = request; } @@ -481,9 +480,9 @@ DhtProxyClient::doPut(const InfoHash& key, Sp<Value> val, DoneCallback cb, time_ requests_.erase(reqid); } }); -#ifdef OPENDHT_PROXY_OPENSSL + if (serverCertificate_) + request->set_certificate(serverCertificate_); request->set_certificate(serverCertificate_); -#endif request->send(); requests_[reqid] = request; } @@ -677,9 +676,8 @@ DhtProxyClient::queryProxyInfo(std::shared_ptr<InfoState> infoState, const sa_fa if (infoState->cancel.load()) return; -#ifdef OPENDHT_PROXY_OPENSSL - request->set_certificate(serverCertificate_); -#endif + if (serverCertificate_) + request->set_certificate(serverCertificate_); request->send(); requests_[reqid] = request; } @@ -952,9 +950,8 @@ DhtProxyClient::handleExpireListener(const asio::error_code &ec, const InfoHash& requests_.erase(reqid); } }); -#ifdef OPENDHT_PROXY_OPENSSL - request->set_certificate(serverCertificate_); -#endif + if (serverCertificate_) + request->set_certificate(serverCertificate_); request->send(); requests_[reqid] = request; } @@ -1059,9 +1056,8 @@ DhtProxyClient::sendListen(const restinio::http_request_header_t header, requests_.erase(reqid); } }); -#ifdef OPENDHT_PROXY_OPENSSL - request->set_certificate(serverCertificate_); -#endif + if (serverCertificate_) + request->set_certificate(serverCertificate_); request->send(); requests_[reqid] = request; } diff --git a/src/dht_proxy_server.cpp b/src/dht_proxy_server.cpp index fff533afa23b06e5e1fbc9fbc213fd42ec9ad508..62b5a5ed404b7f5c322ab37fccad84e3064de1a1 100644 --- a/src/dht_proxy_server.cpp +++ b/src/dht_proxy_server.cpp @@ -47,13 +47,11 @@ constexpr char RESP_MSG_PUT_FAILED[] = "{\"err\":\"Put failed\"}"; constexpr const std::chrono::minutes PRINT_STATS_PERIOD {2}; DhtProxyServer::DhtProxyServer( -#ifdef OPENDHT_PROXY_OPENSSL - dht::crypto::Identity& identity, -#endif + std::shared_ptr<dht::crypto::Identity> identity, std::shared_ptr<DhtRunner> dht, in_port_t port, const std::string& pushServer, std::shared_ptr<dht::Logger> logger -): - dht_(dht), logger_(logger), lockListener_(std::make_shared<std::mutex>()), +) + : dht_(dht), serverIdentity_(identity), logger_(logger), lockListener_(std::make_shared<std::mutex>()), listeners_(std::make_shared<std::map<restinio::connection_id_t, http::ListenerSession>>()), connListener_(std::make_shared<http::ConnectionListener>(dht, listeners_, lockListener_, logger)), pushServer_(pushServer) @@ -80,30 +78,30 @@ DhtProxyServer::DhtProxyServer( auto settings = makeHttpServerSettings(); settings.port(port); -#ifdef OPENDHT_PROXY_OPENSSL - // save self-signed certificate for Request client - serverCertificate_ = identity.second; - // define tls context - asio::ssl::context tls_context { asio::ssl::context::sslv23 }; - tls_context.set_options(asio::ssl::context::default_workarounds - | asio::ssl::context::no_sslv2 - | asio::ssl::context::single_dh_use); - // save keys in memory & set in tls context - asio::error_code ec; - // node private key - auto pk = identity.first->serialize(); // returns Blob - pk_ = std::make_unique<asio::const_buffer>(static_cast<void*>(pk.data()), (std::size_t) pk.size()); - tls_context.use_private_key(*pk_, asio::ssl::context::file_format::pem, ec); - if (ec) - throw std::runtime_error("Error setting node's private key: " + ec.message()); - // certificate chain - auto cc = identity.second->toString(true/*chain*/); - cc_ = std::make_unique<asio::const_buffer>(static_cast<const void*>(cc.data()), (std::size_t) cc.size()); - tls_context.use_certificate_chain(*cc_, ec); - if (ec) - throw std::runtime_error("Error setting certificate chain: " + ec.message()); - settings.tls_context(std::move(tls_context)); -#endif + if (identity){ + // define tls context + asio::ssl::context tls_context { asio::ssl::context::sslv23 }; + tls_context.set_options(asio::ssl::context::default_workarounds + | asio::ssl::context::no_sslv2 + | asio::ssl::context::single_dh_use); + // save keys in memory & set in tls context + asio::error_code ec; + // node private key + auto pk = identity->first->serialize(); // returns Blob + pk_ = std::make_unique<asio::const_buffer>(static_cast<void*>(pk.data()), (std::size_t) pk.size()); + tls_context.use_private_key(*pk_, asio::ssl::context::file_format::pem, ec); + if (ec) + throw std::runtime_error("Error setting node's private key: " + ec.message()); + // certificate chain + auto cc = identity->second->toString(true/*chain*/); + cc_ = std::make_unique<asio::const_buffer>(static_cast<const void*>(cc.data()), (std::size_t) cc.size()); + tls_context.use_certificate_chain(*cc_, ec); + if (ec) + throw std::runtime_error("Error setting certificate chain: " + ec.message()); + if (logger_) + logger_->d("[proxy:server] using certificate chain for ssl:\n%s", cc.c_str()); + settings.tls_context(std::move(tls_context)); + } httpServer_.reset(new restinio::http_server_t<RestRouterTraits>( restinio::own_io_context(), @@ -733,9 +731,6 @@ DhtProxyServer::sendPushNotification(const std::string& token, Json::Value&& jso requests_.erase(reqid); } }); -#ifdef OPENDHT_PROXY_OPENSSL - request->set_certificate(serverCertificate_); -#endif request->send(); requests_[reqid] = request; } diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp index dced635a23bdc9659a1e42dcd11c0ae1d5fe5c6e..cf4aba9f551a3c125c4a2dba0efd5c14a2e5fb5b 100644 --- a/src/dhtrunner.cpp +++ b/src/dhtrunner.cpp @@ -966,9 +966,7 @@ DhtRunner::enableProxy(bool proxify) // Init the proxy client auto dht_via_proxy = std::unique_ptr<DhtInterface>( new DhtProxyClient( -#ifdef OPENDHT_PROXY_OPENSSL config_.dht_config.id.second, -#endif [this]{ if (config_.threaded) { { diff --git a/src/http.cpp b/src/http.cpp index 09d7be5f589a4f3a43e8e2f0457c799165c254f3..54851f3c29c8f9ae703b99d14697b076d07b1d52 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -38,11 +38,16 @@ Connection::Connection(asio::io_context& ctx, const bool ssl, std::shared_ptr<dh if (ssl){ ssl_ctx_ = std::make_shared<asio::ssl::context>(asio::ssl::context::sslv23); ssl_ctx_->set_default_verify_paths(); - ssl_ctx_->set_verify_mode(asio::ssl::verify_peer); + ssl_ctx_->set_verify_mode(asio::ssl::verify_none); ssl_socket_ = std::make_unique<ssl_socket_t>(ctx_, ssl_ctx_); + if (logger_) + logger_->d("[http:connection:%i] [ssl] https init", id_); } - else + else { socket_ = std::make_unique<socket_t>(ctx); + if (logger_) + logger_->d("[http:connection:%i] http init", id_); + } } Connection::Connection(asio::io_context& ctx, std::shared_ptr<dht::crypto::Certificate> certificate, @@ -62,6 +67,8 @@ Connection::Connection(asio::io_context& ctx, std::shared_ptr<dht::crypto::Certi ssl_ctx_->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert); ssl_socket_ = std::make_unique<ssl_socket_t>(ctx_, ssl_ctx_); + if (logger_) + logger_->d("[http:connection:%i] [ssl] https init", id_); } Connection::~Connection() @@ -99,14 +106,22 @@ Connection::is_v6() return endpoint_.address().is_v6(); } +bool +Connection::is_ssl() +{ + return ssl_ctx_ ? true : false; +} + void Connection::set_endpoint(const asio::ip::tcp::endpoint& endpoint, const asio::ssl::verify_mode verify_mode) { endpoint_ = endpoint; - if (ssl_ctx_){ + if (ssl_ctx_ and verify_mode != asio::ssl::verify_none){ auto hostname = endpoint_.address().to_string(); ssl_socket_->asio_ssl_stream().set_verify_mode(verify_mode); ssl_socket_->asio_ssl_stream().set_verify_callback(asio::ssl::rfc2818_verification(hostname)); + if (logger_) + logger_->d("[http:connection:%i] [ssl] verify %s rfc2818 compliance", id_, hostname.c_str()); } } @@ -189,7 +204,7 @@ Connection::timeout(const std::chrono::seconds timeout, HandlerCb cb) { if (!is_open()){ if (logger_) - logger_->e("[connection:%i] closed, can't timeout", id_); + logger_->e("[http:connection:%i] closed, can't timeout", id_); return; } if (!timeout_timer_) @@ -200,7 +215,7 @@ Connection::timeout(const std::chrono::seconds timeout, HandlerCb cb) return; else if (ec){ if (logger_) - logger_->e("[connection:%i] timeout error: %s", id_, ec.message().c_str()); + logger_->e("[http:connection:%i] timeout error: %s", id_, ec.message().c_str()); } if (cb) cb(ec); @@ -269,6 +284,7 @@ Resolver::Resolver(asio::io_context& ctx, const std::string& host, const std::st std::shared_ptr<dht::Logger> logger) : resolver_(ctx), logger_(logger) { + service_ = service; resolve(host, service); } @@ -295,6 +311,12 @@ Resolver::~Resolver() } } +std::string +Resolver::get_service() const +{ + return service_; +} + void Resolver::add_callback(ResolverCb cb) { @@ -400,13 +422,11 @@ Request::get_connection() const return conn_; } -#ifdef OPENDHT_PROXY_OPENSSL void Request::set_certificate(std::shared_ptr<dht::crypto::Certificate> certificate) { certificate_ = certificate; } -#endif void Request::set_logger(std::shared_ptr<dht::Logger> logger) @@ -623,48 +643,42 @@ Request::connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, HandlerCb cb) logger_->d("[http:request:%i] [connect] begin endpoints { %s}", id_, eps.c_str()); } if (certificate_) - conn_ = std::make_shared<Connection>(ctx_, certificate_); + conn_ = std::make_shared<Connection>(ctx_, certificate_, logger_); + else if (resolver_->get_service() == "https" or resolver_->get_service() == "443") + conn_ = std::make_shared<Connection>(ctx_, true/*ssl*/, logger_); else - conn_ = std::make_shared<Connection>(ctx_); + conn_ = std::make_shared<Connection>(ctx_, false/*ssl*/, logger_); // try to connect to any until one works conn_->async_connect(std::move(endpoints), [this, cb] (const asio::error_code& ec, const asio::ip::tcp::endpoint& endpoint){ if (ec == asio::error::operation_aborted) return; - else if (ec){ - if (logger_) - logger_->e("[http:request:%i] [connect] failed with all endpoints", id_); - } + else if (ec and logger_) + logger_->e("[http:request:%i] [connect] failed with all endpoints", id_); else { if (logger_) logger_->d("[http:request:%i] [connect] success", id_); - // save & verify the endpoint + if (!certificate_) - conn_->set_endpoint(endpoint); -#ifdef OPENDHT_PROXY_OPENSSL - else if (certificate_) + conn_->set_endpoint(endpoint, asio::ssl::verify_none); + else conn_->set_endpoint(endpoint, asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert); -#endif - } -#ifdef OPENDHT_PROXY_OPENSSL - conn_->async_handshake([this, cb](const asio::error_code& ec){ - if (ec){ - if (logger_) - logger_->e("[http:request:%i] [connect:ssl] error: %s", id_, ec.message().c_str()); - } - else { - if (logger_) - logger_->d("[http:request:%i] [connect:ssl] secure channel established", id_); + if (conn_->is_ssl()){ + conn_->async_handshake([this, cb](const asio::error_code& ec){ + if (ec and logger_) + logger_->e("[http:request:%i] [ssl:handshake] error: %s", id_, ec.message().c_str()); + else if (logger_) + logger_->d("[http:request:%i] [ssl:handshake] secure channel established", id_); + if (cb) + cb(ec); + }); + return; } - if (cb) - cb(ec); - }); -#else + } if (cb) cb(ec); -#endif }); } diff --git a/tests/dhtproxytester.cpp b/tests/dhtproxytester.cpp index 98bf654f1096e22e81c4925dda11f4e2681dc83f..ecd03e010ec94d66a6db6167610d166b54d38656 100644 --- a/tests/dhtproxytester.cpp +++ b/tests/dhtproxytester.cpp @@ -41,20 +41,17 @@ DhtProxyTester::setUp() { nodeProxy->run(0, /*identity*/{}, /*threaded*/true); nodeProxy->bootstrap(nodePeer.getBound()); -#ifdef OPENDHT_PROXY_OPENSSL serverCAIdentity = std::make_unique<dht::crypto::Identity>( dht::crypto::generateEcIdentity("DHT Node CA")); - serverIdentity = std::make_unique<dht::crypto::Identity>( + serverIdentity = std::make_shared<dht::crypto::Identity>( dht::crypto::generateIdentity("DHT Node", *serverCAIdentity)); -#endif serverProxy = std::unique_ptr<dht::DhtProxyServer>( new dht::DhtProxyServer( -#ifdef OPENDHT_PUSH_NOTIFICATIONS - *serverIdentity, -#endif + serverIdentity, nodeProxy, 8080, /*pushServer*/"127.0.0.1:8090", logger)); + clientConfig.dht_config.id = *serverIdentity; clientConfig.dht_config.node_config.maintain_storage = false; clientConfig.threaded = true; clientConfig.push_node_id = "dhtnode"; diff --git a/tests/dhtproxytester.h b/tests/dhtproxytester.h index 5739235d6bf83f8d500e583773f1ff2a15b98e42..c20867f3b6e17cf81afec22102ebd757660d738a 100644 --- a/tests/dhtproxytester.h +++ b/tests/dhtproxytester.h @@ -68,7 +68,7 @@ class DhtProxyTester : public CppUnit::TestFixture { std::shared_ptr<dht::DhtRunner> nodeProxy; #ifdef OPENDHT_PUSH_NOTIFICATIONS - std::unique_ptr<dht::crypto::Identity> serverIdentity; + std::shared_ptr<dht::crypto::Identity> serverIdentity; std::unique_ptr<dht::crypto::Identity> serverCAIdentity; #endif std::unique_ptr<dht::DhtProxyServer> serverProxy; diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp index 197515cce94849d10c6ba99daa4e58e7d0eff062..bdcfcb55e9fac37a90e313c69da3d1308afe8a2b 100644 --- a/tools/dhtnode.cpp +++ b/tools/dhtnode.cpp @@ -227,9 +227,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params unsigned int port = std::stoi(idstr); proxies.emplace(port, std::unique_ptr<DhtProxyServer>( new DhtProxyServer( -#ifdef OPENDHT_PROXY_OPENSSL - params.id, -#endif + std::make_shared<dht::crypto::Identity>(params.id), node, port #ifdef OPENDHT_PUSH_NOTIFICATIONS ,pushServer @@ -564,9 +562,7 @@ main(int argc, char **argv) #ifdef OPENDHT_PROXY_SERVER proxies.emplace(params.proxyserver, std::unique_ptr<DhtProxyServer>( new DhtProxyServer( -#ifdef OPENDHT_PROXY_OPENSSL - params.id, -#endif + std::make_shared<dht::crypto::Identity>(params.id), node, params.proxyserver, params.pushserver, context.logger))); #else std::cerr << "DHT proxy server requested but OpenDHT built without proxy server support." << std::endl;