Make MASQUE toy client perform DNS on proxy

In most uses of MASQUE, it makes sense to do the DNS on the proxy instead of on the client. When the toy client was written, it was easier to do it on the client so I opted for that. This CL fixes that.

PiperOrigin-RevId: 519456113
diff --git a/quiche/quic/masque/masque_client_bin.cc b/quiche/quic/masque/masque_client_bin.cc
index 76f984c..445e56b 100644
--- a/quiche/quic/masque/masque_client_bin.cc
+++ b/quiche/quic/masque/masque_client_bin.cc
@@ -45,6 +45,12 @@
     "If set to true, no URLs need to be specified and instead a TUN device "
     "is brought up with the assigned IP from the MASQUE CONNECT-IP server");
 
+DEFINE_QUICHE_COMMAND_LINE_FLAG(
+    bool, dns_on_client, false,
+    "If set to true, masque_client will perform DNS for encapsulated URLs and "
+    "send the IP litteral in the CONNECT request. If set to false, "
+    "masque_client send the hostname in the CONNECT request.");
+
 namespace quic {
 
 namespace {
@@ -230,10 +236,14 @@
     QUICHE_NOTREACHED();
   }
 
+  const bool dns_on_client =
+      quiche::GetQuicheCommandLineFlag(FLAGS_dns_on_client);
+
   for (size_t i = 1; i < urls.size(); ++i) {
     if (!tools::SendEncapsulatedMasqueRequest(
             masque_client.get(), event_loop.get(), urls[i],
-            disable_certificate_verification, address_family_for_lookup)) {
+            disable_certificate_verification, address_family_for_lookup,
+            dns_on_client)) {
       return 1;
     }
   }
diff --git a/quiche/quic/masque/masque_client_session.cc b/quiche/quic/masque/masque_client_session.cc
index 5367d9e..637f18f 100644
--- a/quiche/quic/masque/masque_client_session.cc
+++ b/quiche/quic/masque/masque_client_session.cc
@@ -32,7 +32,7 @@
 using ::quiche::RouteAdvertisementCapsule;
 
 constexpr uint64_t kConnectIpPayloadContextId = 0;
-}
+}  // namespace
 
 MasqueClientSession::MasqueClientSession(
     MasqueMode masque_mode, const std::string& uri_template,
@@ -68,6 +68,14 @@
     }
   }
   // No CONNECT-UDP request found, create a new one.
+  std::string target_host;
+  auto it = fake_addresses_.find(target_server_address.host().ToPackedString());
+  if (it != fake_addresses_.end()) {
+    target_host = it->second;
+    fake_addresses_.erase(it);
+  } else {
+    target_host = target_server_address.host().ToString();
+  }
 
   url::Parsed parsed_uri_template;
   url::ParseStandardURL(uri_template_.c_str(), uri_template_.length(),
@@ -85,7 +93,7 @@
                                          parsed_uri_template.query.len));
   }
   absl::flat_hash_map<std::string, std::string> parameters;
-  parameters["target_host"] = target_server_address.host().ToString();
+  parameters["target_host"] = target_host;
   parameters["target_port"] = absl::StrCat(target_server_address.port());
   std::string expanded_path;
   absl::flat_hash_set<std::string> vars_found;
@@ -94,7 +102,8 @@
   if (!expanded || vars_found.find("target_host") == vars_found.end() ||
       vars_found.find("target_port") == vars_found.end()) {
     QUIC_DLOG(ERROR) << "Failed to expand URI template \"" << uri_template_
-                     << "\" for " << target_server_address;
+                     << "\" for " << target_host << " port "
+                     << target_server_address.port();
     return nullptr;
   }
 
