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