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