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