LCOV - code coverage report
Current view: top level - source/common/quic - envoy_quic_client_session.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 184 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 40 0.0 %

          Line data    Source code
       1             : #include "source/common/quic/envoy_quic_client_session.h"
       2             : 
       3             : #include <openssl/ssl.h>
       4             : 
       5             : #include <memory>
       6             : 
       7             : #include "envoy/network/transport_socket.h"
       8             : 
       9             : #include "source/common/event/dispatcher_impl.h"
      10             : #include "source/common/quic/envoy_quic_proof_verifier.h"
      11             : #include "source/common/quic/envoy_quic_utils.h"
      12             : 
      13             : #include "quic_filter_manager_connection_impl.h"
      14             : 
      15             : namespace Envoy {
      16             : namespace Quic {
      17             : 
      18             : // This class is only used to provide extra context during certificate validation. As such it does
      19             : // not implement the various interfaces which are irrelevant to certificate validation.
      20             : class CertValidationContext : public Network::TransportSocketCallbacks {
      21             : public:
      22             :   CertValidationContext(EnvoyQuicClientSession& session, Network::IoHandle& io_handle)
      23           0 :       : session_(session), io_handle_(io_handle) {}
      24             : 
      25             :   // Network::TransportSocketCallbacks
      26           0 :   Network::IoHandle& ioHandle() final { return io_handle_; }
      27           0 :   const Network::IoHandle& ioHandle() const override { return io_handle_; }
      28           0 :   Network::Connection& connection() override { return session_; }
      29             :   // Below methods shouldn't be called during cert verification.
      30           0 :   void raiseEvent(Network::ConnectionEvent /*event*/) override { PANIC("unexpectedly reached"); }
      31           0 :   bool shouldDrainReadBuffer() override { PANIC("unexpectedly reached"); }
      32           0 :   void setTransportSocketIsReadable() override { PANIC("unexpectedly reached"); }
      33           0 :   void flushWriteBuffer() override { PANIC("unexpectedly reached"); }
      34             : 
      35             : private:
      36             :   EnvoyQuicClientSession& session_;
      37             :   Network::IoHandle& io_handle_;
      38             : };
      39             : 
      40             : using CertValidationContextPtr = std::unique_ptr<CertValidationContext>;
      41             : 
      42             : // An implementation of the verify context interface.
      43             : class EnvoyQuicProofVerifyContextImpl : public EnvoyQuicProofVerifyContext {
      44             : public:
      45             :   EnvoyQuicProofVerifyContextImpl(
      46             :       Event::Dispatcher& dispatcher, const bool is_server,
      47             :       const Network::TransportSocketOptionsConstSharedPtr& transport_socket_options,
      48             :       QuicSslConnectionInfo& ssl_info, CertValidationContextPtr validation_context)
      49             :       : dispatcher_(dispatcher), is_server_(is_server),
      50             :         transport_socket_options_(transport_socket_options), ssl_info_(ssl_info),
      51           0 :         validation_context_(std::move(validation_context)) {}
      52             : 
      53             :   // EnvoyQuicProofVerifyContext
      54           0 :   bool isServer() const override { return is_server_; }
      55           0 :   Event::Dispatcher& dispatcher() const override { return dispatcher_; }
      56           0 :   const Network::TransportSocketOptionsConstSharedPtr& transportSocketOptions() const override {
      57           0 :     return transport_socket_options_;
      58           0 :   }
      59             : 
      60             :   Extensions::TransportSockets::Tls::CertValidator::ExtraValidationContext
      61           0 :   extraValidationContext() const override {
      62           0 :     ASSERT(ssl_info_.ssl());
      63           0 :     return {validation_context_.get()};
      64           0 :   }
      65             : 
      66             : private:
      67             :   Event::Dispatcher& dispatcher_;
      68             :   const bool is_server_;
      69             :   const Network::TransportSocketOptionsConstSharedPtr& transport_socket_options_;
      70             :   QuicSslConnectionInfo& ssl_info_;
      71             :   CertValidationContextPtr validation_context_;
      72             : };
      73             : 
      74             : EnvoyQuicClientSession::EnvoyQuicClientSession(
      75             :     const quic::QuicConfig& config, const quic::ParsedQuicVersionVector& supported_versions,
      76             :     std::unique_ptr<EnvoyQuicClientConnection> connection, const quic::QuicServerId& server_id,
      77             :     std::shared_ptr<quic::QuicCryptoClientConfig> crypto_config, Event::Dispatcher& dispatcher,
      78             :     uint32_t send_buffer_limit, EnvoyQuicCryptoClientStreamFactoryInterface& crypto_stream_factory,
      79             :     QuicStatNames& quic_stat_names, OptRef<Http::HttpServerPropertiesCache> rtt_cache,
      80             :     Stats::Scope& scope,
      81             :     const Network::TransportSocketOptionsConstSharedPtr& transport_socket_options,
      82             :     OptRef<Network::UpstreamTransportSocketFactory> transport_socket_factory)
      83             :     : QuicFilterManagerConnectionImpl(
      84             :           *connection, connection->connection_id(), dispatcher, send_buffer_limit,
      85             :           std::make_shared<QuicSslConnectionInfo>(*this),
      86             :           std::make_unique<StreamInfo::StreamInfoImpl>(
      87             :               dispatcher.timeSource(),
      88             :               connection->connectionSocket()->connectionInfoProviderSharedPtr())),
      89             :       quic::QuicSpdyClientSession(config, supported_versions, connection.release(), server_id,
      90             :                                   crypto_config.get()),
      91             :       crypto_config_(crypto_config), crypto_stream_factory_(crypto_stream_factory),
      92             :       quic_stat_names_(quic_stat_names), rtt_cache_(rtt_cache), scope_(scope),
      93             :       transport_socket_options_(transport_socket_options),
      94             :       transport_socket_factory_(makeOptRefFromPtr(
      95           0 :           dynamic_cast<QuicClientTransportSocketFactory*>(transport_socket_factory.ptr()))) {
      96           0 :   streamInfo().setUpstreamInfo(std::make_shared<StreamInfo::UpstreamInfoImpl>());
      97           0 :   if (transport_socket_options_ != nullptr &&
      98           0 :       !transport_socket_options_->applicationProtocolListOverride().empty()) {
      99           0 :     configured_alpns_ = transport_socket_options_->applicationProtocolListOverride();
     100           0 :   } else if (transport_socket_factory_.has_value() &&
     101           0 :              !transport_socket_factory_->supportedAlpnProtocols().empty()) {
     102           0 :     configured_alpns_ =
     103           0 :         std::vector<std::string>(transport_socket_factory_->supportedAlpnProtocols().begin(),
     104           0 :                                  transport_socket_factory_->supportedAlpnProtocols().end());
     105           0 :   }
     106           0 : }
     107             : 
     108           0 : EnvoyQuicClientSession::~EnvoyQuicClientSession() {
     109           0 :   ASSERT(!connection()->connected());
     110           0 :   network_connection_ = nullptr;
     111           0 : }
     112             : 
     113           0 : absl::string_view EnvoyQuicClientSession::requestedServerName() const { return server_id().host(); }
     114             : 
     115           0 : void EnvoyQuicClientSession::connect() {
     116           0 :   streamInfo().upstreamInfo()->upstreamTiming().onUpstreamConnectStart(dispatcher_.timeSource());
     117           0 :   dynamic_cast<EnvoyQuicClientConnection*>(network_connection_)
     118           0 :       ->setUpConnectionSocket(
     119           0 :           *static_cast<EnvoyQuicClientConnection*>(connection())->connectionSocket(), *this);
     120             :   // Start version negotiation and crypto handshake during which the connection may fail if server
     121             :   // doesn't support the one and only supported version.
     122           0 :   CryptoConnect();
     123           0 : }
     124             : 
     125             : void EnvoyQuicClientSession::OnConnectionClosed(const quic::QuicConnectionCloseFrame& frame,
     126           0 :                                                 quic::ConnectionCloseSource source) {
     127             :   // Latch latest srtt.
     128           0 :   if (OneRttKeysAvailable() && rtt_cache_) {
     129           0 :     const quic::QuicConnectionStats& stats = connection()->GetStats();
     130           0 :     if (stats.srtt_us > 0) {
     131           0 :       Http::HttpServerPropertiesCache::Origin origin("https", server_id().host(),
     132           0 :                                                      server_id().port());
     133           0 :       rtt_cache_->setSrtt(origin, std::chrono::microseconds(stats.srtt_us));
     134           0 :     }
     135           0 :   }
     136           0 :   quic::QuicSpdyClientSession::OnConnectionClosed(frame, source);
     137           0 :   quic_stat_names_.chargeQuicConnectionCloseStats(scope_, frame.quic_error_code, source, true);
     138           0 :   onConnectionCloseEvent(frame, source, version());
     139           0 : }
     140             : 
     141           0 : void EnvoyQuicClientSession::Initialize() {
     142           0 :   quic::QuicSpdyClientSession::Initialize();
     143           0 :   initialized_ = true;
     144           0 :   network_connection_->setEnvoyConnection(*this, *this);
     145           0 : }
     146             : 
     147           0 : void EnvoyQuicClientSession::OnCanWrite() {
     148           0 :   uint64_t old_bytes_to_send = bytesToSend();
     149           0 :   quic::QuicSpdyClientSession::OnCanWrite();
     150           0 :   const bool has_sent_any_data = bytesToSend() != old_bytes_to_send;
     151           0 :   maybeUpdateDelayCloseTimer(has_sent_any_data);
     152           0 : }
     153             : 
     154           0 : void EnvoyQuicClientSession::OnHttp3GoAway(uint64_t stream_id) {
     155           0 :   ENVOY_CONN_LOG(debug, "HTTP/3 GOAWAY received", *this);
     156           0 :   quic::QuicSpdyClientSession::OnHttp3GoAway(stream_id);
     157           0 :   if (http_connection_callbacks_ != nullptr) {
     158             :     // HTTP/3 GOAWAY doesn't have an error code field.
     159           0 :     http_connection_callbacks_->onGoAway(Http::GoAwayErrorCode::NoError);
     160           0 :   }
     161           0 : }
     162             : 
     163             : void EnvoyQuicClientSession::MaybeSendRstStreamFrame(quic::QuicStreamId id,
     164             :                                                      quic::QuicResetStreamError error,
     165           0 :                                                      quic::QuicStreamOffset bytes_written) {
     166           0 :   QuicSpdyClientSession::MaybeSendRstStreamFrame(id, error, bytes_written);
     167           0 :   quic_stat_names_.chargeQuicResetStreamErrorStats(scope_, error, /*from_self*/ true,
     168           0 :                                                    /*is_upstream*/ true);
     169           0 : }
     170             : 
     171           0 : void EnvoyQuicClientSession::OnRstStream(const quic::QuicRstStreamFrame& frame) {
     172           0 :   QuicSpdyClientSession::OnRstStream(frame);
     173           0 :   quic_stat_names_.chargeQuicResetStreamErrorStats(scope_, frame.error(),
     174           0 :                                                    /*from_self*/ false, /*is_upstream*/ true);
     175           0 : }
     176             : 
     177           0 : void EnvoyQuicClientSession::OnCanCreateNewOutgoingStream(bool unidirectional) {
     178           0 :   if (!http_connection_callbacks_ || unidirectional) {
     179           0 :     return;
     180           0 :   }
     181           0 :   uint32_t streams_available = streamsAvailable();
     182           0 :   http_connection_callbacks_->onMaxStreamsChanged(streams_available);
     183           0 : }
     184             : 
     185           0 : std::unique_ptr<quic::QuicSpdyClientStream> EnvoyQuicClientSession::CreateClientStream() {
     186           0 :   ASSERT(codec_stats_.has_value() && http3_options_.has_value());
     187           0 :   return std::make_unique<EnvoyQuicClientStream>(GetNextOutgoingBidirectionalStreamId(), this,
     188           0 :                                                  quic::BIDIRECTIONAL, codec_stats_.value(),
     189           0 :                                                  http3_options_.value());
     190           0 : }
     191             : 
     192           0 : quic::QuicSpdyStream* EnvoyQuicClientSession::CreateIncomingStream(quic::QuicStreamId /*id*/) {
     193             :   // Envoy doesn't support server initiated stream.
     194           0 :   return nullptr;
     195           0 : }
     196             : 
     197             : quic::QuicSpdyStream*
     198           0 : EnvoyQuicClientSession::CreateIncomingStream(quic::PendingStream* /*pending*/) {
     199             :   // Envoy doesn't support server push.
     200           0 :   IS_ENVOY_BUG("unexpectes server push call");
     201           0 :   return nullptr;
     202           0 : }
     203             : 
     204           0 : bool EnvoyQuicClientSession::hasDataToWrite() { return HasDataToWrite(); }
     205             : 
     206           0 : const quic::QuicConnection* EnvoyQuicClientSession::quicConnection() const {
     207           0 :   return initialized_ ? connection() : nullptr;
     208           0 : }
     209             : 
     210           0 : quic::QuicConnection* EnvoyQuicClientSession::quicConnection() {
     211           0 :   return initialized_ ? connection() : nullptr;
     212           0 : }
     213             : 
     214           0 : uint64_t EnvoyQuicClientSession::streamsAvailable() {
     215           0 :   const quic::UberQuicStreamIdManager& manager = ietf_streamid_manager();
     216           0 :   ASSERT(manager.max_outgoing_bidirectional_streams() >=
     217           0 :          manager.outgoing_bidirectional_stream_count());
     218           0 :   uint32_t streams_available =
     219           0 :       manager.max_outgoing_bidirectional_streams() - manager.outgoing_bidirectional_stream_count();
     220           0 :   return streams_available;
     221           0 : }
     222             : 
     223           0 : void EnvoyQuicClientSession::OnTlsHandshakeComplete() {
     224           0 :   quic::QuicSpdyClientSession::OnTlsHandshakeComplete();
     225             : 
     226             :   // Fake this to make sure we set the connection pool stream limit correctly
     227             :   // before use. This may result in OnCanCreateNewOutgoingStream with zero
     228             :   // available streams.
     229           0 :   OnCanCreateNewOutgoingStream(false);
     230           0 :   streamInfo().upstreamInfo()->upstreamTiming().onUpstreamConnectComplete(dispatcher_.timeSource());
     231           0 :   streamInfo().upstreamInfo()->upstreamTiming().onUpstreamHandshakeComplete(
     232           0 :       dispatcher_.timeSource());
     233             : 
     234           0 :   raiseConnectionEvent(Network::ConnectionEvent::Connected);
     235           0 : }
     236             : 
     237           0 : std::unique_ptr<quic::QuicCryptoClientStreamBase> EnvoyQuicClientSession::CreateQuicCryptoStream() {
     238           0 :   return crypto_stream_factory_.createEnvoyQuicCryptoClientStream(
     239           0 :       server_id(), this,
     240           0 :       std::make_unique<EnvoyQuicProofVerifyContextImpl>(
     241           0 :           dispatcher_, /*is_server=*/false, transport_socket_options_, *quic_ssl_info_,
     242           0 :           std::make_unique<CertValidationContext>(
     243           0 :               *this, network_connection_->connectionSocket()->ioHandle())),
     244           0 :       crypto_config(), this, /*has_application_state = */ version().UsesHttp3());
     245           0 : }
     246             : 
     247             : void EnvoyQuicClientSession::setHttp3Options(
     248           0 :     const envoy::config::core::v3::Http3ProtocolOptions& http3_options) {
     249           0 :   QuicFilterManagerConnectionImpl::setHttp3Options(http3_options);
     250           0 :   if (!http3_options_->has_quic_protocol_options()) {
     251           0 :     return;
     252           0 :   }
     253           0 :   static_cast<EnvoyQuicClientConnection*>(connection())
     254           0 :       ->setNumPtosForPortMigration(PROTOBUF_GET_WRAPPED_OR_DEFAULT(
     255           0 :           http3_options.quic_protocol_options(), num_timeouts_to_trigger_port_migration, 4));
     256             : 
     257           0 :   if (http3_options_->quic_protocol_options().has_connection_keepalive()) {
     258           0 :     const uint64_t initial_interval = PROTOBUF_GET_MS_OR_DEFAULT(
     259           0 :         http3_options_->quic_protocol_options().connection_keepalive(), initial_interval, 0);
     260           0 :     const uint64_t max_interval =
     261           0 :         PROTOBUF_GET_MS_OR_DEFAULT(http3_options_->quic_protocol_options().connection_keepalive(),
     262           0 :                                    max_interval, quic::kPingTimeoutSecs);
     263             :     // If the keepalive max_interval is configured to zero, disable the probe completely.
     264           0 :     if (max_interval == 0u) {
     265           0 :       disable_keepalive_ = true;
     266           0 :       return;
     267           0 :     }
     268           0 :     connection()->set_keep_alive_ping_timeout(
     269           0 :         quic::QuicTime::Delta::FromMilliseconds(max_interval));
     270           0 :     if (max_interval > initial_interval && initial_interval > 0u) {
     271           0 :       connection()->set_initial_retransmittable_on_wire_timeout(
     272           0 :           quic::QuicTime::Delta::FromMilliseconds(initial_interval));
     273           0 :     }
     274           0 :   }
     275           0 : }
     276             : 
     277           0 : bool EnvoyQuicClientSession::ShouldKeepConnectionAlive() const {
     278             :   // Do not probe at all if keepalive is disabled via config.
     279           0 :   return !disable_keepalive_ && quic::QuicSpdyClientSession::ShouldKeepConnectionAlive();
     280           0 : }
     281             : 
     282             : void EnvoyQuicClientSession::OnProofVerifyDetailsAvailable(
     283           0 :     const quic::ProofVerifyDetails& verify_details) {
     284           0 :   if (static_cast<const CertVerifyResult&>(verify_details).isValid()) {
     285           0 :     quic_ssl_info_->onCertValidated();
     286           0 :   }
     287           0 : }
     288             : 
     289             : void EnvoyQuicClientSession::OnNewEncryptionKeyAvailable(
     290           0 :     quic::EncryptionLevel level, std::unique_ptr<quic::QuicEncrypter> encrypter) {
     291           0 :   quic::QuicSpdyClientSession::OnNewEncryptionKeyAvailable(level, std::move(encrypter));
     292           0 :   if (level == quic::ENCRYPTION_ZERO_RTT) {
     293           0 :     ENVOY_CONN_LOG(trace, "able to send early data", *this);
     294           0 :     raiseConnectionEvent(Network::ConnectionEvent::ConnectedZeroRtt);
     295           0 :   }
     296           0 : }
     297             : void EnvoyQuicClientSession::OnServerPreferredAddressAvailable(
     298           0 :     const quic::QuicSocketAddress& server_preferred_address) {
     299           0 :   static_cast<EnvoyQuicClientConnection*>(connection())
     300           0 :       ->probeAndMigrateToServerPreferredAddress(server_preferred_address);
     301           0 : }
     302             : 
     303           0 : std::vector<std::string> EnvoyQuicClientSession::GetAlpnsToOffer() const {
     304           0 :   return configured_alpns_.empty() ? quic::QuicSpdyClientSession::GetAlpnsToOffer()
     305           0 :                                    : configured_alpns_;
     306           0 : }
     307             : 
     308             : } // namespace Quic
     309             : } // namespace Envoy

Generated by: LCOV version 1.15