@@ -106,7 +115,8 @@
       &canonicalized_path_output, &canonicalized_path_component);
   if (!canonicalized || !canonicalized_path_component.is_nonempty()) {
     QUIC_DLOG(ERROR) << "Failed to canonicalize URI template \""
-                     << uri_template_ << "\" for " << target_server_address;
+                     << uri_template_ << "\" for " << target_host << " port "
+                     << target_server_address.port();
     return nullptr;
   }
   std::string canonicalized_path(
@@ -124,10 +134,10 @@
   std::string scheme = url.scheme();
   std::string authority = url.HostPort();
 
-  QUIC_DLOG(INFO) << "Sending CONNECT-UDP request for " << target_server_address
-                  << " on stream " << stream->id() << " scheme=\"" << scheme
-                  << "\" authority=\"" << authority << "\" path=\""
-                  << canonicalized_path << "\"";
+  QUIC_DLOG(INFO) << "Sending CONNECT-UDP request for " << target_host
+                  << " port " << target_server_address.port() << " on stream "
+                  << stream->id() << " scheme=\"" << scheme << "\" authority=\""
+                  << authority << "\" path=\"" << canonicalized_path << "\"";
 
   // Send the request.
   spdy::Http2HeaderBlock headers;
@@ -493,4 +503,18 @@
 
 void MasqueClientSession::ConnectIpClientState::OnHeadersWritten() {}
 
+quiche::QuicheIpAddress MasqueClientSession::GetFakeAddress(
+    absl::string_view hostname) {
+  quiche::QuicheIpAddress address;
+  uint8_t address_bytes[16] = {0xFD};
+  quiche::QuicheRandom::GetInstance()->RandBytes(&address_bytes[1],
+                                                 sizeof(address_bytes) - 1);
+  address.FromPackedString(reinterpret_cast<const char*>(address_bytes),
+                           sizeof(address_bytes));
+  std::string address_bytes_string(reinterpret_cast<const char*>(address_bytes),
+                                   sizeof(address_bytes));
+  fake_addresses_[address_bytes_string] = std::string(hostname);
+  return address;
+}
+
 }  // namespace quic
diff --git a/quiche/quic/masque/masque_client_session.h b/quiche/quic/masque/masque_client_session.h
index ce79c22..4b537b2 100644
--- a/quiche/quic/masque/masque_client_session.h
+++ b/quiche/quic/masque/masque_client_session.h
@@ -116,6 +116,10 @@
   // Close CONNECT-IP stream tied to this encapsulated client session.
   void CloseConnectIpStream(EncapsulatedIpSession* encapsulated_ip_session);
 
+  // Generate a random Unique Local Address and register a mapping from
+  // that address to the corresponding hostname.
+  quiche::QuicheIpAddress GetFakeAddress(absl::string_view hostname);
+
  private:
   // State that the MasqueClientSession keeps for each CONNECT-UDP request.
   class QUIC_NO_EXPORT ConnectUdpClientState
@@ -219,6 +223,9 @@
   std::string uri_template_;
   std::list<ConnectUdpClientState> connect_udp_client_states_;
   std::list<ConnectIpClientState> connect_ip_client_states_;
+  // Maps fake addresses generated by GetFakeAddress() to their corresponding
+  // hostnames.
+  absl::flat_hash_map<std::string, std::string> fake_addresses_;
   Owner* owner_;  // Unowned;
 };
 
diff --git a/quiche/quic/masque/masque_client_tools.cc b/quiche/quic/masque/masque_client_tools.cc
index e7405ec..d77e94d 100644
--- a/quiche/quic/masque/masque_client_tools.cc
+++ b/quiche/quic/masque/masque_client_tools.cc
@@ -19,7 +19,8 @@
                                    QuicEventLoop* event_loop,
                                    std::string url_string,
                                    bool disable_certificate_verification,
-                                   int address_family_for_lookup) {
+                                   int address_family_for_lookup,
+                                   bool dns_on_client) {
   const QuicUrl url(url_string, "https");
   std::unique_ptr<ProofVerifier> proof_verifier;
   if (disable_certificate_verification) {
@@ -29,11 +30,19 @@
   }
 
   // Build the client, and try to connect.
-  const QuicSocketAddress addr = LookupAddress(
-      address_family_for_lookup, url.host(), absl::StrCat(url.port()));
-  if (!addr.IsInitialized()) {
-    QUIC_LOG(ERROR) << "Unable to resolve address: " << url.host();
-    return false;
+  QuicSocketAddress addr;
+  if (dns_on_client) {
+    addr = LookupAddress(address_family_for_lookup, url.host(),
+                         absl::StrCat(url.port()));
+    if (!addr.IsInitialized()) {
+      QUIC_LOG(ERROR) << "Unable to resolve address: " << url.host();
+      return false;
+    }
+  } else {
+    addr = QuicSocketAddress(
+        masque_client->masque_client_session()->GetFakeAddress(url.host()),
+        url.port());
+    QUICHE_CHECK(addr.IsInitialized());
   }
   const QuicServerId server_id(url.host(), url.port());
   auto client = std::make_unique<MasqueEncapsulatedClient>(
diff --git a/quiche/quic/masque/masque_client_tools.h b/quiche/quic/masque/masque_client_tools.h
index bb30a14..932fdfa 100644
--- a/quiche/quic/masque/masque_client_tools.h
+++ b/quiche/quic/masque/masque_client_tools.h
@@ -18,7 +18,8 @@
                                    QuicEventLoop* event_loop,
                                    std::string url_string,
                                    bool disable_certificate_verification,
-                                   int address_family_for_lookup);
+                                   int address_family_for_lookup,
+                                   bool dns_on_client);
 
 }  // namespace tools
 }  // namespace quic