xref: /aosp_15_r20/external/cronet/net/dns/dns_transaction.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_transaction.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <cstdint>
8*6777b538SAndroid Build Coastguard Worker #include <memory>
9*6777b538SAndroid Build Coastguard Worker #include <optional>
10*6777b538SAndroid Build Coastguard Worker #include <set>
11*6777b538SAndroid Build Coastguard Worker #include <string>
12*6777b538SAndroid Build Coastguard Worker #include <string_view>
13*6777b538SAndroid Build Coastguard Worker #include <unordered_map>
14*6777b538SAndroid Build Coastguard Worker #include <utility>
15*6777b538SAndroid Build Coastguard Worker #include <vector>
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker #include "base/base64url.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/containers/circular_deque.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/memory/ref_counted.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/memory/safe_ref.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/memory/weak_ptr.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_functions.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
30*6777b538SAndroid Build Coastguard Worker #include "base/numerics/byte_conversions.h"
31*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
32*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
33*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
34*6777b538SAndroid Build Coastguard Worker #include "base/task/sequenced_task_runner.h"
35*6777b538SAndroid Build Coastguard Worker #include "base/task/single_thread_task_runner.h"
36*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_checker.h"
37*6777b538SAndroid Build Coastguard Worker #include "base/timer/elapsed_timer.h"
38*6777b538SAndroid Build Coastguard Worker #include "base/timer/timer.h"
39*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
40*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
41*6777b538SAndroid Build Coastguard Worker #include "net/base/backoff_entry.h"
42*6777b538SAndroid Build Coastguard Worker #include "net/base/completion_once_callback.h"
43*6777b538SAndroid Build Coastguard Worker #include "net/base/elements_upload_data_stream.h"
44*6777b538SAndroid Build Coastguard Worker #include "net/base/idempotency.h"
45*6777b538SAndroid Build Coastguard Worker #include "net/base/io_buffer.h"
46*6777b538SAndroid Build Coastguard Worker #include "net/base/ip_address.h"
47*6777b538SAndroid Build Coastguard Worker #include "net/base/ip_endpoint.h"
48*6777b538SAndroid Build Coastguard Worker #include "net/base/load_flags.h"
49*6777b538SAndroid Build Coastguard Worker #include "net/base/net_errors.h"
50*6777b538SAndroid Build Coastguard Worker #include "net/base/upload_bytes_element_reader.h"
51*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_config.h"
52*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_names_util.h"
53*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_query.h"
54*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_response.h"
55*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_response_result_extractor.h"
56*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_server_iterator.h"
57*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_session.h"
58*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_udp_tracker.h"
59*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_util.h"
60*6777b538SAndroid Build Coastguard Worker #include "net/dns/host_cache.h"
61*6777b538SAndroid Build Coastguard Worker #include "net/dns/host_resolver_internal_result.h"
62*6777b538SAndroid Build Coastguard Worker #include "net/dns/public/dns_over_https_config.h"
63*6777b538SAndroid Build Coastguard Worker #include "net/dns/public/dns_over_https_server_config.h"
64*6777b538SAndroid Build Coastguard Worker #include "net/dns/public/dns_protocol.h"
65*6777b538SAndroid Build Coastguard Worker #include "net/dns/public/dns_query_type.h"
66*6777b538SAndroid Build Coastguard Worker #include "net/dns/public/secure_dns_policy.h"
67*6777b538SAndroid Build Coastguard Worker #include "net/dns/resolve_context.h"
68*6777b538SAndroid Build Coastguard Worker #include "net/http/http_request_headers.h"
69*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log.h"
70*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_capture_mode.h"
71*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_event_type.h"
72*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_source.h"
73*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_values.h"
74*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_with_source.h"
75*6777b538SAndroid Build Coastguard Worker #include "net/socket/client_socket_factory.h"
76*6777b538SAndroid Build Coastguard Worker #include "net/socket/datagram_client_socket.h"
77*6777b538SAndroid Build Coastguard Worker #include "net/socket/stream_socket.h"
78*6777b538SAndroid Build Coastguard Worker #include "net/third_party/uri_template/uri_template.h"
79*6777b538SAndroid Build Coastguard Worker #include "net/traffic_annotation/network_traffic_annotation.h"
80*6777b538SAndroid Build Coastguard Worker #include "net/url_request/url_request.h"
81*6777b538SAndroid Build Coastguard Worker #include "net/url_request/url_request_context.h"
82*6777b538SAndroid Build Coastguard Worker #include "net/url_request/url_request_context_builder.h"
83*6777b538SAndroid Build Coastguard Worker #include "url/url_constants.h"
84*6777b538SAndroid Build Coastguard Worker 
85*6777b538SAndroid Build Coastguard Worker namespace net {
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker namespace {
88*6777b538SAndroid Build Coastguard Worker 
89*6777b538SAndroid Build Coastguard Worker constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
90*6777b538SAndroid Build Coastguard Worker     net::DefineNetworkTrafficAnnotation("dns_transaction", R"(
91*6777b538SAndroid Build Coastguard Worker         semantics {
92*6777b538SAndroid Build Coastguard Worker           sender: "DNS Transaction"
93*6777b538SAndroid Build Coastguard Worker           description:
94*6777b538SAndroid Build Coastguard Worker             "DNS Transaction implements a stub DNS resolver as defined in RFC "
95*6777b538SAndroid Build Coastguard Worker             "1034."
96*6777b538SAndroid Build Coastguard Worker           trigger:
97*6777b538SAndroid Build Coastguard Worker             "Any network request that may require DNS resolution, including "
98*6777b538SAndroid Build Coastguard Worker             "navigations, connecting to a proxy server, detecting proxy "
99*6777b538SAndroid Build Coastguard Worker             "settings, getting proxy config, certificate checking, and more."
100*6777b538SAndroid Build Coastguard Worker           data:
101*6777b538SAndroid Build Coastguard Worker             "Domain name that needs resolution."
102*6777b538SAndroid Build Coastguard Worker           destination: OTHER
103*6777b538SAndroid Build Coastguard Worker           destination_other:
104*6777b538SAndroid Build Coastguard Worker             "The connection is made to a DNS server based on user's network "
105*6777b538SAndroid Build Coastguard Worker             "settings."
106*6777b538SAndroid Build Coastguard Worker         }
107*6777b538SAndroid Build Coastguard Worker         policy {
108*6777b538SAndroid Build Coastguard Worker           cookies_allowed: NO
109*6777b538SAndroid Build Coastguard Worker           setting:
110*6777b538SAndroid Build Coastguard Worker             "This feature cannot be disabled. Without DNS Transactions Chrome "
111*6777b538SAndroid Build Coastguard Worker             "cannot resolve host names."
112*6777b538SAndroid Build Coastguard Worker           policy_exception_justification:
113*6777b538SAndroid Build Coastguard Worker             "Essential for Chrome's navigation."
114*6777b538SAndroid Build Coastguard Worker         })");
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker const char kDnsOverHttpResponseContentType[] = "application/dns-message";
117*6777b538SAndroid Build Coastguard Worker 
118*6777b538SAndroid Build Coastguard Worker // The maximum size of the DNS message for DoH, per
119*6777b538SAndroid Build Coastguard Worker // https://datatracker.ietf.org/doc/html/rfc8484#section-6
120*6777b538SAndroid Build Coastguard Worker const int64_t kDnsOverHttpResponseMaximumSize = 65535;
121*6777b538SAndroid Build Coastguard Worker 
122*6777b538SAndroid Build Coastguard Worker // Count labels in the fully-qualified name in DNS format.
CountLabels(base::span<const uint8_t> name)123*6777b538SAndroid Build Coastguard Worker int CountLabels(base::span<const uint8_t> name) {
124*6777b538SAndroid Build Coastguard Worker   size_t count = 0;
125*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < name.size() && name[i]; i += name[i] + 1)
126*6777b538SAndroid Build Coastguard Worker     ++count;
127*6777b538SAndroid Build Coastguard Worker   return count;
128*6777b538SAndroid Build Coastguard Worker }
129*6777b538SAndroid Build Coastguard Worker 
IsIPLiteral(const std::string & hostname)130*6777b538SAndroid Build Coastguard Worker bool IsIPLiteral(const std::string& hostname) {
131*6777b538SAndroid Build Coastguard Worker   IPAddress ip;
132*6777b538SAndroid Build Coastguard Worker   return ip.AssignFromIPLiteral(hostname);
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker 
NetLogStartParams(const std::string & hostname,uint16_t qtype)135*6777b538SAndroid Build Coastguard Worker base::Value::Dict NetLogStartParams(const std::string& hostname,
136*6777b538SAndroid Build Coastguard Worker                                     uint16_t qtype) {
137*6777b538SAndroid Build Coastguard Worker   base::Value::Dict dict;
138*6777b538SAndroid Build Coastguard Worker   dict.Set("hostname", hostname);
139*6777b538SAndroid Build Coastguard Worker   dict.Set("query_type", qtype);
140*6777b538SAndroid Build Coastguard Worker   return dict;
141*6777b538SAndroid Build Coastguard Worker }
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
144*6777b538SAndroid Build Coastguard Worker 
145*6777b538SAndroid Build Coastguard Worker // A single asynchronous DNS exchange, which consists of sending out a
146*6777b538SAndroid Build Coastguard Worker // DNS query, waiting for a response, and returning the response that it
147*6777b538SAndroid Build Coastguard Worker // matches. Logging is done in the socket and in the outer DnsTransaction.
148*6777b538SAndroid Build Coastguard Worker class DnsAttempt {
149*6777b538SAndroid Build Coastguard Worker  public:
DnsAttempt(size_t server_index)150*6777b538SAndroid Build Coastguard Worker   explicit DnsAttempt(size_t server_index) : server_index_(server_index) {}
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker   DnsAttempt(const DnsAttempt&) = delete;
153*6777b538SAndroid Build Coastguard Worker   DnsAttempt& operator=(const DnsAttempt&) = delete;
154*6777b538SAndroid Build Coastguard Worker 
155*6777b538SAndroid Build Coastguard Worker   virtual ~DnsAttempt() = default;
156*6777b538SAndroid Build Coastguard Worker   // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
157*6777b538SAndroid Build Coastguard Worker   // and calls |callback| upon completion.
158*6777b538SAndroid Build Coastguard Worker   virtual int Start(CompletionOnceCallback callback) = 0;
159*6777b538SAndroid Build Coastguard Worker 
160*6777b538SAndroid Build Coastguard Worker   // Returns the query of this attempt.
161*6777b538SAndroid Build Coastguard Worker   virtual const DnsQuery* GetQuery() const = 0;
162*6777b538SAndroid Build Coastguard Worker 
163*6777b538SAndroid Build Coastguard Worker   // Returns the response or NULL if has not received a matching response from
164*6777b538SAndroid Build Coastguard Worker   // the server.
165*6777b538SAndroid Build Coastguard Worker   virtual const DnsResponse* GetResponse() const = 0;
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker   virtual base::Value GetRawResponseBufferForLog() const = 0;
168*6777b538SAndroid Build Coastguard Worker 
169*6777b538SAndroid Build Coastguard Worker   // Returns the net log bound to the source of the socket.
170*6777b538SAndroid Build Coastguard Worker   virtual const NetLogWithSource& GetSocketNetLog() const = 0;
171*6777b538SAndroid Build Coastguard Worker 
172*6777b538SAndroid Build Coastguard Worker   // Returns the index of the destination server within DnsConfig::nameservers
173*6777b538SAndroid Build Coastguard Worker   // (or DnsConfig::dns_over_https_servers for secure transactions).
server_index() const174*6777b538SAndroid Build Coastguard Worker   size_t server_index() const { return server_index_; }
175*6777b538SAndroid Build Coastguard Worker 
176*6777b538SAndroid Build Coastguard Worker   // Returns a Value representing the received response, along with a reference
177*6777b538SAndroid Build Coastguard Worker   // to the NetLog source source of the UDP socket used.  The request must have
178*6777b538SAndroid Build Coastguard Worker   // completed before this is called.
NetLogResponseParams(NetLogCaptureMode capture_mode) const179*6777b538SAndroid Build Coastguard Worker   base::Value::Dict NetLogResponseParams(NetLogCaptureMode capture_mode) const {
180*6777b538SAndroid Build Coastguard Worker     base::Value::Dict dict;
181*6777b538SAndroid Build Coastguard Worker 
182*6777b538SAndroid Build Coastguard Worker     if (GetResponse()) {
183*6777b538SAndroid Build Coastguard Worker       DCHECK(GetResponse()->IsValid());
184*6777b538SAndroid Build Coastguard Worker       dict.Set("rcode", GetResponse()->rcode());
185*6777b538SAndroid Build Coastguard Worker       dict.Set("answer_count", static_cast<int>(GetResponse()->answer_count()));
186*6777b538SAndroid Build Coastguard Worker       dict.Set("additional_answer_count",
187*6777b538SAndroid Build Coastguard Worker                static_cast<int>(GetResponse()->additional_answer_count()));
188*6777b538SAndroid Build Coastguard Worker     }
189*6777b538SAndroid Build Coastguard Worker 
190*6777b538SAndroid Build Coastguard Worker     GetSocketNetLog().source().AddToEventParameters(dict);
191*6777b538SAndroid Build Coastguard Worker 
192*6777b538SAndroid Build Coastguard Worker     if (capture_mode == NetLogCaptureMode::kEverything) {
193*6777b538SAndroid Build Coastguard Worker       dict.Set("response_buffer", GetRawResponseBufferForLog());
194*6777b538SAndroid Build Coastguard Worker     }
195*6777b538SAndroid Build Coastguard Worker 
196*6777b538SAndroid Build Coastguard Worker     return dict;
197*6777b538SAndroid Build Coastguard Worker   }
198*6777b538SAndroid Build Coastguard Worker 
199*6777b538SAndroid Build Coastguard Worker   // True if current attempt is pending (waiting for server response).
200*6777b538SAndroid Build Coastguard Worker   virtual bool IsPending() const = 0;
201*6777b538SAndroid Build Coastguard Worker 
202*6777b538SAndroid Build Coastguard Worker  private:
203*6777b538SAndroid Build Coastguard Worker   const size_t server_index_;
204*6777b538SAndroid Build Coastguard Worker };
205*6777b538SAndroid Build Coastguard Worker 
206*6777b538SAndroid Build Coastguard Worker class DnsUDPAttempt : public DnsAttempt {
207*6777b538SAndroid Build Coastguard Worker  public:
DnsUDPAttempt(size_t server_index,std::unique_ptr<DatagramClientSocket> socket,const IPEndPoint & server,std::unique_ptr<DnsQuery> query,DnsUdpTracker * udp_tracker)208*6777b538SAndroid Build Coastguard Worker   DnsUDPAttempt(size_t server_index,
209*6777b538SAndroid Build Coastguard Worker                 std::unique_ptr<DatagramClientSocket> socket,
210*6777b538SAndroid Build Coastguard Worker                 const IPEndPoint& server,
211*6777b538SAndroid Build Coastguard Worker                 std::unique_ptr<DnsQuery> query,
212*6777b538SAndroid Build Coastguard Worker                 DnsUdpTracker* udp_tracker)
213*6777b538SAndroid Build Coastguard Worker       : DnsAttempt(server_index),
214*6777b538SAndroid Build Coastguard Worker         socket_(std::move(socket)),
215*6777b538SAndroid Build Coastguard Worker         server_(server),
216*6777b538SAndroid Build Coastguard Worker         query_(std::move(query)),
217*6777b538SAndroid Build Coastguard Worker         udp_tracker_(udp_tracker) {}
218*6777b538SAndroid Build Coastguard Worker 
219*6777b538SAndroid Build Coastguard Worker   DnsUDPAttempt(const DnsUDPAttempt&) = delete;
220*6777b538SAndroid Build Coastguard Worker   DnsUDPAttempt& operator=(const DnsUDPAttempt&) = delete;
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker   // DnsAttempt methods.
223*6777b538SAndroid Build Coastguard Worker 
Start(CompletionOnceCallback callback)224*6777b538SAndroid Build Coastguard Worker   int Start(CompletionOnceCallback callback) override {
225*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(STATE_NONE, next_state_);
226*6777b538SAndroid Build Coastguard Worker     callback_ = std::move(callback);
227*6777b538SAndroid Build Coastguard Worker     start_time_ = base::TimeTicks::Now();
228*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_CONNECT_COMPLETE;
229*6777b538SAndroid Build Coastguard Worker 
230*6777b538SAndroid Build Coastguard Worker     int rv = socket_->ConnectAsync(
231*6777b538SAndroid Build Coastguard Worker         server_,
232*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&DnsUDPAttempt::OnIOComplete, base::Unretained(this)));
233*6777b538SAndroid Build Coastguard Worker     if (rv == ERR_IO_PENDING) {
234*6777b538SAndroid Build Coastguard Worker       return rv;
235*6777b538SAndroid Build Coastguard Worker     }
236*6777b538SAndroid Build Coastguard Worker     return DoLoop(rv);
237*6777b538SAndroid Build Coastguard Worker   }
238*6777b538SAndroid Build Coastguard Worker 
GetQuery() const239*6777b538SAndroid Build Coastguard Worker   const DnsQuery* GetQuery() const override { return query_.get(); }
240*6777b538SAndroid Build Coastguard Worker 
GetResponse() const241*6777b538SAndroid Build Coastguard Worker   const DnsResponse* GetResponse() const override {
242*6777b538SAndroid Build Coastguard Worker     const DnsResponse* resp = response_.get();
243*6777b538SAndroid Build Coastguard Worker     return (resp != nullptr && resp->IsValid()) ? resp : nullptr;
244*6777b538SAndroid Build Coastguard Worker   }
245*6777b538SAndroid Build Coastguard Worker 
GetRawResponseBufferForLog() const246*6777b538SAndroid Build Coastguard Worker   base::Value GetRawResponseBufferForLog() const override {
247*6777b538SAndroid Build Coastguard Worker     if (!response_)
248*6777b538SAndroid Build Coastguard Worker       return base::Value();
249*6777b538SAndroid Build Coastguard Worker     return NetLogBinaryValue(response_->io_buffer()->data(), read_size_);
250*6777b538SAndroid Build Coastguard Worker   }
251*6777b538SAndroid Build Coastguard Worker 
GetSocketNetLog() const252*6777b538SAndroid Build Coastguard Worker   const NetLogWithSource& GetSocketNetLog() const override {
253*6777b538SAndroid Build Coastguard Worker     return socket_->NetLog();
254*6777b538SAndroid Build Coastguard Worker   }
255*6777b538SAndroid Build Coastguard Worker 
IsPending() const256*6777b538SAndroid Build Coastguard Worker   bool IsPending() const override { return next_state_ != STATE_NONE; }
257*6777b538SAndroid Build Coastguard Worker 
258*6777b538SAndroid Build Coastguard Worker  private:
259*6777b538SAndroid Build Coastguard Worker   enum State {
260*6777b538SAndroid Build Coastguard Worker     STATE_CONNECT_COMPLETE,
261*6777b538SAndroid Build Coastguard Worker     STATE_SEND_QUERY,
262*6777b538SAndroid Build Coastguard Worker     STATE_SEND_QUERY_COMPLETE,
263*6777b538SAndroid Build Coastguard Worker     STATE_READ_RESPONSE,
264*6777b538SAndroid Build Coastguard Worker     STATE_READ_RESPONSE_COMPLETE,
265*6777b538SAndroid Build Coastguard Worker     STATE_NONE,
266*6777b538SAndroid Build Coastguard Worker   };
267*6777b538SAndroid Build Coastguard Worker 
DoLoop(int result)268*6777b538SAndroid Build Coastguard Worker   int DoLoop(int result) {
269*6777b538SAndroid Build Coastguard Worker     CHECK_NE(STATE_NONE, next_state_);
270*6777b538SAndroid Build Coastguard Worker     int rv = result;
271*6777b538SAndroid Build Coastguard Worker     do {
272*6777b538SAndroid Build Coastguard Worker       State state = next_state_;
273*6777b538SAndroid Build Coastguard Worker       next_state_ = STATE_NONE;
274*6777b538SAndroid Build Coastguard Worker       switch (state) {
275*6777b538SAndroid Build Coastguard Worker         case STATE_CONNECT_COMPLETE:
276*6777b538SAndroid Build Coastguard Worker           rv = DoConnectComplete(rv);
277*6777b538SAndroid Build Coastguard Worker           break;
278*6777b538SAndroid Build Coastguard Worker         case STATE_SEND_QUERY:
279*6777b538SAndroid Build Coastguard Worker           rv = DoSendQuery(rv);
280*6777b538SAndroid Build Coastguard Worker           break;
281*6777b538SAndroid Build Coastguard Worker         case STATE_SEND_QUERY_COMPLETE:
282*6777b538SAndroid Build Coastguard Worker           rv = DoSendQueryComplete(rv);
283*6777b538SAndroid Build Coastguard Worker           break;
284*6777b538SAndroid Build Coastguard Worker         case STATE_READ_RESPONSE:
285*6777b538SAndroid Build Coastguard Worker           rv = DoReadResponse();
286*6777b538SAndroid Build Coastguard Worker           break;
287*6777b538SAndroid Build Coastguard Worker         case STATE_READ_RESPONSE_COMPLETE:
288*6777b538SAndroid Build Coastguard Worker           rv = DoReadResponseComplete(rv);
289*6777b538SAndroid Build Coastguard Worker           break;
290*6777b538SAndroid Build Coastguard Worker         default:
291*6777b538SAndroid Build Coastguard Worker           NOTREACHED();
292*6777b538SAndroid Build Coastguard Worker           break;
293*6777b538SAndroid Build Coastguard Worker       }
294*6777b538SAndroid Build Coastguard Worker     } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
295*6777b538SAndroid Build Coastguard Worker 
296*6777b538SAndroid Build Coastguard Worker     if (rv != ERR_IO_PENDING)
297*6777b538SAndroid Build Coastguard Worker       DCHECK_EQ(STATE_NONE, next_state_);
298*6777b538SAndroid Build Coastguard Worker 
299*6777b538SAndroid Build Coastguard Worker     return rv;
300*6777b538SAndroid Build Coastguard Worker   }
301*6777b538SAndroid Build Coastguard Worker 
DoConnectComplete(int rv)302*6777b538SAndroid Build Coastguard Worker   int DoConnectComplete(int rv) {
303*6777b538SAndroid Build Coastguard Worker     if (rv != OK) {
304*6777b538SAndroid Build Coastguard Worker       DVLOG(1) << "Failed to connect socket: " << rv;
305*6777b538SAndroid Build Coastguard Worker       udp_tracker_->RecordConnectionError(rv);
306*6777b538SAndroid Build Coastguard Worker       return ERR_CONNECTION_REFUSED;
307*6777b538SAndroid Build Coastguard Worker     }
308*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_SEND_QUERY;
309*6777b538SAndroid Build Coastguard Worker     IPEndPoint local_address;
310*6777b538SAndroid Build Coastguard Worker     if (socket_->GetLocalAddress(&local_address) == OK)
311*6777b538SAndroid Build Coastguard Worker       udp_tracker_->RecordQuery(local_address.port(), query_->id());
312*6777b538SAndroid Build Coastguard Worker     return OK;
313*6777b538SAndroid Build Coastguard Worker   }
314*6777b538SAndroid Build Coastguard Worker 
DoSendQuery(int rv)315*6777b538SAndroid Build Coastguard Worker   int DoSendQuery(int rv) {
316*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(ERR_IO_PENDING, rv);
317*6777b538SAndroid Build Coastguard Worker     if (rv < 0)
318*6777b538SAndroid Build Coastguard Worker       return rv;
319*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_SEND_QUERY_COMPLETE;
320*6777b538SAndroid Build Coastguard Worker     return socket_->Write(
321*6777b538SAndroid Build Coastguard Worker         query_->io_buffer(), query_->io_buffer()->size(),
322*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&DnsUDPAttempt::OnIOComplete, base::Unretained(this)),
323*6777b538SAndroid Build Coastguard Worker         kTrafficAnnotation);
324*6777b538SAndroid Build Coastguard Worker   }
325*6777b538SAndroid Build Coastguard Worker 
DoSendQueryComplete(int rv)326*6777b538SAndroid Build Coastguard Worker   int DoSendQueryComplete(int rv) {
327*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(ERR_IO_PENDING, rv);
328*6777b538SAndroid Build Coastguard Worker     if (rv < 0)
329*6777b538SAndroid Build Coastguard Worker       return rv;
330*6777b538SAndroid Build Coastguard Worker 
331*6777b538SAndroid Build Coastguard Worker     // Writing to UDP should not result in a partial datagram.
332*6777b538SAndroid Build Coastguard Worker     if (rv != query_->io_buffer()->size())
333*6777b538SAndroid Build Coastguard Worker       return ERR_MSG_TOO_BIG;
334*6777b538SAndroid Build Coastguard Worker 
335*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_READ_RESPONSE;
336*6777b538SAndroid Build Coastguard Worker     return OK;
337*6777b538SAndroid Build Coastguard Worker   }
338*6777b538SAndroid Build Coastguard Worker 
DoReadResponse()339*6777b538SAndroid Build Coastguard Worker   int DoReadResponse() {
340*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_READ_RESPONSE_COMPLETE;
341*6777b538SAndroid Build Coastguard Worker     response_ = std::make_unique<DnsResponse>();
342*6777b538SAndroid Build Coastguard Worker     return socket_->Read(
343*6777b538SAndroid Build Coastguard Worker         response_->io_buffer(), response_->io_buffer_size(),
344*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&DnsUDPAttempt::OnIOComplete, base::Unretained(this)));
345*6777b538SAndroid Build Coastguard Worker   }
346*6777b538SAndroid Build Coastguard Worker 
DoReadResponseComplete(int rv)347*6777b538SAndroid Build Coastguard Worker   int DoReadResponseComplete(int rv) {
348*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(ERR_IO_PENDING, rv);
349*6777b538SAndroid Build Coastguard Worker     if (rv < 0)
350*6777b538SAndroid Build Coastguard Worker       return rv;
351*6777b538SAndroid Build Coastguard Worker     read_size_ = rv;
352*6777b538SAndroid Build Coastguard Worker 
353*6777b538SAndroid Build Coastguard Worker     bool parse_result = response_->InitParse(rv, *query_);
354*6777b538SAndroid Build Coastguard Worker     if (response_->id())
355*6777b538SAndroid Build Coastguard Worker       udp_tracker_->RecordResponseId(query_->id(), response_->id().value());
356*6777b538SAndroid Build Coastguard Worker 
357*6777b538SAndroid Build Coastguard Worker     if (!parse_result)
358*6777b538SAndroid Build Coastguard Worker       return ERR_DNS_MALFORMED_RESPONSE;
359*6777b538SAndroid Build Coastguard Worker     if (response_->flags() & dns_protocol::kFlagTC)
360*6777b538SAndroid Build Coastguard Worker       return ERR_DNS_SERVER_REQUIRES_TCP;
361*6777b538SAndroid Build Coastguard Worker     if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
362*6777b538SAndroid Build Coastguard Worker       return ERR_NAME_NOT_RESOLVED;
363*6777b538SAndroid Build Coastguard Worker     if (response_->rcode() != dns_protocol::kRcodeNOERROR)
364*6777b538SAndroid Build Coastguard Worker       return ERR_DNS_SERVER_FAILED;
365*6777b538SAndroid Build Coastguard Worker 
366*6777b538SAndroid Build Coastguard Worker     return OK;
367*6777b538SAndroid Build Coastguard Worker   }
368*6777b538SAndroid Build Coastguard Worker 
OnIOComplete(int rv)369*6777b538SAndroid Build Coastguard Worker   void OnIOComplete(int rv) {
370*6777b538SAndroid Build Coastguard Worker     rv = DoLoop(rv);
371*6777b538SAndroid Build Coastguard Worker     if (rv != ERR_IO_PENDING)
372*6777b538SAndroid Build Coastguard Worker       std::move(callback_).Run(rv);
373*6777b538SAndroid Build Coastguard Worker   }
374*6777b538SAndroid Build Coastguard Worker 
375*6777b538SAndroid Build Coastguard Worker   State next_state_ = STATE_NONE;
376*6777b538SAndroid Build Coastguard Worker   base::TimeTicks start_time_;
377*6777b538SAndroid Build Coastguard Worker 
378*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DatagramClientSocket> socket_;
379*6777b538SAndroid Build Coastguard Worker   IPEndPoint server_;
380*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DnsQuery> query_;
381*6777b538SAndroid Build Coastguard Worker 
382*6777b538SAndroid Build Coastguard Worker   // Should be owned by the DnsSession, to which the transaction should own a
383*6777b538SAndroid Build Coastguard Worker   // reference.
384*6777b538SAndroid Build Coastguard Worker   const raw_ptr<DnsUdpTracker> udp_tracker_;
385*6777b538SAndroid Build Coastguard Worker 
386*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DnsResponse> response_;
387*6777b538SAndroid Build Coastguard Worker   int read_size_ = 0;
388*6777b538SAndroid Build Coastguard Worker 
389*6777b538SAndroid Build Coastguard Worker   CompletionOnceCallback callback_;
390*6777b538SAndroid Build Coastguard Worker };
391*6777b538SAndroid Build Coastguard Worker 
392*6777b538SAndroid Build Coastguard Worker class DnsHTTPAttempt : public DnsAttempt, public URLRequest::Delegate {
393*6777b538SAndroid Build Coastguard Worker  public:
DnsHTTPAttempt(size_t doh_server_index,std::unique_ptr<DnsQuery> query,const string & server_template,const GURL & gurl_without_parameters,bool use_post,URLRequestContext * url_request_context,const IsolationInfo & isolation_info,RequestPriority request_priority_,bool is_probe)394*6777b538SAndroid Build Coastguard Worker   DnsHTTPAttempt(size_t doh_server_index,
395*6777b538SAndroid Build Coastguard Worker                  std::unique_ptr<DnsQuery> query,
396*6777b538SAndroid Build Coastguard Worker                  const string& server_template,
397*6777b538SAndroid Build Coastguard Worker                  const GURL& gurl_without_parameters,
398*6777b538SAndroid Build Coastguard Worker                  bool use_post,
399*6777b538SAndroid Build Coastguard Worker                  URLRequestContext* url_request_context,
400*6777b538SAndroid Build Coastguard Worker                  const IsolationInfo& isolation_info,
401*6777b538SAndroid Build Coastguard Worker                  RequestPriority request_priority_,
402*6777b538SAndroid Build Coastguard Worker                  bool is_probe)
403*6777b538SAndroid Build Coastguard Worker       : DnsAttempt(doh_server_index),
404*6777b538SAndroid Build Coastguard Worker         query_(std::move(query)),
405*6777b538SAndroid Build Coastguard Worker         net_log_(NetLogWithSource::Make(NetLog::Get(),
406*6777b538SAndroid Build Coastguard Worker                                         NetLogSourceType::DNS_OVER_HTTPS)) {
407*6777b538SAndroid Build Coastguard Worker     GURL url;
408*6777b538SAndroid Build Coastguard Worker     if (use_post) {
409*6777b538SAndroid Build Coastguard Worker       // Set url for a POST request
410*6777b538SAndroid Build Coastguard Worker       url = gurl_without_parameters;
411*6777b538SAndroid Build Coastguard Worker     } else {
412*6777b538SAndroid Build Coastguard Worker       // Set url for a GET request
413*6777b538SAndroid Build Coastguard Worker       std::string url_string;
414*6777b538SAndroid Build Coastguard Worker       std::unordered_map<string, string> parameters;
415*6777b538SAndroid Build Coastguard Worker       std::string encoded_query;
416*6777b538SAndroid Build Coastguard Worker       base::Base64UrlEncode(std::string_view(query_->io_buffer()->data(),
417*6777b538SAndroid Build Coastguard Worker                                              query_->io_buffer()->size()),
418*6777b538SAndroid Build Coastguard Worker                             base::Base64UrlEncodePolicy::OMIT_PADDING,
419*6777b538SAndroid Build Coastguard Worker                             &encoded_query);
420*6777b538SAndroid Build Coastguard Worker       parameters.emplace("dns", encoded_query);
421*6777b538SAndroid Build Coastguard Worker       uri_template::Expand(server_template, parameters, &url_string);
422*6777b538SAndroid Build Coastguard Worker       url = GURL(url_string);
423*6777b538SAndroid Build Coastguard Worker     }
424*6777b538SAndroid Build Coastguard Worker 
425*6777b538SAndroid Build Coastguard Worker     net_log_.BeginEvent(NetLogEventType::DOH_URL_REQUEST, [&] {
426*6777b538SAndroid Build Coastguard Worker       if (is_probe) {
427*6777b538SAndroid Build Coastguard Worker         return NetLogStartParams("(probe)", query_->qtype());
428*6777b538SAndroid Build Coastguard Worker       }
429*6777b538SAndroid Build Coastguard Worker       std::optional<std::string> hostname =
430*6777b538SAndroid Build Coastguard Worker           dns_names_util::NetworkToDottedName(query_->qname());
431*6777b538SAndroid Build Coastguard Worker       DCHECK(hostname.has_value());
432*6777b538SAndroid Build Coastguard Worker       return NetLogStartParams(*hostname, query_->qtype());
433*6777b538SAndroid Build Coastguard Worker     });
434*6777b538SAndroid Build Coastguard Worker 
435*6777b538SAndroid Build Coastguard Worker     HttpRequestHeaders extra_request_headers;
436*6777b538SAndroid Build Coastguard Worker     extra_request_headers.SetHeader(HttpRequestHeaders::kAccept,
437*6777b538SAndroid Build Coastguard Worker                                     kDnsOverHttpResponseContentType);
438*6777b538SAndroid Build Coastguard Worker     // Send minimal request headers where possible.
439*6777b538SAndroid Build Coastguard Worker     extra_request_headers.SetHeader(HttpRequestHeaders::kAcceptLanguage, "*");
440*6777b538SAndroid Build Coastguard Worker     extra_request_headers.SetHeader(HttpRequestHeaders::kUserAgent, "Chrome");
441*6777b538SAndroid Build Coastguard Worker     extra_request_headers.SetHeader(HttpRequestHeaders::kAcceptEncoding,
442*6777b538SAndroid Build Coastguard Worker                                     "identity");
443*6777b538SAndroid Build Coastguard Worker 
444*6777b538SAndroid Build Coastguard Worker     DCHECK(url_request_context);
445*6777b538SAndroid Build Coastguard Worker     request_ = url_request_context->CreateRequest(
446*6777b538SAndroid Build Coastguard Worker         url, request_priority_, this,
447*6777b538SAndroid Build Coastguard Worker         net::DefineNetworkTrafficAnnotation("dns_over_https", R"(
448*6777b538SAndroid Build Coastguard Worker         semantics {
449*6777b538SAndroid Build Coastguard Worker           sender: "DNS over HTTPS"
450*6777b538SAndroid Build Coastguard Worker           description: "Domain name resolution over HTTPS"
451*6777b538SAndroid Build Coastguard Worker           trigger: "User enters a navigates to a domain or Chrome otherwise "
452*6777b538SAndroid Build Coastguard Worker                    "makes a connection to a domain whose IP address isn't cached"
453*6777b538SAndroid Build Coastguard Worker           data: "The domain name that is being requested"
454*6777b538SAndroid Build Coastguard Worker           destination: OTHER
455*6777b538SAndroid Build Coastguard Worker           destination_other: "The user configured DNS over HTTPS server, which"
456*6777b538SAndroid Build Coastguard Worker                              "may be dns.google.com"
457*6777b538SAndroid Build Coastguard Worker         }
458*6777b538SAndroid Build Coastguard Worker         policy {
459*6777b538SAndroid Build Coastguard Worker           cookies_allowed: NO
460*6777b538SAndroid Build Coastguard Worker           setting:
461*6777b538SAndroid Build Coastguard Worker             "You can configure this feature via that 'dns_over_https_servers' and"
462*6777b538SAndroid Build Coastguard Worker             "'dns_over_https.method' prefs. Empty lists imply this feature is"
463*6777b538SAndroid Build Coastguard Worker             "disabled"
464*6777b538SAndroid Build Coastguard Worker           policy_exception_justification: "Experimental feature that"
465*6777b538SAndroid Build Coastguard Worker                                           "is disabled by default"
466*6777b538SAndroid Build Coastguard Worker         }
467*6777b538SAndroid Build Coastguard Worker       )"),
468*6777b538SAndroid Build Coastguard Worker         /*is_for_websockets=*/false, net_log_.source());
469*6777b538SAndroid Build Coastguard Worker 
470*6777b538SAndroid Build Coastguard Worker     if (use_post) {
471*6777b538SAndroid Build Coastguard Worker       request_->set_method("POST");
472*6777b538SAndroid Build Coastguard Worker       request_->SetIdempotency(IDEMPOTENT);
473*6777b538SAndroid Build Coastguard Worker       std::unique_ptr<UploadElementReader> reader =
474*6777b538SAndroid Build Coastguard Worker           std::make_unique<UploadBytesElementReader>(
475*6777b538SAndroid Build Coastguard Worker               query_->io_buffer()->data(), query_->io_buffer()->size());
476*6777b538SAndroid Build Coastguard Worker       request_->set_upload(
477*6777b538SAndroid Build Coastguard Worker           ElementsUploadDataStream::CreateWithReader(std::move(reader), 0));
478*6777b538SAndroid Build Coastguard Worker       extra_request_headers.SetHeader(HttpRequestHeaders::kContentType,
479*6777b538SAndroid Build Coastguard Worker                                       kDnsOverHttpResponseContentType);
480*6777b538SAndroid Build Coastguard Worker     }
481*6777b538SAndroid Build Coastguard Worker 
482*6777b538SAndroid Build Coastguard Worker     request_->SetExtraRequestHeaders(extra_request_headers);
483*6777b538SAndroid Build Coastguard Worker     // Apply special policy to DNS lookups for for a DoH server hostname to
484*6777b538SAndroid Build Coastguard Worker     // avoid deadlock and enable the use of preconfigured IP addresses.
485*6777b538SAndroid Build Coastguard Worker     request_->SetSecureDnsPolicy(SecureDnsPolicy::kBootstrap);
486*6777b538SAndroid Build Coastguard Worker     request_->SetLoadFlags(request_->load_flags() | LOAD_DISABLE_CACHE |
487*6777b538SAndroid Build Coastguard Worker                            LOAD_BYPASS_PROXY);
488*6777b538SAndroid Build Coastguard Worker     request_->set_allow_credentials(false);
489*6777b538SAndroid Build Coastguard Worker     request_->set_isolation_info(isolation_info);
490*6777b538SAndroid Build Coastguard Worker   }
491*6777b538SAndroid Build Coastguard Worker 
492*6777b538SAndroid Build Coastguard Worker   DnsHTTPAttempt(const DnsHTTPAttempt&) = delete;
493*6777b538SAndroid Build Coastguard Worker   DnsHTTPAttempt& operator=(const DnsHTTPAttempt&) = delete;
494*6777b538SAndroid Build Coastguard Worker 
495*6777b538SAndroid Build Coastguard Worker   // DnsAttempt overrides.
496*6777b538SAndroid Build Coastguard Worker 
497*6777b538SAndroid Build Coastguard Worker   int Start(CompletionOnceCallback callback) override {
498*6777b538SAndroid Build Coastguard Worker     callback_ = std::move(callback);
499*6777b538SAndroid Build Coastguard Worker     // Start the request asynchronously to avoid reentrancy in
500*6777b538SAndroid Build Coastguard Worker     // the network stack.
501*6777b538SAndroid Build Coastguard Worker     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
502*6777b538SAndroid Build Coastguard Worker         FROM_HERE, base::BindOnce(&DnsHTTPAttempt::StartAsync,
503*6777b538SAndroid Build Coastguard Worker                                   weak_factory_.GetWeakPtr()));
504*6777b538SAndroid Build Coastguard Worker     return ERR_IO_PENDING;
505*6777b538SAndroid Build Coastguard Worker   }
506*6777b538SAndroid Build Coastguard Worker 
507*6777b538SAndroid Build Coastguard Worker   const DnsQuery* GetQuery() const override { return query_.get(); }
508*6777b538SAndroid Build Coastguard Worker   const DnsResponse* GetResponse() const override {
509*6777b538SAndroid Build Coastguard Worker     const DnsResponse* resp = response_.get();
510*6777b538SAndroid Build Coastguard Worker     return (resp != nullptr && resp->IsValid()) ? resp : nullptr;
511*6777b538SAndroid Build Coastguard Worker   }
512*6777b538SAndroid Build Coastguard Worker   base::Value GetRawResponseBufferForLog() const override {
513*6777b538SAndroid Build Coastguard Worker     if (!response_)
514*6777b538SAndroid Build Coastguard Worker       return base::Value();
515*6777b538SAndroid Build Coastguard Worker 
516*6777b538SAndroid Build Coastguard Worker     return NetLogBinaryValue(response_->io_buffer()->data(),
517*6777b538SAndroid Build Coastguard Worker                              response_->io_buffer_size());
518*6777b538SAndroid Build Coastguard Worker   }
519*6777b538SAndroid Build Coastguard Worker   const NetLogWithSource& GetSocketNetLog() const override { return net_log_; }
520*6777b538SAndroid Build Coastguard Worker 
521*6777b538SAndroid Build Coastguard Worker   // URLRequest::Delegate overrides
522*6777b538SAndroid Build Coastguard Worker 
523*6777b538SAndroid Build Coastguard Worker   void OnResponseStarted(net::URLRequest* request, int net_error) override {
524*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(net::ERR_IO_PENDING, net_error);
525*6777b538SAndroid Build Coastguard Worker     std::string content_type;
526*6777b538SAndroid Build Coastguard Worker     if (net_error != OK) {
527*6777b538SAndroid Build Coastguard Worker       // Update the error code if there was an issue resolving the secure
528*6777b538SAndroid Build Coastguard Worker       // server hostname.
529*6777b538SAndroid Build Coastguard Worker       if (IsHostnameResolutionError(net_error))
530*6777b538SAndroid Build Coastguard Worker         net_error = ERR_DNS_SECURE_RESOLVER_HOSTNAME_RESOLUTION_FAILED;
531*6777b538SAndroid Build Coastguard Worker       ResponseCompleted(net_error);
532*6777b538SAndroid Build Coastguard Worker       return;
533*6777b538SAndroid Build Coastguard Worker     }
534*6777b538SAndroid Build Coastguard Worker 
535*6777b538SAndroid Build Coastguard Worker     if (request_->GetResponseCode() != 200 ||
536*6777b538SAndroid Build Coastguard Worker         !request->response_headers()->GetMimeType(&content_type) ||
537*6777b538SAndroid Build Coastguard Worker         0 != content_type.compare(kDnsOverHttpResponseContentType)) {
538*6777b538SAndroid Build Coastguard Worker       ResponseCompleted(ERR_DNS_MALFORMED_RESPONSE);
539*6777b538SAndroid Build Coastguard Worker       return;
540*6777b538SAndroid Build Coastguard Worker     }
541*6777b538SAndroid Build Coastguard Worker 
542*6777b538SAndroid Build Coastguard Worker     buffer_ = base::MakeRefCounted<GrowableIOBuffer>();
543*6777b538SAndroid Build Coastguard Worker 
544*6777b538SAndroid Build Coastguard Worker     if (request->response_headers()->HasHeader(
545*6777b538SAndroid Build Coastguard Worker             HttpRequestHeaders::kContentLength)) {
546*6777b538SAndroid Build Coastguard Worker       if (request_->response_headers()->GetContentLength() >
547*6777b538SAndroid Build Coastguard Worker           kDnsOverHttpResponseMaximumSize) {
548*6777b538SAndroid Build Coastguard Worker         ResponseCompleted(ERR_DNS_MALFORMED_RESPONSE);
549*6777b538SAndroid Build Coastguard Worker         return;
550*6777b538SAndroid Build Coastguard Worker       }
551*6777b538SAndroid Build Coastguard Worker 
552*6777b538SAndroid Build Coastguard Worker       buffer_->SetCapacity(request_->response_headers()->GetContentLength() +
553*6777b538SAndroid Build Coastguard Worker                            1);
554*6777b538SAndroid Build Coastguard Worker     } else {
555*6777b538SAndroid Build Coastguard Worker       buffer_->SetCapacity(kDnsOverHttpResponseMaximumSize + 1);
556*6777b538SAndroid Build Coastguard Worker     }
557*6777b538SAndroid Build Coastguard Worker 
558*6777b538SAndroid Build Coastguard Worker     DCHECK(buffer_->data());
559*6777b538SAndroid Build Coastguard Worker     DCHECK_GT(buffer_->capacity(), 0);
560*6777b538SAndroid Build Coastguard Worker 
561*6777b538SAndroid Build Coastguard Worker     int bytes_read =
562*6777b538SAndroid Build Coastguard Worker         request_->Read(buffer_.get(), buffer_->RemainingCapacity());
563*6777b538SAndroid Build Coastguard Worker 
564*6777b538SAndroid Build Coastguard Worker     // If IO is pending, wait for the URLRequest to call OnReadCompleted.
565*6777b538SAndroid Build Coastguard Worker     if (bytes_read == net::ERR_IO_PENDING)
566*6777b538SAndroid Build Coastguard Worker       return;
567*6777b538SAndroid Build Coastguard Worker 
568*6777b538SAndroid Build Coastguard Worker     OnReadCompleted(request_.get(), bytes_read);
569*6777b538SAndroid Build Coastguard Worker   }
570*6777b538SAndroid Build Coastguard Worker 
571*6777b538SAndroid Build Coastguard Worker   void OnReceivedRedirect(URLRequest* request,
572*6777b538SAndroid Build Coastguard Worker                           const RedirectInfo& redirect_info,
573*6777b538SAndroid Build Coastguard Worker                           bool* defer_redirect) override {
574*6777b538SAndroid Build Coastguard Worker     // Section 5 of RFC 8484 states that scheme must be https.
575*6777b538SAndroid Build Coastguard Worker     if (!redirect_info.new_url.SchemeIs(url::kHttpsScheme)) {
576*6777b538SAndroid Build Coastguard Worker       request->Cancel();
577*6777b538SAndroid Build Coastguard Worker     }
578*6777b538SAndroid Build Coastguard Worker   }
579*6777b538SAndroid Build Coastguard Worker 
580*6777b538SAndroid Build Coastguard Worker   void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
581*6777b538SAndroid Build Coastguard Worker     // bytes_read can be an error.
582*6777b538SAndroid Build Coastguard Worker     if (bytes_read < 0) {
583*6777b538SAndroid Build Coastguard Worker       ResponseCompleted(bytes_read);
584*6777b538SAndroid Build Coastguard Worker       return;
585*6777b538SAndroid Build Coastguard Worker     }
586*6777b538SAndroid Build Coastguard Worker 
587*6777b538SAndroid Build Coastguard Worker     DCHECK_GE(bytes_read, 0);
588*6777b538SAndroid Build Coastguard Worker 
589*6777b538SAndroid Build Coastguard Worker     if (bytes_read > 0) {
590*6777b538SAndroid Build Coastguard Worker       if (buffer_->offset() + bytes_read > kDnsOverHttpResponseMaximumSize) {
591*6777b538SAndroid Build Coastguard Worker         ResponseCompleted(ERR_DNS_MALFORMED_RESPONSE);
592*6777b538SAndroid Build Coastguard Worker         return;
593*6777b538SAndroid Build Coastguard Worker       }
594*6777b538SAndroid Build Coastguard Worker 
595*6777b538SAndroid Build Coastguard Worker       buffer_->set_offset(buffer_->offset() + bytes_read);
596*6777b538SAndroid Build Coastguard Worker 
597*6777b538SAndroid Build Coastguard Worker       if (buffer_->RemainingCapacity() == 0) {
598*6777b538SAndroid Build Coastguard Worker         buffer_->SetCapacity(buffer_->capacity() + 16384);  // Grow by 16kb.
599*6777b538SAndroid Build Coastguard Worker       }
600*6777b538SAndroid Build Coastguard Worker 
601*6777b538SAndroid Build Coastguard Worker       DCHECK(buffer_->data());
602*6777b538SAndroid Build Coastguard Worker       DCHECK_GT(buffer_->capacity(), 0);
603*6777b538SAndroid Build Coastguard Worker 
604*6777b538SAndroid Build Coastguard Worker       int read_result =
605*6777b538SAndroid Build Coastguard Worker           request_->Read(buffer_.get(), buffer_->RemainingCapacity());
606*6777b538SAndroid Build Coastguard Worker 
607*6777b538SAndroid Build Coastguard Worker       // If IO is pending, wait for the URLRequest to call OnReadCompleted.
608*6777b538SAndroid Build Coastguard Worker       if (read_result == net::ERR_IO_PENDING)
609*6777b538SAndroid Build Coastguard Worker         return;
610*6777b538SAndroid Build Coastguard Worker 
611*6777b538SAndroid Build Coastguard Worker       if (read_result <= 0) {
612*6777b538SAndroid Build Coastguard Worker         OnReadCompleted(request_.get(), read_result);
613*6777b538SAndroid Build Coastguard Worker       } else {
614*6777b538SAndroid Build Coastguard Worker         // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
615*6777b538SAndroid Build Coastguard Worker         // thread in case the URLRequest can provide data synchronously.
616*6777b538SAndroid Build Coastguard Worker         base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
617*6777b538SAndroid Build Coastguard Worker             FROM_HERE, base::BindOnce(&DnsHTTPAttempt::OnReadCompleted,
618*6777b538SAndroid Build Coastguard Worker                                       weak_factory_.GetWeakPtr(),
619*6777b538SAndroid Build Coastguard Worker                                       request_.get(), read_result));
620*6777b538SAndroid Build Coastguard Worker       }
621*6777b538SAndroid Build Coastguard Worker     } else {
622*6777b538SAndroid Build Coastguard Worker       // URLRequest reported an EOF. Call ResponseCompleted.
623*6777b538SAndroid Build Coastguard Worker       DCHECK_EQ(0, bytes_read);
624*6777b538SAndroid Build Coastguard Worker       ResponseCompleted(net::OK);
625*6777b538SAndroid Build Coastguard Worker     }
626*6777b538SAndroid Build Coastguard Worker   }
627*6777b538SAndroid Build Coastguard Worker 
628*6777b538SAndroid Build Coastguard Worker   bool IsPending() const override { return !callback_.is_null(); }
629*6777b538SAndroid Build Coastguard Worker 
630*6777b538SAndroid Build Coastguard Worker  private:
631*6777b538SAndroid Build Coastguard Worker   void StartAsync() {
632*6777b538SAndroid Build Coastguard Worker     DCHECK(request_);
633*6777b538SAndroid Build Coastguard Worker     request_->Start();
634*6777b538SAndroid Build Coastguard Worker   }
635*6777b538SAndroid Build Coastguard Worker 
636*6777b538SAndroid Build Coastguard Worker   void ResponseCompleted(int net_error) {
637*6777b538SAndroid Build Coastguard Worker     request_.reset();
638*6777b538SAndroid Build Coastguard Worker     std::move(callback_).Run(CompleteResponse(net_error));
639*6777b538SAndroid Build Coastguard Worker   }
640*6777b538SAndroid Build Coastguard Worker 
641*6777b538SAndroid Build Coastguard Worker   int CompleteResponse(int net_error) {
642*6777b538SAndroid Build Coastguard Worker     net_log_.EndEventWithNetErrorCode(NetLogEventType::DOH_URL_REQUEST,
643*6777b538SAndroid Build Coastguard Worker                                       net_error);
644*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(net::ERR_IO_PENDING, net_error);
645*6777b538SAndroid Build Coastguard Worker     if (net_error != OK) {
646*6777b538SAndroid Build Coastguard Worker       return net_error;
647*6777b538SAndroid Build Coastguard Worker     }
648*6777b538SAndroid Build Coastguard Worker     if (!buffer_.get() || 0 == buffer_->capacity())
649*6777b538SAndroid Build Coastguard Worker       return ERR_DNS_MALFORMED_RESPONSE;
650*6777b538SAndroid Build Coastguard Worker 
651*6777b538SAndroid Build Coastguard Worker     size_t size = buffer_->offset();
652*6777b538SAndroid Build Coastguard Worker     buffer_->set_offset(0);
653*6777b538SAndroid Build Coastguard Worker     if (size == 0u)
654*6777b538SAndroid Build Coastguard Worker       return ERR_DNS_MALFORMED_RESPONSE;
655*6777b538SAndroid Build Coastguard Worker     response_ = std::make_unique<DnsResponse>(buffer_, size);
656*6777b538SAndroid Build Coastguard Worker     if (!response_->InitParse(size, *query_))
657*6777b538SAndroid Build Coastguard Worker       return ERR_DNS_MALFORMED_RESPONSE;
658*6777b538SAndroid Build Coastguard Worker     if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
659*6777b538SAndroid Build Coastguard Worker       return ERR_NAME_NOT_RESOLVED;
660*6777b538SAndroid Build Coastguard Worker     if (response_->rcode() != dns_protocol::kRcodeNOERROR)
661*6777b538SAndroid Build Coastguard Worker       return ERR_DNS_SERVER_FAILED;
662*6777b538SAndroid Build Coastguard Worker     return OK;
663*6777b538SAndroid Build Coastguard Worker   }
664*6777b538SAndroid Build Coastguard Worker 
665*6777b538SAndroid Build Coastguard Worker   scoped_refptr<GrowableIOBuffer> buffer_;
666*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DnsQuery> query_;
667*6777b538SAndroid Build Coastguard Worker   CompletionOnceCallback callback_;
668*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DnsResponse> response_;
669*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<URLRequest> request_;
670*6777b538SAndroid Build Coastguard Worker   NetLogWithSource net_log_;
671*6777b538SAndroid Build Coastguard Worker 
672*6777b538SAndroid Build Coastguard Worker   base::WeakPtrFactory<DnsHTTPAttempt> weak_factory_{this};
673*6777b538SAndroid Build Coastguard Worker };
674*6777b538SAndroid Build Coastguard Worker 
675*6777b538SAndroid Build Coastguard Worker void ConstructDnsHTTPAttempt(DnsSession* session,
676*6777b538SAndroid Build Coastguard Worker                              size_t doh_server_index,
677*6777b538SAndroid Build Coastguard Worker                              base::span<const uint8_t> qname,
678*6777b538SAndroid Build Coastguard Worker                              uint16_t qtype,
679*6777b538SAndroid Build Coastguard Worker                              const OptRecordRdata* opt_rdata,
680*6777b538SAndroid Build Coastguard Worker                              std::vector<std::unique_ptr<DnsAttempt>>* attempts,
681*6777b538SAndroid Build Coastguard Worker                              URLRequestContext* url_request_context,
682*6777b538SAndroid Build Coastguard Worker                              const IsolationInfo& isolation_info,
683*6777b538SAndroid Build Coastguard Worker                              RequestPriority request_priority,
684*6777b538SAndroid Build Coastguard Worker                              bool is_probe) {
685*6777b538SAndroid Build Coastguard Worker   DCHECK(url_request_context);
686*6777b538SAndroid Build Coastguard Worker 
687*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DnsQuery> query;
688*6777b538SAndroid Build Coastguard Worker   if (attempts->empty()) {
689*6777b538SAndroid Build Coastguard Worker     query =
690*6777b538SAndroid Build Coastguard Worker         std::make_unique<DnsQuery>(/*id=*/0, qname, qtype, opt_rdata,
691*6777b538SAndroid Build Coastguard Worker                                    DnsQuery::PaddingStrategy::BLOCK_LENGTH_128);
692*6777b538SAndroid Build Coastguard Worker   } else {
693*6777b538SAndroid Build Coastguard Worker     query = std::make_unique<DnsQuery>(*attempts->at(0)->GetQuery());
694*6777b538SAndroid Build Coastguard Worker   }
695*6777b538SAndroid Build Coastguard Worker 
696*6777b538SAndroid Build Coastguard Worker   DCHECK_LT(doh_server_index, session->config().doh_config.servers().size());
697*6777b538SAndroid Build Coastguard Worker   const DnsOverHttpsServerConfig& doh_server =
698*6777b538SAndroid Build Coastguard Worker       session->config().doh_config.servers()[doh_server_index];
699*6777b538SAndroid Build Coastguard Worker   GURL gurl_without_parameters(
700*6777b538SAndroid Build Coastguard Worker       GetURLFromTemplateWithoutParameters(doh_server.server_template()));
701*6777b538SAndroid Build Coastguard Worker   attempts->push_back(std::make_unique<DnsHTTPAttempt>(
702*6777b538SAndroid Build Coastguard Worker       doh_server_index, std::move(query), doh_server.server_template(),
703*6777b538SAndroid Build Coastguard Worker       gurl_without_parameters, doh_server.use_post(), url_request_context,
704*6777b538SAndroid Build Coastguard Worker       isolation_info, request_priority, is_probe));
705*6777b538SAndroid Build Coastguard Worker }
706*6777b538SAndroid Build Coastguard Worker 
707*6777b538SAndroid Build Coastguard Worker class DnsTCPAttempt : public DnsAttempt {
708*6777b538SAndroid Build Coastguard Worker  public:
709*6777b538SAndroid Build Coastguard Worker   DnsTCPAttempt(size_t server_index,
710*6777b538SAndroid Build Coastguard Worker                 std::unique_ptr<StreamSocket> socket,
711*6777b538SAndroid Build Coastguard Worker                 std::unique_ptr<DnsQuery> query)
712*6777b538SAndroid Build Coastguard Worker       : DnsAttempt(server_index),
713*6777b538SAndroid Build Coastguard Worker         socket_(std::move(socket)),
714*6777b538SAndroid Build Coastguard Worker         query_(std::move(query)),
715*6777b538SAndroid Build Coastguard Worker         length_buffer_(
716*6777b538SAndroid Build Coastguard Worker             base::MakeRefCounted<IOBufferWithSize>(sizeof(uint16_t))) {}
717*6777b538SAndroid Build Coastguard Worker 
718*6777b538SAndroid Build Coastguard Worker   DnsTCPAttempt(const DnsTCPAttempt&) = delete;
719*6777b538SAndroid Build Coastguard Worker   DnsTCPAttempt& operator=(const DnsTCPAttempt&) = delete;
720*6777b538SAndroid Build Coastguard Worker 
721*6777b538SAndroid Build Coastguard Worker   // DnsAttempt:
722*6777b538SAndroid Build Coastguard Worker   int Start(CompletionOnceCallback callback) override {
723*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(STATE_NONE, next_state_);
724*6777b538SAndroid Build Coastguard Worker     callback_ = std::move(callback);
725*6777b538SAndroid Build Coastguard Worker     start_time_ = base::TimeTicks::Now();
726*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_CONNECT_COMPLETE;
727*6777b538SAndroid Build Coastguard Worker     int rv = socket_->Connect(
728*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
729*6777b538SAndroid Build Coastguard Worker     if (rv == ERR_IO_PENDING) {
730*6777b538SAndroid Build Coastguard Worker       return rv;
731*6777b538SAndroid Build Coastguard Worker     }
732*6777b538SAndroid Build Coastguard Worker     return DoLoop(rv);
733*6777b538SAndroid Build Coastguard Worker   }
734*6777b538SAndroid Build Coastguard Worker 
735*6777b538SAndroid Build Coastguard Worker   const DnsQuery* GetQuery() const override { return query_.get(); }
736*6777b538SAndroid Build Coastguard Worker 
737*6777b538SAndroid Build Coastguard Worker   const DnsResponse* GetResponse() const override {
738*6777b538SAndroid Build Coastguard Worker     const DnsResponse* resp = response_.get();
739*6777b538SAndroid Build Coastguard Worker     return (resp != nullptr && resp->IsValid()) ? resp : nullptr;
740*6777b538SAndroid Build Coastguard Worker   }
741*6777b538SAndroid Build Coastguard Worker 
742*6777b538SAndroid Build Coastguard Worker   base::Value GetRawResponseBufferForLog() const override {
743*6777b538SAndroid Build Coastguard Worker     if (!response_)
744*6777b538SAndroid Build Coastguard Worker       return base::Value();
745*6777b538SAndroid Build Coastguard Worker 
746*6777b538SAndroid Build Coastguard Worker     return NetLogBinaryValue(response_->io_buffer()->data(),
747*6777b538SAndroid Build Coastguard Worker                              response_->io_buffer_size());
748*6777b538SAndroid Build Coastguard Worker   }
749*6777b538SAndroid Build Coastguard Worker 
750*6777b538SAndroid Build Coastguard Worker   const NetLogWithSource& GetSocketNetLog() const override {
751*6777b538SAndroid Build Coastguard Worker     return socket_->NetLog();
752*6777b538SAndroid Build Coastguard Worker   }
753*6777b538SAndroid Build Coastguard Worker 
754*6777b538SAndroid Build Coastguard Worker   bool IsPending() const override { return next_state_ != STATE_NONE; }
755*6777b538SAndroid Build Coastguard Worker 
756*6777b538SAndroid Build Coastguard Worker  private:
757*6777b538SAndroid Build Coastguard Worker   enum State {
758*6777b538SAndroid Build Coastguard Worker     STATE_CONNECT_COMPLETE,
759*6777b538SAndroid Build Coastguard Worker     STATE_SEND_LENGTH,
760*6777b538SAndroid Build Coastguard Worker     STATE_SEND_QUERY,
761*6777b538SAndroid Build Coastguard Worker     STATE_READ_LENGTH,
762*6777b538SAndroid Build Coastguard Worker     STATE_READ_LENGTH_COMPLETE,
763*6777b538SAndroid Build Coastguard Worker     STATE_READ_RESPONSE,
764*6777b538SAndroid Build Coastguard Worker     STATE_READ_RESPONSE_COMPLETE,
765*6777b538SAndroid Build Coastguard Worker     STATE_NONE,
766*6777b538SAndroid Build Coastguard Worker   };
767*6777b538SAndroid Build Coastguard Worker 
768*6777b538SAndroid Build Coastguard Worker   int DoLoop(int result) {
769*6777b538SAndroid Build Coastguard Worker     CHECK_NE(STATE_NONE, next_state_);
770*6777b538SAndroid Build Coastguard Worker     int rv = result;
771*6777b538SAndroid Build Coastguard Worker     do {
772*6777b538SAndroid Build Coastguard Worker       State state = next_state_;
773*6777b538SAndroid Build Coastguard Worker       next_state_ = STATE_NONE;
774*6777b538SAndroid Build Coastguard Worker       switch (state) {
775*6777b538SAndroid Build Coastguard Worker         case STATE_CONNECT_COMPLETE:
776*6777b538SAndroid Build Coastguard Worker           rv = DoConnectComplete(rv);
777*6777b538SAndroid Build Coastguard Worker           break;
778*6777b538SAndroid Build Coastguard Worker         case STATE_SEND_LENGTH:
779*6777b538SAndroid Build Coastguard Worker           rv = DoSendLength(rv);
780*6777b538SAndroid Build Coastguard Worker           break;
781*6777b538SAndroid Build Coastguard Worker         case STATE_SEND_QUERY:
782*6777b538SAndroid Build Coastguard Worker           rv = DoSendQuery(rv);
783*6777b538SAndroid Build Coastguard Worker           break;
784*6777b538SAndroid Build Coastguard Worker         case STATE_READ_LENGTH:
785*6777b538SAndroid Build Coastguard Worker           rv = DoReadLength(rv);
786*6777b538SAndroid Build Coastguard Worker           break;
787*6777b538SAndroid Build Coastguard Worker         case STATE_READ_LENGTH_COMPLETE:
788*6777b538SAndroid Build Coastguard Worker           rv = DoReadLengthComplete(rv);
789*6777b538SAndroid Build Coastguard Worker           break;
790*6777b538SAndroid Build Coastguard Worker         case STATE_READ_RESPONSE:
791*6777b538SAndroid Build Coastguard Worker           rv = DoReadResponse(rv);
792*6777b538SAndroid Build Coastguard Worker           break;
793*6777b538SAndroid Build Coastguard Worker         case STATE_READ_RESPONSE_COMPLETE:
794*6777b538SAndroid Build Coastguard Worker           rv = DoReadResponseComplete(rv);
795*6777b538SAndroid Build Coastguard Worker           break;
796*6777b538SAndroid Build Coastguard Worker         default:
797*6777b538SAndroid Build Coastguard Worker           NOTREACHED();
798*6777b538SAndroid Build Coastguard Worker           break;
799*6777b538SAndroid Build Coastguard Worker       }
800*6777b538SAndroid Build Coastguard Worker     } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
801*6777b538SAndroid Build Coastguard Worker 
802*6777b538SAndroid Build Coastguard Worker     if (rv != ERR_IO_PENDING)
803*6777b538SAndroid Build Coastguard Worker       DCHECK_EQ(STATE_NONE, next_state_);
804*6777b538SAndroid Build Coastguard Worker 
805*6777b538SAndroid Build Coastguard Worker     return rv;
806*6777b538SAndroid Build Coastguard Worker   }
807*6777b538SAndroid Build Coastguard Worker 
808*6777b538SAndroid Build Coastguard Worker   int DoConnectComplete(int rv) {
809*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(ERR_IO_PENDING, rv);
810*6777b538SAndroid Build Coastguard Worker     if (rv < 0)
811*6777b538SAndroid Build Coastguard Worker       return rv;
812*6777b538SAndroid Build Coastguard Worker 
813*6777b538SAndroid Build Coastguard Worker     uint16_t query_size = static_cast<uint16_t>(query_->io_buffer()->size());
814*6777b538SAndroid Build Coastguard Worker     if (static_cast<int>(query_size) != query_->io_buffer()->size())
815*6777b538SAndroid Build Coastguard Worker       return ERR_FAILED;
816*6777b538SAndroid Build Coastguard Worker     base::as_writable_bytes(length_buffer_->span())
817*6777b538SAndroid Build Coastguard Worker         .copy_from(base::U16ToBigEndian(query_size));
818*6777b538SAndroid Build Coastguard Worker     buffer_ = base::MakeRefCounted<DrainableIOBuffer>(length_buffer_,
819*6777b538SAndroid Build Coastguard Worker                                                       length_buffer_->size());
820*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_SEND_LENGTH;
821*6777b538SAndroid Build Coastguard Worker     return OK;
822*6777b538SAndroid Build Coastguard Worker   }
823*6777b538SAndroid Build Coastguard Worker 
824*6777b538SAndroid Build Coastguard Worker   int DoSendLength(int rv) {
825*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(ERR_IO_PENDING, rv);
826*6777b538SAndroid Build Coastguard Worker     if (rv < 0)
827*6777b538SAndroid Build Coastguard Worker       return rv;
828*6777b538SAndroid Build Coastguard Worker 
829*6777b538SAndroid Build Coastguard Worker     buffer_->DidConsume(rv);
830*6777b538SAndroid Build Coastguard Worker     if (buffer_->BytesRemaining() > 0) {
831*6777b538SAndroid Build Coastguard Worker       next_state_ = STATE_SEND_LENGTH;
832*6777b538SAndroid Build Coastguard Worker       return socket_->Write(
833*6777b538SAndroid Build Coastguard Worker           buffer_.get(), buffer_->BytesRemaining(),
834*6777b538SAndroid Build Coastguard Worker           base::BindOnce(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)),
835*6777b538SAndroid Build Coastguard Worker           kTrafficAnnotation);
836*6777b538SAndroid Build Coastguard Worker     }
837*6777b538SAndroid Build Coastguard Worker     buffer_ = base::MakeRefCounted<DrainableIOBuffer>(
838*6777b538SAndroid Build Coastguard Worker         query_->io_buffer(), query_->io_buffer()->size());
839*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_SEND_QUERY;
840*6777b538SAndroid Build Coastguard Worker     return OK;
841*6777b538SAndroid Build Coastguard Worker   }
842*6777b538SAndroid Build Coastguard Worker 
843*6777b538SAndroid Build Coastguard Worker   int DoSendQuery(int rv) {
844*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(ERR_IO_PENDING, rv);
845*6777b538SAndroid Build Coastguard Worker     if (rv < 0)
846*6777b538SAndroid Build Coastguard Worker       return rv;
847*6777b538SAndroid Build Coastguard Worker 
848*6777b538SAndroid Build Coastguard Worker     buffer_->DidConsume(rv);
849*6777b538SAndroid Build Coastguard Worker     if (buffer_->BytesRemaining() > 0) {
850*6777b538SAndroid Build Coastguard Worker       next_state_ = STATE_SEND_QUERY;
851*6777b538SAndroid Build Coastguard Worker       return socket_->Write(
852*6777b538SAndroid Build Coastguard Worker           buffer_.get(), buffer_->BytesRemaining(),
853*6777b538SAndroid Build Coastguard Worker           base::BindOnce(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)),
854*6777b538SAndroid Build Coastguard Worker           kTrafficAnnotation);
855*6777b538SAndroid Build Coastguard Worker     }
856*6777b538SAndroid Build Coastguard Worker     buffer_ = base::MakeRefCounted<DrainableIOBuffer>(length_buffer_,
857*6777b538SAndroid Build Coastguard Worker                                                       length_buffer_->size());
858*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_READ_LENGTH;
859*6777b538SAndroid Build Coastguard Worker     return OK;
860*6777b538SAndroid Build Coastguard Worker   }
861*6777b538SAndroid Build Coastguard Worker 
862*6777b538SAndroid Build Coastguard Worker   int DoReadLength(int rv) {
863*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(OK, rv);
864*6777b538SAndroid Build Coastguard Worker 
865*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_READ_LENGTH_COMPLETE;
866*6777b538SAndroid Build Coastguard Worker     return ReadIntoBuffer();
867*6777b538SAndroid Build Coastguard Worker   }
868*6777b538SAndroid Build Coastguard Worker 
869*6777b538SAndroid Build Coastguard Worker   int DoReadLengthComplete(int rv) {
870*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(ERR_IO_PENDING, rv);
871*6777b538SAndroid Build Coastguard Worker     if (rv < 0)
872*6777b538SAndroid Build Coastguard Worker       return rv;
873*6777b538SAndroid Build Coastguard Worker     if (rv == 0)
874*6777b538SAndroid Build Coastguard Worker       return ERR_CONNECTION_CLOSED;
875*6777b538SAndroid Build Coastguard Worker 
876*6777b538SAndroid Build Coastguard Worker     buffer_->DidConsume(rv);
877*6777b538SAndroid Build Coastguard Worker     if (buffer_->BytesRemaining() > 0) {
878*6777b538SAndroid Build Coastguard Worker       next_state_ = STATE_READ_LENGTH;
879*6777b538SAndroid Build Coastguard Worker       return OK;
880*6777b538SAndroid Build Coastguard Worker     }
881*6777b538SAndroid Build Coastguard Worker 
882*6777b538SAndroid Build Coastguard Worker     response_length_ = base::U16FromBigEndian(
883*6777b538SAndroid Build Coastguard Worker         base::as_bytes(length_buffer_->span().first<2u>()));
884*6777b538SAndroid Build Coastguard Worker     // Check if advertised response is too short. (Optimization only.)
885*6777b538SAndroid Build Coastguard Worker     if (response_length_ < query_->io_buffer()->size())
886*6777b538SAndroid Build Coastguard Worker       return ERR_DNS_MALFORMED_RESPONSE;
887*6777b538SAndroid Build Coastguard Worker     response_ = std::make_unique<DnsResponse>(response_length_);
888*6777b538SAndroid Build Coastguard Worker     buffer_ = base::MakeRefCounted<DrainableIOBuffer>(response_->io_buffer(),
889*6777b538SAndroid Build Coastguard Worker                                                       response_length_);
890*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_READ_RESPONSE;
891*6777b538SAndroid Build Coastguard Worker     return OK;
892*6777b538SAndroid Build Coastguard Worker   }
893*6777b538SAndroid Build Coastguard Worker 
894*6777b538SAndroid Build Coastguard Worker   int DoReadResponse(int rv) {
895*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(OK, rv);
896*6777b538SAndroid Build Coastguard Worker 
897*6777b538SAndroid Build Coastguard Worker     next_state_ = STATE_READ_RESPONSE_COMPLETE;
898*6777b538SAndroid Build Coastguard Worker     return ReadIntoBuffer();
899*6777b538SAndroid Build Coastguard Worker   }
900*6777b538SAndroid Build Coastguard Worker 
901*6777b538SAndroid Build Coastguard Worker   int DoReadResponseComplete(int rv) {
902*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(ERR_IO_PENDING, rv);
903*6777b538SAndroid Build Coastguard Worker     if (rv < 0)
904*6777b538SAndroid Build Coastguard Worker       return rv;
905*6777b538SAndroid Build Coastguard Worker     if (rv == 0)
906*6777b538SAndroid Build Coastguard Worker       return ERR_CONNECTION_CLOSED;
907*6777b538SAndroid Build Coastguard Worker 
908*6777b538SAndroid Build Coastguard Worker     buffer_->DidConsume(rv);
909*6777b538SAndroid Build Coastguard Worker     if (buffer_->BytesRemaining() > 0) {
910*6777b538SAndroid Build Coastguard Worker       next_state_ = STATE_READ_RESPONSE;
911*6777b538SAndroid Build Coastguard Worker       return OK;
912*6777b538SAndroid Build Coastguard Worker     }
913*6777b538SAndroid Build Coastguard Worker     DCHECK_GT(buffer_->BytesConsumed(), 0);
914*6777b538SAndroid Build Coastguard Worker     if (!response_->InitParse(buffer_->BytesConsumed(), *query_))
915*6777b538SAndroid Build Coastguard Worker       return ERR_DNS_MALFORMED_RESPONSE;
916*6777b538SAndroid Build Coastguard Worker     if (response_->flags() & dns_protocol::kFlagTC)
917*6777b538SAndroid Build Coastguard Worker       return ERR_UNEXPECTED;
918*6777b538SAndroid Build Coastguard Worker     // TODO(szym): Frankly, none of these are expected.
919*6777b538SAndroid Build Coastguard Worker     if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
920*6777b538SAndroid Build Coastguard Worker       return ERR_NAME_NOT_RESOLVED;
921*6777b538SAndroid Build Coastguard Worker     if (response_->rcode() != dns_protocol::kRcodeNOERROR)
922*6777b538SAndroid Build Coastguard Worker       return ERR_DNS_SERVER_FAILED;
923*6777b538SAndroid Build Coastguard Worker 
924*6777b538SAndroid Build Coastguard Worker     return OK;
925*6777b538SAndroid Build Coastguard Worker   }
926*6777b538SAndroid Build Coastguard Worker 
927*6777b538SAndroid Build Coastguard Worker   void OnIOComplete(int rv) {
928*6777b538SAndroid Build Coastguard Worker     rv = DoLoop(rv);
929*6777b538SAndroid Build Coastguard Worker     if (rv != ERR_IO_PENDING)
930*6777b538SAndroid Build Coastguard Worker       std::move(callback_).Run(rv);
931*6777b538SAndroid Build Coastguard Worker   }
932*6777b538SAndroid Build Coastguard Worker 
933*6777b538SAndroid Build Coastguard Worker   int ReadIntoBuffer() {
934*6777b538SAndroid Build Coastguard Worker     return socket_->Read(
935*6777b538SAndroid Build Coastguard Worker         buffer_.get(), buffer_->BytesRemaining(),
936*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
937*6777b538SAndroid Build Coastguard Worker   }
938*6777b538SAndroid Build Coastguard Worker 
939*6777b538SAndroid Build Coastguard Worker   State next_state_ = STATE_NONE;
940*6777b538SAndroid Build Coastguard Worker   base::TimeTicks start_time_;
941*6777b538SAndroid Build Coastguard Worker 
942*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<StreamSocket> socket_;
943*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DnsQuery> query_;
944*6777b538SAndroid Build Coastguard Worker   scoped_refptr<IOBufferWithSize> length_buffer_;
945*6777b538SAndroid Build Coastguard Worker   scoped_refptr<DrainableIOBuffer> buffer_;
946*6777b538SAndroid Build Coastguard Worker 
947*6777b538SAndroid Build Coastguard Worker   uint16_t response_length_ = 0;
948*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DnsResponse> response_;
949*6777b538SAndroid Build Coastguard Worker 
950*6777b538SAndroid Build Coastguard Worker   CompletionOnceCallback callback_;
951*6777b538SAndroid Build Coastguard Worker };
952*6777b538SAndroid Build Coastguard Worker 
953*6777b538SAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
954*6777b538SAndroid Build Coastguard Worker 
955*6777b538SAndroid Build Coastguard Worker const net::BackoffEntry::Policy kProbeBackoffPolicy = {
956*6777b538SAndroid Build Coastguard Worker     // Apply exponential backoff rules after the first error.
957*6777b538SAndroid Build Coastguard Worker     0,
958*6777b538SAndroid Build Coastguard Worker     // Begin with a 1s delay between probes.
959*6777b538SAndroid Build Coastguard Worker     1000,
960*6777b538SAndroid Build Coastguard Worker     // Increase the delay between consecutive probes by a factor of 1.5.
961*6777b538SAndroid Build Coastguard Worker     1.5,
962*6777b538SAndroid Build Coastguard Worker     // Fuzz the delay between consecutive probes between 80%-100% of the
963*6777b538SAndroid Build Coastguard Worker     // calculated time.
964*6777b538SAndroid Build Coastguard Worker     0.2,
965*6777b538SAndroid Build Coastguard Worker     // Cap the maximum delay between consecutive probes at 1 hour.
966*6777b538SAndroid Build Coastguard Worker     1000 * 60 * 60,
967*6777b538SAndroid Build Coastguard Worker     // Never expire entries.
968*6777b538SAndroid Build Coastguard Worker     -1,
969*6777b538SAndroid Build Coastguard Worker     // Do not apply an initial delay.
970*6777b538SAndroid Build Coastguard Worker     false,
971*6777b538SAndroid Build Coastguard Worker };
972*6777b538SAndroid Build Coastguard Worker 
973*6777b538SAndroid Build Coastguard Worker // Probe runner that continually sends test queries (with backoff) to DoH
974*6777b538SAndroid Build Coastguard Worker // servers to determine availability.
975*6777b538SAndroid Build Coastguard Worker //
976*6777b538SAndroid Build Coastguard Worker // Expected to be contained in request classes owned externally to HostResolver,
977*6777b538SAndroid Build Coastguard Worker // so no assumptions are made regarding cancellation compared to the DnsSession
978*6777b538SAndroid Build Coastguard Worker // or ResolveContext. Instead, uses WeakPtrs to gracefully clean itself up and
979*6777b538SAndroid Build Coastguard Worker // stop probing after session or context destruction.
980*6777b538SAndroid Build Coastguard Worker class DnsOverHttpsProbeRunner : public DnsProbeRunner {
981*6777b538SAndroid Build Coastguard Worker  public:
982*6777b538SAndroid Build Coastguard Worker   DnsOverHttpsProbeRunner(base::WeakPtr<DnsSession> session,
983*6777b538SAndroid Build Coastguard Worker                           base::WeakPtr<ResolveContext> context)
984*6777b538SAndroid Build Coastguard Worker       : session_(session), context_(context) {
985*6777b538SAndroid Build Coastguard Worker     DCHECK(session_);
986*6777b538SAndroid Build Coastguard Worker     DCHECK(!session_->config().doh_config.servers().empty());
987*6777b538SAndroid Build Coastguard Worker     DCHECK(context_);
988*6777b538SAndroid Build Coastguard Worker 
989*6777b538SAndroid Build Coastguard Worker     std::optional<std::vector<uint8_t>> qname =
990*6777b538SAndroid Build Coastguard Worker         dns_names_util::DottedNameToNetwork(kDohProbeHostname);
991*6777b538SAndroid Build Coastguard Worker     DCHECK(qname.has_value());
992*6777b538SAndroid Build Coastguard Worker     formatted_probe_qname_ = std::move(qname).value();
993*6777b538SAndroid Build Coastguard Worker 
994*6777b538SAndroid Build Coastguard Worker     for (size_t i = 0; i < session_->config().doh_config.servers().size();
995*6777b538SAndroid Build Coastguard Worker          i++) {
996*6777b538SAndroid Build Coastguard Worker       probe_stats_list_.push_back(nullptr);
997*6777b538SAndroid Build Coastguard Worker     }
998*6777b538SAndroid Build Coastguard Worker   }
999*6777b538SAndroid Build Coastguard Worker 
1000*6777b538SAndroid Build Coastguard Worker   ~DnsOverHttpsProbeRunner() override = default;
1001*6777b538SAndroid Build Coastguard Worker 
1002*6777b538SAndroid Build Coastguard Worker   void Start(bool network_change) override {
1003*6777b538SAndroid Build Coastguard Worker     DCHECK(session_);
1004*6777b538SAndroid Build Coastguard Worker     DCHECK(context_);
1005*6777b538SAndroid Build Coastguard Worker 
1006*6777b538SAndroid Build Coastguard Worker     const auto& config = session_->config().doh_config;
1007*6777b538SAndroid Build Coastguard Worker     // Start probe sequences for any servers where it is not currently running.
1008*6777b538SAndroid Build Coastguard Worker     for (size_t i = 0; i < config.servers().size(); i++) {
1009*6777b538SAndroid Build Coastguard Worker       if (!probe_stats_list_[i]) {
1010*6777b538SAndroid Build Coastguard Worker         probe_stats_list_[i] = std::make_unique<ProbeStats>();
1011*6777b538SAndroid Build Coastguard Worker         ContinueProbe(i, probe_stats_list_[i]->weak_factory.GetWeakPtr(),
1012*6777b538SAndroid Build Coastguard Worker                       network_change,
1013*6777b538SAndroid Build Coastguard Worker                       base::TimeTicks::Now() /* sequence_start_time */);
1014*6777b538SAndroid Build Coastguard Worker       }
1015*6777b538SAndroid Build Coastguard Worker     }
1016*6777b538SAndroid Build Coastguard Worker   }
1017*6777b538SAndroid Build Coastguard Worker 
1018*6777b538SAndroid Build Coastguard Worker   base::TimeDelta GetDelayUntilNextProbeForTest(
1019*6777b538SAndroid Build Coastguard Worker       size_t doh_server_index) const override {
1020*6777b538SAndroid Build Coastguard Worker     if (doh_server_index >= probe_stats_list_.size() ||
1021*6777b538SAndroid Build Coastguard Worker         !probe_stats_list_[doh_server_index])
1022*6777b538SAndroid Build Coastguard Worker       return base::TimeDelta();
1023*6777b538SAndroid Build Coastguard Worker 
1024*6777b538SAndroid Build Coastguard Worker     return probe_stats_list_[doh_server_index]
1025*6777b538SAndroid Build Coastguard Worker         ->backoff_entry->GetTimeUntilRelease();
1026*6777b538SAndroid Build Coastguard Worker   }
1027*6777b538SAndroid Build Coastguard Worker 
1028*6777b538SAndroid Build Coastguard Worker  private:
1029*6777b538SAndroid Build Coastguard Worker   struct ProbeStats {
1030*6777b538SAndroid Build Coastguard Worker     ProbeStats()
1031*6777b538SAndroid Build Coastguard Worker         : backoff_entry(
1032*6777b538SAndroid Build Coastguard Worker               std::make_unique<net::BackoffEntry>(&kProbeBackoffPolicy)) {}
1033*6777b538SAndroid Build Coastguard Worker 
1034*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<net::BackoffEntry> backoff_entry;
1035*6777b538SAndroid Build Coastguard Worker     std::vector<std::unique_ptr<DnsAttempt>> probe_attempts;
1036*6777b538SAndroid Build Coastguard Worker     base::WeakPtrFactory<ProbeStats> weak_factory{this};
1037*6777b538SAndroid Build Coastguard Worker   };
1038*6777b538SAndroid Build Coastguard Worker 
1039*6777b538SAndroid Build Coastguard Worker   void ContinueProbe(size_t doh_server_index,
1040*6777b538SAndroid Build Coastguard Worker                      base::WeakPtr<ProbeStats> probe_stats,
1041*6777b538SAndroid Build Coastguard Worker                      bool network_change,
1042*6777b538SAndroid Build Coastguard Worker                      base::TimeTicks sequence_start_time) {
1043*6777b538SAndroid Build Coastguard Worker     // If the DnsSession or ResolveContext has been destroyed, no reason to
1044*6777b538SAndroid Build Coastguard Worker     // continue probing.
1045*6777b538SAndroid Build Coastguard Worker     if (!session_ || !context_) {
1046*6777b538SAndroid Build Coastguard Worker       probe_stats_list_.clear();
1047*6777b538SAndroid Build Coastguard Worker       return;
1048*6777b538SAndroid Build Coastguard Worker     }
1049*6777b538SAndroid Build Coastguard Worker 
1050*6777b538SAndroid Build Coastguard Worker     // If the ProbeStats for which this probe was scheduled has been deleted,
1051*6777b538SAndroid Build Coastguard Worker     // don't continue to send probes.
1052*6777b538SAndroid Build Coastguard Worker     if (!probe_stats)
1053*6777b538SAndroid Build Coastguard Worker       return;
1054*6777b538SAndroid Build Coastguard Worker 
1055*6777b538SAndroid Build Coastguard Worker     // Cancel the probe sequence for this server if the server is already
1056*6777b538SAndroid Build Coastguard Worker     // available.
1057*6777b538SAndroid Build Coastguard Worker     if (context_->GetDohServerAvailability(doh_server_index, session_.get())) {
1058*6777b538SAndroid Build Coastguard Worker       probe_stats_list_[doh_server_index] = nullptr;
1059*6777b538SAndroid Build Coastguard Worker       return;
1060*6777b538SAndroid Build Coastguard Worker     }
1061*6777b538SAndroid Build Coastguard Worker 
1062*6777b538SAndroid Build Coastguard Worker     // Schedule a new probe assuming this one will fail. The newly scheduled
1063*6777b538SAndroid Build Coastguard Worker     // probe will not run if an earlier probe has already succeeded. Probes may
1064*6777b538SAndroid Build Coastguard Worker     // take awhile to fail, which is why we schedule the next one here rather
1065*6777b538SAndroid Build Coastguard Worker     // than on probe completion.
1066*6777b538SAndroid Build Coastguard Worker     DCHECK(probe_stats);
1067*6777b538SAndroid Build Coastguard Worker     DCHECK(probe_stats->backoff_entry);
1068*6777b538SAndroid Build Coastguard Worker     probe_stats->backoff_entry->InformOfRequest(false /* success */);
1069*6777b538SAndroid Build Coastguard Worker     base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
1070*6777b538SAndroid Build Coastguard Worker         FROM_HERE,
1071*6777b538SAndroid Build Coastguard Worker         base::BindOnce(&DnsOverHttpsProbeRunner::ContinueProbe,
1072*6777b538SAndroid Build Coastguard Worker                        weak_ptr_factory_.GetWeakPtr(), doh_server_index,
1073*6777b538SAndroid Build Coastguard Worker                        probe_stats, network_change, sequence_start_time),
1074*6777b538SAndroid Build Coastguard Worker         probe_stats->backoff_entry->GetTimeUntilRelease());
1075*6777b538SAndroid Build Coastguard Worker 
1076*6777b538SAndroid Build Coastguard Worker     unsigned attempt_number = probe_stats->probe_attempts.size();
1077*6777b538SAndroid Build Coastguard Worker     ConstructDnsHTTPAttempt(
1078*6777b538SAndroid Build Coastguard Worker         session_.get(), doh_server_index, formatted_probe_qname_,
1079*6777b538SAndroid Build Coastguard Worker         dns_protocol::kTypeA, /*opt_rdata=*/nullptr,
1080*6777b538SAndroid Build Coastguard Worker         &probe_stats->probe_attempts, context_->url_request_context(),
1081*6777b538SAndroid Build Coastguard Worker         context_->isolation_info(), RequestPriority::DEFAULT_PRIORITY,
1082*6777b538SAndroid Build Coastguard Worker         /*is_probe=*/true);
1083*6777b538SAndroid Build Coastguard Worker 
1084*6777b538SAndroid Build Coastguard Worker     DnsAttempt* probe_attempt = probe_stats->probe_attempts.back().get();
1085*6777b538SAndroid Build Coastguard Worker     probe_attempt->Start(base::BindOnce(
1086*6777b538SAndroid Build Coastguard Worker         &DnsOverHttpsProbeRunner::ProbeComplete, weak_ptr_factory_.GetWeakPtr(),
1087*6777b538SAndroid Build Coastguard Worker         attempt_number, doh_server_index, std::move(probe_stats),
1088*6777b538SAndroid Build Coastguard Worker         network_change, sequence_start_time,
1089*6777b538SAndroid Build Coastguard Worker         base::TimeTicks::Now() /* query_start_time */));
1090*6777b538SAndroid Build Coastguard Worker   }
1091*6777b538SAndroid Build Coastguard Worker 
ProbeComplete(unsigned attempt_number,size_t doh_server_index,base::WeakPtr<ProbeStats> probe_stats,bool network_change,base::TimeTicks sequence_start_time,base::TimeTicks query_start_time,int rv)1092*6777b538SAndroid Build Coastguard Worker   void ProbeComplete(unsigned attempt_number,
1093*6777b538SAndroid Build Coastguard Worker                      size_t doh_server_index,
1094*6777b538SAndroid Build Coastguard Worker                      base::WeakPtr<ProbeStats> probe_stats,
1095*6777b538SAndroid Build Coastguard Worker                      bool network_change,
1096*6777b538SAndroid Build Coastguard Worker                      base::TimeTicks sequence_start_time,
1097*6777b538SAndroid Build Coastguard Worker                      base::TimeTicks query_start_time,
1098*6777b538SAndroid Build Coastguard Worker                      int rv) {
1099*6777b538SAndroid Build Coastguard Worker     bool success = false;
1100*6777b538SAndroid Build Coastguard Worker     while (probe_stats && session_ && context_) {
1101*6777b538SAndroid Build Coastguard Worker       if (rv != OK) {
1102*6777b538SAndroid Build Coastguard Worker         // The DoH probe queries don't go through the standard DnsAttempt path,
1103*6777b538SAndroid Build Coastguard Worker         // so the ServerStats have not been updated yet.
1104*6777b538SAndroid Build Coastguard Worker         context_->RecordServerFailure(doh_server_index, /*is_doh_server=*/true,
1105*6777b538SAndroid Build Coastguard Worker                                       rv, session_.get());
1106*6777b538SAndroid Build Coastguard Worker         break;
1107*6777b538SAndroid Build Coastguard Worker       }
1108*6777b538SAndroid Build Coastguard Worker       // Check that the response parses properly before considering it a
1109*6777b538SAndroid Build Coastguard Worker       // success.
1110*6777b538SAndroid Build Coastguard Worker       DCHECK_LT(attempt_number, probe_stats->probe_attempts.size());
1111*6777b538SAndroid Build Coastguard Worker       const DnsAttempt* attempt =
1112*6777b538SAndroid Build Coastguard Worker           probe_stats->probe_attempts[attempt_number].get();
1113*6777b538SAndroid Build Coastguard Worker       const DnsResponse* response = attempt->GetResponse();
1114*6777b538SAndroid Build Coastguard Worker       if (response) {
1115*6777b538SAndroid Build Coastguard Worker         DnsResponseResultExtractor extractor(*response);
1116*6777b538SAndroid Build Coastguard Worker         DnsResponseResultExtractor::ResultsOrError results =
1117*6777b538SAndroid Build Coastguard Worker             extractor.ExtractDnsResults(
1118*6777b538SAndroid Build Coastguard Worker                 DnsQueryType::A,
1119*6777b538SAndroid Build Coastguard Worker                 /*original_domain_name=*/kDohProbeHostname,
1120*6777b538SAndroid Build Coastguard Worker                 /*request_port=*/0);
1121*6777b538SAndroid Build Coastguard Worker 
1122*6777b538SAndroid Build Coastguard Worker         if (results.has_value()) {
1123*6777b538SAndroid Build Coastguard Worker           for (const auto& result : results.value()) {
1124*6777b538SAndroid Build Coastguard Worker             if (result->type() == HostResolverInternalResult::Type::kData &&
1125*6777b538SAndroid Build Coastguard Worker                 !result->AsData().endpoints().empty()) {
1126*6777b538SAndroid Build Coastguard Worker               context_->RecordServerSuccess(
1127*6777b538SAndroid Build Coastguard Worker                   doh_server_index, /*is_doh_server=*/true, session_.get());
1128*6777b538SAndroid Build Coastguard Worker               context_->RecordRtt(doh_server_index, /*is_doh_server=*/true,
1129*6777b538SAndroid Build Coastguard Worker                                   base::TimeTicks::Now() - query_start_time, rv,
1130*6777b538SAndroid Build Coastguard Worker                                   session_.get());
1131*6777b538SAndroid Build Coastguard Worker               success = true;
1132*6777b538SAndroid Build Coastguard Worker 
1133*6777b538SAndroid Build Coastguard Worker               // Do not delete the ProbeStats and cancel the probe sequence. It
1134*6777b538SAndroid Build Coastguard Worker               // will cancel itself on the next scheduled ContinueProbe() call
1135*6777b538SAndroid Build Coastguard Worker               // if the server is still available. This way, the backoff
1136*6777b538SAndroid Build Coastguard Worker               // schedule will be maintained if a server quickly becomes
1137*6777b538SAndroid Build Coastguard Worker               // unavailable again before that scheduled call.
1138*6777b538SAndroid Build Coastguard Worker               break;
1139*6777b538SAndroid Build Coastguard Worker             }
1140*6777b538SAndroid Build Coastguard Worker           }
1141*6777b538SAndroid Build Coastguard Worker         }
1142*6777b538SAndroid Build Coastguard Worker       }
1143*6777b538SAndroid Build Coastguard Worker       if (!success) {
1144*6777b538SAndroid Build Coastguard Worker         context_->RecordServerFailure(
1145*6777b538SAndroid Build Coastguard Worker             doh_server_index, /*is_doh_server=*/true,
1146*6777b538SAndroid Build Coastguard Worker             /*rv=*/ERR_DNS_SECURE_PROBE_RECORD_INVALID, session_.get());
1147*6777b538SAndroid Build Coastguard Worker       }
1148*6777b538SAndroid Build Coastguard Worker       break;
1149*6777b538SAndroid Build Coastguard Worker     }
1150*6777b538SAndroid Build Coastguard Worker 
1151*6777b538SAndroid Build Coastguard Worker     base::UmaHistogramLongTimes(
1152*6777b538SAndroid Build Coastguard Worker         base::JoinString({"Net.DNS.ProbeSequence",
1153*6777b538SAndroid Build Coastguard Worker                           network_change ? "NetworkChange" : "ConfigChange",
1154*6777b538SAndroid Build Coastguard Worker                           success ? "Success" : "Failure", "AttemptTime"},
1155*6777b538SAndroid Build Coastguard Worker                          "."),
1156*6777b538SAndroid Build Coastguard Worker         base::TimeTicks::Now() - sequence_start_time);
1157*6777b538SAndroid Build Coastguard Worker   }
1158*6777b538SAndroid Build Coastguard Worker 
1159*6777b538SAndroid Build Coastguard Worker   base::WeakPtr<DnsSession> session_;
1160*6777b538SAndroid Build Coastguard Worker   base::WeakPtr<ResolveContext> context_;
1161*6777b538SAndroid Build Coastguard Worker   std::vector<uint8_t> formatted_probe_qname_;
1162*6777b538SAndroid Build Coastguard Worker 
1163*6777b538SAndroid Build Coastguard Worker   // List of ProbeStats, one for each DoH server, indexed by the DoH server
1164*6777b538SAndroid Build Coastguard Worker   // config index.
1165*6777b538SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<ProbeStats>> probe_stats_list_;
1166*6777b538SAndroid Build Coastguard Worker 
1167*6777b538SAndroid Build Coastguard Worker   base::WeakPtrFactory<DnsOverHttpsProbeRunner> weak_ptr_factory_{this};
1168*6777b538SAndroid Build Coastguard Worker };
1169*6777b538SAndroid Build Coastguard Worker 
1170*6777b538SAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
1171*6777b538SAndroid Build Coastguard Worker 
1172*6777b538SAndroid Build Coastguard Worker // Implements DnsTransaction. Configuration is supplied by DnsSession.
1173*6777b538SAndroid Build Coastguard Worker // The suffix list is built according to the DnsConfig from the session.
1174*6777b538SAndroid Build Coastguard Worker // The fallback period for each DnsUDPAttempt is given by
1175*6777b538SAndroid Build Coastguard Worker // ResolveContext::NextClassicFallbackPeriod(). The first server to attempt on
1176*6777b538SAndroid Build Coastguard Worker // each query is given by ResolveContext::NextFirstServerIndex, and the order is
1177*6777b538SAndroid Build Coastguard Worker // round-robin afterwards. Each server is attempted DnsConfig::attempts times.
1178*6777b538SAndroid Build Coastguard Worker class DnsTransactionImpl final : public DnsTransaction {
1179*6777b538SAndroid Build Coastguard Worker  public:
DnsTransactionImpl(DnsSession * session,std::string hostname,uint16_t qtype,const NetLogWithSource & parent_net_log,const OptRecordRdata * opt_rdata,bool secure,SecureDnsMode secure_dns_mode,ResolveContext * resolve_context,bool fast_timeout)1180*6777b538SAndroid Build Coastguard Worker   DnsTransactionImpl(DnsSession* session,
1181*6777b538SAndroid Build Coastguard Worker                      std::string hostname,
1182*6777b538SAndroid Build Coastguard Worker                      uint16_t qtype,
1183*6777b538SAndroid Build Coastguard Worker                      const NetLogWithSource& parent_net_log,
1184*6777b538SAndroid Build Coastguard Worker                      const OptRecordRdata* opt_rdata,
1185*6777b538SAndroid Build Coastguard Worker                      bool secure,
1186*6777b538SAndroid Build Coastguard Worker                      SecureDnsMode secure_dns_mode,
1187*6777b538SAndroid Build Coastguard Worker                      ResolveContext* resolve_context,
1188*6777b538SAndroid Build Coastguard Worker                      bool fast_timeout)
1189*6777b538SAndroid Build Coastguard Worker       : session_(session),
1190*6777b538SAndroid Build Coastguard Worker         hostname_(std::move(hostname)),
1191*6777b538SAndroid Build Coastguard Worker         qtype_(qtype),
1192*6777b538SAndroid Build Coastguard Worker         opt_rdata_(opt_rdata),
1193*6777b538SAndroid Build Coastguard Worker         secure_(secure),
1194*6777b538SAndroid Build Coastguard Worker         secure_dns_mode_(secure_dns_mode),
1195*6777b538SAndroid Build Coastguard Worker         fast_timeout_(fast_timeout),
1196*6777b538SAndroid Build Coastguard Worker         net_log_(NetLogWithSource::Make(NetLog::Get(),
1197*6777b538SAndroid Build Coastguard Worker                                         NetLogSourceType::DNS_TRANSACTION)),
1198*6777b538SAndroid Build Coastguard Worker         resolve_context_(resolve_context->AsSafeRef()) {
1199*6777b538SAndroid Build Coastguard Worker     DCHECK(session_.get());
1200*6777b538SAndroid Build Coastguard Worker     DCHECK(!hostname_.empty());
1201*6777b538SAndroid Build Coastguard Worker     DCHECK(!IsIPLiteral(hostname_));
1202*6777b538SAndroid Build Coastguard Worker     parent_net_log.AddEventReferencingSource(NetLogEventType::DNS_TRANSACTION,
1203*6777b538SAndroid Build Coastguard Worker                                              net_log_.source());
1204*6777b538SAndroid Build Coastguard Worker   }
1205*6777b538SAndroid Build Coastguard Worker 
1206*6777b538SAndroid Build Coastguard Worker   DnsTransactionImpl(const DnsTransactionImpl&) = delete;
1207*6777b538SAndroid Build Coastguard Worker   DnsTransactionImpl& operator=(const DnsTransactionImpl&) = delete;
1208*6777b538SAndroid Build Coastguard Worker 
~DnsTransactionImpl()1209*6777b538SAndroid Build Coastguard Worker   ~DnsTransactionImpl() override {
1210*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1211*6777b538SAndroid Build Coastguard Worker     if (!callback_.is_null()) {
1212*6777b538SAndroid Build Coastguard Worker       net_log_.EndEventWithNetErrorCode(NetLogEventType::DNS_TRANSACTION,
1213*6777b538SAndroid Build Coastguard Worker                                         ERR_ABORTED);
1214*6777b538SAndroid Build Coastguard Worker     }  // otherwise logged in DoCallback or Start
1215*6777b538SAndroid Build Coastguard Worker   }
1216*6777b538SAndroid Build Coastguard Worker 
GetHostname() const1217*6777b538SAndroid Build Coastguard Worker   const std::string& GetHostname() const override {
1218*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1219*6777b538SAndroid Build Coastguard Worker     return hostname_;
1220*6777b538SAndroid Build Coastguard Worker   }
1221*6777b538SAndroid Build Coastguard Worker 
GetType() const1222*6777b538SAndroid Build Coastguard Worker   uint16_t GetType() const override {
1223*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1224*6777b538SAndroid Build Coastguard Worker     return qtype_;
1225*6777b538SAndroid Build Coastguard Worker   }
1226*6777b538SAndroid Build Coastguard Worker 
Start(ResponseCallback callback)1227*6777b538SAndroid Build Coastguard Worker   void Start(ResponseCallback callback) override {
1228*6777b538SAndroid Build Coastguard Worker     DCHECK(!callback.is_null());
1229*6777b538SAndroid Build Coastguard Worker     DCHECK(callback_.is_null());
1230*6777b538SAndroid Build Coastguard Worker     DCHECK(attempts_.empty());
1231*6777b538SAndroid Build Coastguard Worker 
1232*6777b538SAndroid Build Coastguard Worker     callback_ = std::move(callback);
1233*6777b538SAndroid Build Coastguard Worker 
1234*6777b538SAndroid Build Coastguard Worker     net_log_.BeginEvent(NetLogEventType::DNS_TRANSACTION,
1235*6777b538SAndroid Build Coastguard Worker                         [&] { return NetLogStartParams(hostname_, qtype_); });
1236*6777b538SAndroid Build Coastguard Worker     time_from_start_ = std::make_unique<base::ElapsedTimer>();
1237*6777b538SAndroid Build Coastguard Worker     AttemptResult result(PrepareSearch(), nullptr);
1238*6777b538SAndroid Build Coastguard Worker     if (result.rv == OK) {
1239*6777b538SAndroid Build Coastguard Worker       qnames_initial_size_ = qnames_.size();
1240*6777b538SAndroid Build Coastguard Worker       result = ProcessAttemptResult(StartQuery());
1241*6777b538SAndroid Build Coastguard Worker     }
1242*6777b538SAndroid Build Coastguard Worker 
1243*6777b538SAndroid Build Coastguard Worker     // Must always return result asynchronously, to avoid reentrancy.
1244*6777b538SAndroid Build Coastguard Worker     if (result.rv != ERR_IO_PENDING) {
1245*6777b538SAndroid Build Coastguard Worker       // Clear all other non-completed attempts. They are no longer needed and
1246*6777b538SAndroid Build Coastguard Worker       // they may interfere with this posted result.
1247*6777b538SAndroid Build Coastguard Worker       ClearAttempts(result.attempt);
1248*6777b538SAndroid Build Coastguard Worker       base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1249*6777b538SAndroid Build Coastguard Worker           FROM_HERE, base::BindOnce(&DnsTransactionImpl::DoCallback,
1250*6777b538SAndroid Build Coastguard Worker                                     weak_ptr_factory_.GetWeakPtr(), result));
1251*6777b538SAndroid Build Coastguard Worker     }
1252*6777b538SAndroid Build Coastguard Worker   }
1253*6777b538SAndroid Build Coastguard Worker 
SetRequestPriority(RequestPriority priority)1254*6777b538SAndroid Build Coastguard Worker   void SetRequestPriority(RequestPriority priority) override {
1255*6777b538SAndroid Build Coastguard Worker     request_priority_ = priority;
1256*6777b538SAndroid Build Coastguard Worker   }
1257*6777b538SAndroid Build Coastguard Worker 
1258*6777b538SAndroid Build Coastguard Worker  private:
1259*6777b538SAndroid Build Coastguard Worker   // Wrapper for the result of a DnsUDPAttempt.
1260*6777b538SAndroid Build Coastguard Worker   struct AttemptResult {
1261*6777b538SAndroid Build Coastguard Worker     AttemptResult() = default;
AttemptResultnet::__anond9c6f5e90111::DnsTransactionImpl::AttemptResult1262*6777b538SAndroid Build Coastguard Worker     AttemptResult(int rv, const DnsAttempt* attempt)
1263*6777b538SAndroid Build Coastguard Worker         : rv(rv), attempt(attempt) {}
1264*6777b538SAndroid Build Coastguard Worker 
1265*6777b538SAndroid Build Coastguard Worker     int rv;
1266*6777b538SAndroid Build Coastguard Worker     raw_ptr<const DnsAttempt, AcrossTasksDanglingUntriaged> attempt;
1267*6777b538SAndroid Build Coastguard Worker   };
1268*6777b538SAndroid Build Coastguard Worker 
1269*6777b538SAndroid Build Coastguard Worker   // Used in UMA (DNS.AttemptType). Do not renumber or remove values.
1270*6777b538SAndroid Build Coastguard Worker   enum class DnsAttemptType {
1271*6777b538SAndroid Build Coastguard Worker     kUdp = 0,
1272*6777b538SAndroid Build Coastguard Worker     kTcpLowEntropy = 1,
1273*6777b538SAndroid Build Coastguard Worker     kTcpTruncationRetry = 2,
1274*6777b538SAndroid Build Coastguard Worker     kHttp = 3,
1275*6777b538SAndroid Build Coastguard Worker     kMaxValue = kHttp,
1276*6777b538SAndroid Build Coastguard Worker   };
1277*6777b538SAndroid Build Coastguard Worker 
1278*6777b538SAndroid Build Coastguard Worker   // Prepares |qnames_| according to the DnsConfig.
PrepareSearch()1279*6777b538SAndroid Build Coastguard Worker   int PrepareSearch() {
1280*6777b538SAndroid Build Coastguard Worker     const DnsConfig& config = session_->config();
1281*6777b538SAndroid Build Coastguard Worker 
1282*6777b538SAndroid Build Coastguard Worker     std::optional<std::vector<uint8_t>> labeled_qname =
1283*6777b538SAndroid Build Coastguard Worker         dns_names_util::DottedNameToNetwork(
1284*6777b538SAndroid Build Coastguard Worker             hostname_,
1285*6777b538SAndroid Build Coastguard Worker             /*require_valid_internet_hostname=*/true);
1286*6777b538SAndroid Build Coastguard Worker     if (!labeled_qname.has_value())
1287*6777b538SAndroid Build Coastguard Worker       return ERR_INVALID_ARGUMENT;
1288*6777b538SAndroid Build Coastguard Worker 
1289*6777b538SAndroid Build Coastguard Worker     if (hostname_.back() == '.') {
1290*6777b538SAndroid Build Coastguard Worker       // It's a fully-qualified name, no suffix search.
1291*6777b538SAndroid Build Coastguard Worker       qnames_.push_back(std::move(labeled_qname).value());
1292*6777b538SAndroid Build Coastguard Worker       return OK;
1293*6777b538SAndroid Build Coastguard Worker     }
1294*6777b538SAndroid Build Coastguard Worker 
1295*6777b538SAndroid Build Coastguard Worker     int ndots = CountLabels(labeled_qname.value()) - 1;
1296*6777b538SAndroid Build Coastguard Worker 
1297*6777b538SAndroid Build Coastguard Worker     if (ndots > 0 && !config.append_to_multi_label_name) {
1298*6777b538SAndroid Build Coastguard Worker       qnames_.push_back(std::move(labeled_qname).value());
1299*6777b538SAndroid Build Coastguard Worker       return OK;
1300*6777b538SAndroid Build Coastguard Worker     }
1301*6777b538SAndroid Build Coastguard Worker 
1302*6777b538SAndroid Build Coastguard Worker     // Set true when `labeled_qname` is put on the list.
1303*6777b538SAndroid Build Coastguard Worker     bool had_qname = false;
1304*6777b538SAndroid Build Coastguard Worker 
1305*6777b538SAndroid Build Coastguard Worker     if (ndots >= config.ndots) {
1306*6777b538SAndroid Build Coastguard Worker       qnames_.push_back(labeled_qname.value());
1307*6777b538SAndroid Build Coastguard Worker       had_qname = true;
1308*6777b538SAndroid Build Coastguard Worker     }
1309*6777b538SAndroid Build Coastguard Worker 
1310*6777b538SAndroid Build Coastguard Worker     for (const auto& suffix : config.search) {
1311*6777b538SAndroid Build Coastguard Worker       std::optional<std::vector<uint8_t>> qname =
1312*6777b538SAndroid Build Coastguard Worker           dns_names_util::DottedNameToNetwork(
1313*6777b538SAndroid Build Coastguard Worker               hostname_ + "." + suffix,
1314*6777b538SAndroid Build Coastguard Worker               /*require_valid_internet_hostname=*/true);
1315*6777b538SAndroid Build Coastguard Worker       // Ignore invalid (too long) combinations.
1316*6777b538SAndroid Build Coastguard Worker       if (!qname.has_value())
1317*6777b538SAndroid Build Coastguard Worker         continue;
1318*6777b538SAndroid Build Coastguard Worker       if (qname.value().size() == labeled_qname.value().size()) {
1319*6777b538SAndroid Build Coastguard Worker         if (had_qname)
1320*6777b538SAndroid Build Coastguard Worker           continue;
1321*6777b538SAndroid Build Coastguard Worker         had_qname = true;
1322*6777b538SAndroid Build Coastguard Worker       }
1323*6777b538SAndroid Build Coastguard Worker       qnames_.push_back(std::move(qname).value());
1324*6777b538SAndroid Build Coastguard Worker     }
1325*6777b538SAndroid Build Coastguard Worker 
1326*6777b538SAndroid Build Coastguard Worker     if (ndots > 0 && !had_qname)
1327*6777b538SAndroid Build Coastguard Worker       qnames_.push_back(std::move(labeled_qname).value());
1328*6777b538SAndroid Build Coastguard Worker 
1329*6777b538SAndroid Build Coastguard Worker     return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK;
1330*6777b538SAndroid Build Coastguard Worker   }
1331*6777b538SAndroid Build Coastguard Worker 
DoCallback(AttemptResult result)1332*6777b538SAndroid Build Coastguard Worker   void DoCallback(AttemptResult result) {
1333*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(ERR_IO_PENDING, result.rv);
1334*6777b538SAndroid Build Coastguard Worker 
1335*6777b538SAndroid Build Coastguard Worker     // TODO(mgersh): consider changing back to a DCHECK once
1336*6777b538SAndroid Build Coastguard Worker     // https://crbug.com/779589 is fixed.
1337*6777b538SAndroid Build Coastguard Worker     if (callback_.is_null())
1338*6777b538SAndroid Build Coastguard Worker       return;
1339*6777b538SAndroid Build Coastguard Worker 
1340*6777b538SAndroid Build Coastguard Worker     const DnsResponse* response =
1341*6777b538SAndroid Build Coastguard Worker         result.attempt ? result.attempt->GetResponse() : nullptr;
1342*6777b538SAndroid Build Coastguard Worker     CHECK(result.rv != OK || response != nullptr);
1343*6777b538SAndroid Build Coastguard Worker 
1344*6777b538SAndroid Build Coastguard Worker     timer_.Stop();
1345*6777b538SAndroid Build Coastguard Worker 
1346*6777b538SAndroid Build Coastguard Worker     net_log_.EndEventWithNetErrorCode(NetLogEventType::DNS_TRANSACTION,
1347*6777b538SAndroid Build Coastguard Worker                                       result.rv);
1348*6777b538SAndroid Build Coastguard Worker 
1349*6777b538SAndroid Build Coastguard Worker     std::move(callback_).Run(result.rv, response);
1350*6777b538SAndroid Build Coastguard Worker   }
1351*6777b538SAndroid Build Coastguard Worker 
RecordAttemptUma(DnsAttemptType attempt_type)1352*6777b538SAndroid Build Coastguard Worker   void RecordAttemptUma(DnsAttemptType attempt_type) {
1353*6777b538SAndroid Build Coastguard Worker     UMA_HISTOGRAM_ENUMERATION("Net.DNS.DnsTransaction.AttemptType",
1354*6777b538SAndroid Build Coastguard Worker                               attempt_type);
1355*6777b538SAndroid Build Coastguard Worker   }
1356*6777b538SAndroid Build Coastguard Worker 
MakeAttempt()1357*6777b538SAndroid Build Coastguard Worker   AttemptResult MakeAttempt() {
1358*6777b538SAndroid Build Coastguard Worker     DCHECK(MoreAttemptsAllowed());
1359*6777b538SAndroid Build Coastguard Worker 
1360*6777b538SAndroid Build Coastguard Worker     DnsConfig config = session_->config();
1361*6777b538SAndroid Build Coastguard Worker     if (secure_) {
1362*6777b538SAndroid Build Coastguard Worker       DCHECK(!config.doh_config.servers().empty());
1363*6777b538SAndroid Build Coastguard Worker       RecordAttemptUma(DnsAttemptType::kHttp);
1364*6777b538SAndroid Build Coastguard Worker       return MakeHTTPAttempt();
1365*6777b538SAndroid Build Coastguard Worker     }
1366*6777b538SAndroid Build Coastguard Worker 
1367*6777b538SAndroid Build Coastguard Worker     DCHECK_GT(config.nameservers.size(), 0u);
1368*6777b538SAndroid Build Coastguard Worker     return MakeClassicDnsAttempt();
1369*6777b538SAndroid Build Coastguard Worker   }
1370*6777b538SAndroid Build Coastguard Worker 
MakeClassicDnsAttempt()1371*6777b538SAndroid Build Coastguard Worker   AttemptResult MakeClassicDnsAttempt() {
1372*6777b538SAndroid Build Coastguard Worker     uint16_t id = session_->NextQueryId();
1373*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<DnsQuery> query;
1374*6777b538SAndroid Build Coastguard Worker     if (attempts_.empty()) {
1375*6777b538SAndroid Build Coastguard Worker       query =
1376*6777b538SAndroid Build Coastguard Worker           std::make_unique<DnsQuery>(id, qnames_.front(), qtype_, opt_rdata_);
1377*6777b538SAndroid Build Coastguard Worker     } else {
1378*6777b538SAndroid Build Coastguard Worker       query = attempts_[0]->GetQuery()->CloneWithNewId(id);
1379*6777b538SAndroid Build Coastguard Worker     }
1380*6777b538SAndroid Build Coastguard Worker     DCHECK(dns_server_iterator_->AttemptAvailable());
1381*6777b538SAndroid Build Coastguard Worker     size_t server_index = dns_server_iterator_->GetNextAttemptIndex();
1382*6777b538SAndroid Build Coastguard Worker 
1383*6777b538SAndroid Build Coastguard Worker     size_t attempt_number = attempts_.size();
1384*6777b538SAndroid Build Coastguard Worker     AttemptResult result;
1385*6777b538SAndroid Build Coastguard Worker     if (session_->udp_tracker()->low_entropy()) {
1386*6777b538SAndroid Build Coastguard Worker       result = MakeTcpAttempt(server_index, std::move(query));
1387*6777b538SAndroid Build Coastguard Worker       RecordAttemptUma(DnsAttemptType::kTcpLowEntropy);
1388*6777b538SAndroid Build Coastguard Worker     } else {
1389*6777b538SAndroid Build Coastguard Worker       result = MakeUdpAttempt(server_index, std::move(query));
1390*6777b538SAndroid Build Coastguard Worker       RecordAttemptUma(DnsAttemptType::kUdp);
1391*6777b538SAndroid Build Coastguard Worker     }
1392*6777b538SAndroid Build Coastguard Worker 
1393*6777b538SAndroid Build Coastguard Worker     if (result.rv == ERR_IO_PENDING) {
1394*6777b538SAndroid Build Coastguard Worker       base::TimeDelta fallback_period =
1395*6777b538SAndroid Build Coastguard Worker           resolve_context_->NextClassicFallbackPeriod(
1396*6777b538SAndroid Build Coastguard Worker               server_index, attempt_number, session_.get());
1397*6777b538SAndroid Build Coastguard Worker       timer_.Start(FROM_HERE, fallback_period, this,
1398*6777b538SAndroid Build Coastguard Worker                    &DnsTransactionImpl::OnFallbackPeriodExpired);
1399*6777b538SAndroid Build Coastguard Worker     }
1400*6777b538SAndroid Build Coastguard Worker 
1401*6777b538SAndroid Build Coastguard Worker     return result;
1402*6777b538SAndroid Build Coastguard Worker   }
1403*6777b538SAndroid Build Coastguard Worker 
1404*6777b538SAndroid Build Coastguard Worker   // Makes another attempt at the current name, |qnames_.front()|, using the
1405*6777b538SAndroid Build Coastguard Worker   // next nameserver.
MakeUdpAttempt(size_t server_index,std::unique_ptr<DnsQuery> query)1406*6777b538SAndroid Build Coastguard Worker   AttemptResult MakeUdpAttempt(size_t server_index,
1407*6777b538SAndroid Build Coastguard Worker                                std::unique_ptr<DnsQuery> query) {
1408*6777b538SAndroid Build Coastguard Worker     DCHECK(!secure_);
1409*6777b538SAndroid Build Coastguard Worker     DCHECK(!session_->udp_tracker()->low_entropy());
1410*6777b538SAndroid Build Coastguard Worker 
1411*6777b538SAndroid Build Coastguard Worker     const DnsConfig& config = session_->config();
1412*6777b538SAndroid Build Coastguard Worker     DCHECK_LT(server_index, config.nameservers.size());
1413*6777b538SAndroid Build Coastguard Worker     size_t attempt_number = attempts_.size();
1414*6777b538SAndroid Build Coastguard Worker 
1415*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<DatagramClientSocket> socket =
1416*6777b538SAndroid Build Coastguard Worker         resolve_context_->url_request_context()
1417*6777b538SAndroid Build Coastguard Worker             ->GetNetworkSessionContext()
1418*6777b538SAndroid Build Coastguard Worker             ->client_socket_factory->CreateDatagramClientSocket(
1419*6777b538SAndroid Build Coastguard Worker                 DatagramSocket::RANDOM_BIND, net_log_.net_log(),
1420*6777b538SAndroid Build Coastguard Worker                 net_log_.source());
1421*6777b538SAndroid Build Coastguard Worker 
1422*6777b538SAndroid Build Coastguard Worker     attempts_.push_back(std::make_unique<DnsUDPAttempt>(
1423*6777b538SAndroid Build Coastguard Worker         server_index, std::move(socket), config.nameservers[server_index],
1424*6777b538SAndroid Build Coastguard Worker         std::move(query), session_->udp_tracker()));
1425*6777b538SAndroid Build Coastguard Worker     ++attempts_count_;
1426*6777b538SAndroid Build Coastguard Worker 
1427*6777b538SAndroid Build Coastguard Worker     DnsAttempt* attempt = attempts_.back().get();
1428*6777b538SAndroid Build Coastguard Worker     net_log_.AddEventReferencingSource(NetLogEventType::DNS_TRANSACTION_ATTEMPT,
1429*6777b538SAndroid Build Coastguard Worker                                        attempt->GetSocketNetLog().source());
1430*6777b538SAndroid Build Coastguard Worker 
1431*6777b538SAndroid Build Coastguard Worker     int rv = attempt->Start(base::BindOnce(
1432*6777b538SAndroid Build Coastguard Worker         &DnsTransactionImpl::OnAttemptComplete, base::Unretained(this),
1433*6777b538SAndroid Build Coastguard Worker         attempt_number, true /* record_rtt */, base::TimeTicks::Now()));
1434*6777b538SAndroid Build Coastguard Worker     return AttemptResult(rv, attempt);
1435*6777b538SAndroid Build Coastguard Worker   }
1436*6777b538SAndroid Build Coastguard Worker 
MakeHTTPAttempt()1437*6777b538SAndroid Build Coastguard Worker   AttemptResult MakeHTTPAttempt() {
1438*6777b538SAndroid Build Coastguard Worker     DCHECK(secure_);
1439*6777b538SAndroid Build Coastguard Worker 
1440*6777b538SAndroid Build Coastguard Worker     size_t doh_server_index = dns_server_iterator_->GetNextAttemptIndex();
1441*6777b538SAndroid Build Coastguard Worker 
1442*6777b538SAndroid Build Coastguard Worker     unsigned attempt_number = attempts_.size();
1443*6777b538SAndroid Build Coastguard Worker     ConstructDnsHTTPAttempt(session_.get(), doh_server_index, qnames_.front(),
1444*6777b538SAndroid Build Coastguard Worker                             qtype_, opt_rdata_, &attempts_,
1445*6777b538SAndroid Build Coastguard Worker                             resolve_context_->url_request_context(),
1446*6777b538SAndroid Build Coastguard Worker                             resolve_context_->isolation_info(),
1447*6777b538SAndroid Build Coastguard Worker                             request_priority_, /*is_probe=*/false);
1448*6777b538SAndroid Build Coastguard Worker     ++attempts_count_;
1449*6777b538SAndroid Build Coastguard Worker     DnsAttempt* attempt = attempts_.back().get();
1450*6777b538SAndroid Build Coastguard Worker     // Associate this attempt with the DoH request in NetLog.
1451*6777b538SAndroid Build Coastguard Worker     net_log_.AddEventReferencingSource(
1452*6777b538SAndroid Build Coastguard Worker         NetLogEventType::DNS_TRANSACTION_HTTPS_ATTEMPT,
1453*6777b538SAndroid Build Coastguard Worker         attempt->GetSocketNetLog().source());
1454*6777b538SAndroid Build Coastguard Worker     attempt->GetSocketNetLog().AddEventReferencingSource(
1455*6777b538SAndroid Build Coastguard Worker         NetLogEventType::DNS_TRANSACTION_HTTPS_ATTEMPT, net_log_.source());
1456*6777b538SAndroid Build Coastguard Worker     int rv = attempt->Start(base::BindOnce(
1457*6777b538SAndroid Build Coastguard Worker         &DnsTransactionImpl::OnAttemptComplete, base::Unretained(this),
1458*6777b538SAndroid Build Coastguard Worker         attempt_number, true /* record_rtt */, base::TimeTicks::Now()));
1459*6777b538SAndroid Build Coastguard Worker     if (rv == ERR_IO_PENDING) {
1460*6777b538SAndroid Build Coastguard Worker       base::TimeDelta fallback_period = resolve_context_->NextDohFallbackPeriod(
1461*6777b538SAndroid Build Coastguard Worker           doh_server_index, session_.get());
1462*6777b538SAndroid Build Coastguard Worker       timer_.Start(FROM_HERE, fallback_period, this,
1463*6777b538SAndroid Build Coastguard Worker                    &DnsTransactionImpl::OnFallbackPeriodExpired);
1464*6777b538SAndroid Build Coastguard Worker     }
1465*6777b538SAndroid Build Coastguard Worker     return AttemptResult(rv, attempts_.back().get());
1466*6777b538SAndroid Build Coastguard Worker   }
1467*6777b538SAndroid Build Coastguard Worker 
RetryUdpAttemptAsTcp(const DnsAttempt * previous_attempt)1468*6777b538SAndroid Build Coastguard Worker   AttemptResult RetryUdpAttemptAsTcp(const DnsAttempt* previous_attempt) {
1469*6777b538SAndroid Build Coastguard Worker     DCHECK(previous_attempt);
1470*6777b538SAndroid Build Coastguard Worker     DCHECK(!had_tcp_retry_);
1471*6777b538SAndroid Build Coastguard Worker 
1472*6777b538SAndroid Build Coastguard Worker     // Only allow a single TCP retry per query.
1473*6777b538SAndroid Build Coastguard Worker     had_tcp_retry_ = true;
1474*6777b538SAndroid Build Coastguard Worker 
1475*6777b538SAndroid Build Coastguard Worker     size_t server_index = previous_attempt->server_index();
1476*6777b538SAndroid Build Coastguard Worker     // Use a new query ID instead of reusing the same one from the UDP attempt.
1477*6777b538SAndroid Build Coastguard Worker     // RFC5452, section 9.2 requires an unpredictable ID for all outgoing
1478*6777b538SAndroid Build Coastguard Worker     // queries, with no distinction made between queries made via TCP or UDP.
1479*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<DnsQuery> query =
1480*6777b538SAndroid Build Coastguard Worker         previous_attempt->GetQuery()->CloneWithNewId(session_->NextQueryId());
1481*6777b538SAndroid Build Coastguard Worker 
1482*6777b538SAndroid Build Coastguard Worker     // Cancel all attempts that have not received a response, as they will
1483*6777b538SAndroid Build Coastguard Worker     // likely similarly require TCP retry.
1484*6777b538SAndroid Build Coastguard Worker     ClearAttempts(nullptr);
1485*6777b538SAndroid Build Coastguard Worker 
1486*6777b538SAndroid Build Coastguard Worker     AttemptResult result = MakeTcpAttempt(server_index, std::move(query));
1487*6777b538SAndroid Build Coastguard Worker     RecordAttemptUma(DnsAttemptType::kTcpTruncationRetry);
1488*6777b538SAndroid Build Coastguard Worker 
1489*6777b538SAndroid Build Coastguard Worker     if (result.rv == ERR_IO_PENDING) {
1490*6777b538SAndroid Build Coastguard Worker       // On TCP upgrade, use 2x the upgraded fallback period.
1491*6777b538SAndroid Build Coastguard Worker       base::TimeDelta fallback_period = timer_.GetCurrentDelay() * 2;
1492*6777b538SAndroid Build Coastguard Worker       timer_.Start(FROM_HERE, fallback_period, this,
1493*6777b538SAndroid Build Coastguard Worker                    &DnsTransactionImpl::OnFallbackPeriodExpired);
1494*6777b538SAndroid Build Coastguard Worker     }
1495*6777b538SAndroid Build Coastguard Worker 
1496*6777b538SAndroid Build Coastguard Worker     return result;
1497*6777b538SAndroid Build Coastguard Worker   }
1498*6777b538SAndroid Build Coastguard Worker 
MakeTcpAttempt(size_t server_index,std::unique_ptr<DnsQuery> query)1499*6777b538SAndroid Build Coastguard Worker   AttemptResult MakeTcpAttempt(size_t server_index,
1500*6777b538SAndroid Build Coastguard Worker                                std::unique_ptr<DnsQuery> query) {
1501*6777b538SAndroid Build Coastguard Worker     DCHECK(!secure_);
1502*6777b538SAndroid Build Coastguard Worker     const DnsConfig& config = session_->config();
1503*6777b538SAndroid Build Coastguard Worker     DCHECK_LT(server_index, config.nameservers.size());
1504*6777b538SAndroid Build Coastguard Worker 
1505*6777b538SAndroid Build Coastguard Worker     // TODO(https://crbug.com/1123197): Pass a non-null NetworkQualityEstimator.
1506*6777b538SAndroid Build Coastguard Worker     NetworkQualityEstimator* network_quality_estimator = nullptr;
1507*6777b538SAndroid Build Coastguard Worker 
1508*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<StreamSocket> socket =
1509*6777b538SAndroid Build Coastguard Worker         resolve_context_->url_request_context()
1510*6777b538SAndroid Build Coastguard Worker             ->GetNetworkSessionContext()
1511*6777b538SAndroid Build Coastguard Worker             ->client_socket_factory->CreateTransportClientSocket(
1512*6777b538SAndroid Build Coastguard Worker                 AddressList(config.nameservers[server_index]), nullptr,
1513*6777b538SAndroid Build Coastguard Worker                 network_quality_estimator, net_log_.net_log(),
1514*6777b538SAndroid Build Coastguard Worker                 net_log_.source());
1515*6777b538SAndroid Build Coastguard Worker 
1516*6777b538SAndroid Build Coastguard Worker     unsigned attempt_number = attempts_.size();
1517*6777b538SAndroid Build Coastguard Worker 
1518*6777b538SAndroid Build Coastguard Worker     attempts_.push_back(std::make_unique<DnsTCPAttempt>(
1519*6777b538SAndroid Build Coastguard Worker         server_index, std::move(socket), std::move(query)));
1520*6777b538SAndroid Build Coastguard Worker     ++attempts_count_;
1521*6777b538SAndroid Build Coastguard Worker 
1522*6777b538SAndroid Build Coastguard Worker     DnsAttempt* attempt = attempts_.back().get();
1523*6777b538SAndroid Build Coastguard Worker     net_log_.AddEventReferencingSource(
1524*6777b538SAndroid Build Coastguard Worker         NetLogEventType::DNS_TRANSACTION_TCP_ATTEMPT,
1525*6777b538SAndroid Build Coastguard Worker         attempt->GetSocketNetLog().source());
1526*6777b538SAndroid Build Coastguard Worker 
1527*6777b538SAndroid Build Coastguard Worker     int rv = attempt->Start(base::BindOnce(
1528*6777b538SAndroid Build Coastguard Worker         &DnsTransactionImpl::OnAttemptComplete, base::Unretained(this),
1529*6777b538SAndroid Build Coastguard Worker         attempt_number, false /* record_rtt */, base::TimeTicks::Now()));
1530*6777b538SAndroid Build Coastguard Worker     return AttemptResult(rv, attempt);
1531*6777b538SAndroid Build Coastguard Worker   }
1532*6777b538SAndroid Build Coastguard Worker 
1533*6777b538SAndroid Build Coastguard Worker   // Begins query for the current name. Makes the first attempt.
StartQuery()1534*6777b538SAndroid Build Coastguard Worker   AttemptResult StartQuery() {
1535*6777b538SAndroid Build Coastguard Worker     std::optional<std::string> dotted_qname =
1536*6777b538SAndroid Build Coastguard Worker         dns_names_util::NetworkToDottedName(qnames_.front());
1537*6777b538SAndroid Build Coastguard Worker     net_log_.BeginEventWithStringParams(
1538*6777b538SAndroid Build Coastguard Worker         NetLogEventType::DNS_TRANSACTION_QUERY, "qname",
1539*6777b538SAndroid Build Coastguard Worker         dotted_qname.value_or("???MALFORMED_NAME???"));
1540*6777b538SAndroid Build Coastguard Worker 
1541*6777b538SAndroid Build Coastguard Worker     attempts_.clear();
1542*6777b538SAndroid Build Coastguard Worker     had_tcp_retry_ = false;
1543*6777b538SAndroid Build Coastguard Worker     if (secure_) {
1544*6777b538SAndroid Build Coastguard Worker       dns_server_iterator_ = resolve_context_->GetDohIterator(
1545*6777b538SAndroid Build Coastguard Worker           session_->config(), secure_dns_mode_, session_.get());
1546*6777b538SAndroid Build Coastguard Worker     } else {
1547*6777b538SAndroid Build Coastguard Worker       dns_server_iterator_ = resolve_context_->GetClassicDnsIterator(
1548*6777b538SAndroid Build Coastguard Worker           session_->config(), session_.get());
1549*6777b538SAndroid Build Coastguard Worker     }
1550*6777b538SAndroid Build Coastguard Worker     DCHECK(dns_server_iterator_);
1551*6777b538SAndroid Build Coastguard Worker     // Check for available server before starting as DoH servers might be
1552*6777b538SAndroid Build Coastguard Worker     // unavailable.
1553*6777b538SAndroid Build Coastguard Worker     if (!dns_server_iterator_->AttemptAvailable())
1554*6777b538SAndroid Build Coastguard Worker       return AttemptResult(ERR_BLOCKED_BY_CLIENT, nullptr);
1555*6777b538SAndroid Build Coastguard Worker 
1556*6777b538SAndroid Build Coastguard Worker     return MakeAttempt();
1557*6777b538SAndroid Build Coastguard Worker   }
1558*6777b538SAndroid Build Coastguard Worker 
OnAttemptComplete(unsigned attempt_number,bool record_rtt,base::TimeTicks start,int rv)1559*6777b538SAndroid Build Coastguard Worker   void OnAttemptComplete(unsigned attempt_number,
1560*6777b538SAndroid Build Coastguard Worker                          bool record_rtt,
1561*6777b538SAndroid Build Coastguard Worker                          base::TimeTicks start,
1562*6777b538SAndroid Build Coastguard Worker                          int rv) {
1563*6777b538SAndroid Build Coastguard Worker     DCHECK_LT(attempt_number, attempts_.size());
1564*6777b538SAndroid Build Coastguard Worker     const DnsAttempt* attempt = attempts_[attempt_number].get();
1565*6777b538SAndroid Build Coastguard Worker     if (record_rtt && attempt->GetResponse()) {
1566*6777b538SAndroid Build Coastguard Worker       resolve_context_->RecordRtt(
1567*6777b538SAndroid Build Coastguard Worker           attempt->server_index(), secure_ /* is_doh_server */,
1568*6777b538SAndroid Build Coastguard Worker           base::TimeTicks::Now() - start, rv, session_.get());
1569*6777b538SAndroid Build Coastguard Worker     }
1570*6777b538SAndroid Build Coastguard Worker     if (callback_.is_null())
1571*6777b538SAndroid Build Coastguard Worker       return;
1572*6777b538SAndroid Build Coastguard Worker     AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt));
1573*6777b538SAndroid Build Coastguard Worker     if (result.rv != ERR_IO_PENDING)
1574*6777b538SAndroid Build Coastguard Worker       DoCallback(result);
1575*6777b538SAndroid Build Coastguard Worker   }
1576*6777b538SAndroid Build Coastguard Worker 
LogResponse(const DnsAttempt * attempt)1577*6777b538SAndroid Build Coastguard Worker   void LogResponse(const DnsAttempt* attempt) {
1578*6777b538SAndroid Build Coastguard Worker     if (attempt) {
1579*6777b538SAndroid Build Coastguard Worker       net_log_.AddEvent(NetLogEventType::DNS_TRANSACTION_RESPONSE,
1580*6777b538SAndroid Build Coastguard Worker                         [&](NetLogCaptureMode capture_mode) {
1581*6777b538SAndroid Build Coastguard Worker                           return attempt->NetLogResponseParams(capture_mode);
1582*6777b538SAndroid Build Coastguard Worker                         });
1583*6777b538SAndroid Build Coastguard Worker     }
1584*6777b538SAndroid Build Coastguard Worker   }
1585*6777b538SAndroid Build Coastguard Worker 
MoreAttemptsAllowed() const1586*6777b538SAndroid Build Coastguard Worker   bool MoreAttemptsAllowed() const {
1587*6777b538SAndroid Build Coastguard Worker     if (had_tcp_retry_)
1588*6777b538SAndroid Build Coastguard Worker       return false;
1589*6777b538SAndroid Build Coastguard Worker 
1590*6777b538SAndroid Build Coastguard Worker     return dns_server_iterator_->AttemptAvailable();
1591*6777b538SAndroid Build Coastguard Worker   }
1592*6777b538SAndroid Build Coastguard Worker 
1593*6777b538SAndroid Build Coastguard Worker   // Resolves the result of a DnsAttempt until a terminal result is reached
1594*6777b538SAndroid Build Coastguard Worker   // or it will complete asynchronously (ERR_IO_PENDING).
ProcessAttemptResult(AttemptResult result)1595*6777b538SAndroid Build Coastguard Worker   AttemptResult ProcessAttemptResult(AttemptResult result) {
1596*6777b538SAndroid Build Coastguard Worker     while (result.rv != ERR_IO_PENDING) {
1597*6777b538SAndroid Build Coastguard Worker       LogResponse(result.attempt);
1598*6777b538SAndroid Build Coastguard Worker 
1599*6777b538SAndroid Build Coastguard Worker       switch (result.rv) {
1600*6777b538SAndroid Build Coastguard Worker         case OK:
1601*6777b538SAndroid Build Coastguard Worker           resolve_context_->RecordServerSuccess(result.attempt->server_index(),
1602*6777b538SAndroid Build Coastguard Worker                                                 secure_ /* is_doh_server */,
1603*6777b538SAndroid Build Coastguard Worker                                                 session_.get());
1604*6777b538SAndroid Build Coastguard Worker           net_log_.EndEventWithNetErrorCode(
1605*6777b538SAndroid Build Coastguard Worker               NetLogEventType::DNS_TRANSACTION_QUERY, result.rv);
1606*6777b538SAndroid Build Coastguard Worker           DCHECK(result.attempt);
1607*6777b538SAndroid Build Coastguard Worker           DCHECK(result.attempt->GetResponse());
1608*6777b538SAndroid Build Coastguard Worker           return result;
1609*6777b538SAndroid Build Coastguard Worker         case ERR_NAME_NOT_RESOLVED:
1610*6777b538SAndroid Build Coastguard Worker           resolve_context_->RecordServerSuccess(result.attempt->server_index(),
1611*6777b538SAndroid Build Coastguard Worker                                                 secure_ /* is_doh_server */,
1612*6777b538SAndroid Build Coastguard Worker                                                 session_.get());
1613*6777b538SAndroid Build Coastguard Worker           net_log_.EndEventWithNetErrorCode(
1614*6777b538SAndroid Build Coastguard Worker               NetLogEventType::DNS_TRANSACTION_QUERY, result.rv);
1615*6777b538SAndroid Build Coastguard Worker           // Try next suffix. Check that qnames_ isn't already empty first,
1616*6777b538SAndroid Build Coastguard Worker           // which can happen when there are two attempts running at once.
1617*6777b538SAndroid Build Coastguard Worker           // TODO(mgersh): remove this workaround for https://crbug.com/774846
1618*6777b538SAndroid Build Coastguard Worker           // when https://crbug.com/779589 is fixed.
1619*6777b538SAndroid Build Coastguard Worker           if (!qnames_.empty())
1620*6777b538SAndroid Build Coastguard Worker             qnames_.pop_front();
1621*6777b538SAndroid Build Coastguard Worker           if (qnames_.empty()) {
1622*6777b538SAndroid Build Coastguard Worker             return result;
1623*6777b538SAndroid Build Coastguard Worker           } else {
1624*6777b538SAndroid Build Coastguard Worker             result = StartQuery();
1625*6777b538SAndroid Build Coastguard Worker           }
1626*6777b538SAndroid Build Coastguard Worker           break;
1627*6777b538SAndroid Build Coastguard Worker         case ERR_DNS_TIMED_OUT:
1628*6777b538SAndroid Build Coastguard Worker           timer_.Stop();
1629*6777b538SAndroid Build Coastguard Worker 
1630*6777b538SAndroid Build Coastguard Worker           if (result.attempt) {
1631*6777b538SAndroid Build Coastguard Worker             DCHECK(result.attempt == attempts_.back().get());
1632*6777b538SAndroid Build Coastguard Worker             resolve_context_->RecordServerFailure(
1633*6777b538SAndroid Build Coastguard Worker                 result.attempt->server_index(), secure_ /* is_doh_server */,
1634*6777b538SAndroid Build Coastguard Worker                 result.rv, session_.get());
1635*6777b538SAndroid Build Coastguard Worker           }
1636*6777b538SAndroid Build Coastguard Worker           if (MoreAttemptsAllowed()) {
1637*6777b538SAndroid Build Coastguard Worker             result = MakeAttempt();
1638*6777b538SAndroid Build Coastguard Worker             break;
1639*6777b538SAndroid Build Coastguard Worker           }
1640*6777b538SAndroid Build Coastguard Worker 
1641*6777b538SAndroid Build Coastguard Worker           if (!fast_timeout_ && AnyAttemptPending()) {
1642*6777b538SAndroid Build Coastguard Worker             StartTimeoutTimer();
1643*6777b538SAndroid Build Coastguard Worker             return AttemptResult(ERR_IO_PENDING, nullptr);
1644*6777b538SAndroid Build Coastguard Worker           }
1645*6777b538SAndroid Build Coastguard Worker 
1646*6777b538SAndroid Build Coastguard Worker           return result;
1647*6777b538SAndroid Build Coastguard Worker         case ERR_DNS_SERVER_REQUIRES_TCP:
1648*6777b538SAndroid Build Coastguard Worker           result = RetryUdpAttemptAsTcp(result.attempt);
1649*6777b538SAndroid Build Coastguard Worker           break;
1650*6777b538SAndroid Build Coastguard Worker         case ERR_BLOCKED_BY_CLIENT:
1651*6777b538SAndroid Build Coastguard Worker           net_log_.EndEventWithNetErrorCode(
1652*6777b538SAndroid Build Coastguard Worker               NetLogEventType::DNS_TRANSACTION_QUERY, result.rv);
1653*6777b538SAndroid Build Coastguard Worker           return result;
1654*6777b538SAndroid Build Coastguard Worker         default:
1655*6777b538SAndroid Build Coastguard Worker           // Server failure.
1656*6777b538SAndroid Build Coastguard Worker           DCHECK(result.attempt);
1657*6777b538SAndroid Build Coastguard Worker 
1658*6777b538SAndroid Build Coastguard Worker           // If attempt is not the most recent attempt, means this error is for
1659*6777b538SAndroid Build Coastguard Worker           // a previous attempt that already passed its fallback period and
1660*6777b538SAndroid Build Coastguard Worker           // continued attempting in parallel with new attempts (see the
1661*6777b538SAndroid Build Coastguard Worker           // ERR_DNS_TIMED_OUT case above). As the failure was already recorded
1662*6777b538SAndroid Build Coastguard Worker           // at fallback time and is no longer being waited on, ignore this
1663*6777b538SAndroid Build Coastguard Worker           // failure.
1664*6777b538SAndroid Build Coastguard Worker           if (result.attempt == attempts_.back().get()) {
1665*6777b538SAndroid Build Coastguard Worker             timer_.Stop();
1666*6777b538SAndroid Build Coastguard Worker             resolve_context_->RecordServerFailure(
1667*6777b538SAndroid Build Coastguard Worker                 result.attempt->server_index(), secure_ /* is_doh_server */,
1668*6777b538SAndroid Build Coastguard Worker                 result.rv, session_.get());
1669*6777b538SAndroid Build Coastguard Worker 
1670*6777b538SAndroid Build Coastguard Worker             if (MoreAttemptsAllowed()) {
1671*6777b538SAndroid Build Coastguard Worker               result = MakeAttempt();
1672*6777b538SAndroid Build Coastguard Worker               break;
1673*6777b538SAndroid Build Coastguard Worker             }
1674*6777b538SAndroid Build Coastguard Worker 
1675*6777b538SAndroid Build Coastguard Worker             if (fast_timeout_) {
1676*6777b538SAndroid Build Coastguard Worker               return result;
1677*6777b538SAndroid Build Coastguard Worker             }
1678*6777b538SAndroid Build Coastguard Worker 
1679*6777b538SAndroid Build Coastguard Worker             // No more attempts can be made, but there may be other attempts
1680*6777b538SAndroid Build Coastguard Worker             // still pending, so start the timeout timer.
1681*6777b538SAndroid Build Coastguard Worker             StartTimeoutTimer();
1682*6777b538SAndroid Build Coastguard Worker           }
1683*6777b538SAndroid Build Coastguard Worker 
1684*6777b538SAndroid Build Coastguard Worker           // If any attempts are still pending, continue to wait for them.
1685*6777b538SAndroid Build Coastguard Worker           if (AnyAttemptPending()) {
1686*6777b538SAndroid Build Coastguard Worker             DCHECK(timer_.IsRunning());
1687*6777b538SAndroid Build Coastguard Worker             return AttemptResult(ERR_IO_PENDING, nullptr);
1688*6777b538SAndroid Build Coastguard Worker           }
1689*6777b538SAndroid Build Coastguard Worker 
1690*6777b538SAndroid Build Coastguard Worker           return result;
1691*6777b538SAndroid Build Coastguard Worker       }
1692*6777b538SAndroid Build Coastguard Worker     }
1693*6777b538SAndroid Build Coastguard Worker     return result;
1694*6777b538SAndroid Build Coastguard Worker   }
1695*6777b538SAndroid Build Coastguard Worker 
1696*6777b538SAndroid Build Coastguard Worker   // Clears and cancels all pending attempts. If |leave_attempt| is not
1697*6777b538SAndroid Build Coastguard Worker   // null, that attempt is not cleared even if pending.
ClearAttempts(const DnsAttempt * leave_attempt)1698*6777b538SAndroid Build Coastguard Worker   void ClearAttempts(const DnsAttempt* leave_attempt) {
1699*6777b538SAndroid Build Coastguard Worker     for (auto it = attempts_.begin(); it != attempts_.end();) {
1700*6777b538SAndroid Build Coastguard Worker       if ((*it)->IsPending() && it->get() != leave_attempt) {
1701*6777b538SAndroid Build Coastguard Worker         it = attempts_.erase(it);
1702*6777b538SAndroid Build Coastguard Worker       } else {
1703*6777b538SAndroid Build Coastguard Worker         ++it;
1704*6777b538SAndroid Build Coastguard Worker       }
1705*6777b538SAndroid Build Coastguard Worker     }
1706*6777b538SAndroid Build Coastguard Worker   }
1707*6777b538SAndroid Build Coastguard Worker 
AnyAttemptPending()1708*6777b538SAndroid Build Coastguard Worker   bool AnyAttemptPending() {
1709*6777b538SAndroid Build Coastguard Worker     return base::ranges::any_of(attempts_,
1710*6777b538SAndroid Build Coastguard Worker                                 [](std::unique_ptr<DnsAttempt>& attempt) {
1711*6777b538SAndroid Build Coastguard Worker                                   return attempt->IsPending();
1712*6777b538SAndroid Build Coastguard Worker                                 });
1713*6777b538SAndroid Build Coastguard Worker   }
1714*6777b538SAndroid Build Coastguard Worker 
OnFallbackPeriodExpired()1715*6777b538SAndroid Build Coastguard Worker   void OnFallbackPeriodExpired() {
1716*6777b538SAndroid Build Coastguard Worker     if (callback_.is_null())
1717*6777b538SAndroid Build Coastguard Worker       return;
1718*6777b538SAndroid Build Coastguard Worker     DCHECK(!attempts_.empty());
1719*6777b538SAndroid Build Coastguard Worker     AttemptResult result = ProcessAttemptResult(
1720*6777b538SAndroid Build Coastguard Worker         AttemptResult(ERR_DNS_TIMED_OUT, attempts_.back().get()));
1721*6777b538SAndroid Build Coastguard Worker     if (result.rv != ERR_IO_PENDING)
1722*6777b538SAndroid Build Coastguard Worker       DoCallback(result);
1723*6777b538SAndroid Build Coastguard Worker   }
1724*6777b538SAndroid Build Coastguard Worker 
StartTimeoutTimer()1725*6777b538SAndroid Build Coastguard Worker   void StartTimeoutTimer() {
1726*6777b538SAndroid Build Coastguard Worker     DCHECK(!fast_timeout_);
1727*6777b538SAndroid Build Coastguard Worker     DCHECK(!timer_.IsRunning());
1728*6777b538SAndroid Build Coastguard Worker     DCHECK(!callback_.is_null());
1729*6777b538SAndroid Build Coastguard Worker 
1730*6777b538SAndroid Build Coastguard Worker     base::TimeDelta timeout;
1731*6777b538SAndroid Build Coastguard Worker     if (secure_) {
1732*6777b538SAndroid Build Coastguard Worker       timeout = resolve_context_->SecureTransactionTimeout(secure_dns_mode_,
1733*6777b538SAndroid Build Coastguard Worker                                                            session_.get());
1734*6777b538SAndroid Build Coastguard Worker     } else {
1735*6777b538SAndroid Build Coastguard Worker       timeout = resolve_context_->ClassicTransactionTimeout(session_.get());
1736*6777b538SAndroid Build Coastguard Worker     }
1737*6777b538SAndroid Build Coastguard Worker     timeout -= time_from_start_->Elapsed();
1738*6777b538SAndroid Build Coastguard Worker 
1739*6777b538SAndroid Build Coastguard Worker     timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
1740*6777b538SAndroid Build Coastguard Worker   }
1741*6777b538SAndroid Build Coastguard Worker 
OnTimeout()1742*6777b538SAndroid Build Coastguard Worker   void OnTimeout() {
1743*6777b538SAndroid Build Coastguard Worker     if (callback_.is_null())
1744*6777b538SAndroid Build Coastguard Worker       return;
1745*6777b538SAndroid Build Coastguard Worker     DoCallback(AttemptResult(ERR_DNS_TIMED_OUT, nullptr));
1746*6777b538SAndroid Build Coastguard Worker   }
1747*6777b538SAndroid Build Coastguard Worker 
1748*6777b538SAndroid Build Coastguard Worker   scoped_refptr<DnsSession> session_;
1749*6777b538SAndroid Build Coastguard Worker   std::string hostname_;
1750*6777b538SAndroid Build Coastguard Worker   uint16_t qtype_;
1751*6777b538SAndroid Build Coastguard Worker   raw_ptr<const OptRecordRdata, DanglingUntriaged> opt_rdata_;
1752*6777b538SAndroid Build Coastguard Worker   const bool secure_;
1753*6777b538SAndroid Build Coastguard Worker   const SecureDnsMode secure_dns_mode_;
1754*6777b538SAndroid Build Coastguard Worker   // Cleared in DoCallback.
1755*6777b538SAndroid Build Coastguard Worker   ResponseCallback callback_;
1756*6777b538SAndroid Build Coastguard Worker 
1757*6777b538SAndroid Build Coastguard Worker   // When true, transaction should time out immediately on expiration of the
1758*6777b538SAndroid Build Coastguard Worker   // last attempt fallback period rather than waiting the overall transaction
1759*6777b538SAndroid Build Coastguard Worker   // timeout period.
1760*6777b538SAndroid Build Coastguard Worker   const bool fast_timeout_;
1761*6777b538SAndroid Build Coastguard Worker 
1762*6777b538SAndroid Build Coastguard Worker   NetLogWithSource net_log_;
1763*6777b538SAndroid Build Coastguard Worker 
1764*6777b538SAndroid Build Coastguard Worker   // Search list of fully-qualified DNS names to query next (in DNS format).
1765*6777b538SAndroid Build Coastguard Worker   base::circular_deque<std::vector<uint8_t>> qnames_;
1766*6777b538SAndroid Build Coastguard Worker   size_t qnames_initial_size_ = 0;
1767*6777b538SAndroid Build Coastguard Worker 
1768*6777b538SAndroid Build Coastguard Worker   // List of attempts for the current name.
1769*6777b538SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<DnsAttempt>> attempts_;
1770*6777b538SAndroid Build Coastguard Worker   // Count of attempts, not reset when |attempts_| vector is cleared.
1771*6777b538SAndroid Build Coastguard Worker   int attempts_count_ = 0;
1772*6777b538SAndroid Build Coastguard Worker 
1773*6777b538SAndroid Build Coastguard Worker   // Records when an attempt was retried via TCP due to a truncation error.
1774*6777b538SAndroid Build Coastguard Worker   bool had_tcp_retry_ = false;
1775*6777b538SAndroid Build Coastguard Worker 
1776*6777b538SAndroid Build Coastguard Worker   // Iterator to get the index of the DNS server for each search query.
1777*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DnsServerIterator> dns_server_iterator_;
1778*6777b538SAndroid Build Coastguard Worker 
1779*6777b538SAndroid Build Coastguard Worker   base::OneShotTimer timer_;
1780*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<base::ElapsedTimer> time_from_start_;
1781*6777b538SAndroid Build Coastguard Worker 
1782*6777b538SAndroid Build Coastguard Worker   base::SafeRef<ResolveContext> resolve_context_;
1783*6777b538SAndroid Build Coastguard Worker   RequestPriority request_priority_ = DEFAULT_PRIORITY;
1784*6777b538SAndroid Build Coastguard Worker 
1785*6777b538SAndroid Build Coastguard Worker   THREAD_CHECKER(thread_checker_);
1786*6777b538SAndroid Build Coastguard Worker 
1787*6777b538SAndroid Build Coastguard Worker   base::WeakPtrFactory<DnsTransactionImpl> weak_ptr_factory_{this};
1788*6777b538SAndroid Build Coastguard Worker };
1789*6777b538SAndroid Build Coastguard Worker 
1790*6777b538SAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
1791*6777b538SAndroid Build Coastguard Worker 
1792*6777b538SAndroid Build Coastguard Worker // Implementation of DnsTransactionFactory that returns instances of
1793*6777b538SAndroid Build Coastguard Worker // DnsTransactionImpl.
1794*6777b538SAndroid Build Coastguard Worker class DnsTransactionFactoryImpl : public DnsTransactionFactory {
1795*6777b538SAndroid Build Coastguard Worker  public:
DnsTransactionFactoryImpl(DnsSession * session)1796*6777b538SAndroid Build Coastguard Worker   explicit DnsTransactionFactoryImpl(DnsSession* session) {
1797*6777b538SAndroid Build Coastguard Worker     session_ = session;
1798*6777b538SAndroid Build Coastguard Worker   }
1799*6777b538SAndroid Build Coastguard Worker 
CreateTransaction(std::string hostname,uint16_t qtype,const NetLogWithSource & net_log,bool secure,SecureDnsMode secure_dns_mode,ResolveContext * resolve_context,bool fast_timeout)1800*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DnsTransaction> CreateTransaction(
1801*6777b538SAndroid Build Coastguard Worker       std::string hostname,
1802*6777b538SAndroid Build Coastguard Worker       uint16_t qtype,
1803*6777b538SAndroid Build Coastguard Worker       const NetLogWithSource& net_log,
1804*6777b538SAndroid Build Coastguard Worker       bool secure,
1805*6777b538SAndroid Build Coastguard Worker       SecureDnsMode secure_dns_mode,
1806*6777b538SAndroid Build Coastguard Worker       ResolveContext* resolve_context,
1807*6777b538SAndroid Build Coastguard Worker       bool fast_timeout) override {
1808*6777b538SAndroid Build Coastguard Worker     return std::make_unique<DnsTransactionImpl>(
1809*6777b538SAndroid Build Coastguard Worker         session_.get(), std::move(hostname), qtype, net_log, opt_rdata_.get(),
1810*6777b538SAndroid Build Coastguard Worker         secure, secure_dns_mode, resolve_context, fast_timeout);
1811*6777b538SAndroid Build Coastguard Worker   }
1812*6777b538SAndroid Build Coastguard Worker 
CreateDohProbeRunner(ResolveContext * resolve_context)1813*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<DnsProbeRunner> CreateDohProbeRunner(
1814*6777b538SAndroid Build Coastguard Worker       ResolveContext* resolve_context) override {
1815*6777b538SAndroid Build Coastguard Worker     // Start a timer that will emit metrics after a timeout to indicate whether
1816*6777b538SAndroid Build Coastguard Worker     // DoH auto-upgrade was successful for this session.
1817*6777b538SAndroid Build Coastguard Worker     resolve_context->StartDohAutoupgradeSuccessTimer(session_.get());
1818*6777b538SAndroid Build Coastguard Worker 
1819*6777b538SAndroid Build Coastguard Worker     return std::make_unique<DnsOverHttpsProbeRunner>(
1820*6777b538SAndroid Build Coastguard Worker         session_->GetWeakPtr(), resolve_context->GetWeakPtr());
1821*6777b538SAndroid Build Coastguard Worker   }
1822*6777b538SAndroid Build Coastguard Worker 
AddEDNSOption(std::unique_ptr<OptRecordRdata::Opt> opt)1823*6777b538SAndroid Build Coastguard Worker   void AddEDNSOption(std::unique_ptr<OptRecordRdata::Opt> opt) override {
1824*6777b538SAndroid Build Coastguard Worker     DCHECK(opt);
1825*6777b538SAndroid Build Coastguard Worker     if (opt_rdata_ == nullptr)
1826*6777b538SAndroid Build Coastguard Worker       opt_rdata_ = std::make_unique<OptRecordRdata>();
1827*6777b538SAndroid Build Coastguard Worker 
1828*6777b538SAndroid Build Coastguard Worker     opt_rdata_->AddOpt(std::move(opt));
1829*6777b538SAndroid Build Coastguard Worker   }
1830*6777b538SAndroid Build Coastguard Worker 
GetSecureDnsModeForTest()1831*6777b538SAndroid Build Coastguard Worker   SecureDnsMode GetSecureDnsModeForTest() override {
1832*6777b538SAndroid Build Coastguard Worker     return session_->config().secure_dns_mode;
1833*6777b538SAndroid Build Coastguard Worker   }
1834*6777b538SAndroid Build Coastguard Worker 
1835*6777b538SAndroid Build Coastguard Worker  private:
1836*6777b538SAndroid Build Coastguard Worker   scoped_refptr<DnsSession> session_;
1837*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<OptRecordRdata> opt_rdata_;
1838*6777b538SAndroid Build Coastguard Worker };
1839*6777b538SAndroid Build Coastguard Worker 
1840*6777b538SAndroid Build Coastguard Worker }  // namespace
1841*6777b538SAndroid Build Coastguard Worker 
1842*6777b538SAndroid Build Coastguard Worker DnsTransactionFactory::DnsTransactionFactory() = default;
1843*6777b538SAndroid Build Coastguard Worker DnsTransactionFactory::~DnsTransactionFactory() = default;
1844*6777b538SAndroid Build Coastguard Worker 
1845*6777b538SAndroid Build Coastguard Worker // static
CreateFactory(DnsSession * session)1846*6777b538SAndroid Build Coastguard Worker std::unique_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
1847*6777b538SAndroid Build Coastguard Worker     DnsSession* session) {
1848*6777b538SAndroid Build Coastguard Worker   return std::make_unique<DnsTransactionFactoryImpl>(session);
1849*6777b538SAndroid Build Coastguard Worker }
1850*6777b538SAndroid Build Coastguard Worker 
1851*6777b538SAndroid Build Coastguard Worker }  // namespace net
1852