| // Copyright 2019 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef QUICHE_QUIC_MASQUE_MASQUE_SERVER_SESSION_H_ | |
| #define QUICHE_QUIC_MASQUE_MASQUE_SERVER_SESSION_H_ | |
| #include <sys/types.h> | |
| #include <cstdint> | |
| #include <limits> | |
| #include <list> | |
| #include <memory> | |
| #include "absl/strings/string_view.h" | |
| #include "quiche/quic/core/crypto/quic_compressed_certs_cache.h" | |
| #include "quiche/quic/core/crypto/quic_crypto_server_config.h" | |
| #include "quiche/quic/core/frames/quic_connection_close_frame.h" | |
| #include "quiche/quic/core/http/http_frames.h" | |
| #include "quiche/quic/core/http/quic_spdy_session.h" | |
| #include "quiche/quic/core/http/quic_spdy_stream.h" | |
| #include "quiche/quic/core/io/quic_event_loop.h" | |
| #include "quiche/quic/core/quic_config.h" | |
| #include "quiche/quic/core/quic_connection.h" | |
| #include "quiche/quic/core/quic_crypto_server_stream_base.h" | |
| #include "quiche/quic/core/quic_session.h" | |
| #include "quiche/quic/core/quic_time.h" | |
| #include "quiche/quic/core/quic_types.h" | |
| #include "quiche/quic/core/quic_udp_socket.h" | |
| #include "quiche/quic/core/quic_versions.h" | |
| #include "quiche/quic/masque/masque_server_backend.h" | |
| #include "quiche/quic/masque/masque_utils.h" | |
| #include "quiche/quic/platform/api/quic_export.h" | |
| #include "quiche/quic/platform/api/quic_ip_address.h" | |
| #include "quiche/quic/platform/api/quic_socket_address.h" | |
| #include "quiche/quic/tools/quic_backend_response.h" | |
| #include "quiche/quic/tools/quic_simple_server_backend.h" | |
| #include "quiche/quic/tools/quic_simple_server_session.h" | |
| #include "quiche/common/capsule.h" | |
| #include "quiche/common/http/http_header_block.h" | |
| namespace quic { | |
| // QUIC server session for connection to MASQUE proxy. | |
| class QUIC_NO_EXPORT MasqueServerSession | |
| : public QuicSimpleServerSession, | |
| public MasqueServerBackend::BackendClient, | |
| public QuicSocketEventListener { | |
| public: | |
| using ContextId = uint64_t; | |
| constexpr static ContextId kInvalidContextId = | |
| std::numeric_limits<uint64_t>::max(); | |
| explicit MasqueServerSession( | |
| MasqueMode masque_mode, const QuicConfig& config, | |
| const ParsedQuicVersionVector& supported_versions, | |
| QuicConnection* connection, QuicSession::Visitor* visitor, | |
| QuicEventLoop* event_loop, QuicCryptoServerStreamBase::Helper* helper, | |
| const QuicCryptoServerConfig* crypto_config, | |
| QuicCompressedCertsCache* compressed_certs_cache, | |
| MasqueServerBackend* masque_server_backend); | |
| // Disallow copy and assign. | |
| MasqueServerSession(const MasqueServerSession&) = delete; | |
| MasqueServerSession& operator=(const MasqueServerSession&) = delete; | |
| // From QuicSession. | |
| void OnDatagramAcked(QuicDatagramId datagram_id) override; | |
| void OnDatagramLost(QuicDatagramId datagram_id) override; | |
| void OnConnectionClosed(const QuicConnectionCloseFrame& frame, | |
| ConnectionCloseSource source) override; | |
| void OnStreamClosed(QuicStreamId stream_id) override; | |
| // From MasqueServerBackend::BackendClient. | |
| std::unique_ptr<QuicBackendResponse> HandleMasqueRequest( | |
| const quiche::HttpHeaderBlock& request_headers, | |
| QuicSimpleServerBackend::RequestHandler* request_handler) override; | |
| QuicSpdySession* GetQuicSpdySession() override; | |
| // From QuicSocketEventListener. | |
| void OnSocketEvent(QuicEventLoop* event_loop, QuicUdpSocketFd fd, | |
| QuicSocketEventMask events) override; | |
| QuicEventLoop* event_loop() const { return event_loop_; } | |
| MasqueServerBackend* masque_server_backend() const { | |
| return masque_server_backend_; | |
| } | |
| // Send DNS_ASSIGN capsule to all active CONNECT-IP client streams. | |
| void SendDnsAssignCapsule(const DnsAssignCapsule& capsule); | |
| // Send PREF64 capsule to all active CONNECT-IP client streams. | |
| void SendPref64Capsule(const Pref64Capsule& capsule); | |
| private: | |
| bool HandleConnectUdpSocketEvent(QuicUdpSocketFd fd, | |
| QuicSocketEventMask events); | |
| bool HandleConnectIpSocketEvent(QuicUdpSocketFd fd, | |
| QuicSocketEventMask events); | |
| bool HandleConnectEthernetSocketEvent(QuicUdpSocketFd fd, | |
| QuicSocketEventMask events); | |
| std::unique_ptr<QuicBackendResponse> MaybeCheckConcealedAuth( | |
| const quiche::HttpHeaderBlock& request_headers, | |
| absl::string_view authority, absl::string_view scheme, | |
| QuicSimpleServerBackend::RequestHandler* request_handler); | |
| // State that the MasqueServerSession keeps for each CONNECT-UDP request. | |
| class QUIC_NO_EXPORT ConnectUdpServerState | |
| : public QuicSpdyStream::Http3DatagramVisitor, | |
| public QuicSpdyStream::ConnectUdpBindVisitor { | |
| public: | |
| // Server state for CONNECT-UDP and CONNECT-UDP-BIND. | |
| // is_bind is true for CONNECT-UDP-BIND. | |
| explicit ConnectUdpServerState( | |
| QuicSpdyStream* stream, const QuicSocketAddress& target_server_address, | |
| QuicUdpSocketFd bind_fd, MasqueServerSession* masque_session, | |
| bool is_bind = false); | |
| ~ConnectUdpServerState(); | |
| // Disallow copy but allow move. | |
| ConnectUdpServerState(const ConnectUdpServerState&) = delete; | |
| ConnectUdpServerState(ConnectUdpServerState&&); | |
| ConnectUdpServerState& operator=(const ConnectUdpServerState&) = delete; | |
| ConnectUdpServerState& operator=(ConnectUdpServerState&&); | |
| QuicSpdyStream* stream() const { return stream_; } | |
| const QuicSocketAddress& target_server_address() const { | |
| return target_server_address_; | |
| } | |
| QuicUdpSocketFd fd() const { return fd_; } | |
| // CONNECT-UDP-BIND. | |
| bool is_bind() const { return is_bind_; } | |
| // From QuicSpdyStream::Http3DatagramVisitor. | |
| void OnHttp3Datagram(QuicStreamId stream_id, | |
| absl::string_view payload) override; | |
| void OnUnknownCapsule(QuicStreamId /*stream_id*/, | |
| const quiche::UnknownCapsule& /*capsule*/) override {} | |
| // From QuicSpdyStream::ConnectUdpBindVisitor. | |
| bool OnCompressionAssignCapsule( | |
| const quiche::CompressionAssignCapsule& capsule) override; | |
| bool OnCompressionCloseCapsule( | |
| const quiche::CompressionCloseCapsule& capsule) override; | |
| absl::flat_hash_map<ContextId, quic::QuicSocketAddress>& | |
| bind_context_ip_map() { | |
| return bind_context_ip_map_; | |
| } | |
| private: | |
| QuicSpdyStream* stream_; | |
| QuicSocketAddress target_server_address_; | |
| QuicUdpSocketFd fd_; // Owned. | |
| MasqueServerSession* masque_session_; // Unowned. | |
| bool is_bind_; | |
| // CONNECT-UDP-BIND context id to ip:port map. | |
| absl::flat_hash_map<ContextId, quic::QuicSocketAddress> | |
| bind_context_ip_map_ = {}; | |
| // TODO(abhisinghx): Add Server's ability to request compression | |
| // or close contexts. | |
| }; | |
| // State that the MasqueServerSession keeps for each CONNECT-IP request. | |
| class QUIC_NO_EXPORT ConnectIpServerState | |
| : public QuicSpdyStream::Http3DatagramVisitor, | |
| public QuicSpdyStream::ConnectIpVisitor { | |
| public: | |
| // ConnectIpServerState takes ownership of |fd|. It will unregister it | |
| // from |event_loop| and close the file descriptor when destructed. | |
| explicit ConnectIpServerState(QuicIpAddress client_ip, | |
| QuicSpdyStream* stream, QuicUdpSocketFd fd, | |
| MasqueServerSession* masque_session); | |
| ~ConnectIpServerState(); | |
| // Disallow copy but allow move. | |
| ConnectIpServerState(const ConnectIpServerState&) = delete; | |
| ConnectIpServerState(ConnectIpServerState&&); | |
| ConnectIpServerState& operator=(const ConnectIpServerState&) = delete; | |
| ConnectIpServerState& operator=(ConnectIpServerState&&); | |
| QuicSpdyStream* stream() const { return stream_; } | |
| QuicUdpSocketFd fd() const { return fd_; } | |
| // From QuicSpdyStream::Http3DatagramVisitor. | |
| void OnHttp3Datagram(QuicStreamId stream_id, | |
| absl::string_view payload) override; | |
| void OnUnknownCapsule(QuicStreamId stream_id, | |
| const quiche::UnknownCapsule& capsule) override; | |
| // From QuicSpdyStream::ConnectIpVisitor. | |
| bool OnAddressAssignCapsule( | |
| const quiche::AddressAssignCapsule& capsule) override; | |
| bool OnAddressRequestCapsule( | |
| const quiche::AddressRequestCapsule& capsule) override; | |
| bool OnRouteAdvertisementCapsule( | |
| const quiche::RouteAdvertisementCapsule& capsule) override; | |
| virtual bool OnDnsAssignCapsule(const DnsAssignCapsule& capsule); | |
| virtual bool OnPref64Capsule(const Pref64Capsule& capsule); | |
| void OnHeadersWritten() override; | |
| private: | |
| QuicIpAddress client_ip_; | |
| QuicSpdyStream* stream_; | |
| QuicUdpSocketFd fd_; // Owned. | |
| MasqueServerSession* masque_session_; // Unowned. | |
| }; | |
| // State that the MasqueServerSession keeps for each CONNECT-ETHERNET request. | |
| class QUIC_NO_EXPORT ConnectEthernetServerState | |
| : public QuicSpdyStream::Http3DatagramVisitor { | |
| public: | |
| // ConnectEthernetServerState takes ownership of |fd|. It will unregister it | |
| // from |event_loop| and close the file descriptor when destructed. | |
| explicit ConnectEthernetServerState(QuicSpdyStream* stream, | |
| QuicUdpSocketFd fd, | |
| MasqueServerSession* masque_session); | |
| ~ConnectEthernetServerState(); | |
| // Disallow copy but allow move. | |
| ConnectEthernetServerState(const ConnectEthernetServerState&) = delete; | |
| ConnectEthernetServerState(ConnectEthernetServerState&&); | |
| ConnectEthernetServerState& operator=(const ConnectEthernetServerState&) = | |
| delete; | |
| ConnectEthernetServerState& operator=(ConnectEthernetServerState&&); | |
| QuicSpdyStream* stream() const { return stream_; } | |
| QuicUdpSocketFd fd() const { return fd_; } | |
| // From QuicSpdyStream::Http3DatagramVisitor. | |
| void OnHttp3Datagram(QuicStreamId stream_id, | |
| absl::string_view payload) override; | |
| void OnUnknownCapsule(QuicStreamId /*stream_id*/, | |
| const quiche::UnknownCapsule& /*capsule*/) override {} | |
| private: | |
| QuicSpdyStream* stream_; | |
| QuicUdpSocketFd fd_; // Owned. | |
| MasqueServerSession* masque_session_; // Unowned. | |
| }; | |
| // From QuicSpdySession. | |
| bool OnSettingsFrame(const SettingsFrame& frame) override; | |
| HttpDatagramSupport LocalHttpDatagramSupport() override { | |
| return HttpDatagramSupport::kRfc; | |
| } | |
| MasqueServerBackend* masque_server_backend_; // Unowned. | |
| QuicEventLoop* event_loop_; // Unowned. | |
| MasqueMode masque_mode_; | |
| std::list<ConnectUdpServerState> connect_udp_server_states_; | |
| std::list<ConnectIpServerState> connect_ip_server_states_; | |
| std::list<ConnectEthernetServerState> connect_ethernet_server_states_; | |
| }; | |
| } // namespace quic | |
| #endif // QUICHE_QUIC_MASQUE_MASQUE_SERVER_SESSION_H_ |