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

          Line data    Source code
       1             : #include "source/common/quic/envoy_quic_dispatcher.h"
       2             : 
       3             : #include <openssl/crypto.h>
       4             : 
       5             : #include <functional>
       6             : #include <list>
       7             : 
       8             : #include "envoy/common/optref.h"
       9             : 
      10             : #include "source/common/common/safe_memcpy.h"
      11             : #include "source/common/quic/envoy_quic_server_connection.h"
      12             : #include "source/common/quic/envoy_quic_utils.h"
      13             : 
      14             : namespace Envoy {
      15             : namespace Quic {
      16             : 
      17             : namespace {
      18             : 
      19           0 : QuicDispatcherStats generateStats(Stats::Scope& store) {
      20           0 :   return {QUIC_DISPATCHER_STATS(POOL_COUNTER_PREFIX(store, "quic.dispatcher"))};
      21           0 : }
      22             : 
      23             : } // namespace
      24             : 
      25             : EnvoyQuicTimeWaitListManager::EnvoyQuicTimeWaitListManager(quic::QuicPacketWriter* writer,
      26             :                                                            Visitor* visitor,
      27             :                                                            const quic::QuicClock* clock,
      28             :                                                            quic::QuicAlarmFactory* alarm_factory,
      29             :                                                            QuicDispatcherStats& stats)
      30           0 :     : quic::QuicTimeWaitListManager(writer, visitor, clock, alarm_factory), stats_(stats) {}
      31             : 
      32             : void EnvoyQuicTimeWaitListManager::SendPublicReset(
      33             :     const quic::QuicSocketAddress& self_address, const quic::QuicSocketAddress& peer_address,
      34             :     quic::QuicConnectionId connection_id, bool ietf_quic, size_t received_packet_length,
      35           0 :     std::unique_ptr<quic::QuicPerPacketContext> packet_context) {
      36           0 :   ENVOY_LOG_EVERY_POW_2_MISC(info, "Sending Stateless Reset on connection {}",
      37           0 :                              connection_id.ToString());
      38           0 :   stats_.stateless_reset_packets_sent_.inc();
      39           0 :   quic::QuicTimeWaitListManager::SendPublicReset(self_address, peer_address, connection_id,
      40           0 :                                                  ietf_quic, received_packet_length,
      41           0 :                                                  std::move(packet_context));
      42           0 : }
      43             : 
      44             : EnvoyQuicDispatcher::EnvoyQuicDispatcher(
      45             :     const quic::QuicCryptoServerConfig* crypto_config, const quic::QuicConfig& quic_config,
      46             :     quic::QuicVersionManager* version_manager,
      47             :     std::unique_ptr<quic::QuicConnectionHelperInterface> helper,
      48             :     std::unique_ptr<quic::QuicAlarmFactory> alarm_factory,
      49             :     uint8_t expected_server_connection_id_length, Network::ConnectionHandler& connection_handler,
      50             :     Network::ListenerConfig& listener_config, Server::ListenerStats& listener_stats,
      51             :     Server::PerHandlerListenerStats& per_worker_stats, Event::Dispatcher& dispatcher,
      52             :     Network::Socket& listen_socket, QuicStatNames& quic_stat_names,
      53             :     EnvoyQuicCryptoServerStreamFactoryInterface& crypto_server_stream_factory,
      54             :     quic::ConnectionIdGeneratorInterface& generator)
      55             :     : quic::QuicDispatcher(&quic_config, crypto_config, version_manager, std::move(helper),
      56             :                            std::make_unique<EnvoyQuicCryptoServerStreamHelper>(),
      57             :                            std::move(alarm_factory), expected_server_connection_id_length,
      58             :                            generator),
      59             :       connection_handler_(connection_handler), listener_config_(&listener_config),
      60             :       listener_stats_(listener_stats), per_worker_stats_(per_worker_stats), dispatcher_(dispatcher),
      61             :       listen_socket_(listen_socket), quic_stat_names_(quic_stat_names),
      62             :       crypto_server_stream_factory_(crypto_server_stream_factory),
      63             :       quic_stats_(generateStats(listener_config.listenerScope())),
      64             :       connection_stats_({QUIC_CONNECTION_STATS(
      65           0 :           POOL_COUNTER_PREFIX(listener_config.listenerScope(), "quic.connection"))}) {}
      66             : 
      67             : void EnvoyQuicDispatcher::OnConnectionClosed(quic::QuicConnectionId connection_id,
      68             :                                              quic::QuicErrorCode error,
      69             :                                              const std::string& error_details,
      70           0 :                                              quic::ConnectionCloseSource source) {
      71           0 :   quic::QuicDispatcher::OnConnectionClosed(connection_id, error, error_details, source);
      72           0 :   listener_stats_.downstream_cx_active_.dec();
      73           0 :   per_worker_stats_.downstream_cx_active_.dec();
      74           0 :   connection_handler_.decNumConnections();
      75           0 :   quic_stat_names_.chargeQuicConnectionCloseStats(listener_config_->listenerScope(), error, source,
      76           0 :                                                   /*is_upstream*/ false);
      77           0 : }
      78             : 
      79           0 : quic::QuicTimeWaitListManager* EnvoyQuicDispatcher::CreateQuicTimeWaitListManager() {
      80           0 :   return new EnvoyQuicTimeWaitListManager(writer(), this, helper()->GetClock(), alarm_factory(),
      81           0 :                                           quic_stats_);
      82           0 : }
      83             : 
      84             : std::unique_ptr<quic::QuicSession> EnvoyQuicDispatcher::CreateQuicSession(
      85             :     quic::QuicConnectionId server_connection_id, const quic::QuicSocketAddress& self_address,
      86             :     const quic::QuicSocketAddress& peer_address, absl::string_view /*alpn*/,
      87             :     const quic::ParsedQuicVersion& version, const quic::ParsedClientHello& parsed_chlo,
      88           0 :     quic::ConnectionIdGeneratorInterface& connection_id_generator) {
      89           0 :   quic::QuicConfig quic_config = config();
      90             :   // TODO(danzh) use passed-in ALPN instead of hard-coded h3 after proof source interfaces takes in
      91             :   // ALPN.
      92           0 :   Network::ConnectionSocketPtr connection_socket = createServerConnectionSocket(
      93           0 :       listen_socket_.ioHandle(), self_address, peer_address, std::string(parsed_chlo.sni), "h3");
      94           0 :   auto stream_info = std::make_unique<StreamInfo::StreamInfoImpl>(
      95           0 :       dispatcher_.timeSource(), connection_socket->connectionInfoProviderSharedPtr());
      96             : 
      97           0 :   auto listener_filter_manager = std::make_unique<QuicListenerFilterManagerImpl>(
      98           0 :       dispatcher_, *connection_socket, *stream_info);
      99           0 :   const bool success = listener_config_->filterChainFactory().createQuicListenerFilterChain(
     100           0 :       *listener_filter_manager);
     101           0 :   const Network::FilterChain* filter_chain = nullptr;
     102           0 :   if (success) {
     103           0 :     listener_filter_manager->startFilterChain();
     104             :     // Quic listener filters are not supposed to pause the filter chain iteration unless it closes
     105             :     // the connection socket. If any listener filter have closed the socket, do not get a network
     106             :     // filter chain. Thus early fail the connection.
     107           0 :     if (connection_socket->ioHandle().isOpen()) {
     108           0 :       for (auto address_family : {quiche::IpAddressFamily::IP_V4, quiche::IpAddressFamily::IP_V6}) {
     109           0 :         absl::optional<quic::QuicSocketAddress> address =
     110           0 :             quic_config.GetPreferredAddressToSend(address_family);
     111           0 :         if (address.has_value() && address->IsInitialized() &&
     112           0 :             !listener_filter_manager->shouldAdvertiseServerPreferredAddress(address.value())) {
     113           0 :           quic_config.ClearAlternateServerAddressToSend(address_family);
     114           0 :         }
     115           0 :       }
     116           0 :       filter_chain =
     117           0 :           listener_config_->filterChainManager().findFilterChain(*connection_socket, *stream_info);
     118           0 :     }
     119           0 :   }
     120             : 
     121           0 :   auto quic_connection = std::make_unique<EnvoyQuicServerConnection>(
     122           0 :       server_connection_id, self_address, peer_address, *helper(), *alarm_factory(), writer(),
     123           0 :       /*owns_writer=*/false, quic::ParsedQuicVersionVector{version}, std::move(connection_socket),
     124           0 :       connection_id_generator, std::move(listener_filter_manager));
     125           0 :   auto quic_session = std::make_unique<EnvoyQuicServerSession>(
     126           0 :       quic_config, quic::ParsedQuicVersionVector{version}, std::move(quic_connection), this,
     127           0 :       session_helper(), crypto_config(), compressed_certs_cache(), dispatcher_,
     128           0 :       listener_config_->perConnectionBufferLimitBytes(), quic_stat_names_,
     129           0 :       listener_config_->listenerScope(), crypto_server_stream_factory_, std::move(stream_info),
     130           0 :       connection_stats_);
     131           0 :   if (filter_chain != nullptr) {
     132             :     // Setup filter chain before Initialize().
     133           0 :     const bool has_filter_initialized =
     134           0 :         listener_config_->filterChainFactory().createNetworkFilterChain(
     135           0 :             *quic_session, filter_chain->networkFilterFactories());
     136             :     // QUIC listener must have HCM filter configured. Otherwise, stream creation later will fail.
     137           0 :     ASSERT(has_filter_initialized);
     138           0 :     connections_by_filter_chain_[filter_chain].push_front(
     139           0 :         std::reference_wrapper<Network::Connection>(*quic_session));
     140           0 :     quic_session->storeConnectionMapPosition(connections_by_filter_chain_, *filter_chain,
     141           0 :                                              connections_by_filter_chain_[filter_chain].begin());
     142           0 :   } else {
     143           0 :     quic_session->close(Network::ConnectionCloseType::FlushWrite, "no filter chain found");
     144           0 :   }
     145           0 :   quic_session->Initialize();
     146           0 :   connection_handler_.incNumConnections();
     147           0 :   listener_stats_.downstream_cx_active_.inc();
     148           0 :   listener_stats_.downstream_cx_total_.inc();
     149           0 :   per_worker_stats_.downstream_cx_active_.inc();
     150           0 :   per_worker_stats_.downstream_cx_total_.inc();
     151           0 :   return quic_session;
     152           0 : }
     153             : 
     154             : bool EnvoyQuicDispatcher::processPacket(const quic::QuicSocketAddress& self_address,
     155             :                                         const quic::QuicSocketAddress& peer_address,
     156           0 :                                         const quic::QuicReceivedPacket& packet) {
     157             :   // Assume a packet was dispatched successfully, if OnFailedToDispatchPacket is not called.
     158           0 :   current_packet_dispatch_success_ = true;
     159           0 :   ProcessPacket(self_address, peer_address, packet);
     160           0 :   return current_packet_dispatch_success_;
     161           0 : }
     162             : 
     163             : bool EnvoyQuicDispatcher::OnFailedToDispatchPacket(
     164           0 :     const quic::ReceivedPacketInfo& received_packet_info) {
     165           0 :   if (!accept_new_connections()) {
     166           0 :     current_packet_dispatch_success_ = false;
     167           0 :     return true;
     168           0 :   }
     169           0 :   return quic::QuicDispatcher::OnFailedToDispatchPacket(received_packet_info);
     170           0 : }
     171             : 
     172             : void EnvoyQuicDispatcher::closeConnectionsWithFilterChain(
     173           0 :     const Network::FilterChain* filter_chain) {
     174           0 :   auto iter = connections_by_filter_chain_.find(filter_chain);
     175           0 :   if (iter != connections_by_filter_chain_.end()) {
     176           0 :     std::list<std::reference_wrapper<Network::Connection>>& connections = iter->second;
     177             :     // Retain the number of connections in the list early because closing the connection will change
     178             :     // the size.
     179           0 :     const size_t num_connections = connections.size();
     180           0 :     bool delete_sessions_immediately = false;
     181           0 :     for (size_t i = 0; i < num_connections; ++i) {
     182           0 :       Network::Connection& connection = connections.front().get();
     183             :       // This will remove the connection from the list. And the last removal will remove connections
     184             :       // from the map as well.
     185           0 :       connection.close(Network::ConnectionCloseType::NoFlush);
     186           0 :       if (!delete_sessions_immediately &&
     187           0 :           dynamic_cast<QuicFilterManagerConnectionImpl&>(connection).fix_quic_lifetime_issues()) {
     188             :         // If `envoy.reloadable_features.quic_fix_filter_manager_uaf` is true, the closed sessions
     189             :         // need to be deleted right away to consistently handle quic lifetimes. Because upon
     190             :         // returning the filter chain configs will be destroyed, and no longer safe to be accessed.
     191             :         // If any filters access those configs during destruction, it'll be use-after-free
     192           0 :         delete_sessions_immediately = true;
     193           0 :       }
     194           0 :     }
     195           0 :     ASSERT(connections_by_filter_chain_.find(filter_chain) == connections_by_filter_chain_.end());
     196           0 :     if (delete_sessions_immediately) {
     197             :       // Explicitly destroy closed sessions in the current call stack.
     198           0 :       DeleteSessions();
     199           0 :     }
     200           0 :   }
     201           0 : }
     202             : 
     203           0 : void EnvoyQuicDispatcher::updateListenerConfig(Network::ListenerConfig& new_listener_config) {
     204           0 :   listener_config_ = &new_listener_config;
     205           0 : }
     206             : 
     207             : } // namespace Quic
     208             : } // namespace Envoy

Generated by: LCOV version 1.15