1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 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/base/address_tracker_linux.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <errno.h>
8*6777b538SAndroid Build Coastguard Worker #include <linux/if.h>
9*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
10*6777b538SAndroid Build Coastguard Worker #include <sys/ioctl.h>
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker #include <optional>
13*6777b538SAndroid Build Coastguard Worker #include <utility>
14*6777b538SAndroid Build Coastguard Worker #include <vector>
15*6777b538SAndroid Build Coastguard Worker
16*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/dcheck_is_on.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/files/scoped_file.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/memory/page_size.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/posix/eintr_wrapper.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/sequence_checker.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/task/current_thread.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
30*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
31*6777b538SAndroid Build Coastguard Worker #include "net/base/network_interfaces_linux.h"
32*6777b538SAndroid Build Coastguard Worker
33*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
34*6777b538SAndroid Build Coastguard Worker #include "base/android/build_info.h"
35*6777b538SAndroid Build Coastguard Worker #endif
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Worker namespace net::internal {
38*6777b538SAndroid Build Coastguard Worker
39*6777b538SAndroid Build Coastguard Worker namespace {
40*6777b538SAndroid Build Coastguard Worker
41*6777b538SAndroid Build Coastguard Worker // Some kernel functions such as wireless_send_event and rtnetlink_ifinfo_prep
42*6777b538SAndroid Build Coastguard Worker // may send spurious messages over rtnetlink. RTM_NEWLINK messages where
43*6777b538SAndroid Build Coastguard Worker // ifi_change == 0 and rta_type == IFLA_WIRELESS should be ignored.
IgnoreWirelessChange(const struct ifinfomsg * msg,int length)44*6777b538SAndroid Build Coastguard Worker bool IgnoreWirelessChange(const struct ifinfomsg* msg, int length) {
45*6777b538SAndroid Build Coastguard Worker for (const struct rtattr* attr = IFLA_RTA(msg); RTA_OK(attr, length);
46*6777b538SAndroid Build Coastguard Worker attr = RTA_NEXT(attr, length)) {
47*6777b538SAndroid Build Coastguard Worker if (attr->rta_type == IFLA_WIRELESS && msg->ifi_change == 0)
48*6777b538SAndroid Build Coastguard Worker return true;
49*6777b538SAndroid Build Coastguard Worker }
50*6777b538SAndroid Build Coastguard Worker return false;
51*6777b538SAndroid Build Coastguard Worker }
52*6777b538SAndroid Build Coastguard Worker
53*6777b538SAndroid Build Coastguard Worker // Retrieves address from NETLINK address message.
54*6777b538SAndroid Build Coastguard Worker // Sets |really_deprecated| for IPv6 addresses with preferred lifetimes of 0.
55*6777b538SAndroid Build Coastguard Worker // Precondition: |header| must already be validated with NLMSG_OK.
GetAddress(const struct nlmsghdr * header,int header_length,IPAddress * out,bool * really_deprecated)56*6777b538SAndroid Build Coastguard Worker bool GetAddress(const struct nlmsghdr* header,
57*6777b538SAndroid Build Coastguard Worker int header_length,
58*6777b538SAndroid Build Coastguard Worker IPAddress* out,
59*6777b538SAndroid Build Coastguard Worker bool* really_deprecated) {
60*6777b538SAndroid Build Coastguard Worker if (really_deprecated)
61*6777b538SAndroid Build Coastguard Worker *really_deprecated = false;
62*6777b538SAndroid Build Coastguard Worker
63*6777b538SAndroid Build Coastguard Worker // Extract the message and update |header_length| to be the number of
64*6777b538SAndroid Build Coastguard Worker // remaining bytes.
65*6777b538SAndroid Build Coastguard Worker const struct ifaddrmsg* msg =
66*6777b538SAndroid Build Coastguard Worker reinterpret_cast<const struct ifaddrmsg*>(NLMSG_DATA(header));
67*6777b538SAndroid Build Coastguard Worker header_length -= NLMSG_HDRLEN;
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker size_t address_length = 0;
70*6777b538SAndroid Build Coastguard Worker switch (msg->ifa_family) {
71*6777b538SAndroid Build Coastguard Worker case AF_INET:
72*6777b538SAndroid Build Coastguard Worker address_length = IPAddress::kIPv4AddressSize;
73*6777b538SAndroid Build Coastguard Worker break;
74*6777b538SAndroid Build Coastguard Worker case AF_INET6:
75*6777b538SAndroid Build Coastguard Worker address_length = IPAddress::kIPv6AddressSize;
76*6777b538SAndroid Build Coastguard Worker break;
77*6777b538SAndroid Build Coastguard Worker default:
78*6777b538SAndroid Build Coastguard Worker // Unknown family.
79*6777b538SAndroid Build Coastguard Worker return false;
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker // Use IFA_ADDRESS unless IFA_LOCAL is present. This behavior here is based on
82*6777b538SAndroid Build Coastguard Worker // getaddrinfo in glibc (check_pf.c). Judging from kernel implementation of
83*6777b538SAndroid Build Coastguard Worker // NETLINK, IPv4 addresses have only the IFA_ADDRESS attribute, while IPv6
84*6777b538SAndroid Build Coastguard Worker // have the IFA_LOCAL attribute.
85*6777b538SAndroid Build Coastguard Worker uint8_t* address = nullptr;
86*6777b538SAndroid Build Coastguard Worker uint8_t* local = nullptr;
87*6777b538SAndroid Build Coastguard Worker int length = IFA_PAYLOAD(header);
88*6777b538SAndroid Build Coastguard Worker if (length > header_length) {
89*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "ifaddrmsg length exceeds bounds";
90*6777b538SAndroid Build Coastguard Worker return false;
91*6777b538SAndroid Build Coastguard Worker }
92*6777b538SAndroid Build Coastguard Worker for (const struct rtattr* attr =
93*6777b538SAndroid Build Coastguard Worker reinterpret_cast<const struct rtattr*>(IFA_RTA(msg));
94*6777b538SAndroid Build Coastguard Worker RTA_OK(attr, length); attr = RTA_NEXT(attr, length)) {
95*6777b538SAndroid Build Coastguard Worker switch (attr->rta_type) {
96*6777b538SAndroid Build Coastguard Worker case IFA_ADDRESS:
97*6777b538SAndroid Build Coastguard Worker if (RTA_PAYLOAD(attr) < address_length) {
98*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "attr does not have enough bytes to read an address";
99*6777b538SAndroid Build Coastguard Worker return false;
100*6777b538SAndroid Build Coastguard Worker }
101*6777b538SAndroid Build Coastguard Worker address = reinterpret_cast<uint8_t*>(RTA_DATA(attr));
102*6777b538SAndroid Build Coastguard Worker break;
103*6777b538SAndroid Build Coastguard Worker case IFA_LOCAL:
104*6777b538SAndroid Build Coastguard Worker if (RTA_PAYLOAD(attr) < address_length) {
105*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "attr does not have enough bytes to read an address";
106*6777b538SAndroid Build Coastguard Worker return false;
107*6777b538SAndroid Build Coastguard Worker }
108*6777b538SAndroid Build Coastguard Worker local = reinterpret_cast<uint8_t*>(RTA_DATA(attr));
109*6777b538SAndroid Build Coastguard Worker break;
110*6777b538SAndroid Build Coastguard Worker case IFA_CACHEINFO: {
111*6777b538SAndroid Build Coastguard Worker if (RTA_PAYLOAD(attr) < sizeof(struct ifa_cacheinfo)) {
112*6777b538SAndroid Build Coastguard Worker LOG(ERROR)
113*6777b538SAndroid Build Coastguard Worker << "attr does not have enough bytes to read an ifa_cacheinfo";
114*6777b538SAndroid Build Coastguard Worker return false;
115*6777b538SAndroid Build Coastguard Worker }
116*6777b538SAndroid Build Coastguard Worker const struct ifa_cacheinfo* cache_info =
117*6777b538SAndroid Build Coastguard Worker reinterpret_cast<const struct ifa_cacheinfo*>(RTA_DATA(attr));
118*6777b538SAndroid Build Coastguard Worker if (really_deprecated)
119*6777b538SAndroid Build Coastguard Worker *really_deprecated = (cache_info->ifa_prefered == 0);
120*6777b538SAndroid Build Coastguard Worker } break;
121*6777b538SAndroid Build Coastguard Worker default:
122*6777b538SAndroid Build Coastguard Worker break;
123*6777b538SAndroid Build Coastguard Worker }
124*6777b538SAndroid Build Coastguard Worker }
125*6777b538SAndroid Build Coastguard Worker if (local)
126*6777b538SAndroid Build Coastguard Worker address = local;
127*6777b538SAndroid Build Coastguard Worker if (!address)
128*6777b538SAndroid Build Coastguard Worker return false;
129*6777b538SAndroid Build Coastguard Worker // SAFETY: `address` is only set above after `RTA_PAYLOAD` is checked against
130*6777b538SAndroid Build Coastguard Worker // `address_length`.
131*6777b538SAndroid Build Coastguard Worker *out = IPAddress(UNSAFE_BUFFERS(base::span(address, address_length)));
132*6777b538SAndroid Build Coastguard Worker return true;
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Worker // SafelyCastNetlinkMsgData<T> performs a bounds check before casting |header|'s
136*6777b538SAndroid Build Coastguard Worker // data to a |T*|. When the bounds check fails, returns nullptr.
137*6777b538SAndroid Build Coastguard Worker template <typename T>
SafelyCastNetlinkMsgData(const struct nlmsghdr * header,int length)138*6777b538SAndroid Build Coastguard Worker T* SafelyCastNetlinkMsgData(const struct nlmsghdr* header, int length) {
139*6777b538SAndroid Build Coastguard Worker DCHECK(NLMSG_OK(header, static_cast<__u32>(length)));
140*6777b538SAndroid Build Coastguard Worker if (length <= 0 || static_cast<size_t>(length) < NLMSG_HDRLEN + sizeof(T))
141*6777b538SAndroid Build Coastguard Worker return nullptr;
142*6777b538SAndroid Build Coastguard Worker return reinterpret_cast<const T*>(NLMSG_DATA(header));
143*6777b538SAndroid Build Coastguard Worker }
144*6777b538SAndroid Build Coastguard Worker
145*6777b538SAndroid Build Coastguard Worker } // namespace
146*6777b538SAndroid Build Coastguard Worker
147*6777b538SAndroid Build Coastguard Worker // static
GetInterfaceName(int interface_index,char * buf)148*6777b538SAndroid Build Coastguard Worker char* AddressTrackerLinux::GetInterfaceName(int interface_index, char* buf) {
149*6777b538SAndroid Build Coastguard Worker memset(buf, 0, IFNAMSIZ);
150*6777b538SAndroid Build Coastguard Worker base::ScopedFD ioctl_socket = GetSocketForIoctl();
151*6777b538SAndroid Build Coastguard Worker if (!ioctl_socket.is_valid())
152*6777b538SAndroid Build Coastguard Worker return buf;
153*6777b538SAndroid Build Coastguard Worker
154*6777b538SAndroid Build Coastguard Worker struct ifreq ifr = {};
155*6777b538SAndroid Build Coastguard Worker ifr.ifr_ifindex = interface_index;
156*6777b538SAndroid Build Coastguard Worker
157*6777b538SAndroid Build Coastguard Worker if (ioctl(ioctl_socket.get(), SIOCGIFNAME, &ifr) == 0)
158*6777b538SAndroid Build Coastguard Worker strncpy(buf, ifr.ifr_name, IFNAMSIZ - 1);
159*6777b538SAndroid Build Coastguard Worker return buf;
160*6777b538SAndroid Build Coastguard Worker }
161*6777b538SAndroid Build Coastguard Worker
AddressTrackerLinux()162*6777b538SAndroid Build Coastguard Worker AddressTrackerLinux::AddressTrackerLinux()
163*6777b538SAndroid Build Coastguard Worker : get_interface_name_(GetInterfaceName),
164*6777b538SAndroid Build Coastguard Worker address_callback_(base::DoNothing()),
165*6777b538SAndroid Build Coastguard Worker link_callback_(base::DoNothing()),
166*6777b538SAndroid Build Coastguard Worker tunnel_callback_(base::DoNothing()),
167*6777b538SAndroid Build Coastguard Worker ignored_interfaces_(),
168*6777b538SAndroid Build Coastguard Worker connection_type_initialized_cv_(&connection_type_lock_),
169*6777b538SAndroid Build Coastguard Worker tracking_(false) {}
170*6777b538SAndroid Build Coastguard Worker
AddressTrackerLinux(const base::RepeatingClosure & address_callback,const base::RepeatingClosure & link_callback,const base::RepeatingClosure & tunnel_callback,const std::unordered_set<std::string> & ignored_interfaces,scoped_refptr<base::SequencedTaskRunner> blocking_thread_runner)171*6777b538SAndroid Build Coastguard Worker AddressTrackerLinux::AddressTrackerLinux(
172*6777b538SAndroid Build Coastguard Worker const base::RepeatingClosure& address_callback,
173*6777b538SAndroid Build Coastguard Worker const base::RepeatingClosure& link_callback,
174*6777b538SAndroid Build Coastguard Worker const base::RepeatingClosure& tunnel_callback,
175*6777b538SAndroid Build Coastguard Worker const std::unordered_set<std::string>& ignored_interfaces,
176*6777b538SAndroid Build Coastguard Worker scoped_refptr<base::SequencedTaskRunner> blocking_thread_runner)
177*6777b538SAndroid Build Coastguard Worker : get_interface_name_(GetInterfaceName),
178*6777b538SAndroid Build Coastguard Worker address_callback_(address_callback),
179*6777b538SAndroid Build Coastguard Worker link_callback_(link_callback),
180*6777b538SAndroid Build Coastguard Worker tunnel_callback_(tunnel_callback),
181*6777b538SAndroid Build Coastguard Worker ignored_interfaces_(ignored_interfaces),
182*6777b538SAndroid Build Coastguard Worker connection_type_initialized_cv_(&connection_type_lock_),
183*6777b538SAndroid Build Coastguard Worker tracking_(true),
184*6777b538SAndroid Build Coastguard Worker sequenced_task_runner_(std::move(blocking_thread_runner)) {
185*6777b538SAndroid Build Coastguard Worker DCHECK(!address_callback.is_null());
186*6777b538SAndroid Build Coastguard Worker DCHECK(!link_callback.is_null());
187*6777b538SAndroid Build Coastguard Worker DETACH_FROM_SEQUENCE(sequence_checker_);
188*6777b538SAndroid Build Coastguard Worker }
189*6777b538SAndroid Build Coastguard Worker
190*6777b538SAndroid Build Coastguard Worker AddressTrackerLinux::~AddressTrackerLinux() = default;
191*6777b538SAndroid Build Coastguard Worker
InitWithFdForTesting(base::ScopedFD fd)192*6777b538SAndroid Build Coastguard Worker void AddressTrackerLinux::InitWithFdForTesting(base::ScopedFD fd) {
193*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
194*6777b538SAndroid Build Coastguard Worker
195*6777b538SAndroid Build Coastguard Worker netlink_fd_ = std::move(fd);
196*6777b538SAndroid Build Coastguard Worker DumpInitialAddressesAndWatch();
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker
Init()199*6777b538SAndroid Build Coastguard Worker void AddressTrackerLinux::Init() {
200*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
201*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
202*6777b538SAndroid Build Coastguard Worker // RTM_GETLINK stopped working in Android 11 (see
203*6777b538SAndroid Build Coastguard Worker // https://developer.android.com/preview/privacy/mac-address),
204*6777b538SAndroid Build Coastguard Worker // so AddressTrackerLinux should not be used in later versions
205*6777b538SAndroid Build Coastguard Worker // of Android. Chromium code doesn't need it past Android P.
206*6777b538SAndroid Build Coastguard Worker DCHECK_LT(base::android::BuildInfo::GetInstance()->sdk_int(),
207*6777b538SAndroid Build Coastguard Worker base::android::SDK_VERSION_P);
208*6777b538SAndroid Build Coastguard Worker #endif
209*6777b538SAndroid Build Coastguard Worker netlink_fd_.reset(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE));
210*6777b538SAndroid Build Coastguard Worker if (!netlink_fd_.is_valid()) {
211*6777b538SAndroid Build Coastguard Worker PLOG(ERROR) << "Could not create NETLINK socket";
212*6777b538SAndroid Build Coastguard Worker AbortAndForceOnline();
213*6777b538SAndroid Build Coastguard Worker return;
214*6777b538SAndroid Build Coastguard Worker }
215*6777b538SAndroid Build Coastguard Worker
216*6777b538SAndroid Build Coastguard Worker int rv;
217*6777b538SAndroid Build Coastguard Worker
218*6777b538SAndroid Build Coastguard Worker if (tracking_) {
219*6777b538SAndroid Build Coastguard Worker // Request notifications.
220*6777b538SAndroid Build Coastguard Worker struct sockaddr_nl addr = {};
221*6777b538SAndroid Build Coastguard Worker addr.nl_family = AF_NETLINK;
222*6777b538SAndroid Build Coastguard Worker addr.nl_pid = 0; // Let the kernel select a unique value.
223*6777b538SAndroid Build Coastguard Worker // TODO(szym): Track RTMGRP_LINK as well for ifi_type,
224*6777b538SAndroid Build Coastguard Worker // http://crbug.com/113993
225*6777b538SAndroid Build Coastguard Worker addr.nl_groups =
226*6777b538SAndroid Build Coastguard Worker RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY | RTMGRP_LINK;
227*6777b538SAndroid Build Coastguard Worker rv = bind(netlink_fd_.get(), reinterpret_cast<struct sockaddr*>(&addr),
228*6777b538SAndroid Build Coastguard Worker sizeof(addr));
229*6777b538SAndroid Build Coastguard Worker if (rv < 0) {
230*6777b538SAndroid Build Coastguard Worker PLOG(ERROR) << "Could not bind NETLINK socket";
231*6777b538SAndroid Build Coastguard Worker AbortAndForceOnline();
232*6777b538SAndroid Build Coastguard Worker return;
233*6777b538SAndroid Build Coastguard Worker }
234*6777b538SAndroid Build Coastguard Worker }
235*6777b538SAndroid Build Coastguard Worker
236*6777b538SAndroid Build Coastguard Worker DumpInitialAddressesAndWatch();
237*6777b538SAndroid Build Coastguard Worker }
238*6777b538SAndroid Build Coastguard Worker
DidTrackingInitSucceedForTesting() const239*6777b538SAndroid Build Coastguard Worker bool AddressTrackerLinux::DidTrackingInitSucceedForTesting() const {
240*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
241*6777b538SAndroid Build Coastguard Worker CHECK(tracking_);
242*6777b538SAndroid Build Coastguard Worker return watcher_ != nullptr;
243*6777b538SAndroid Build Coastguard Worker }
244*6777b538SAndroid Build Coastguard Worker
AbortAndForceOnline()245*6777b538SAndroid Build Coastguard Worker void AddressTrackerLinux::AbortAndForceOnline() {
246*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
247*6777b538SAndroid Build Coastguard Worker watcher_.reset();
248*6777b538SAndroid Build Coastguard Worker netlink_fd_.reset();
249*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, connection_type_lock_);
250*6777b538SAndroid Build Coastguard Worker current_connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN;
251*6777b538SAndroid Build Coastguard Worker connection_type_initialized_ = true;
252*6777b538SAndroid Build Coastguard Worker connection_type_initialized_cv_.Broadcast();
253*6777b538SAndroid Build Coastguard Worker }
254*6777b538SAndroid Build Coastguard Worker
GetAddressMap() const255*6777b538SAndroid Build Coastguard Worker AddressTrackerLinux::AddressMap AddressTrackerLinux::GetAddressMap() const {
256*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, address_map_lock_);
257*6777b538SAndroid Build Coastguard Worker return address_map_;
258*6777b538SAndroid Build Coastguard Worker }
259*6777b538SAndroid Build Coastguard Worker
GetOnlineLinks() const260*6777b538SAndroid Build Coastguard Worker std::unordered_set<int> AddressTrackerLinux::GetOnlineLinks() const {
261*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, online_links_lock_);
262*6777b538SAndroid Build Coastguard Worker return online_links_;
263*6777b538SAndroid Build Coastguard Worker }
264*6777b538SAndroid Build Coastguard Worker
GetAddressTrackerLinux()265*6777b538SAndroid Build Coastguard Worker AddressTrackerLinux* AddressTrackerLinux::GetAddressTrackerLinux() {
266*6777b538SAndroid Build Coastguard Worker return this;
267*6777b538SAndroid Build Coastguard Worker }
268*6777b538SAndroid Build Coastguard Worker
269*6777b538SAndroid Build Coastguard Worker std::pair<AddressTrackerLinux::AddressMap, std::unordered_set<int>>
GetInitialDataAndStartRecordingDiffs()270*6777b538SAndroid Build Coastguard Worker AddressTrackerLinux::GetInitialDataAndStartRecordingDiffs() {
271*6777b538SAndroid Build Coastguard Worker DCHECK(tracking_);
272*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock_address_map(*this, address_map_lock_);
273*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock_online_links(*this, online_links_lock_);
274*6777b538SAndroid Build Coastguard Worker address_map_diff_ = AddressMapDiff();
275*6777b538SAndroid Build Coastguard Worker online_links_diff_ = OnlineLinksDiff();
276*6777b538SAndroid Build Coastguard Worker return {address_map_, online_links_};
277*6777b538SAndroid Build Coastguard Worker }
278*6777b538SAndroid Build Coastguard Worker
SetDiffCallback(DiffCallback diff_callback)279*6777b538SAndroid Build Coastguard Worker void AddressTrackerLinux::SetDiffCallback(DiffCallback diff_callback) {
280*6777b538SAndroid Build Coastguard Worker DCHECK(tracking_);
281*6777b538SAndroid Build Coastguard Worker DCHECK(sequenced_task_runner_);
282*6777b538SAndroid Build Coastguard Worker
283*6777b538SAndroid Build Coastguard Worker if (!sequenced_task_runner_->RunsTasksInCurrentSequence()) {
284*6777b538SAndroid Build Coastguard Worker sequenced_task_runner_->PostTask(
285*6777b538SAndroid Build Coastguard Worker FROM_HERE, base::BindOnce(&AddressTrackerLinux::SetDiffCallback,
286*6777b538SAndroid Build Coastguard Worker weak_ptr_factory_.GetWeakPtr(),
287*6777b538SAndroid Build Coastguard Worker std::move(diff_callback)));
288*6777b538SAndroid Build Coastguard Worker return;
289*6777b538SAndroid Build Coastguard Worker }
290*6777b538SAndroid Build Coastguard Worker
291*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
292*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
293*6777b538SAndroid Build Coastguard Worker {
294*6777b538SAndroid Build Coastguard Worker // GetInitialDataAndStartRecordingDiffs() must be called before
295*6777b538SAndroid Build Coastguard Worker // SetDiffCallback().
296*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock_address_map(*this, address_map_lock_);
297*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock_online_links(*this, online_links_lock_);
298*6777b538SAndroid Build Coastguard Worker DCHECK(address_map_diff_.has_value());
299*6777b538SAndroid Build Coastguard Worker DCHECK(online_links_diff_.has_value());
300*6777b538SAndroid Build Coastguard Worker }
301*6777b538SAndroid Build Coastguard Worker #endif // DCHECK_IS_ON()
302*6777b538SAndroid Build Coastguard Worker diff_callback_ = std::move(diff_callback);
303*6777b538SAndroid Build Coastguard Worker RunDiffCallback();
304*6777b538SAndroid Build Coastguard Worker }
305*6777b538SAndroid Build Coastguard Worker
IsInterfaceIgnored(int interface_index) const306*6777b538SAndroid Build Coastguard Worker bool AddressTrackerLinux::IsInterfaceIgnored(int interface_index) const {
307*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
308*6777b538SAndroid Build Coastguard Worker if (ignored_interfaces_.empty())
309*6777b538SAndroid Build Coastguard Worker return false;
310*6777b538SAndroid Build Coastguard Worker
311*6777b538SAndroid Build Coastguard Worker char buf[IFNAMSIZ] = {0};
312*6777b538SAndroid Build Coastguard Worker const char* interface_name = get_interface_name_(interface_index, buf);
313*6777b538SAndroid Build Coastguard Worker return ignored_interfaces_.find(interface_name) != ignored_interfaces_.end();
314*6777b538SAndroid Build Coastguard Worker }
315*6777b538SAndroid Build Coastguard Worker
316*6777b538SAndroid Build Coastguard Worker NetworkChangeNotifier::ConnectionType
GetCurrentConnectionType()317*6777b538SAndroid Build Coastguard Worker AddressTrackerLinux::GetCurrentConnectionType() {
318*6777b538SAndroid Build Coastguard Worker // http://crbug.com/125097
319*6777b538SAndroid Build Coastguard Worker base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
320*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, connection_type_lock_);
321*6777b538SAndroid Build Coastguard Worker // Make sure the initial connection type is set before returning.
322*6777b538SAndroid Build Coastguard Worker threads_waiting_for_connection_type_initialization_++;
323*6777b538SAndroid Build Coastguard Worker while (!connection_type_initialized_) {
324*6777b538SAndroid Build Coastguard Worker connection_type_initialized_cv_.Wait();
325*6777b538SAndroid Build Coastguard Worker }
326*6777b538SAndroid Build Coastguard Worker threads_waiting_for_connection_type_initialization_--;
327*6777b538SAndroid Build Coastguard Worker return current_connection_type_;
328*6777b538SAndroid Build Coastguard Worker }
329*6777b538SAndroid Build Coastguard Worker
DumpInitialAddressesAndWatch()330*6777b538SAndroid Build Coastguard Worker void AddressTrackerLinux::DumpInitialAddressesAndWatch() {
331*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
332*6777b538SAndroid Build Coastguard Worker
333*6777b538SAndroid Build Coastguard Worker // Request dump of addresses.
334*6777b538SAndroid Build Coastguard Worker struct sockaddr_nl peer = {};
335*6777b538SAndroid Build Coastguard Worker peer.nl_family = AF_NETLINK;
336*6777b538SAndroid Build Coastguard Worker
337*6777b538SAndroid Build Coastguard Worker struct {
338*6777b538SAndroid Build Coastguard Worker struct nlmsghdr header;
339*6777b538SAndroid Build Coastguard Worker struct rtgenmsg msg;
340*6777b538SAndroid Build Coastguard Worker } request = {};
341*6777b538SAndroid Build Coastguard Worker
342*6777b538SAndroid Build Coastguard Worker request.header.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg));
343*6777b538SAndroid Build Coastguard Worker request.header.nlmsg_type = RTM_GETADDR;
344*6777b538SAndroid Build Coastguard Worker request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
345*6777b538SAndroid Build Coastguard Worker request.header.nlmsg_pid = 0; // This field is opaque to netlink.
346*6777b538SAndroid Build Coastguard Worker request.msg.rtgen_family = AF_UNSPEC;
347*6777b538SAndroid Build Coastguard Worker
348*6777b538SAndroid Build Coastguard Worker int rv = HANDLE_EINTR(
349*6777b538SAndroid Build Coastguard Worker sendto(netlink_fd_.get(), &request, request.header.nlmsg_len, 0,
350*6777b538SAndroid Build Coastguard Worker reinterpret_cast<struct sockaddr*>(&peer), sizeof(peer)));
351*6777b538SAndroid Build Coastguard Worker if (rv < 0) {
352*6777b538SAndroid Build Coastguard Worker PLOG(ERROR) << "Could not send NETLINK request";
353*6777b538SAndroid Build Coastguard Worker AbortAndForceOnline();
354*6777b538SAndroid Build Coastguard Worker return;
355*6777b538SAndroid Build Coastguard Worker }
356*6777b538SAndroid Build Coastguard Worker
357*6777b538SAndroid Build Coastguard Worker // Consume pending message to populate the AddressMap, but don't notify.
358*6777b538SAndroid Build Coastguard Worker // Sending another request without first reading responses results in EBUSY.
359*6777b538SAndroid Build Coastguard Worker bool address_changed;
360*6777b538SAndroid Build Coastguard Worker bool link_changed;
361*6777b538SAndroid Build Coastguard Worker bool tunnel_changed;
362*6777b538SAndroid Build Coastguard Worker ReadMessages(&address_changed, &link_changed, &tunnel_changed);
363*6777b538SAndroid Build Coastguard Worker
364*6777b538SAndroid Build Coastguard Worker // Request dump of link state
365*6777b538SAndroid Build Coastguard Worker request.header.nlmsg_type = RTM_GETLINK;
366*6777b538SAndroid Build Coastguard Worker
367*6777b538SAndroid Build Coastguard Worker rv = HANDLE_EINTR(
368*6777b538SAndroid Build Coastguard Worker sendto(netlink_fd_.get(), &request, request.header.nlmsg_len, 0,
369*6777b538SAndroid Build Coastguard Worker reinterpret_cast<struct sockaddr*>(&peer), sizeof(peer)));
370*6777b538SAndroid Build Coastguard Worker if (rv < 0) {
371*6777b538SAndroid Build Coastguard Worker PLOG(ERROR) << "Could not send NETLINK request";
372*6777b538SAndroid Build Coastguard Worker AbortAndForceOnline();
373*6777b538SAndroid Build Coastguard Worker return;
374*6777b538SAndroid Build Coastguard Worker }
375*6777b538SAndroid Build Coastguard Worker
376*6777b538SAndroid Build Coastguard Worker // Consume pending message to populate links_online_, but don't notify.
377*6777b538SAndroid Build Coastguard Worker ReadMessages(&address_changed, &link_changed, &tunnel_changed);
378*6777b538SAndroid Build Coastguard Worker {
379*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, connection_type_lock_);
380*6777b538SAndroid Build Coastguard Worker connection_type_initialized_ = true;
381*6777b538SAndroid Build Coastguard Worker connection_type_initialized_cv_.Broadcast();
382*6777b538SAndroid Build Coastguard Worker }
383*6777b538SAndroid Build Coastguard Worker
384*6777b538SAndroid Build Coastguard Worker if (tracking_) {
385*6777b538SAndroid Build Coastguard Worker DCHECK(!sequenced_task_runner_ ||
386*6777b538SAndroid Build Coastguard Worker sequenced_task_runner_->RunsTasksInCurrentSequence());
387*6777b538SAndroid Build Coastguard Worker
388*6777b538SAndroid Build Coastguard Worker watcher_ = base::FileDescriptorWatcher::WatchReadable(
389*6777b538SAndroid Build Coastguard Worker netlink_fd_.get(),
390*6777b538SAndroid Build Coastguard Worker base::BindRepeating(&AddressTrackerLinux::OnFileCanReadWithoutBlocking,
391*6777b538SAndroid Build Coastguard Worker base::Unretained(this)));
392*6777b538SAndroid Build Coastguard Worker }
393*6777b538SAndroid Build Coastguard Worker }
394*6777b538SAndroid Build Coastguard Worker
ReadMessages(bool * address_changed,bool * link_changed,bool * tunnel_changed)395*6777b538SAndroid Build Coastguard Worker void AddressTrackerLinux::ReadMessages(bool* address_changed,
396*6777b538SAndroid Build Coastguard Worker bool* link_changed,
397*6777b538SAndroid Build Coastguard Worker bool* tunnel_changed) {
398*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
399*6777b538SAndroid Build Coastguard Worker *address_changed = false;
400*6777b538SAndroid Build Coastguard Worker *link_changed = false;
401*6777b538SAndroid Build Coastguard Worker *tunnel_changed = false;
402*6777b538SAndroid Build Coastguard Worker bool first_loop = true;
403*6777b538SAndroid Build Coastguard Worker
404*6777b538SAndroid Build Coastguard Worker // Varying sources have different opinions regarding the buffer size needed
405*6777b538SAndroid Build Coastguard Worker // for netlink messages to avoid truncation:
406*6777b538SAndroid Build Coastguard Worker // - The official documentation on netlink says messages are generally 8kb
407*6777b538SAndroid Build Coastguard Worker // or the system page size, whichever is *larger*:
408*6777b538SAndroid Build Coastguard Worker // https://www.kernel.org/doc/html/v6.2/userspace-api/netlink/intro.html#buffer-sizing
409*6777b538SAndroid Build Coastguard Worker // - The kernel headers would imply that messages are generally the system
410*6777b538SAndroid Build Coastguard Worker // page size or 8kb, whichever is *smaller*:
411*6777b538SAndroid Build Coastguard Worker // https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/netlink.h?h=v6.2.2#n226
412*6777b538SAndroid Build Coastguard Worker // (libmnl follows this.)
413*6777b538SAndroid Build Coastguard Worker // - The netlink(7) man page's example always uses a fixed size 8kb buffer:
414*6777b538SAndroid Build Coastguard Worker // https://man7.org/linux/man-pages/man7/netlink.7.html
415*6777b538SAndroid Build Coastguard Worker // Here, we follow the guidelines in the documentation, for two primary
416*6777b538SAndroid Build Coastguard Worker // reasons:
417*6777b538SAndroid Build Coastguard Worker // - Erring on the side of a larger size is the safer way to go to avoid
418*6777b538SAndroid Build Coastguard Worker // MSG_TRUNC.
419*6777b538SAndroid Build Coastguard Worker // - Since this is heap-allocated anyway, there's no risk to the stack by
420*6777b538SAndroid Build Coastguard Worker // using the larger size.
421*6777b538SAndroid Build Coastguard Worker
422*6777b538SAndroid Build Coastguard Worker constexpr size_t kMinNetlinkBufferSize = 8 * 1024;
423*6777b538SAndroid Build Coastguard Worker std::vector<char> buffer(
424*6777b538SAndroid Build Coastguard Worker std::max(base::GetPageSize(), kMinNetlinkBufferSize));
425*6777b538SAndroid Build Coastguard Worker
426*6777b538SAndroid Build Coastguard Worker {
427*6777b538SAndroid Build Coastguard Worker std::optional<base::ScopedBlockingCall> blocking_call;
428*6777b538SAndroid Build Coastguard Worker if (tracking_) {
429*6777b538SAndroid Build Coastguard Worker // If the loop below takes a long time to run, a new thread should added
430*6777b538SAndroid Build Coastguard Worker // to the current thread pool to ensure forward progress of all tasks.
431*6777b538SAndroid Build Coastguard Worker blocking_call.emplace(FROM_HERE, base::BlockingType::MAY_BLOCK);
432*6777b538SAndroid Build Coastguard Worker }
433*6777b538SAndroid Build Coastguard Worker
434*6777b538SAndroid Build Coastguard Worker for (;;) {
435*6777b538SAndroid Build Coastguard Worker int rv =
436*6777b538SAndroid Build Coastguard Worker HANDLE_EINTR(recv(netlink_fd_.get(), buffer.data(), buffer.size(),
437*6777b538SAndroid Build Coastguard Worker // Block the first time through loop.
438*6777b538SAndroid Build Coastguard Worker first_loop ? 0 : MSG_DONTWAIT));
439*6777b538SAndroid Build Coastguard Worker first_loop = false;
440*6777b538SAndroid Build Coastguard Worker if (rv == 0) {
441*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Unexpected shutdown of NETLINK socket.";
442*6777b538SAndroid Build Coastguard Worker return;
443*6777b538SAndroid Build Coastguard Worker }
444*6777b538SAndroid Build Coastguard Worker if (rv < 0) {
445*6777b538SAndroid Build Coastguard Worker if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
446*6777b538SAndroid Build Coastguard Worker break;
447*6777b538SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to recv from netlink socket";
448*6777b538SAndroid Build Coastguard Worker return;
449*6777b538SAndroid Build Coastguard Worker }
450*6777b538SAndroid Build Coastguard Worker HandleMessage(buffer.data(), rv, address_changed, link_changed,
451*6777b538SAndroid Build Coastguard Worker tunnel_changed);
452*6777b538SAndroid Build Coastguard Worker }
453*6777b538SAndroid Build Coastguard Worker }
454*6777b538SAndroid Build Coastguard Worker if (*link_changed || *address_changed)
455*6777b538SAndroid Build Coastguard Worker UpdateCurrentConnectionType();
456*6777b538SAndroid Build Coastguard Worker }
457*6777b538SAndroid Build Coastguard Worker
HandleMessage(const char * buffer,int length,bool * address_changed,bool * link_changed,bool * tunnel_changed)458*6777b538SAndroid Build Coastguard Worker void AddressTrackerLinux::HandleMessage(const char* buffer,
459*6777b538SAndroid Build Coastguard Worker int length,
460*6777b538SAndroid Build Coastguard Worker bool* address_changed,
461*6777b538SAndroid Build Coastguard Worker bool* link_changed,
462*6777b538SAndroid Build Coastguard Worker bool* tunnel_changed) {
463*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
464*6777b538SAndroid Build Coastguard Worker DCHECK(buffer);
465*6777b538SAndroid Build Coastguard Worker // Note that NLMSG_NEXT decrements |length| to reflect the number of bytes
466*6777b538SAndroid Build Coastguard Worker // remaining in |buffer|.
467*6777b538SAndroid Build Coastguard Worker for (const struct nlmsghdr* header =
468*6777b538SAndroid Build Coastguard Worker reinterpret_cast<const struct nlmsghdr*>(buffer);
469*6777b538SAndroid Build Coastguard Worker length >= 0 && NLMSG_OK(header, static_cast<__u32>(length));
470*6777b538SAndroid Build Coastguard Worker header = NLMSG_NEXT(header, length)) {
471*6777b538SAndroid Build Coastguard Worker // The |header| pointer should never precede |buffer|.
472*6777b538SAndroid Build Coastguard Worker DCHECK_LE(buffer, reinterpret_cast<const char*>(header));
473*6777b538SAndroid Build Coastguard Worker switch (header->nlmsg_type) {
474*6777b538SAndroid Build Coastguard Worker case NLMSG_DONE:
475*6777b538SAndroid Build Coastguard Worker return;
476*6777b538SAndroid Build Coastguard Worker case NLMSG_ERROR: {
477*6777b538SAndroid Build Coastguard Worker const struct nlmsgerr* msg =
478*6777b538SAndroid Build Coastguard Worker SafelyCastNetlinkMsgData<const struct nlmsgerr>(header, length);
479*6777b538SAndroid Build Coastguard Worker if (msg == nullptr)
480*6777b538SAndroid Build Coastguard Worker return;
481*6777b538SAndroid Build Coastguard Worker LOG(ERROR) << "Unexpected netlink error " << msg->error << ".";
482*6777b538SAndroid Build Coastguard Worker } return;
483*6777b538SAndroid Build Coastguard Worker case RTM_NEWADDR: {
484*6777b538SAndroid Build Coastguard Worker IPAddress address;
485*6777b538SAndroid Build Coastguard Worker bool really_deprecated;
486*6777b538SAndroid Build Coastguard Worker const struct ifaddrmsg* msg =
487*6777b538SAndroid Build Coastguard Worker SafelyCastNetlinkMsgData<const struct ifaddrmsg>(header, length);
488*6777b538SAndroid Build Coastguard Worker if (msg == nullptr)
489*6777b538SAndroid Build Coastguard Worker return;
490*6777b538SAndroid Build Coastguard Worker if (IsInterfaceIgnored(msg->ifa_index))
491*6777b538SAndroid Build Coastguard Worker break;
492*6777b538SAndroid Build Coastguard Worker if (GetAddress(header, length, &address, &really_deprecated)) {
493*6777b538SAndroid Build Coastguard Worker struct ifaddrmsg msg_copy = *msg;
494*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, address_map_lock_);
495*6777b538SAndroid Build Coastguard Worker // Routers may frequently (every few seconds) output the IPv6 ULA
496*6777b538SAndroid Build Coastguard Worker // prefix which can cause the linux kernel to frequently output two
497*6777b538SAndroid Build Coastguard Worker // back-to-back messages, one without the deprecated flag and one with
498*6777b538SAndroid Build Coastguard Worker // the deprecated flag but both with preferred lifetimes of 0. Avoid
499*6777b538SAndroid Build Coastguard Worker // interpreting this as an actual change by canonicalizing the two
500*6777b538SAndroid Build Coastguard Worker // messages by setting the deprecated flag based on the preferred
501*6777b538SAndroid Build Coastguard Worker // lifetime also. http://crbug.com/268042
502*6777b538SAndroid Build Coastguard Worker if (really_deprecated)
503*6777b538SAndroid Build Coastguard Worker msg_copy.ifa_flags |= IFA_F_DEPRECATED;
504*6777b538SAndroid Build Coastguard Worker // Only indicate change if the address is new or ifaddrmsg info has
505*6777b538SAndroid Build Coastguard Worker // changed.
506*6777b538SAndroid Build Coastguard Worker auto it = address_map_.find(address);
507*6777b538SAndroid Build Coastguard Worker if (it == address_map_.end()) {
508*6777b538SAndroid Build Coastguard Worker address_map_.insert(it, std::pair(address, msg_copy));
509*6777b538SAndroid Build Coastguard Worker *address_changed = true;
510*6777b538SAndroid Build Coastguard Worker } else if (memcmp(&it->second, &msg_copy, sizeof(msg_copy))) {
511*6777b538SAndroid Build Coastguard Worker it->second = msg_copy;
512*6777b538SAndroid Build Coastguard Worker *address_changed = true;
513*6777b538SAndroid Build Coastguard Worker }
514*6777b538SAndroid Build Coastguard Worker if (*address_changed && address_map_diff_.has_value()) {
515*6777b538SAndroid Build Coastguard Worker (*address_map_diff_)[address] = msg_copy;
516*6777b538SAndroid Build Coastguard Worker }
517*6777b538SAndroid Build Coastguard Worker }
518*6777b538SAndroid Build Coastguard Worker } break;
519*6777b538SAndroid Build Coastguard Worker case RTM_DELADDR: {
520*6777b538SAndroid Build Coastguard Worker IPAddress address;
521*6777b538SAndroid Build Coastguard Worker const struct ifaddrmsg* msg =
522*6777b538SAndroid Build Coastguard Worker SafelyCastNetlinkMsgData<const struct ifaddrmsg>(header, length);
523*6777b538SAndroid Build Coastguard Worker if (msg == nullptr)
524*6777b538SAndroid Build Coastguard Worker return;
525*6777b538SAndroid Build Coastguard Worker if (IsInterfaceIgnored(msg->ifa_index))
526*6777b538SAndroid Build Coastguard Worker break;
527*6777b538SAndroid Build Coastguard Worker if (GetAddress(header, length, &address, nullptr)) {
528*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, address_map_lock_);
529*6777b538SAndroid Build Coastguard Worker if (address_map_.erase(address)) {
530*6777b538SAndroid Build Coastguard Worker *address_changed = true;
531*6777b538SAndroid Build Coastguard Worker if (address_map_diff_.has_value()) {
532*6777b538SAndroid Build Coastguard Worker (*address_map_diff_)[address] = std::nullopt;
533*6777b538SAndroid Build Coastguard Worker }
534*6777b538SAndroid Build Coastguard Worker }
535*6777b538SAndroid Build Coastguard Worker }
536*6777b538SAndroid Build Coastguard Worker } break;
537*6777b538SAndroid Build Coastguard Worker case RTM_NEWLINK: {
538*6777b538SAndroid Build Coastguard Worker const struct ifinfomsg* msg =
539*6777b538SAndroid Build Coastguard Worker SafelyCastNetlinkMsgData<const struct ifinfomsg>(header, length);
540*6777b538SAndroid Build Coastguard Worker if (msg == nullptr)
541*6777b538SAndroid Build Coastguard Worker return;
542*6777b538SAndroid Build Coastguard Worker if (IsInterfaceIgnored(msg->ifi_index))
543*6777b538SAndroid Build Coastguard Worker break;
544*6777b538SAndroid Build Coastguard Worker if (IgnoreWirelessChange(msg, IFLA_PAYLOAD(header))) {
545*6777b538SAndroid Build Coastguard Worker VLOG(2) << "Ignoring RTM_NEWLINK message";
546*6777b538SAndroid Build Coastguard Worker break;
547*6777b538SAndroid Build Coastguard Worker }
548*6777b538SAndroid Build Coastguard Worker if (!(msg->ifi_flags & IFF_LOOPBACK) && (msg->ifi_flags & IFF_UP) &&
549*6777b538SAndroid Build Coastguard Worker (msg->ifi_flags & IFF_LOWER_UP) && (msg->ifi_flags & IFF_RUNNING)) {
550*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, online_links_lock_);
551*6777b538SAndroid Build Coastguard Worker if (online_links_.insert(msg->ifi_index).second) {
552*6777b538SAndroid Build Coastguard Worker *link_changed = true;
553*6777b538SAndroid Build Coastguard Worker if (online_links_diff_.has_value()) {
554*6777b538SAndroid Build Coastguard Worker (*online_links_diff_)[msg->ifi_index] = true;
555*6777b538SAndroid Build Coastguard Worker }
556*6777b538SAndroid Build Coastguard Worker if (IsTunnelInterface(msg->ifi_index))
557*6777b538SAndroid Build Coastguard Worker *tunnel_changed = true;
558*6777b538SAndroid Build Coastguard Worker }
559*6777b538SAndroid Build Coastguard Worker } else {
560*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, online_links_lock_);
561*6777b538SAndroid Build Coastguard Worker if (online_links_.erase(msg->ifi_index)) {
562*6777b538SAndroid Build Coastguard Worker *link_changed = true;
563*6777b538SAndroid Build Coastguard Worker if (online_links_diff_.has_value()) {
564*6777b538SAndroid Build Coastguard Worker (*online_links_diff_)[msg->ifi_index] = false;
565*6777b538SAndroid Build Coastguard Worker }
566*6777b538SAndroid Build Coastguard Worker if (IsTunnelInterface(msg->ifi_index))
567*6777b538SAndroid Build Coastguard Worker *tunnel_changed = true;
568*6777b538SAndroid Build Coastguard Worker }
569*6777b538SAndroid Build Coastguard Worker }
570*6777b538SAndroid Build Coastguard Worker } break;
571*6777b538SAndroid Build Coastguard Worker case RTM_DELLINK: {
572*6777b538SAndroid Build Coastguard Worker const struct ifinfomsg* msg =
573*6777b538SAndroid Build Coastguard Worker SafelyCastNetlinkMsgData<const struct ifinfomsg>(header, length);
574*6777b538SAndroid Build Coastguard Worker if (msg == nullptr)
575*6777b538SAndroid Build Coastguard Worker return;
576*6777b538SAndroid Build Coastguard Worker if (IsInterfaceIgnored(msg->ifi_index))
577*6777b538SAndroid Build Coastguard Worker break;
578*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, online_links_lock_);
579*6777b538SAndroid Build Coastguard Worker if (online_links_.erase(msg->ifi_index)) {
580*6777b538SAndroid Build Coastguard Worker *link_changed = true;
581*6777b538SAndroid Build Coastguard Worker if (online_links_diff_.has_value()) {
582*6777b538SAndroid Build Coastguard Worker (*online_links_diff_)[msg->ifi_index] = false;
583*6777b538SAndroid Build Coastguard Worker }
584*6777b538SAndroid Build Coastguard Worker if (IsTunnelInterface(msg->ifi_index))
585*6777b538SAndroid Build Coastguard Worker *tunnel_changed = true;
586*6777b538SAndroid Build Coastguard Worker }
587*6777b538SAndroid Build Coastguard Worker } break;
588*6777b538SAndroid Build Coastguard Worker default:
589*6777b538SAndroid Build Coastguard Worker break;
590*6777b538SAndroid Build Coastguard Worker }
591*6777b538SAndroid Build Coastguard Worker }
592*6777b538SAndroid Build Coastguard Worker }
593*6777b538SAndroid Build Coastguard Worker
OnFileCanReadWithoutBlocking()594*6777b538SAndroid Build Coastguard Worker void AddressTrackerLinux::OnFileCanReadWithoutBlocking() {
595*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
596*6777b538SAndroid Build Coastguard Worker bool address_changed;
597*6777b538SAndroid Build Coastguard Worker bool link_changed;
598*6777b538SAndroid Build Coastguard Worker bool tunnel_changed;
599*6777b538SAndroid Build Coastguard Worker ReadMessages(&address_changed, &link_changed, &tunnel_changed);
600*6777b538SAndroid Build Coastguard Worker if (diff_callback_) {
601*6777b538SAndroid Build Coastguard Worker RunDiffCallback();
602*6777b538SAndroid Build Coastguard Worker }
603*6777b538SAndroid Build Coastguard Worker if (address_changed) {
604*6777b538SAndroid Build Coastguard Worker address_callback_.Run();
605*6777b538SAndroid Build Coastguard Worker }
606*6777b538SAndroid Build Coastguard Worker if (link_changed) {
607*6777b538SAndroid Build Coastguard Worker link_callback_.Run();
608*6777b538SAndroid Build Coastguard Worker }
609*6777b538SAndroid Build Coastguard Worker if (tunnel_changed) {
610*6777b538SAndroid Build Coastguard Worker tunnel_callback_.Run();
611*6777b538SAndroid Build Coastguard Worker }
612*6777b538SAndroid Build Coastguard Worker }
613*6777b538SAndroid Build Coastguard Worker
IsTunnelInterface(int interface_index) const614*6777b538SAndroid Build Coastguard Worker bool AddressTrackerLinux::IsTunnelInterface(int interface_index) const {
615*6777b538SAndroid Build Coastguard Worker char buf[IFNAMSIZ] = {0};
616*6777b538SAndroid Build Coastguard Worker return IsTunnelInterfaceName(get_interface_name_(interface_index, buf));
617*6777b538SAndroid Build Coastguard Worker }
618*6777b538SAndroid Build Coastguard Worker
619*6777b538SAndroid Build Coastguard Worker // static
IsTunnelInterfaceName(const char * name)620*6777b538SAndroid Build Coastguard Worker bool AddressTrackerLinux::IsTunnelInterfaceName(const char* name) {
621*6777b538SAndroid Build Coastguard Worker // Linux kernel drivers/net/tun.c uses "tun" name prefix.
622*6777b538SAndroid Build Coastguard Worker return strncmp(name, "tun", 3) == 0;
623*6777b538SAndroid Build Coastguard Worker }
624*6777b538SAndroid Build Coastguard Worker
UpdateCurrentConnectionType()625*6777b538SAndroid Build Coastguard Worker void AddressTrackerLinux::UpdateCurrentConnectionType() {
626*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
627*6777b538SAndroid Build Coastguard Worker AddressTrackerLinux::AddressMap address_map = GetAddressMap();
628*6777b538SAndroid Build Coastguard Worker std::unordered_set<int> online_links = GetOnlineLinks();
629*6777b538SAndroid Build Coastguard Worker
630*6777b538SAndroid Build Coastguard Worker // Strip out tunnel interfaces from online_links
631*6777b538SAndroid Build Coastguard Worker for (auto it = online_links.cbegin(); it != online_links.cend();) {
632*6777b538SAndroid Build Coastguard Worker if (IsTunnelInterface(*it)) {
633*6777b538SAndroid Build Coastguard Worker it = online_links.erase(it);
634*6777b538SAndroid Build Coastguard Worker } else {
635*6777b538SAndroid Build Coastguard Worker ++it;
636*6777b538SAndroid Build Coastguard Worker }
637*6777b538SAndroid Build Coastguard Worker }
638*6777b538SAndroid Build Coastguard Worker
639*6777b538SAndroid Build Coastguard Worker NetworkInterfaceList networks;
640*6777b538SAndroid Build Coastguard Worker NetworkChangeNotifier::ConnectionType type =
641*6777b538SAndroid Build Coastguard Worker NetworkChangeNotifier::CONNECTION_NONE;
642*6777b538SAndroid Build Coastguard Worker if (GetNetworkListImpl(&networks, 0, online_links, address_map,
643*6777b538SAndroid Build Coastguard Worker get_interface_name_)) {
644*6777b538SAndroid Build Coastguard Worker type = NetworkChangeNotifier::ConnectionTypeFromInterfaceList(networks);
645*6777b538SAndroid Build Coastguard Worker } else {
646*6777b538SAndroid Build Coastguard Worker type = online_links.empty() ? NetworkChangeNotifier::CONNECTION_NONE
647*6777b538SAndroid Build Coastguard Worker : NetworkChangeNotifier::CONNECTION_UNKNOWN;
648*6777b538SAndroid Build Coastguard Worker }
649*6777b538SAndroid Build Coastguard Worker
650*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, connection_type_lock_);
651*6777b538SAndroid Build Coastguard Worker current_connection_type_ = type;
652*6777b538SAndroid Build Coastguard Worker }
653*6777b538SAndroid Build Coastguard Worker
RunDiffCallback()654*6777b538SAndroid Build Coastguard Worker void AddressTrackerLinux::RunDiffCallback() {
655*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
656*6777b538SAndroid Build Coastguard Worker DCHECK(tracking_);
657*6777b538SAndroid Build Coastguard Worker DCHECK(address_map_diff_.has_value());
658*6777b538SAndroid Build Coastguard Worker DCHECK(online_links_diff_.has_value());
659*6777b538SAndroid Build Coastguard Worker // It's fine to access `address_map_diff_` and `online_links_diff_` without
660*6777b538SAndroid Build Coastguard Worker // any locking here, as the only time they are ever accessed on another thread
661*6777b538SAndroid Build Coastguard Worker // is in GetInitialDataAndStartRecordingDiffs(). But
662*6777b538SAndroid Build Coastguard Worker // GetInitialDataAndStartRecordingDiffs() must be called before
663*6777b538SAndroid Build Coastguard Worker // SetDiffCallback(), which must be called before RunDiffCallback(), so this
664*6777b538SAndroid Build Coastguard Worker // function cannot overlap with any modifications on another thread.
665*6777b538SAndroid Build Coastguard Worker
666*6777b538SAndroid Build Coastguard Worker // There should be a diff or the DiffCallback shouldn't be run.
667*6777b538SAndroid Build Coastguard Worker if (address_map_diff_->empty() && online_links_diff_->empty()) {
668*6777b538SAndroid Build Coastguard Worker return;
669*6777b538SAndroid Build Coastguard Worker }
670*6777b538SAndroid Build Coastguard Worker diff_callback_.Run(address_map_diff_.value(), online_links_diff_.value());
671*6777b538SAndroid Build Coastguard Worker address_map_diff_->clear();
672*6777b538SAndroid Build Coastguard Worker online_links_diff_->clear();
673*6777b538SAndroid Build Coastguard Worker }
674*6777b538SAndroid Build Coastguard Worker
GetThreadsWaitingForConnectionTypeInitForTesting()675*6777b538SAndroid Build Coastguard Worker int AddressTrackerLinux::GetThreadsWaitingForConnectionTypeInitForTesting() {
676*6777b538SAndroid Build Coastguard Worker AddressTrackerAutoLock lock(*this, connection_type_lock_);
677*6777b538SAndroid Build Coastguard Worker return threads_waiting_for_connection_type_initialization_;
678*6777b538SAndroid Build Coastguard Worker }
679*6777b538SAndroid Build Coastguard Worker
AddressTrackerAutoLock(const AddressTrackerLinux & tracker,base::Lock & lock)680*6777b538SAndroid Build Coastguard Worker AddressTrackerLinux::AddressTrackerAutoLock::AddressTrackerAutoLock(
681*6777b538SAndroid Build Coastguard Worker const AddressTrackerLinux& tracker,
682*6777b538SAndroid Build Coastguard Worker base::Lock& lock)
683*6777b538SAndroid Build Coastguard Worker : tracker_(tracker), lock_(lock) {
684*6777b538SAndroid Build Coastguard Worker if (tracker_->tracking_) {
685*6777b538SAndroid Build Coastguard Worker lock_->Acquire();
686*6777b538SAndroid Build Coastguard Worker } else {
687*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(tracker_->sequence_checker_);
688*6777b538SAndroid Build Coastguard Worker }
689*6777b538SAndroid Build Coastguard Worker }
690*6777b538SAndroid Build Coastguard Worker
~AddressTrackerAutoLock()691*6777b538SAndroid Build Coastguard Worker AddressTrackerLinux::AddressTrackerAutoLock::~AddressTrackerAutoLock() {
692*6777b538SAndroid Build Coastguard Worker if (tracker_->tracking_) {
693*6777b538SAndroid Build Coastguard Worker lock_->AssertAcquired();
694*6777b538SAndroid Build Coastguard Worker lock_->Release();
695*6777b538SAndroid Build Coastguard Worker } else {
696*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(tracker_->sequence_checker_);
697*6777b538SAndroid Build Coastguard Worker }
698*6777b538SAndroid Build Coastguard Worker }
699*6777b538SAndroid Build Coastguard Worker
700*6777b538SAndroid Build Coastguard Worker } // namespace net::internal
701