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