From 90071f831853125249cb967c90f2ad2b7286d744 Mon Sep 17 00:00:00 2001 From: Alexandros Konstantinakis-Karmis Date: Fri, 29 May 2020 15:25:20 +0300 Subject: [PATCH] add local endpoint selection for tls client connections --- src/asio_client_session.cc | 21 +++++++++++++++++++++ src/asio_client_session_tls_impl.cc | 23 ++++++++++++++++++++++- src/asio_client_session_tls_impl.h | 9 ++++++++- src/asio_common.cc | 22 ++++++++++++++++++++++ src/asio_common.h | 4 +++- src/includes/nghttp2/asio_http2_client.h | 15 +++++++++++++++ 6 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/asio_client_session.cc b/src/asio_client_session.cc index 5cf01c74..91f44771 100644 --- a/src/asio_client_session.cc +++ b/src/asio_client_session.cc @@ -78,6 +78,16 @@ session::session(boost::asio::io_service &io_service, impl_->start_resolve(host, service); } +session::session(boost::asio::io_service &io_service, + boost::asio::ssl::context &tls_ctx, + const boost::asio::ip::tcp::endpoint &local_endpoint, + const std::string &host, + const std::string &service) + : impl_(std::make_shared( + io_service, tls_ctx, local_endpoint, host, service, boost::posix_time::seconds(60))) { + impl_->start_resolve(host, service); +} + session::session(boost::asio::io_service &io_service, boost::asio::ssl::context &tls_ctx, const std::string &host, const std::string &service, @@ -87,6 +97,17 @@ session::session(boost::asio::io_service &io_service, impl_->start_resolve(host, service); } +session::session(boost::asio::io_service &io_service, + boost::asio::ssl::context &tls_ctx, + const boost::asio::ip::tcp::endpoint &local_endpoint, + const std::string &host, + const std::string &service, + const boost::posix_time::time_duration &connect_timeout) + : impl_(std::make_shared(io_service, tls_ctx, local_endpoint, host, + service, connect_timeout)) { + impl_->start_resolve(host, service); +} + session::~session() {} session::session(session &&other) noexcept : impl_(std::move(other.impl_)) {} diff --git a/src/asio_client_session_tls_impl.cc b/src/asio_client_session_tls_impl.cc index 377886ca..32772d57 100644 --- a/src/asio_client_session_tls_impl.cc +++ b/src/asio_client_session_tls_impl.cc @@ -33,7 +33,7 @@ session_tls_impl::session_tls_impl( boost::asio::io_service &io_service, boost::asio::ssl::context &tls_ctx, const std::string &host, const std::string &service, const boost::posix_time::time_duration &connect_timeout) - : session_impl(io_service, connect_timeout), socket_(io_service, tls_ctx) { + : session_impl(io_service, connect_timeout), tcp_socket_(io_service), socket_(tcp_socket_, tls_ctx) { // this callback setting is no effect is // ssl::context::set_verify_mode(boost::asio::ssl::verify_peer) is // not used, which is what we want. @@ -44,6 +44,27 @@ session_tls_impl::session_tls_impl( } } +session_tls_impl::session_tls_impl( + boost::asio::io_service &io_service, boost::asio::ssl::context &tls_ctx, + const boost::asio::ip::tcp::endpoint &local_endpoint, + const std::string &host, const std::string &service, + const boost::posix_time::time_duration &connect_timeout) + : session_impl(io_service, connect_timeout), tcp_socket_(io_service), socket_(tcp_socket_, tls_ctx) { + // this callback setting is no effect is + // ssl::context::set_verify_mode(boost::asio::ssl::verify_peer) is + // not used, which is what we want. + tcp_socket_.open(local_endpoint.protocol()); + boost::asio::socket_base::reuse_address option(true); + tcp_socket_.set_option(option); + tcp_socket_.bind(local_endpoint); + + socket_.set_verify_callback(boost::asio::ssl::rfc2818_verification(host)); + auto ssl = socket_.native_handle(); + if (!util::numeric_host(host.c_str())) { + SSL_set_tlsext_host_name(ssl, host.c_str()); + } +} + session_tls_impl::~session_tls_impl() {} void session_tls_impl::start_connect(tcp::resolver::iterator endpoint_it) { diff --git a/src/asio_client_session_tls_impl.h b/src/asio_client_session_tls_impl.h index 645c60f4..c095b284 100644 --- a/src/asio_client_session_tls_impl.h +++ b/src/asio_client_session_tls_impl.h @@ -35,7 +35,7 @@ namespace client { using boost::asio::ip::tcp; -using ssl_socket = boost::asio::ssl::stream; +using ssl_socket = boost::asio::ssl::stream; class session_tls_impl : public session_impl { public: @@ -43,6 +43,12 @@ public: boost::asio::ssl::context &tls_ctx, const std::string &host, const std::string &service, const boost::posix_time::time_duration &connect_timeout); + session_tls_impl(boost::asio::io_service &io_service, + boost::asio::ssl::context &tls_ctx, + const boost::asio::ip::tcp::endpoint & local_endpoint, + const std::string &host, + const std::string &service, + const boost::posix_time::time_duration &connect_timeout); virtual ~session_tls_impl(); virtual void start_connect(tcp::resolver::iterator endpoint_it); @@ -56,6 +62,7 @@ public: virtual void shutdown_socket(); private: + tcp::socket tcp_socket_; ssl_socket socket_; }; diff --git a/src/asio_common.cc b/src/asio_common.cc index 90762d3d..15145eb6 100644 --- a/src/asio_common.cc +++ b/src/asio_common.cc @@ -193,5 +193,27 @@ bool tls_h2_negotiated(ssl_socket &socket) { return util::check_h2_is_selected(StringRef{next_proto, next_proto_len}); } +bool tls_h2_negotiated(ssl_tcp_socket &socket) { + auto ssl = socket.native_handle(); + + const unsigned char *next_proto = nullptr; + unsigned int next_proto_len = 0; + +#ifndef OPENSSL_NO_NEXTPROTONEG + SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len); +#endif // !OPENSSL_NO_NEXTPROTONEG +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + if (next_proto == nullptr) { + SSL_get0_alpn_selected(ssl, &next_proto, &next_proto_len); + } +#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L + + if (next_proto == nullptr) { + return false; + } + + return util::check_h2_is_selected(StringRef{next_proto, next_proto_len}); +} + } // namespace asio_http2 } // namespace nghttp2 diff --git a/src/asio_common.h b/src/asio_common.h index 7eacfa51..fbf68c18 100644 --- a/src/asio_common.h +++ b/src/asio_common.h @@ -62,9 +62,11 @@ void split_path(uri_ref &dst, InputIt first, InputIt last) { using boost::asio::ip::tcp; -using ssl_socket = boost::asio::ssl::stream; +using ssl_socket = boost::asio::ssl::stream; +using ssl_tcp_socket = boost::asio::ssl::stream; bool tls_h2_negotiated(ssl_socket &socket); +bool tls_h2_negotiated(ssl_tcp_socket &socket); } // namespace asio_http2 diff --git a/src/includes/nghttp2/asio_http2_client.h b/src/includes/nghttp2/asio_http2_client.h index 59ba9b26..0ecc5375 100644 --- a/src/includes/nghttp2/asio_http2_client.h +++ b/src/includes/nghttp2/asio_http2_client.h @@ -175,6 +175,13 @@ public: boost::asio::ssl::context &tls_context, const std::string &host, const std::string &service); + // save as previous with pegged local endpoint + session(boost::asio::io_service &io_service, + boost::asio::ssl::context &tls_context, + const boost::asio::ip::tcp::endpoint &local_endpoint, + const std::string &host, + const std::string &service); + // Starts HTTP/2 session by connecting to |host| and |service| // (e.g., "443") using encrypted SSL/TLS connection with given // connect timeout. @@ -183,6 +190,14 @@ public: const std::string &service, const boost::posix_time::time_duration &connect_timeout); + // same as previous with pegged local endpoint + session(boost::asio::io_service &io_service, + boost::asio::ssl::context &tls_context, + const boost::asio::ip::tcp::endpoint &local_endpoint, + const std::string &host, + const std::string &service, + const boost::posix_time::time_duration &connect_timeout); + ~session(); session(session &&other) noexcept;