This is an automated email from the ASF dual-hosted git repository. grag pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mesos.git
commit e258059d49779a02b6267a9d0829bd244b882ed5 Author: Joseph Wu <jos...@mesosphere.io> AuthorDate: Wed Feb 26 17:14:50 2020 +0100 SSL Socket: Moved accept callback logic into protected function. To support SSL downgrades, this logic will need to be called from two potential callsites. Also fixes a slight typo in a comment within the moved code. Review: https://reviews.apache.org/r/72014/ --- 3rdparty/libprocess/src/ssl/openssl_socket.cpp | 185 +++++++++++++------------ 3rdparty/libprocess/src/ssl/openssl_socket.hpp | 6 + 2 files changed, 104 insertions(+), 87 deletions(-) diff --git a/3rdparty/libprocess/src/ssl/openssl_socket.cpp b/3rdparty/libprocess/src/ssl/openssl_socket.cpp index 74f9fe2..43909f0 100644 --- a/3rdparty/libprocess/src/ssl/openssl_socket.cpp +++ b/3rdparty/libprocess/src/ssl/openssl_socket.cpp @@ -573,93 +573,7 @@ Future<std::shared_ptr<SocketImpl>> OpenSSLSocketImpl::accept() return Break(); } - // Wrap this new socket up into our SSL wrapper class by releasing - // the FD and creating a new OpenSSLSocketImpl object with the FD. - const std::shared_ptr<OpenSSLSocketImpl> ssl_socket = - std::make_shared<OpenSSLSocketImpl>(socket->release()); - - // Set up SSL object. - SSL* accept_ssl = SSL_new(openssl::context()); - if (accept_ssl == nullptr) { - self->accept_queue.put(Failure("Accept failed, SSL_new")); - return Continue(); - } - - Try<Address> peer_address = network::peer(ssl_socket->get()); - if (!peer_address.isSome()) { - SSL_free(accept_ssl); - self->accept_queue.put( - Failure("Could not determine peer IP for connection")); - return Continue(); - } - - // NOTE: Right now, `openssl::configure_socket` does not do anything - // in server mode, but we still pass the correct peer address to - // enable modules to implement application-level logic in the future. - Try<Nothing> configured = openssl::configure_socket( - accept_ssl, Mode::SERVER, peer_address.get(), None()); - - if (configured.isError()) { - SSL_free(accept_ssl); - self->accept_queue.put( - Failure("Could not configure socket: " + configured.error())); - return Continue(); - } - - // Set the SSL context in server mode. - SSL_set_accept_state(accept_ssl); - - // Pass ownership of `accept_ssl` to the newly accepted socket, - // and wtart the SSL handshake. When the SSL handshake completes, - // the listening socket will place the result (failure or success) - // onto the listening socket's `accept_queue`. - // - // TODO(josephw): Add a timeout to catch/close incoming sockets which - // never finish the SSL handshake. - ssl_socket->set_ssl_and_do_handshake(accept_ssl) - .onAny([weak_self, ssl_socket](Future<size_t> result) { - std::shared_ptr<OpenSSLSocketImpl> self(weak_self.lock()); - - if (self == nullptr) { - return; - } - - if (result.isFailed()) { - self->accept_queue.put(Failure(result.failure())); - return; - } - - // For verification purposes, we need to grab the address (again). - Try<Address> address = network::address(ssl_socket->get()); - if (address.isError()) { - self->accept_queue.put( - Failure("Failed to get address: " + address.error())); - return; - } - - Try<inet::Address> inet_address = - network::convert<inet::Address>(address.get()); - - Try<Nothing> verify = openssl::verify( - ssl_socket->ssl, - Mode::SERVER, - None(), - inet_address.isSome() - ? Some(inet_address->ip) - : Option<net::IP>::none()); - - if (verify.isError()) { - VLOG(1) << "Failed accept, verification error: " - << verify.error(); - - self->accept_queue.put(Failure(verify.error())); - return; - } - - self->accept_queue.put(ssl_socket); - }); - - return Continue(); + return self->handle_accept_callback(socket); }); accept_loop_started.done(); @@ -735,6 +649,103 @@ Try<Nothing, SocketError> OpenSSLSocketImpl::shutdown(int how) } +Future<ControlFlow<Nothing>> OpenSSLSocketImpl::handle_accept_callback( + const std::shared_ptr<SocketImpl>& socket) +{ + // Wrap this new socket up into our SSL wrapper class by releasing + // the FD and creating a new OpenSSLSocketImpl object with the FD. + const std::shared_ptr<OpenSSLSocketImpl> ssl_socket = + std::make_shared<OpenSSLSocketImpl>(socket->release()); + + // Set up SSL object. + SSL* accept_ssl = SSL_new(openssl::context()); + if (accept_ssl == nullptr) { + accept_queue.put(Failure("Accept failed, SSL_new")); + return Continue(); + } + + Try<Address> peer_address = network::peer(ssl_socket->get()); + if (!peer_address.isSome()) { + SSL_free(accept_ssl); + accept_queue.put( + Failure("Could not determine peer IP for connection")); + return Continue(); + } + + // NOTE: Right now, `openssl::configure_socket` does not do anything + // in server mode, but we still pass the correct peer address to + // enable modules to implement application-level logic in the future. + Try<Nothing> configured = openssl::configure_socket( + accept_ssl, Mode::SERVER, peer_address.get(), None()); + + if (configured.isError()) { + SSL_free(accept_ssl); + accept_queue.put( + Failure("Could not configure socket: " + configured.error())); + return Continue(); + } + + // Set the SSL context in server mode. + SSL_set_accept_state(accept_ssl); + + // Hold a weak pointer since we do not want this accept function to extend + // the lifetime of `this` unnecessarily. + std::weak_ptr<OpenSSLSocketImpl> weak_self(shared(this)); + + // Pass ownership of `accept_ssl` to the newly accepted socket, + // and start the SSL handshake. When the SSL handshake completes, + // the listening socket will place the result (failure or success) + // onto the listening socket's `accept_queue`. + // + // TODO(josephw): Add a timeout to catch/close incoming sockets which + // never finish the SSL handshake. + ssl_socket->set_ssl_and_do_handshake(accept_ssl) + .onAny([weak_self, ssl_socket](Future<size_t> result) { + std::shared_ptr<OpenSSLSocketImpl> self(weak_self.lock()); + + if (self == nullptr) { + return; + } + + if (result.isFailed()) { + self->accept_queue.put(Failure(result.failure())); + return; + } + + // For verification purposes, we need to grab the address (again). + Try<Address> address = network::address(ssl_socket->get()); + if (address.isError()) { + self->accept_queue.put( + Failure("Failed to get address: " + address.error())); + return; + } + + Try<inet::Address> inet_address = + network::convert<inet::Address>(address.get()); + + Try<Nothing> verify = openssl::verify( + ssl_socket->ssl, + Mode::SERVER, + None(), + inet_address.isSome() + ? Some(inet_address->ip) + : Option<net::IP>::none()); + + if (verify.isError()) { + VLOG(1) << "Failed accept, verification error: " + << verify.error(); + + self->accept_queue.put(Failure(verify.error())); + return; + } + + self->accept_queue.put(ssl_socket); + }); + + return Continue(); +} + + Future<size_t> OpenSSLSocketImpl::set_ssl_and_do_handshake(SSL* _ssl) { // NOTE: We would normally create this UPID in the socket's constructor. diff --git a/3rdparty/libprocess/src/ssl/openssl_socket.hpp b/3rdparty/libprocess/src/ssl/openssl_socket.hpp index 2d0259d..0528c03 100644 --- a/3rdparty/libprocess/src/ssl/openssl_socket.hpp +++ b/3rdparty/libprocess/src/ssl/openssl_socket.hpp @@ -55,6 +55,12 @@ public: Try<Nothing, SocketError> shutdown(int how) override; protected: + // Verifies incoming sockets and initiates the SSL handshake. + // Upon completion or failure of the SSL handshake, the peer socket + // (or Failure object) will be enqueued on the server socket's accept queue. + Future<ControlFlow<Nothing>> handle_accept_callback( + const std::shared_ptr<SocketImpl>& socket); + // Takes ownership of the given SSL object and performs an SSL handshake // with the context of the SSL object. Either `SSL_set_connect_state` // or `SSL_set_accept_state` must be called on the context beforehand,