1 // Copyright 2012 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/address_sorter_posix.h"
6
7 #include <netinet/in.h>
8
9 #include <memory>
10 #include <utility>
11 #include <vector>
12
13 #include "base/memory/raw_ptr.h"
14 #include "build/build_config.h"
15
16 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_BSD)
17 #include <sys/socket.h> // Must be included before ifaddrs.h.
18 #include <ifaddrs.h>
19 #include <net/if.h>
20 #include <string.h>
21 #include <sys/ioctl.h>
22 #if BUILDFLAG(IS_IOS)
23 // The code in the following header file is copied from [1]. This file has the
24 // minimum definitions needed to retrieve the IP attributes, since iOS SDK
25 // doesn't include a necessary header <netinet/in_var.h>.
26 // [1] https://chromium.googlesource.com/external/webrtc/+/master/rtc_base/mac_ifaddrs_converter.cc
27 #include "net/dns/netinet_in_var_ios.h"
28 #else
29 #include <netinet/in_var.h>
30 #endif // BUILDFLAG(IS_IOS)
31 #endif
32 #include <vector>
33
34 #include "base/containers/unique_ptr_adapters.h"
35 #include "base/logging.h"
36 #include "net/base/ip_endpoint.h"
37 #include "net/base/net_errors.h"
38 #include "net/log/net_log_source.h"
39 #include "net/socket/client_socket_factory.h"
40 #include "net/socket/datagram_client_socket.h"
41
42 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
43 #include "net/base/address_tracker_linux.h"
44 #endif
45
46 namespace net {
47 namespace {
48 // Address sorting is performed according to RFC3484 with revisions.
49 // http://tools.ietf.org/html/draft-ietf-6man-rfc3484bis-06
50 // Precedence and label are separate to support override through
51 // /etc/gai.conf.
52
53 // Returns true if |p1| should precede |p2| in the table.
54 // Sorts table by decreasing prefix size to allow longest prefix matching.
ComparePolicy(const AddressSorterPosix::PolicyEntry & p1,const AddressSorterPosix::PolicyEntry & p2)55 bool ComparePolicy(const AddressSorterPosix::PolicyEntry& p1,
56 const AddressSorterPosix::PolicyEntry& p2) {
57 return p1.prefix_length > p2.prefix_length;
58 }
59
60 // Creates sorted PolicyTable from |table| with |size| entries.
LoadPolicy(const AddressSorterPosix::PolicyEntry * table,size_t size)61 AddressSorterPosix::PolicyTable LoadPolicy(
62 const AddressSorterPosix::PolicyEntry* table,
63 size_t size) {
64 AddressSorterPosix::PolicyTable result(table, table + size);
65 std::sort(result.begin(), result.end(), ComparePolicy);
66 return result;
67 }
68
69 // Search |table| for matching prefix of |address|. |table| must be sorted by
70 // descending prefix (prefix of another prefix must be later in table).
GetPolicyValue(const AddressSorterPosix::PolicyTable & table,const IPAddress & address)71 unsigned GetPolicyValue(const AddressSorterPosix::PolicyTable& table,
72 const IPAddress& address) {
73 if (address.IsIPv4())
74 return GetPolicyValue(table, ConvertIPv4ToIPv4MappedIPv6(address));
75 for (const auto& entry : table) {
76 IPAddress prefix(entry.prefix);
77 if (IPAddressMatchesPrefix(address, prefix, entry.prefix_length))
78 return entry.value;
79 }
80 NOTREACHED();
81 // The last entry is the least restrictive, so assume it's default.
82 return table.back().value;
83 }
84
IsIPv6Multicast(const IPAddress & address)85 bool IsIPv6Multicast(const IPAddress& address) {
86 DCHECK(address.IsIPv6());
87 return address.bytes()[0] == 0xFF;
88 }
89
GetIPv6MulticastScope(const IPAddress & address)90 AddressSorterPosix::AddressScope GetIPv6MulticastScope(
91 const IPAddress& address) {
92 DCHECK(address.IsIPv6());
93 return static_cast<AddressSorterPosix::AddressScope>(address.bytes()[1] &
94 0x0F);
95 }
96
IsIPv6Loopback(const IPAddress & address)97 bool IsIPv6Loopback(const IPAddress& address) {
98 DCHECK(address.IsIPv6());
99 return address == IPAddress::IPv6Localhost();
100 }
101
IsIPv6LinkLocal(const IPAddress & address)102 bool IsIPv6LinkLocal(const IPAddress& address) {
103 DCHECK(address.IsIPv6());
104 // IN6_IS_ADDR_LINKLOCAL
105 return (address.bytes()[0] == 0xFE) && ((address.bytes()[1] & 0xC0) == 0x80);
106 }
107
IsIPv6SiteLocal(const IPAddress & address)108 bool IsIPv6SiteLocal(const IPAddress& address) {
109 DCHECK(address.IsIPv6());
110 // IN6_IS_ADDR_SITELOCAL
111 return (address.bytes()[0] == 0xFE) && ((address.bytes()[1] & 0xC0) == 0xC0);
112 }
113
GetScope(const AddressSorterPosix::PolicyTable & ipv4_scope_table,const IPAddress & address)114 AddressSorterPosix::AddressScope GetScope(
115 const AddressSorterPosix::PolicyTable& ipv4_scope_table,
116 const IPAddress& address) {
117 if (address.IsIPv6()) {
118 if (IsIPv6Multicast(address)) {
119 return GetIPv6MulticastScope(address);
120 } else if (IsIPv6Loopback(address) || IsIPv6LinkLocal(address)) {
121 return AddressSorterPosix::SCOPE_LINKLOCAL;
122 } else if (IsIPv6SiteLocal(address)) {
123 return AddressSorterPosix::SCOPE_SITELOCAL;
124 } else {
125 return AddressSorterPosix::SCOPE_GLOBAL;
126 }
127 } else if (address.IsIPv4()) {
128 return static_cast<AddressSorterPosix::AddressScope>(
129 GetPolicyValue(ipv4_scope_table, address));
130 } else {
131 NOTREACHED();
132 return AddressSorterPosix::SCOPE_NODELOCAL;
133 }
134 }
135
136 // Default policy table. RFC 3484, Section 2.1.
137 const AddressSorterPosix::PolicyEntry kDefaultPrecedenceTable[] = {
138 // ::1/128 -- loopback
139 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 128, 50},
140 // ::/0 -- any
141 {{}, 0, 40},
142 // ::ffff:0:0/96 -- IPv4 mapped
143 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF}, 96, 35},
144 // 2002::/16 -- 6to4
145 {{
146 0x20,
147 0x02,
148 },
149 16,
150 30},
151 // 2001::/32 -- Teredo
152 {{0x20, 0x01, 0, 0}, 32, 5},
153 // fc00::/7 -- unique local address
154 {{0xFC}, 7, 3},
155 // ::/96 -- IPv4 compatible
156 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 96, 1},
157 // fec0::/10 -- site-local expanded scope
158 {{0xFE, 0xC0}, 10, 1},
159 // 3ffe::/16 -- 6bone
160 {{0x3F, 0xFE}, 16, 1},
161 };
162
163 const AddressSorterPosix::PolicyEntry kDefaultLabelTable[] = {
164 // ::1/128 -- loopback
165 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 128, 0},
166 // ::/0 -- any
167 {{}, 0, 1},
168 // ::ffff:0:0/96 -- IPv4 mapped
169 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF}, 96, 4},
170 // 2002::/16 -- 6to4
171 {{
172 0x20,
173 0x02,
174 },
175 16,
176 2},
177 // 2001::/32 -- Teredo
178 {{0x20, 0x01, 0, 0}, 32, 5},
179 // fc00::/7 -- unique local address
180 {{0xFC}, 7, 13},
181 // ::/96 -- IPv4 compatible
182 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 96, 3},
183 // fec0::/10 -- site-local expanded scope
184 {{0xFE, 0xC0}, 10, 11},
185 // 3ffe::/16 -- 6bone
186 {{0x3F, 0xFE}, 16, 12},
187 };
188
189 // Default mapping of IPv4 addresses to scope.
190 const AddressSorterPosix::PolicyEntry kDefaultIPv4ScopeTable[] = {
191 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0x7F},
192 104,
193 AddressSorterPosix::SCOPE_LINKLOCAL},
194 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0xA9, 0xFE},
195 112,
196 AddressSorterPosix::SCOPE_LINKLOCAL},
197 {{}, 0, AddressSorterPosix::SCOPE_GLOBAL},
198 };
199
200 struct DestinationInfo {
201 IPEndPoint endpoint;
202 AddressSorterPosix::AddressScope scope;
203 unsigned precedence;
204 unsigned label;
205 AddressSorterPosix::SourceAddressInfo src;
206 std::unique_ptr<DatagramClientSocket> socket;
207 size_t common_prefix_length;
208 bool failed = false;
209 };
210
211 // Returns true iff |dst_a| should precede |dst_b| in the address list.
212 // RFC 3484, section 6.
CompareDestinations(const DestinationInfo & dst_a,const DestinationInfo & dst_b)213 bool CompareDestinations(const DestinationInfo& dst_a,
214 const DestinationInfo& dst_b) {
215 // Rule 1: Avoid unusable destinations.
216 // Nothing to do here because unusable destinations are already filtered out.
217
218 // Rule 2: Prefer matching scope.
219 bool scope_match1 = (dst_a.src.scope == dst_a.scope);
220 bool scope_match2 = (dst_b.src.scope == dst_b.scope);
221 if (scope_match1 != scope_match2)
222 return scope_match1;
223
224 // Rule 3: Avoid deprecated addresses.
225 if (dst_a.src.deprecated != dst_b.src.deprecated) {
226 return !dst_a.src.deprecated;
227 }
228
229 // Rule 4: Prefer home addresses.
230 if (dst_a.src.home != dst_b.src.home) {
231 return dst_a.src.home;
232 }
233
234 // Rule 5: Prefer matching label.
235 bool label_match1 = (dst_a.src.label == dst_a.label);
236 bool label_match2 = (dst_b.src.label == dst_b.label);
237 if (label_match1 != label_match2)
238 return label_match1;
239
240 // Rule 6: Prefer higher precedence.
241 if (dst_a.precedence != dst_b.precedence)
242 return dst_a.precedence > dst_b.precedence;
243
244 // Rule 7: Prefer native transport.
245 if (dst_a.src.native != dst_b.src.native) {
246 return dst_a.src.native;
247 }
248
249 // Rule 8: Prefer smaller scope.
250 if (dst_a.scope != dst_b.scope)
251 return dst_a.scope < dst_b.scope;
252
253 // Rule 9: Use longest matching prefix. Only for matching address families.
254 if (dst_a.endpoint.address().size() == dst_b.endpoint.address().size()) {
255 if (dst_a.common_prefix_length != dst_b.common_prefix_length)
256 return dst_a.common_prefix_length > dst_b.common_prefix_length;
257 }
258
259 // Rule 10: Leave the order unchanged.
260 // stable_sort takes care of that.
261 return false;
262 }
263
264 } // namespace
265
266 class AddressSorterPosix::SortContext {
267 public:
SortContext(size_t in_num_endpoints,AddressSorter::CallbackType callback,const AddressSorterPosix * sorter)268 SortContext(size_t in_num_endpoints,
269 AddressSorter::CallbackType callback,
270 const AddressSorterPosix* sorter)
271 : num_endpoints_(in_num_endpoints),
272 callback_(std::move(callback)),
273 sorter_(sorter) {}
274 ~SortContext() = default;
DidCompleteConnect(IPEndPoint dest,size_t info_index,int rv)275 void DidCompleteConnect(IPEndPoint dest, size_t info_index, int rv) {
276 ++num_completed_;
277 if (rv != OK) {
278 VLOG(1) << "Could not connect to " << dest.ToStringWithoutPort()
279 << " reason " << rv;
280 sort_list_[info_index].failed = true;
281 }
282
283 MaybeFinishSort();
284 }
285
sort_list()286 std::vector<DestinationInfo>& sort_list() { return sort_list_; }
287
288 private:
MaybeFinishSort()289 void MaybeFinishSort() {
290 // Sort the list of endpoints only after each Connect call has been made.
291 if (num_completed_ != num_endpoints_) {
292 return;
293 }
294 for (auto& info : sort_list_) {
295 if (info.failed) {
296 continue;
297 }
298
299 IPEndPoint src;
300 // Filter out unusable destinations.
301 int rv = info.socket->GetLocalAddress(&src);
302 if (rv != OK) {
303 LOG(WARNING) << "Could not get local address for "
304 << info.endpoint.ToStringWithoutPort() << " reason " << rv;
305 info.failed = true;
306 continue;
307 }
308
309 auto iter = sorter_->source_map_.find(src.address());
310 if (iter == sorter_->source_map_.end()) {
311 // |src.address| may not be in the map if |source_info_| has not been
312 // updated from the OS yet. It will be updated and HostCache cleared
313 // soon, but we still want to sort, so fill in an empty
314 info.src = AddressSorterPosix::SourceAddressInfo();
315 } else {
316 info.src = iter->second;
317 }
318
319 if (info.src.scope == AddressSorterPosix::SCOPE_UNDEFINED) {
320 sorter_->FillPolicy(src.address(), &info.src);
321 }
322
323 if (info.endpoint.address().size() == src.address().size()) {
324 info.common_prefix_length =
325 std::min(CommonPrefixLength(info.endpoint.address(), src.address()),
326 info.src.prefix_length);
327 }
328 }
329 std::erase_if(sort_list_, [](auto& element) { return element.failed; });
330 std::stable_sort(sort_list_.begin(), sort_list_.end(), CompareDestinations);
331
332 std::vector<IPEndPoint> sorted_result;
333 for (const auto& info : sort_list_)
334 sorted_result.push_back(info.endpoint);
335
336 CallbackType callback = std::move(callback_);
337 sorter_->FinishedSort(this); // deletes this
338 std::move(callback).Run(true, std::move(sorted_result));
339 }
340
341 const size_t num_endpoints_;
342 size_t num_completed_ = 0;
343 std::vector<DestinationInfo> sort_list_;
344 AddressSorter::CallbackType callback_;
345
346 raw_ptr<const AddressSorterPosix> sorter_;
347 };
348
AddressSorterPosix(ClientSocketFactory * socket_factory)349 AddressSorterPosix::AddressSorterPosix(ClientSocketFactory* socket_factory)
350 : socket_factory_(socket_factory),
351 precedence_table_(LoadPolicy(kDefaultPrecedenceTable,
352 std::size(kDefaultPrecedenceTable))),
353 label_table_(
354 LoadPolicy(kDefaultLabelTable, std::size(kDefaultLabelTable))),
355 ipv4_scope_table_(LoadPolicy(kDefaultIPv4ScopeTable,
356 std::size(kDefaultIPv4ScopeTable))) {
357 NetworkChangeNotifier::AddIPAddressObserver(this);
358 OnIPAddressChanged();
359 }
360
~AddressSorterPosix()361 AddressSorterPosix::~AddressSorterPosix() {
362 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
363 NetworkChangeNotifier::RemoveIPAddressObserver(this);
364 }
365
Sort(const std::vector<IPEndPoint> & endpoints,CallbackType callback) const366 void AddressSorterPosix::Sort(const std::vector<IPEndPoint>& endpoints,
367 CallbackType callback) const {
368 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
369 sort_contexts_.insert(std::make_unique<SortContext>(
370 endpoints.size(), std::move(callback), this));
371 auto* sort_context = sort_contexts_.rbegin()->get();
372 for (const IPEndPoint& endpoint : endpoints) {
373 DestinationInfo info;
374 info.endpoint = endpoint;
375 info.scope = GetScope(ipv4_scope_table_, info.endpoint.address());
376 info.precedence =
377 GetPolicyValue(precedence_table_, info.endpoint.address());
378 info.label = GetPolicyValue(label_table_, info.endpoint.address());
379
380 // Each socket can only be bound once.
381 info.socket = socket_factory_->CreateDatagramClientSocket(
382 DatagramSocket::DEFAULT_BIND, nullptr /* NetLog */, NetLogSource());
383 IPEndPoint dest = info.endpoint;
384 // Even though no packets are sent, cannot use port 0 in Connect.
385 if (dest.port() == 0) {
386 dest = IPEndPoint(dest.address(), /*port=*/80);
387 }
388 sort_context->sort_list().push_back(std::move(info));
389 size_t info_index = sort_context->sort_list().size() - 1;
390 // Destroying a SortContext destroys the underlying socket.
391 int rv = sort_context->sort_list().back().socket->ConnectAsync(
392 dest,
393 base::BindOnce(&AddressSorterPosix::SortContext::DidCompleteConnect,
394 base::Unretained(sort_context), dest, info_index));
395 if (rv != ERR_IO_PENDING) {
396 sort_context->DidCompleteConnect(dest, info_index, rv);
397 }
398 }
399 }
400
OnIPAddressChanged()401 void AddressSorterPosix::OnIPAddressChanged() {
402 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
403 source_map_.clear();
404 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
405 // TODO(crbug.com/1431364): This always returns nullptr on ChromeOS.
406 const AddressMapOwnerLinux* address_map_owner =
407 NetworkChangeNotifier::GetAddressMapOwner();
408 if (!address_map_owner) {
409 return;
410 }
411 AddressMapOwnerLinux::AddressMap map = address_map_owner->GetAddressMap();
412 for (const auto& [address, msg] : map) {
413 SourceAddressInfo& info = source_map_[address];
414 info.native = false; // TODO(szym): obtain this via netlink.
415 info.deprecated = msg.ifa_flags & IFA_F_DEPRECATED;
416 info.home = msg.ifa_flags & IFA_F_HOMEADDRESS;
417 info.prefix_length = msg.ifa_prefixlen;
418 FillPolicy(address, &info);
419 }
420 #elif BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_BSD)
421 // It's not clear we will receive notification when deprecated flag changes.
422 // Socket for ioctl.
423 int ioctl_socket = socket(AF_INET6, SOCK_DGRAM, 0);
424 if (ioctl_socket < 0)
425 return;
426
427 struct ifaddrs* addrs;
428 int rv = getifaddrs(&addrs);
429 if (rv < 0) {
430 LOG(WARNING) << "getifaddrs failed " << rv;
431 close(ioctl_socket);
432 return;
433 }
434
435 for (struct ifaddrs* ifa = addrs; ifa != nullptr; ifa = ifa->ifa_next) {
436 IPEndPoint src;
437 if (!src.FromSockAddr(ifa->ifa_addr, ifa->ifa_addr->sa_len))
438 continue;
439 SourceAddressInfo& info = source_map_[src.address()];
440 // Note: no known way to fill in |native| and |home|.
441 info.native = info.home = info.deprecated = false;
442 if (ifa->ifa_addr->sa_family == AF_INET6) {
443 struct in6_ifreq ifr = {};
444 strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name) - 1);
445 DCHECK_LE(ifa->ifa_addr->sa_len, sizeof(ifr.ifr_ifru.ifru_addr));
446 memcpy(&ifr.ifr_ifru.ifru_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
447 rv = ioctl(ioctl_socket, SIOCGIFAFLAG_IN6, &ifr);
448 if (rv >= 0) {
449 info.deprecated = ifr.ifr_ifru.ifru_flags & IN6_IFF_DEPRECATED;
450 } else {
451 LOG(WARNING) << "SIOCGIFAFLAG_IN6 failed " << rv;
452 }
453 }
454 if (ifa->ifa_netmask) {
455 IPEndPoint netmask;
456 if (netmask.FromSockAddr(ifa->ifa_netmask, ifa->ifa_addr->sa_len)) {
457 info.prefix_length = MaskPrefixLength(netmask.address());
458 } else {
459 LOG(WARNING) << "FromSockAddr failed on netmask";
460 }
461 }
462 FillPolicy(src.address(), &info);
463 }
464 freeifaddrs(addrs);
465 close(ioctl_socket);
466 #endif
467 }
468
FillPolicy(const IPAddress & address,SourceAddressInfo * info) const469 void AddressSorterPosix::FillPolicy(const IPAddress& address,
470 SourceAddressInfo* info) const {
471 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
472 info->scope = GetScope(ipv4_scope_table_, address);
473 info->label = GetPolicyValue(label_table_, address);
474 }
475
FinishedSort(SortContext * sort_context) const476 void AddressSorterPosix::FinishedSort(SortContext* sort_context) const {
477 auto it = sort_contexts_.find(sort_context);
478 sort_contexts_.erase(it);
479 }
480
481 // static
CreateAddressSorter()482 std::unique_ptr<AddressSorter> AddressSorter::CreateAddressSorter() {
483 return std::make_unique<AddressSorterPosix>(
484 ClientSocketFactory::GetDefaultFactory());
485 }
486
487 } // namespace net
488