File: loopback_only.cc

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (158 lines) | stat: -rw-r--r-- 5,684 bytes parent folder | download | duplicates (2)
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