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