xref: /aosp_15_r20/external/cronet/net/dns/host_resolver_nat64_task.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/dns/host_resolver_nat64_task.h"
6 
7 #include <algorithm>
8 #include <string_view>
9 #include <utility>
10 
11 #include "base/check_op.h"
12 #include "base/functional/bind.h"
13 #include "base/functional/callback.h"
14 #include "base/location.h"
15 #include "base/memory/raw_ptr.h"
16 #include "base/notreached.h"
17 #include "base/strings/string_util.h"
18 #include "base/task/sequenced_task_runner.h"
19 #include "net/base/address_list.h"
20 #include "net/base/ip_endpoint.h"
21 #include "net/base/net_errors.h"
22 #include "net/dns/host_resolver.h"
23 #include "net/dns/host_resolver_manager.h"
24 #include "net/dns/public/dns_query_type.h"
25 
26 namespace net {
27 
HostResolverNat64Task(std::string_view hostname,NetworkAnonymizationKey network_anonymization_key,NetLogWithSource net_log,ResolveContext * resolve_context,base::WeakPtr<HostResolverManager> resolver)28 HostResolverNat64Task::HostResolverNat64Task(
29     std::string_view hostname,
30     NetworkAnonymizationKey network_anonymization_key,
31     NetLogWithSource net_log,
32     ResolveContext* resolve_context,
33     base::WeakPtr<HostResolverManager> resolver)
34     : hostname_(hostname),
35       network_anonymization_key_(std::move(network_anonymization_key)),
36       net_log_(std::move(net_log)),
37       resolve_context_(resolve_context),
38       resolver_(std::move(resolver)) {}
39 
~HostResolverNat64Task()40 HostResolverNat64Task::~HostResolverNat64Task() {
41   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
42 }
43 
Start(base::OnceClosure completion_closure)44 void HostResolverNat64Task::Start(base::OnceClosure completion_closure) {
45   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
46   DCHECK(!completion_closure_);
47 
48   completion_closure_ = std::move(completion_closure);
49 
50   next_state_ = State::kResolve;
51   int rv = DoLoop(OK);
52   if (rv != ERR_IO_PENDING) {
53     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
54         FROM_HERE, std::move(completion_closure_));
55   }
56 }
57 
GetResults() const58 HostCache::Entry HostResolverNat64Task::GetResults() const {
59   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
60   DCHECK(!completion_closure_);
61   return results_;
62 }
63 
DoLoop(int result)64 int HostResolverNat64Task::DoLoop(int result) {
65   DCHECK_NE(next_state_, State::kStateNone);
66   int rv = result;
67   do {
68     State state = next_state_;
69     next_state_ = State::kStateNone;
70     switch (state) {
71       case State::kResolve:
72         DCHECK_EQ(OK, rv);
73         rv = DoResolve();
74         break;
75       case State::kResolveComplete:
76         rv = DoResolveComplete(rv);
77         break;
78       case State::kSynthesizeToIpv6:
79         DCHECK_EQ(OK, rv);
80         rv = DoSynthesizeToIpv6();
81         break;
82       default:
83         NOTREACHED();
84         rv = ERR_FAILED;
85         break;
86     }
87   } while (rv != ERR_IO_PENDING && next_state_ != State::kStateNone);
88   return rv;
89 }
90 
DoResolve()91 int HostResolverNat64Task::DoResolve() {
92   next_state_ = State::kResolveComplete;
93   HostResolver::ResolveHostParameters parameters;
94   parameters.dns_query_type = DnsQueryType::AAAA;
95 
96   if (!resolver_) {
97     return ERR_FAILED;
98   }
99 
100   request_ipv4onlyarpa_ = resolver_->CreateRequest(
101       HostPortPair("ipv4only.arpa", 80), network_anonymization_key_, net_log_,
102       parameters, resolve_context_);
103 
104   return request_ipv4onlyarpa_->Start(base::BindOnce(
105       &HostResolverNat64Task::OnIOComplete, weak_ptr_factory_.GetWeakPtr()));
106 }
107 
DoResolveComplete(int result)108 int HostResolverNat64Task::DoResolveComplete(int result) {
109   // If not under DNS64 and resolving ipv4only.arpa fails, return the original
110   // IPv4 address.
111   if (result != OK || request_ipv4onlyarpa_->GetEndpointResults()->empty()) {
112     IPAddress ipv4_address;
113     bool is_ip = ipv4_address.AssignFromIPLiteral(hostname_);
114     DCHECK(is_ip);
115     std::set<std::string> aliases;
116     results_ =
117         HostCache::Entry(OK, {IPEndPoint(ipv4_address, 0)}, std::move(aliases),
118                          HostCache::Entry::SOURCE_UNKNOWN);
119     return OK;
120   }
121 
122   next_state_ = State::kSynthesizeToIpv6;
123   return OK;
124 }
125 
DoSynthesizeToIpv6()126 int HostResolverNat64Task::DoSynthesizeToIpv6() {
127   IPAddress ipv4_address;
128   bool is_ip = ipv4_address.AssignFromIPLiteral(hostname_);
129   DCHECK(is_ip);
130 
131   IPAddress ipv4onlyarpa_AAAA_address;
132 
133   std::vector<IPEndPoint> converted_addresses;
134 
135   for (const auto& endpoints : *request_ipv4onlyarpa_->GetEndpointResults()) {
136     for (const auto& ip_endpoint : endpoints.ip_endpoints) {
137       ipv4onlyarpa_AAAA_address = ip_endpoint.address();
138 
139       Dns64PrefixLength pref64_length =
140           ExtractPref64FromIpv4onlyArpaAAAA(ipv4onlyarpa_AAAA_address);
141 
142       IPAddress converted_address = ConvertIPv4ToIPv4EmbeddedIPv6(
143           ipv4_address, ipv4onlyarpa_AAAA_address, pref64_length);
144 
145       IPEndPoint converted_ip_endpoint(converted_address, 0);
146       if (!base::Contains(converted_addresses, converted_ip_endpoint)) {
147         converted_addresses.push_back(std::move(converted_ip_endpoint));
148       }
149     }
150   }
151 
152   std::set<std::string> aliases;
153 
154   if (converted_addresses.empty()) {
155     converted_addresses = {IPEndPoint(ipv4_address, 0)};
156   }
157 
158   results_ = HostCache::Entry(OK, converted_addresses, std::move(aliases),
159                               HostCache::Entry::SOURCE_UNKNOWN);
160   return OK;
161 }
162 
OnIOComplete(int result)163 void HostResolverNat64Task::OnIOComplete(int result) {
164   result = DoLoop(result);
165   if (result != ERR_IO_PENDING)
166     std::move(completion_closure_).Run();
167 }
168 
169 }  // namespace net
170