• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     }
85   } while (rv != ERR_IO_PENDING && next_state_ != State::kStateNone);
86   return rv;
87 }
88 
DoResolve()89 int HostResolverNat64Task::DoResolve() {
90   next_state_ = State::kResolveComplete;
91   HostResolver::ResolveHostParameters parameters;
92   parameters.dns_query_type = DnsQueryType::AAAA;
93 
94   if (!resolver_) {
95     return ERR_FAILED;
96   }
97 
98   request_ipv4onlyarpa_ = resolver_->CreateRequest(
99       HostPortPair("ipv4only.arpa", 80), network_anonymization_key_, net_log_,
100       parameters, resolve_context_);
101 
102   return request_ipv4onlyarpa_->Start(base::BindOnce(
103       &HostResolverNat64Task::OnIOComplete, weak_ptr_factory_.GetWeakPtr()));
104 }
105 
DoResolveComplete(int result)106 int HostResolverNat64Task::DoResolveComplete(int result) {
107   // If not under DNS64 and resolving ipv4only.arpa fails, return the original
108   // IPv4 address.
109   if (result != OK || request_ipv4onlyarpa_->GetEndpointResults()->empty()) {
110     IPAddress ipv4_address;
111     bool is_ip = ipv4_address.AssignFromIPLiteral(hostname_);
112     DCHECK(is_ip);
113     std::set<std::string> aliases;
114     results_ =
115         HostCache::Entry(OK, {IPEndPoint(ipv4_address, 0)}, std::move(aliases),
116                          HostCache::Entry::SOURCE_UNKNOWN);
117     return OK;
118   }
119 
120   next_state_ = State::kSynthesizeToIpv6;
121   return OK;
122 }
123 
DoSynthesizeToIpv6()124 int HostResolverNat64Task::DoSynthesizeToIpv6() {
125   IPAddress ipv4_address;
126   bool is_ip = ipv4_address.AssignFromIPLiteral(hostname_);
127   DCHECK(is_ip);
128 
129   IPAddress ipv4onlyarpa_AAAA_address;
130 
131   std::vector<IPEndPoint> converted_addresses;
132 
133   for (const auto& endpoints : *request_ipv4onlyarpa_->GetEndpointResults()) {
134     for (const auto& ip_endpoint : endpoints.ip_endpoints) {
135       ipv4onlyarpa_AAAA_address = ip_endpoint.address();
136 
137       Dns64PrefixLength pref64_length =
138           ExtractPref64FromIpv4onlyArpaAAAA(ipv4onlyarpa_AAAA_address);
139 
140       IPAddress converted_address = ConvertIPv4ToIPv4EmbeddedIPv6(
141           ipv4_address, ipv4onlyarpa_AAAA_address, pref64_length);
142 
143       IPEndPoint converted_ip_endpoint(converted_address, 0);
144       if (!base::Contains(converted_addresses, converted_ip_endpoint)) {
145         converted_addresses.push_back(std::move(converted_ip_endpoint));
146       }
147     }
148   }
149 
150   std::set<std::string> aliases;
151 
152   if (converted_addresses.empty()) {
153     converted_addresses = {IPEndPoint(ipv4_address, 0)};
154   }
155 
156   results_ =
157       HostCache::Entry(OK, std::move(converted_addresses), std::move(aliases),
158                        HostCache::Entry::SOURCE_UNKNOWN);
159   return OK;
160 }
161 
OnIOComplete(int result)162 void HostResolverNat64Task::OnIOComplete(int result) {
163   result = DoLoop(result);
164   if (result != ERR_IO_PENDING)
165     std::move(completion_closure_).Run();
166 }
167 
168 }  // namespace net
169