xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/masque/masque_client_session.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/masque/masque_client_session.h"
6 
7 #include <cstdint>
8 #include <cstring>
9 #include <optional>
10 #include <string>
11 #include <utility>
12 #include <vector>
13 
14 #include "absl/container/flat_hash_map.h"
15 #include "absl/container/flat_hash_set.h"
16 #include "absl/strings/escaping.h"
17 #include "absl/strings/str_cat.h"
18 #include "absl/strings/str_split.h"
19 #include "absl/strings/string_view.h"
20 #include "openssl/curve25519.h"
21 #include "quiche/quic/core/crypto/quic_crypto_client_config.h"
22 #include "quiche/quic/core/frames/quic_connection_close_frame.h"
23 #include "quiche/quic/core/http/http_frames.h"
24 #include "quiche/quic/core/http/quic_spdy_client_session.h"
25 #include "quiche/quic/core/http/quic_spdy_client_stream.h"
26 #include "quiche/quic/core/quic_config.h"
27 #include "quiche/quic/core/quic_connection.h"
28 #include "quiche/quic/core/quic_data_reader.h"
29 #include "quiche/quic/core/quic_data_writer.h"
30 #include "quiche/quic/core/quic_error_codes.h"
31 #include "quiche/quic/core/quic_server_id.h"
32 #include "quiche/quic/core/quic_time.h"
33 #include "quiche/quic/core/quic_types.h"
34 #include "quiche/quic/core/quic_utils.h"
35 #include "quiche/quic/core/quic_versions.h"
36 #include "quiche/quic/masque/masque_utils.h"
37 #include "quiche/quic/platform/api/quic_bug_tracker.h"
38 #include "quiche/quic/platform/api/quic_logging.h"
39 #include "quiche/quic/platform/api/quic_socket_address.h"
40 #include "quiche/quic/tools/quic_url.h"
41 #include "quiche/common/capsule.h"
42 #include "quiche/common/platform/api/quiche_googleurl.h"
43 #include "quiche/common/platform/api/quiche_logging.h"
44 #include "quiche/common/platform/api/quiche_url_utils.h"
45 #include "quiche/common/quiche_ip_address.h"
46 #include "quiche/common/quiche_random.h"
47 #include "quiche/common/quiche_text_utils.h"
48 #include "quiche/spdy/core/http2_header_block.h"
49 
50 namespace quic {
51 
52 namespace {
53 
54 using ::quiche::AddressAssignCapsule;
55 using ::quiche::AddressRequestCapsule;
56 using ::quiche::RouteAdvertisementCapsule;
57 
58 constexpr uint64_t kConnectIpPayloadContextId = 0;
59 constexpr uint64_t kConnectEthernetPayloadContextId = 0;
60 }  // namespace
61 
MasqueClientSession(MasqueMode masque_mode,const std::string & uri_template,const QuicConfig & config,const ParsedQuicVersionVector & supported_versions,QuicConnection * connection,const QuicServerId & server_id,QuicCryptoClientConfig * crypto_config,Owner * owner)62 MasqueClientSession::MasqueClientSession(
63     MasqueMode masque_mode, const std::string& uri_template,
64     const QuicConfig& config, const ParsedQuicVersionVector& supported_versions,
65     QuicConnection* connection, const QuicServerId& server_id,
66     QuicCryptoClientConfig* crypto_config, Owner* owner)
67     : QuicSpdyClientSession(config, supported_versions, connection, server_id,
68                             crypto_config),
69       masque_mode_(masque_mode),
70       uri_template_(uri_template),
71       owner_(owner) {
72   // We don't currently use `masque_mode_` but will in the future. To silence
73   // clang's `-Wunused-private-field` warning for this when building QUICHE for
74   // Chrome, add a use of it here.
75   (void)masque_mode_;
76 }
77 
OnMessageAcked(QuicMessageId message_id,QuicTime)78 void MasqueClientSession::OnMessageAcked(QuicMessageId message_id,
79                                          QuicTime /*receive_timestamp*/) {
80   QUIC_DVLOG(1) << "Received ack for DATAGRAM frame " << message_id;
81 }
82 
OnMessageLost(QuicMessageId message_id)83 void MasqueClientSession::OnMessageLost(QuicMessageId message_id) {
84   QUIC_DVLOG(1) << "We believe DATAGRAM frame " << message_id << " was lost";
85 }
86 
87 const MasqueClientSession::ConnectUdpClientState*
GetOrCreateConnectUdpClientState(const QuicSocketAddress & target_server_address,EncapsulatedClientSession * encapsulated_client_session)88 MasqueClientSession::GetOrCreateConnectUdpClientState(
89     const QuicSocketAddress& target_server_address,
90     EncapsulatedClientSession* encapsulated_client_session) {
91   for (const ConnectUdpClientState& client_state : connect_udp_client_states_) {
92     if (client_state.target_server_address() == target_server_address &&
93         client_state.encapsulated_client_session() ==
94             encapsulated_client_session) {
95       // Found existing CONNECT-UDP request.
96       return &client_state;
97     }
98   }
99   // No CONNECT-UDP request found, create a new one.
100   std::string target_host;
101   auto it = fake_addresses_.find(target_server_address.host().ToPackedString());
102   if (it != fake_addresses_.end()) {
103     target_host = it->second;
104   } else {
105     target_host = target_server_address.host().ToString();
106   }
107 
108   url::Parsed parsed_uri_template;
109   url::ParseStandardURL(uri_template_.c_str(), uri_template_.length(),
110                         &parsed_uri_template);
111   if (!parsed_uri_template.path.is_nonempty()) {
112     QUIC_BUG(bad URI template path)
113         << "Cannot parse path from URI template " << uri_template_;
114     return nullptr;
115   }
116   std::string path = uri_template_.substr(parsed_uri_template.path.begin,
117                                           parsed_uri_template.path.len);
118   if (parsed_uri_template.query.is_valid()) {
119     absl::StrAppend(&path, "?",
120                     uri_template_.substr(parsed_uri_template.query.begin,
121                                          parsed_uri_template.query.len));
122   }
123   absl::flat_hash_map<std::string, std::string> parameters;
124   parameters["target_host"] = target_host;
125   parameters["target_port"] = absl::StrCat(target_server_address.port());
126   std::string expanded_path;
127   absl::flat_hash_set<std::string> vars_found;
128   bool expanded =
129       quiche::ExpandURITemplate(path, parameters, &expanded_path, &vars_found);
130   if (!expanded || vars_found.find("target_host") == vars_found.end() ||
131       vars_found.find("target_port") == vars_found.end()) {
132     QUIC_DLOG(ERROR) << "Failed to expand URI template \"" << uri_template_
133                      << "\" for " << target_host << " port "
134                      << target_server_address.port();
135     return nullptr;
136   }
137 
138   url::Component expanded_path_component(0, expanded_path.length());
139   url::RawCanonOutput<1024> canonicalized_path_output;
140   url::Component canonicalized_path_component;
141   bool canonicalized = url::CanonicalizePath(
142       expanded_path.c_str(), expanded_path_component,
143       &canonicalized_path_output, &canonicalized_path_component);
144   if (!canonicalized || !canonicalized_path_component.is_nonempty()) {
145     QUIC_DLOG(ERROR) << "Failed to canonicalize URI template \""
146                      << uri_template_ << "\" for " << target_host << " port "
147                      << target_server_address.port();
148     return nullptr;
149   }
150   std::string canonicalized_path(
151       canonicalized_path_output.data() + canonicalized_path_component.begin,
152       canonicalized_path_component.len);
153 
154   QuicSpdyClientStream* stream = CreateOutgoingBidirectionalStream();
155   if (stream == nullptr) {
156     // Stream flow control limits prevented us from opening a new stream.
157     QUIC_DLOG(ERROR) << "Failed to open CONNECT-UDP stream";
158     return nullptr;
159   }
160 
161   QuicUrl url(uri_template_);
162   std::string scheme = url.scheme();
163   std::string authority = url.HostPort();
164 
165   QUIC_DLOG(INFO) << "Sending CONNECT-UDP request for " << target_host
166                   << " port " << target_server_address.port() << " on stream "
167                   << stream->id() << " scheme=\"" << scheme << "\" authority=\""
168                   << authority << "\" path=\"" << canonicalized_path << "\"";
169 
170   // Send the request.
171   spdy::Http2HeaderBlock headers;
172   headers[":method"] = "CONNECT";
173   headers[":protocol"] = "connect-udp";
174   headers[":scheme"] = scheme;
175   headers[":authority"] = authority;
176   headers[":path"] = canonicalized_path;
177   AddAdditionalHeaders(headers, url);
178   QUIC_DVLOG(1) << "Sending request headers: " << headers.DebugString();
179   size_t bytes_sent =
180       stream->SendRequest(std::move(headers), /*body=*/"", /*fin=*/false);
181   if (bytes_sent == 0) {
182     QUIC_DLOG(ERROR) << "Failed to send CONNECT-UDP request";
183     return nullptr;
184   }
185 
186   connect_udp_client_states_.push_back(ConnectUdpClientState(
187       stream, encapsulated_client_session, this, target_server_address));
188   return &connect_udp_client_states_.back();
189 }
190 
191 const MasqueClientSession::ConnectIpClientState*
GetOrCreateConnectIpClientState(MasqueClientSession::EncapsulatedIpSession * encapsulated_ip_session)192 MasqueClientSession::GetOrCreateConnectIpClientState(
193     MasqueClientSession::EncapsulatedIpSession* encapsulated_ip_session) {
194   for (const ConnectIpClientState& client_state : connect_ip_client_states_) {
195     if (client_state.encapsulated_ip_session() == encapsulated_ip_session) {
196       // Found existing CONNECT-IP request.
197       return &client_state;
198     }
199   }
200   // No CONNECT-IP request found, create a new one.
201   QuicSpdyClientStream* stream = CreateOutgoingBidirectionalStream();
202   if (stream == nullptr) {
203     // Stream flow control limits prevented us from opening a new stream.
204     QUIC_DLOG(ERROR) << "Failed to open CONNECT-IP stream";
205     return nullptr;
206   }
207 
208   QuicUrl url(uri_template_);
209   std::string scheme = url.scheme();
210   std::string authority = url.HostPort();
211   std::string path = "/.well-known/masque/ip/*/*/";
212 
213   QUIC_DLOG(INFO) << "Sending CONNECT-IP request on stream " << stream->id()
214                   << " scheme=\"" << scheme << "\" authority=\"" << authority
215                   << "\" path=\"" << path << "\"";
216 
217   // Send the request.
218   spdy::Http2HeaderBlock headers;
219   headers[":method"] = "CONNECT";
220   headers[":protocol"] = "connect-ip";
221   headers[":scheme"] = scheme;
222   headers[":authority"] = authority;
223   headers[":path"] = path;
224   headers["connect-ip-version"] = "3";
225   AddAdditionalHeaders(headers, url);
226   QUIC_DVLOG(1) << "Sending request headers: " << headers.DebugString();
227   size_t bytes_sent =
228       stream->SendRequest(std::move(headers), /*body=*/"", /*fin=*/false);
229   if (bytes_sent == 0) {
230     QUIC_DLOG(ERROR) << "Failed to send CONNECT-IP request";
231     return nullptr;
232   }
233 
234   connect_ip_client_states_.push_back(
235       ConnectIpClientState(stream, encapsulated_ip_session, this));
236   return &connect_ip_client_states_.back();
237 }
238 
239 const MasqueClientSession::ConnectEthernetClientState*
GetOrCreateConnectEthernetClientState(MasqueClientSession::EncapsulatedEthernetSession * encapsulated_ethernet_session)240 MasqueClientSession::GetOrCreateConnectEthernetClientState(
241     MasqueClientSession::EncapsulatedEthernetSession*
242         encapsulated_ethernet_session) {
243   for (const ConnectEthernetClientState& client_state :
244        connect_ethernet_client_states_) {
245     if (client_state.encapsulated_ethernet_session() ==
246         encapsulated_ethernet_session) {
247       // Found existing CONNECT-ETHERNET request.
248       return &client_state;
249     }
250   }
251   // No CONNECT-ETHERNET request found, create a new one.
252   QuicSpdyClientStream* stream = CreateOutgoingBidirectionalStream();
253   if (stream == nullptr) {
254     // Stream flow control limits prevented us from opening a new stream.
255     QUIC_DLOG(ERROR) << "Failed to open CONNECT-ETHERNET stream";
256     return nullptr;
257   }
258 
259   QuicUrl url(uri_template_);
260   std::string scheme = url.scheme();
261   std::string authority = url.HostPort();
262   std::string path = "/.well-known/masque/ethernet/";
263 
264   QUIC_DLOG(INFO) << "Sending CONNECT-ETHERNET request on stream "
265                   << stream->id() << " scheme=\"" << scheme << "\" authority=\""
266                   << authority << "\" path=\"" << path << "\"";
267 
268   // Send the request.
269   spdy::Http2HeaderBlock headers;
270   headers[":method"] = "CONNECT";
271   headers[":protocol"] = "connect-ethernet";
272   headers[":scheme"] = scheme;
273   headers[":authority"] = authority;
274   headers[":path"] = path;
275   AddAdditionalHeaders(headers, url);
276   QUIC_DVLOG(1) << "Sending request headers: " << headers.DebugString();
277   size_t bytes_sent =
278       stream->SendRequest(std::move(headers), /*body=*/"", /*fin=*/false);
279   if (bytes_sent == 0) {
280     QUIC_DLOG(ERROR) << "Failed to send CONNECT-ETHERNET request";
281     return nullptr;
282   }
283 
284   connect_ethernet_client_states_.push_back(
285       ConnectEthernetClientState(stream, encapsulated_ethernet_session, this));
286   return &connect_ethernet_client_states_.back();
287 }
288 
SendIpPacket(absl::string_view packet,MasqueClientSession::EncapsulatedIpSession * encapsulated_ip_session)289 void MasqueClientSession::SendIpPacket(
290     absl::string_view packet,
291     MasqueClientSession::EncapsulatedIpSession* encapsulated_ip_session) {
292   const ConnectIpClientState* connect_ip =
293       GetOrCreateConnectIpClientState(encapsulated_ip_session);
294   if (connect_ip == nullptr) {
295     QUIC_DLOG(ERROR) << "Failed to create CONNECT-IP request";
296     return;
297   }
298 
299   std::string http_payload;
300   http_payload.resize(
301       QuicDataWriter::GetVarInt62Len(kConnectIpPayloadContextId) +
302       packet.size());
303   QuicDataWriter writer(http_payload.size(), http_payload.data());
304   if (!writer.WriteVarInt62(kConnectIpPayloadContextId)) {
305     QUIC_BUG(IP context write fail) << "Failed to write CONNECT-IP context ID";
306     return;
307   }
308   if (!writer.WriteStringPiece(packet)) {
309     QUIC_BUG(IP packet write fail) << "Failed to write CONNECT-IP packet";
310     return;
311   }
312   MessageStatus message_status =
313       SendHttp3Datagram(connect_ip->stream()->id(), http_payload);
314 
315   QUIC_DVLOG(1) << "Sent encapsulated IP packet of length " << packet.size()
316                 << " with stream ID " << connect_ip->stream()->id()
317                 << " and got message status "
318                 << MessageStatusToString(message_status);
319 }
320 
SendEthernetFrame(absl::string_view frame,MasqueClientSession::EncapsulatedEthernetSession * encapsulated_ethernet_session)321 void MasqueClientSession::SendEthernetFrame(
322     absl::string_view frame, MasqueClientSession::EncapsulatedEthernetSession*
323                                  encapsulated_ethernet_session) {
324   const ConnectEthernetClientState* connect_ethernet =
325       GetOrCreateConnectEthernetClientState(encapsulated_ethernet_session);
326   if (connect_ethernet == nullptr) {
327     QUIC_DLOG(ERROR) << "Failed to create CONNECT-ETHERNET request";
328     return;
329   }
330 
331   std::string http_payload;
332   http_payload.resize(
333       QuicDataWriter::GetVarInt62Len(kConnectEthernetPayloadContextId) +
334       frame.size());
335   QuicDataWriter writer(http_payload.size(), http_payload.data());
336   if (!writer.WriteVarInt62(kConnectEthernetPayloadContextId)) {
337     QUIC_BUG(IP context write fail)
338         << "Failed to write CONNECT-ETHERNET context ID";
339     return;
340   }
341   if (!writer.WriteStringPiece(frame)) {
342     QUIC_BUG(IP packet write fail) << "Failed to write CONNECT-ETHERNET frame";
343     return;
344   }
345   MessageStatus message_status =
346       SendHttp3Datagram(connect_ethernet->stream()->id(), http_payload);
347 
348   QUIC_DVLOG(1) << "Sent encapsulated Ethernet frame of length " << frame.size()
349                 << " with stream ID " << connect_ethernet->stream()->id()
350                 << " and got message status "
351                 << MessageStatusToString(message_status);
352 }
353 
SendPacket(absl::string_view packet,const QuicSocketAddress & target_server_address,EncapsulatedClientSession * encapsulated_client_session)354 void MasqueClientSession::SendPacket(
355     absl::string_view packet, const QuicSocketAddress& target_server_address,
356     EncapsulatedClientSession* encapsulated_client_session) {
357   const ConnectUdpClientState* connect_udp = GetOrCreateConnectUdpClientState(
358       target_server_address, encapsulated_client_session);
359   if (connect_udp == nullptr) {
360     QUIC_DLOG(ERROR) << "Failed to create CONNECT-UDP request";
361     return;
362   }
363 
364   std::string http_payload;
365   http_payload.resize(1 + packet.size());
366   http_payload[0] = 0;
367   memcpy(&http_payload[1], packet.data(), packet.size());
368   MessageStatus message_status =
369       SendHttp3Datagram(connect_udp->stream()->id(), http_payload);
370 
371   QUIC_DVLOG(1) << "Sent packet to " << target_server_address
372                 << " compressed with stream ID " << connect_udp->stream()->id()
373                 << " and got message status "
374                 << MessageStatusToString(message_status);
375 }
376 
CloseConnectUdpStream(EncapsulatedClientSession * encapsulated_client_session)377 void MasqueClientSession::CloseConnectUdpStream(
378     EncapsulatedClientSession* encapsulated_client_session) {
379   for (auto it = connect_udp_client_states_.begin();
380        it != connect_udp_client_states_.end();) {
381     if (it->encapsulated_client_session() == encapsulated_client_session) {
382       QUIC_DLOG(INFO) << "Removing CONNECT-UDP state for stream ID "
383                       << it->stream()->id();
384       auto* stream = it->stream();
385       it = connect_udp_client_states_.erase(it);
386       if (!stream->write_side_closed()) {
387         stream->Reset(QUIC_STREAM_CANCELLED);
388       }
389     } else {
390       ++it;
391     }
392   }
393 }
394 
CloseConnectIpStream(EncapsulatedIpSession * encapsulated_ip_session)395 void MasqueClientSession::CloseConnectIpStream(
396     EncapsulatedIpSession* encapsulated_ip_session) {
397   for (auto it = connect_ip_client_states_.begin();
398        it != connect_ip_client_states_.end();) {
399     if (it->encapsulated_ip_session() == encapsulated_ip_session) {
400       QUIC_DLOG(INFO) << "Removing CONNECT-IP state for stream ID "
401                       << it->stream()->id();
402       auto* stream = it->stream();
403       it = connect_ip_client_states_.erase(it);
404       if (!stream->write_side_closed()) {
405         stream->Reset(QUIC_STREAM_CANCELLED);
406       }
407     } else {
408       ++it;
409     }
410   }
411 }
412 
CloseConnectEthernetStream(EncapsulatedEthernetSession * encapsulated_ethernet_session)413 void MasqueClientSession::CloseConnectEthernetStream(
414     EncapsulatedEthernetSession* encapsulated_ethernet_session) {
415   for (auto it = connect_ethernet_client_states_.begin();
416        it != connect_ethernet_client_states_.end();) {
417     if (it->encapsulated_ethernet_session() == encapsulated_ethernet_session) {
418       QUIC_DLOG(INFO) << "Removing CONNECT-ETHERNET state for stream ID "
419                       << it->stream()->id();
420       auto* stream = it->stream();
421       it = connect_ethernet_client_states_.erase(it);
422       if (!stream->write_side_closed()) {
423         stream->Reset(QUIC_STREAM_CANCELLED);
424       }
425     } else {
426       ++it;
427     }
428   }
429 }
430 
OnConnectionClosed(const QuicConnectionCloseFrame & frame,ConnectionCloseSource source)431 void MasqueClientSession::OnConnectionClosed(
432     const QuicConnectionCloseFrame& frame, ConnectionCloseSource source) {
433   QuicSpdyClientSession::OnConnectionClosed(frame, source);
434   // Close all encapsulated sessions.
435   for (const auto& client_state : connect_udp_client_states_) {
436     client_state.encapsulated_client_session()->CloseConnection(
437         QUIC_CONNECTION_CANCELLED, "Underlying MASQUE connection was closed",
438         ConnectionCloseBehavior::SILENT_CLOSE);
439   }
440   for (const auto& client_state : connect_ip_client_states_) {
441     client_state.encapsulated_ip_session()->CloseIpSession(
442         "Underlying MASQUE connection was closed");
443   }
444 }
445 
OnStreamClosed(QuicStreamId stream_id)446 void MasqueClientSession::OnStreamClosed(QuicStreamId stream_id) {
447   if (QuicUtils::IsBidirectionalStreamId(stream_id, version()) &&
448       QuicUtils::IsClientInitiatedStreamId(transport_version(), stream_id)) {
449     QuicSpdyClientStream* stream =
450         reinterpret_cast<QuicSpdyClientStream*>(GetActiveStream(stream_id));
451     if (stream != nullptr) {
452       QUIC_DLOG(INFO) << "Stream " << stream_id
453                       << " closed, got response headers:"
454                       << stream->response_headers().DebugString();
455     }
456   }
457   for (auto it = connect_udp_client_states_.begin();
458        it != connect_udp_client_states_.end();) {
459     if (it->stream()->id() == stream_id) {
460       QUIC_DLOG(INFO) << "Stream " << stream_id
461                       << " was closed, removing CONNECT-UDP state";
462       auto* encapsulated_client_session = it->encapsulated_client_session();
463       it = connect_udp_client_states_.erase(it);
464       encapsulated_client_session->CloseConnection(
465           QUIC_CONNECTION_CANCELLED,
466           "Underlying MASQUE CONNECT-UDP stream was closed",
467           ConnectionCloseBehavior::SILENT_CLOSE);
468     } else {
469       ++it;
470     }
471   }
472   for (auto it = connect_ip_client_states_.begin();
473        it != connect_ip_client_states_.end();) {
474     if (it->stream()->id() == stream_id) {
475       QUIC_DLOG(INFO) << "Stream " << stream_id
476                       << " was closed, removing CONNECT-IP state";
477       auto* encapsulated_ip_session = it->encapsulated_ip_session();
478       it = connect_ip_client_states_.erase(it);
479       encapsulated_ip_session->CloseIpSession(
480           "Underlying MASQUE CONNECT-IP stream was closed");
481     } else {
482       ++it;
483     }
484   }
485 
486   QuicSpdyClientSession::OnStreamClosed(stream_id);
487 }
488 
OnSettingsFrame(const SettingsFrame & frame)489 bool MasqueClientSession::OnSettingsFrame(const SettingsFrame& frame) {
490   QUIC_DLOG(INFO) << "Received SETTINGS: " << frame;
491   if (!QuicSpdyClientSession::OnSettingsFrame(frame)) {
492     QUIC_DLOG(ERROR) << "Failed to parse received settings";
493     return false;
494   }
495   if (!SupportsH3Datagram()) {
496     QUIC_DLOG(ERROR) << "Warning: MasqueClientSession without HTTP/3 Datagrams";
497   }
498   QUIC_DLOG(INFO) << "Using HTTP Datagram: " << http_datagram_support();
499   owner_->OnSettingsReceived();
500   return true;
501 }
502 
ConnectUdpClientState(QuicSpdyClientStream * stream,EncapsulatedClientSession * encapsulated_client_session,MasqueClientSession * masque_session,const QuicSocketAddress & target_server_address)503 MasqueClientSession::ConnectUdpClientState::ConnectUdpClientState(
504     QuicSpdyClientStream* stream,
505     EncapsulatedClientSession* encapsulated_client_session,
506     MasqueClientSession* masque_session,
507     const QuicSocketAddress& target_server_address)
508     : stream_(stream),
509       encapsulated_client_session_(encapsulated_client_session),
510       masque_session_(masque_session),
511       target_server_address_(target_server_address) {
512   QUICHE_DCHECK_NE(masque_session_, nullptr);
513   this->stream()->RegisterHttp3DatagramVisitor(this);
514 }
515 
~ConnectUdpClientState()516 MasqueClientSession::ConnectUdpClientState::~ConnectUdpClientState() {
517   if (stream() != nullptr) {
518     stream()->UnregisterHttp3DatagramVisitor();
519   }
520 }
521 
ConnectUdpClientState(MasqueClientSession::ConnectUdpClientState && other)522 MasqueClientSession::ConnectUdpClientState::ConnectUdpClientState(
523     MasqueClientSession::ConnectUdpClientState&& other) {
524   *this = std::move(other);
525 }
526 
527 MasqueClientSession::ConnectUdpClientState&
operator =(MasqueClientSession::ConnectUdpClientState && other)528 MasqueClientSession::ConnectUdpClientState::operator=(
529     MasqueClientSession::ConnectUdpClientState&& other) {
530   stream_ = other.stream_;
531   encapsulated_client_session_ = other.encapsulated_client_session_;
532   masque_session_ = other.masque_session_;
533   target_server_address_ = other.target_server_address_;
534   other.stream_ = nullptr;
535   if (stream() != nullptr) {
536     stream()->ReplaceHttp3DatagramVisitor(this);
537   }
538   return *this;
539 }
540 
OnHttp3Datagram(QuicStreamId stream_id,absl::string_view payload)541 void MasqueClientSession::ConnectUdpClientState::OnHttp3Datagram(
542     QuicStreamId stream_id, absl::string_view payload) {
543   QUICHE_DCHECK_EQ(stream_id, stream()->id());
544   QuicDataReader reader(payload);
545   uint64_t context_id;
546   if (!reader.ReadVarInt62(&context_id)) {
547     QUIC_DLOG(ERROR) << "Failed to read context ID";
548     return;
549   }
550   if (context_id != 0) {
551     QUIC_DLOG(ERROR) << "Ignoring HTTP Datagram with unexpected context ID "
552                      << context_id;
553     return;
554   }
555   absl::string_view http_payload = reader.ReadRemainingPayload();
556   encapsulated_client_session_->ProcessPacket(http_payload,
557                                               target_server_address_);
558   QUIC_DVLOG(1) << "Sent " << http_payload.size()
559                 << " bytes to connection for stream ID " << stream_id;
560 }
561 
ConnectIpClientState(QuicSpdyClientStream * stream,EncapsulatedIpSession * encapsulated_ip_session,MasqueClientSession * masque_session)562 MasqueClientSession::ConnectIpClientState::ConnectIpClientState(
563     QuicSpdyClientStream* stream,
564     EncapsulatedIpSession* encapsulated_ip_session,
565     MasqueClientSession* masque_session)
566     : stream_(stream),
567       encapsulated_ip_session_(encapsulated_ip_session),
568       masque_session_(masque_session) {
569   QUICHE_DCHECK_NE(masque_session_, nullptr);
570   this->stream()->RegisterHttp3DatagramVisitor(this);
571   this->stream()->RegisterConnectIpVisitor(this);
572 }
573 
~ConnectIpClientState()574 MasqueClientSession::ConnectIpClientState::~ConnectIpClientState() {
575   if (stream() != nullptr) {
576     stream()->UnregisterHttp3DatagramVisitor();
577     stream()->UnregisterConnectIpVisitor();
578   }
579 }
580 
ConnectIpClientState(MasqueClientSession::ConnectIpClientState && other)581 MasqueClientSession::ConnectIpClientState::ConnectIpClientState(
582     MasqueClientSession::ConnectIpClientState&& other) {
583   *this = std::move(other);
584 }
585 
586 MasqueClientSession::ConnectIpClientState&
operator =(MasqueClientSession::ConnectIpClientState && other)587 MasqueClientSession::ConnectIpClientState::operator=(
588     MasqueClientSession::ConnectIpClientState&& other) {
589   stream_ = other.stream_;
590   encapsulated_ip_session_ = other.encapsulated_ip_session_;
591   masque_session_ = other.masque_session_;
592   other.stream_ = nullptr;
593   if (stream() != nullptr) {
594     stream()->ReplaceHttp3DatagramVisitor(this);
595     stream()->ReplaceConnectIpVisitor(this);
596   }
597   return *this;
598 }
599 
OnHttp3Datagram(QuicStreamId stream_id,absl::string_view payload)600 void MasqueClientSession::ConnectIpClientState::OnHttp3Datagram(
601     QuicStreamId stream_id, absl::string_view payload) {
602   QUICHE_DCHECK_EQ(stream_id, stream()->id());
603   QuicDataReader reader(payload);
604   uint64_t context_id;
605   if (!reader.ReadVarInt62(&context_id)) {
606     QUIC_DLOG(ERROR) << "Failed to read context ID";
607     return;
608   }
609   if (context_id != kConnectIpPayloadContextId) {
610     QUIC_DLOG(ERROR) << "Ignoring HTTP Datagram with unexpected context ID "
611                      << context_id;
612     return;
613   }
614   absl::string_view http_payload = reader.ReadRemainingPayload();
615   encapsulated_ip_session_->ProcessIpPacket(http_payload);
616   QUIC_DVLOG(1) << "Sent " << http_payload.size()
617                 << " IP bytes to connection for stream ID " << stream_id;
618 }
619 
OnAddressAssignCapsule(const AddressAssignCapsule & capsule)620 bool MasqueClientSession::ConnectIpClientState::OnAddressAssignCapsule(
621     const AddressAssignCapsule& capsule) {
622   return encapsulated_ip_session_->OnAddressAssignCapsule(capsule);
623 }
624 
OnAddressRequestCapsule(const AddressRequestCapsule & capsule)625 bool MasqueClientSession::ConnectIpClientState::OnAddressRequestCapsule(
626     const AddressRequestCapsule& capsule) {
627   return encapsulated_ip_session_->OnAddressRequestCapsule(capsule);
628 }
629 
OnRouteAdvertisementCapsule(const RouteAdvertisementCapsule & capsule)630 bool MasqueClientSession::ConnectIpClientState::OnRouteAdvertisementCapsule(
631     const RouteAdvertisementCapsule& capsule) {
632   return encapsulated_ip_session_->OnRouteAdvertisementCapsule(capsule);
633 }
634 
OnHeadersWritten()635 void MasqueClientSession::ConnectIpClientState::OnHeadersWritten() {}
636 
637 // ConnectEthernetClientState
638 
ConnectEthernetClientState(QuicSpdyClientStream * stream,EncapsulatedEthernetSession * encapsulated_ethernet_session,MasqueClientSession * masque_session)639 MasqueClientSession::ConnectEthernetClientState::ConnectEthernetClientState(
640     QuicSpdyClientStream* stream,
641     EncapsulatedEthernetSession* encapsulated_ethernet_session,
642     MasqueClientSession* masque_session)
643     : stream_(stream),
644       encapsulated_ethernet_session_(encapsulated_ethernet_session),
645       masque_session_(masque_session) {
646   QUICHE_DCHECK_NE(masque_session_, nullptr);
647   this->stream()->RegisterHttp3DatagramVisitor(this);
648 }
649 
~ConnectEthernetClientState()650 MasqueClientSession::ConnectEthernetClientState::~ConnectEthernetClientState() {
651   if (stream() != nullptr) {
652     stream()->UnregisterHttp3DatagramVisitor();
653   }
654 }
655 
ConnectEthernetClientState(MasqueClientSession::ConnectEthernetClientState && other)656 MasqueClientSession::ConnectEthernetClientState::ConnectEthernetClientState(
657     MasqueClientSession::ConnectEthernetClientState&& other) {
658   *this = std::move(other);
659 }
660 
661 MasqueClientSession::ConnectEthernetClientState&
operator =(MasqueClientSession::ConnectEthernetClientState && other)662 MasqueClientSession::ConnectEthernetClientState::operator=(
663     MasqueClientSession::ConnectEthernetClientState&& other) {
664   stream_ = other.stream_;
665   encapsulated_ethernet_session_ = other.encapsulated_ethernet_session_;
666   masque_session_ = other.masque_session_;
667   other.stream_ = nullptr;
668   if (stream() != nullptr) {
669     stream()->ReplaceHttp3DatagramVisitor(this);
670   }
671   return *this;
672 }
673 
OnHttp3Datagram(QuicStreamId stream_id,absl::string_view payload)674 void MasqueClientSession::ConnectEthernetClientState::OnHttp3Datagram(
675     QuicStreamId stream_id, absl::string_view payload) {
676   QUICHE_DCHECK_EQ(stream_id, stream()->id());
677   QuicDataReader reader(payload);
678   uint64_t context_id;
679   if (!reader.ReadVarInt62(&context_id)) {
680     QUIC_DLOG(ERROR) << "Failed to read context ID";
681     return;
682   }
683   if (context_id != kConnectEthernetPayloadContextId) {
684     QUIC_DLOG(ERROR) << "Ignoring HTTP Datagram with unexpected context ID "
685                      << context_id;
686     return;
687   }
688   absl::string_view http_payload = reader.ReadRemainingPayload();
689   encapsulated_ethernet_session_->ProcessEthernetFrame(http_payload);
690   QUIC_DVLOG(1) << "Sent " << http_payload.size()
691                 << " ETHERNET bytes to connection for stream ID " << stream_id;
692 }
693 
694 // End ConnectEthernetClientState
695 
GetFakeAddress(absl::string_view hostname)696 quiche::QuicheIpAddress MasqueClientSession::GetFakeAddress(
697     absl::string_view hostname) {
698   quiche::QuicheIpAddress address;
699   uint8_t address_bytes[16] = {0xFD};
700   quiche::QuicheRandom::GetInstance()->RandBytes(&address_bytes[1],
701                                                  sizeof(address_bytes) - 1);
702   address.FromPackedString(reinterpret_cast<const char*>(address_bytes),
703                            sizeof(address_bytes));
704   std::string address_bytes_string(reinterpret_cast<const char*>(address_bytes),
705                                    sizeof(address_bytes));
706   fake_addresses_[address_bytes_string] = std::string(hostname);
707   return address;
708 }
709 
RemoveFakeAddress(const quiche::QuicheIpAddress & fake_address)710 void MasqueClientSession::RemoveFakeAddress(
711     const quiche::QuicheIpAddress& fake_address) {
712   fake_addresses_.erase(fake_address.ToPackedString());
713 }
714 
EnableSignatureAuth(absl::string_view key_id,absl::string_view private_key,absl::string_view public_key)715 void MasqueClientSession::EnableSignatureAuth(absl::string_view key_id,
716                                               absl::string_view private_key,
717                                               absl::string_view public_key) {
718   QUICHE_CHECK(!key_id.empty());
719   QUICHE_CHECK_EQ(private_key.size(),
720                   static_cast<size_t>(ED25519_PRIVATE_KEY_LEN));
721   QUICHE_CHECK_EQ(public_key.size(),
722                   static_cast<size_t>(ED25519_PUBLIC_KEY_LEN));
723   signature_auth_key_id_ = key_id;
724   signature_auth_private_key_ = private_key;
725   signature_auth_public_key_ = public_key;
726 }
727 
SendGetRequest(absl::string_view path)728 QuicSpdyClientStream* MasqueClientSession::SendGetRequest(
729     absl::string_view path) {
730   QuicSpdyClientStream* stream = CreateOutgoingBidirectionalStream();
731   if (stream == nullptr) {
732     // Stream flow control limits prevented us from opening a new stream.
733     QUIC_DLOG(ERROR) << "Failed to open GET stream";
734     return nullptr;
735   }
736 
737   QuicUrl url(uri_template_);
738   std::string scheme = url.scheme();
739   std::string authority = url.HostPort();
740 
741   QUIC_DLOG(INFO) << "Sending GET request on stream " << stream->id()
742                   << " scheme=\"" << scheme << "\" authority=\"" << authority
743                   << "\" path=\"" << path << "\"";
744 
745   // Send the request.
746   spdy::Http2HeaderBlock headers;
747   headers[":method"] = "GET";
748   headers[":scheme"] = scheme;
749   headers[":authority"] = authority;
750   headers[":path"] = path;
751   AddAdditionalHeaders(headers, url);
752   QUIC_DVLOG(1) << "Sending request headers: " << headers.DebugString();
753   // Setting the stream visitor is required to enable reading of the response
754   // body from the stream.
755   stream->set_visitor(this);
756   size_t bytes_sent =
757       stream->SendRequest(std::move(headers), /*body=*/"", /*fin=*/true);
758   if (bytes_sent == 0) {
759     QUIC_DLOG(ERROR) << "Failed to send GET request";
760     return nullptr;
761   }
762   return stream;
763 }
764 
OnClose(QuicSpdyStream * stream)765 void MasqueClientSession::OnClose(QuicSpdyStream* stream) {
766   QUIC_DVLOG(1) << "Closing stream " << stream->id();
767 }
768 
ComputeSignatureAuthHeader(const QuicUrl & url)769 std::optional<std::string> MasqueClientSession::ComputeSignatureAuthHeader(
770     const QuicUrl& url) {
771   if (signature_auth_private_key_.empty()) {
772     return std::nullopt;
773   }
774   std::string scheme = url.scheme();
775   std::string host = url.host();
776   uint16_t port = url.port();
777   std::string realm = "";
778   std::string key_exporter_output;
779   std::string key_exporter_context = ComputeSignatureAuthContext(
780       kEd25519SignatureScheme, signature_auth_key_id_,
781       signature_auth_public_key_, scheme, host, port, realm);
782   QUIC_DVLOG(1) << "key_exporter_context: "
783                 << absl::WebSafeBase64Escape(key_exporter_context);
784   QUICHE_DCHECK(!key_exporter_context.empty());
785   if (!GetMutableCryptoStream()->ExportKeyingMaterial(
786           kSignatureAuthLabel, key_exporter_context, kSignatureAuthExporterSize,
787           &key_exporter_output)) {
788     QUIC_LOG(FATAL) << "Signature auth TLS exporter failed";
789     return std::nullopt;
790   }
791   QUICHE_CHECK_EQ(key_exporter_output.size(), kSignatureAuthExporterSize);
792   std::string signature_input =
793       key_exporter_output.substr(0, kSignatureAuthSignatureInputSize);
794   QUIC_DVLOG(1) << "signature_input: "
795                 << absl::WebSafeBase64Escape(signature_input);
796   std::string verification = key_exporter_output.substr(
797       kSignatureAuthSignatureInputSize, kSignatureAuthVerificationSize);
798   std::string data_covered_by_signature =
799       SignatureAuthDataCoveredBySignature(signature_input);
800   QUIC_DVLOG(1) << "data_covered_by_signature: "
801                 << absl::WebSafeBase64Escape(data_covered_by_signature);
802   uint8_t signature[ED25519_SIGNATURE_LEN];
803   if (ED25519_sign(
804           signature,
805           reinterpret_cast<const uint8_t*>(data_covered_by_signature.data()),
806           data_covered_by_signature.size(),
807           reinterpret_cast<const uint8_t*>(
808               signature_auth_private_key_.data())) != 1) {
809     QUIC_LOG(FATAL) << "Signature auth signature failed";
810     return std::nullopt;
811   }
812   return absl::StrCat(
813       "Signature k=", absl::WebSafeBase64Escape(signature_auth_key_id_),
814       ", a=", absl::WebSafeBase64Escape(signature_auth_public_key_), ", p=",
815       absl::WebSafeBase64Escape(absl::string_view(
816           reinterpret_cast<const char*>(signature), sizeof(signature))),
817       ", s=", kEd25519SignatureScheme,
818       ", v=", absl::WebSafeBase64Escape(verification));
819 }
820 
AddAdditionalHeaders(spdy::Http2HeaderBlock & headers,const QuicUrl & url)821 void MasqueClientSession::AddAdditionalHeaders(spdy::Http2HeaderBlock& headers,
822                                                const QuicUrl& url) {
823   std::optional<std::string> signature_auth_header =
824       ComputeSignatureAuthHeader(url);
825   if (signature_auth_header.has_value()) {
826     headers["authorization"] = *signature_auth_header;
827   }
828   if (additional_headers_.empty()) {
829     return;
830   }
831   for (absl::string_view sp : absl::StrSplit(additional_headers_, ';')) {
832     quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&sp);
833     if (sp.empty()) {
834       continue;
835     }
836     std::vector<absl::string_view> kv =
837         absl::StrSplit(sp, absl::MaxSplits(':', 1));
838     quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[0]);
839     quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[1]);
840     headers[kv[0]] = kv[1];
841   }
842 }
843 
844 }  // namespace quic
845