• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/dns/loopback_only.h"
11 
12 #include "base/functional/bind.h"
13 #include "base/functional/callback.h"
14 #include "base/logging.h"
15 #include "base/task/sequenced_task_runner.h"
16 #include "base/task/task_traits.h"
17 #include "base/task/thread_pool.h"
18 #include "base/threading/scoped_blocking_call.h"
19 #include "build/build_config.h"
20 #include "net/base/network_change_notifier.h"
21 #include "net/base/network_interfaces.h"
22 #include "net/base/sys_addrinfo.h"
23 
24 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
25 #include <net/if.h>
26 #if BUILDFLAG(IS_ANDROID)
27 #include "net/android/network_library.h"
28 #else  // BUILDFLAG(IS_ANDROID)
29 #include <ifaddrs.h>
30 #endif  // BUILDFLAG(IS_ANDROID)
31 #endif  // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
32 
33 #if BUILDFLAG(IS_LINUX)
34 #include <linux/rtnetlink.h>
35 #include "net/base/address_map_linux.h"
36 #include "net/base/address_tracker_linux.h"
37 #include "net/base/network_interfaces_linux.h"
38 #endif
39 
40 namespace net {
41 
42 namespace {
43 
44 #if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID)) || BUILDFLAG(IS_FUCHSIA)
HaveOnlyLoopbackAddressesUsingGetifaddrs()45 bool HaveOnlyLoopbackAddressesUsingGetifaddrs() {
46   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
47                                                 base::BlockingType::MAY_BLOCK);
48   struct ifaddrs* interface_addr = nullptr;
49   int rv = getifaddrs(&interface_addr);
50   if (rv != 0) {
51     DVPLOG(1) << "getifaddrs() failed";
52     return false;
53   }
54 
55   bool result = true;
56   for (struct ifaddrs* interface = interface_addr; interface != nullptr;
57        interface = interface->ifa_next) {
58     if (!(IFF_UP & interface->ifa_flags)) {
59       continue;
60     }
61     if (IFF_LOOPBACK & interface->ifa_flags) {
62       continue;
63     }
64     const struct sockaddr* addr = interface->ifa_addr;
65     if (!addr) {
66       continue;
67     }
68     if (addr->sa_family == AF_INET6) {
69       // Safe cast since this is AF_INET6.
70       const struct sockaddr_in6* addr_in6 =
71           reinterpret_cast<const struct sockaddr_in6*>(addr);
72       const struct in6_addr* sin6_addr = &addr_in6->sin6_addr;
73       if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr)) {
74         continue;
75       }
76     }
77     if (addr->sa_family != AF_INET6 && addr->sa_family != AF_INET) {
78       continue;
79     }
80 
81     result = false;
82     break;
83   }
84   freeifaddrs(interface_addr);
85   return result;
86 }
87 #endif  // (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID)) ||
88         // BUILDFLAG(IS_FUCHSIA)
89 
90 // This implementation will always be posted to a thread pool.
HaveOnlyLoopbackAddressesSlow()91 bool HaveOnlyLoopbackAddressesSlow() {
92 #if BUILDFLAG(IS_WIN)
93   // TODO(wtc): implement with the GetAdaptersAddresses function.
94   NOTIMPLEMENTED();
95   return false;
96 #elif BUILDFLAG(IS_ANDROID)
97   return android::HaveOnlyLoopbackAddresses();
98 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
99   return HaveOnlyLoopbackAddressesUsingGetifaddrs();
100 #endif  // defined(various platforms)
101 }
102 
103 #if BUILDFLAG(IS_LINUX)
104 // This implementation can run on the main thread as it will not block.
HaveOnlyLoopbackAddressesFast(AddressMapOwnerLinux * address_map_owner)105 bool HaveOnlyLoopbackAddressesFast(AddressMapOwnerLinux* address_map_owner) {
106   // The AddressMapOwnerLinux has already cached all the information necessary
107   // to determine if only loopback addresses exist.
108   AddressMapOwnerLinux::AddressMap address_map =
109       address_map_owner->GetAddressMap();
110   std::unordered_set<int> online_links = address_map_owner->GetOnlineLinks();
111   for (const auto& [address, ifaddrmsg] : address_map) {
112     // If there is an online link that isn't loopback or IPv6 link-local, return
113     // false.
114     // `online_links` shouldn't ever contain a loopback address, but keep the
115     // check as it is clearer and harmless.
116     //
117     // NOTE(2023-05-26): `online_links` only contains links with *both*
118     // IFF_LOWER_UP and IFF_UP, which is stricter than the
119     // HaveOnlyLoopbackAddressesUsingGetifaddrs() check above. LOWER_UP means
120     // the physical link layer is up and IFF_UP means the interface is
121     // administratively up. This new behavior might even be desirable, but if
122     // this causes issues it will need to be reverted.
123     if (online_links.contains(ifaddrmsg.ifa_index) && !address.IsLoopback() &&
124         !(address.IsIPv6() && address.IsLinkLocal())) {
125       return false;
126     }
127   }
128 
129   return true;
130 }
131 #endif  // BUILDFLAG(IS_LINUX)
132 
133 }  // namespace
134 
RunHaveOnlyLoopbackAddressesJob(base::OnceCallback<void (bool)> finished_cb)135 void RunHaveOnlyLoopbackAddressesJob(
136     base::OnceCallback<void(bool)> finished_cb) {
137 #if BUILDFLAG(IS_LINUX)
138   // On Linux, this check can be fast if it accesses only network information
139   // that's cached by NetworkChangeNotifier, so there's no need to post this
140   // task to a thread pool. If HaveOnlyLoopbackAddressesFast() *is* posted to a
141   // different thread, it can cause a TSAN error when also setting a mock
142   // NetworkChangeNotifier in tests. So it's important to not run off the main
143   // thread if using cached, global information.
144   AddressMapOwnerLinux* address_map_owner =
145       NetworkChangeNotifier::GetAddressMapOwner();
146   if (address_map_owner) {
147     // Post `finished_cb` to avoid the bug-prone sometimes-synchronous behavior,
148     // which is only useful in latency-sensitive situations.
149     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
150         FROM_HERE,
151         base::BindOnce(std::move(finished_cb),
152                        HaveOnlyLoopbackAddressesFast(address_map_owner)));
153     return;
154   }
155 #endif  // BUILDFLAG(IS_LINUX)
156 
157   base::ThreadPool::PostTaskAndReplyWithResult(
158       FROM_HERE,
159       {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
160       base::BindOnce(&HaveOnlyLoopbackAddressesSlow), std::move(finished_cb));
161 }
162 
163 }  // namespace net
164