1 // Copyright 2022 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef QUICHE_QUIC_TOOLS_CONNECT_UDP_TUNNEL_H_ 6 #define QUICHE_QUIC_TOOLS_CONNECT_UDP_TUNNEL_H_ 7 8 #include <cstdint> 9 #include <memory> 10 #include <string> 11 #include <utility> 12 13 #include "absl/container/flat_hash_set.h" 14 #include "absl/status/status.h" 15 #include "absl/status/statusor.h" 16 #include "absl/strings/string_view.h" 17 #include "quiche/quic/core/connecting_client_socket.h" 18 #include "quiche/quic/core/http/quic_spdy_stream.h" 19 #include "quiche/quic/core/quic_error_codes.h" 20 #include "quiche/quic/core/quic_server_id.h" 21 #include "quiche/quic/core/quic_types.h" 22 #include "quiche/quic/core/socket_factory.h" 23 #include "quiche/quic/tools/quic_simple_server_backend.h" 24 #include "quiche/common/platform/api/quiche_mem_slice.h" 25 #include "quiche/spdy/core/http2_header_block.h" 26 27 namespace quic { 28 29 // Manages a single UDP tunnel for a CONNECT-UDP proxy (see RFC 9298). 30 class ConnectUdpTunnel : public ConnectingClientSocket::AsyncVisitor, 31 public QuicSpdyStream::Http3DatagramVisitor { 32 public: 33 // `client_stream_request_handler` and `socket_factory` must both outlive the 34 // created ConnectUdpTunnel. `server_label` is an identifier (typically 35 // randomly generated) to indentify the server or backend in error headers, 36 // per the requirements of RFC 9209, Section 2. 37 ConnectUdpTunnel( 38 QuicSimpleServerBackend::RequestHandler* client_stream_request_handler, 39 SocketFactory* socket_factory, std::string server_label, 40 absl::flat_hash_set<QuicServerId> acceptable_targets); 41 ~ConnectUdpTunnel(); 42 ConnectUdpTunnel(const ConnectUdpTunnel&) = delete; 43 ConnectUdpTunnel& operator=(const ConnectUdpTunnel&) = delete; 44 45 // Attempts to open UDP tunnel to target server and then sends appropriate 46 // success/error response to the request stream. `request_headers` must 47 // represent headers from a CONNECT-UDP request, that is ":method"="CONNECT" 48 // and ":protocol"="connect-udp". 49 void OpenTunnel(const spdy::Http2HeaderBlock& request_headers); 50 51 // Returns true iff the tunnel to the target server is currently open 52 bool IsTunnelOpenToTarget() const; 53 54 // Called when the client stream has been closed. Tunnel to target 55 // server is closed if open. The RequestHandler will no longer be 56 // interacted with after completion. 57 void OnClientStreamClose(); 58 59 // ConnectingClientSocket::AsyncVisitor: 60 void ConnectComplete(absl::Status status) override; 61 void ReceiveComplete(absl::StatusOr<quiche::QuicheMemSlice> data) override; 62 void SendComplete(absl::Status status) override; 63 64 // QuicSpdyStream::Http3DatagramVisitor: 65 void OnHttp3Datagram(QuicStreamId stream_id, 66 absl::string_view payload) override; OnUnknownCapsule(QuicStreamId,const quiche::UnknownCapsule &)67 void OnUnknownCapsule(QuicStreamId /*stream_id*/, 68 const quiche::UnknownCapsule& /*capsule*/) override {} 69 70 private: 71 void BeginAsyncReadFromTarget(); 72 void OnDataReceivedFromTarget(bool success); 73 74 void SendUdpPacketToTarget(absl::string_view packet); 75 76 void SendConnectResponse(); 77 void SendErrorResponse(absl::string_view status, 78 absl::string_view proxy_status_error, 79 absl::string_view error_details); 80 void TerminateClientStream(absl::string_view error_description, 81 QuicResetStreamError error_code); 82 83 const absl::flat_hash_set<QuicServerId> acceptable_targets_; 84 SocketFactory* const socket_factory_; 85 const std::string server_label_; 86 87 // Null when client stream closed. 88 QuicSimpleServerBackend::RequestHandler* client_stream_request_handler_; 89 90 // Null when target connection disconnected. 91 std::unique_ptr<ConnectingClientSocket> target_socket_; 92 93 bool receive_started_ = false; 94 bool datagram_visitor_registered_ = false; 95 }; 96 97 } // namespace quic 98 99 #endif // QUICHE_QUIC_TOOLS_CONNECT_UDP_TUNNEL_H_ 100