blob: 4976caeb99d9286fc7c33257def9b5b889bdccbf [file] [log] [blame]
Avi Drissman64595482022-09-14 20:52:291// Copyright 2012 The Chromium Authors
[email protected]67172802012-07-16 22:27:242// 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/base/address_tracker_linux.h"
6
7#include <errno.h>
[email protected]d3eada52012-11-29 17:11:558#include <linux/if.h>
martijnfe8914e2016-03-09 08:33:449#include <stdint.h>
[email protected]cf71d772014-02-09 10:44:0710#include <sys/ioctl.h>
Daniel McArdle47d05072019-10-18 18:27:2811#include <utility>
[email protected]67172802012-07-16 22:27:2412
Dan McArdle3a2da5a2021-07-16 21:45:4713#include "base/check.h"
derekjchow5482d5e2015-01-31 01:04:5114#include "base/files/scoped_file.h"
Avi Drissman41c4a412023-01-11 22:45:3715#include "base/functional/callback_helpers.h"
[email protected]67172802012-07-16 22:27:2416#include "base/logging.h"
[email protected]2025d002012-11-14 20:54:3517#include "base/posix/eintr_wrapper.h"
Carlos Caballerob25fe8472020-07-17 10:27:1718#include "base/task/current_thread.h"
Francois Doray6d622442018-05-31 22:46:3219#include "base/threading/scoped_blocking_call.h"
Paul Jensen3a754972020-07-25 13:47:4520#include "build/build_config.h"
eromanc69886a42015-06-03 18:19:5221#include "net/base/network_interfaces_linux.h"
Anton Bikineev068d2912021-05-15 20:43:5222#include "third_party/abseil-cpp/absl/types/optional.h"
[email protected]67172802012-07-16 22:27:2423
Xiaohan Wang2a6845b2022-01-08 04:40:5724#if BUILDFLAG(IS_ANDROID)
Paul Jensen3a754972020-07-25 13:47:4525#include "base/android/build_info.h"
26#endif
27
Tsuyoshi Horo4f516be2022-06-14 11:53:1328namespace net::internal {
[email protected]67172802012-07-16 22:27:2429
30namespace {
31
derekjchow72407efa2015-06-20 02:59:4332// Some kernel functions such as wireless_send_event and rtnetlink_ifinfo_prep
33// may send spurious messages over rtnetlink. RTM_NEWLINK messages where
34// ifi_change == 0 and rta_type == IFLA_WIRELESS should be ignored.
Daniel McArdle47d05072019-10-18 18:27:2835bool IgnoreWirelessChange(const struct ifinfomsg* msg, int length) {
derekjchow72407efa2015-06-20 02:59:4336 for (const struct rtattr* attr = IFLA_RTA(msg); RTA_OK(attr, length);
37 attr = RTA_NEXT(attr, length)) {
38 if (attr->rta_type == IFLA_WIRELESS && msg->ifi_change == 0)
39 return true;
40 }
41 return false;
42}
43
[email protected]67172802012-07-16 22:27:2444// Retrieves address from NETLINK address message.
[email protected]fb5dead2014-01-23 18:12:2045// Sets |really_deprecated| for IPv6 addresses with preferred lifetimes of 0.
Daniel McArdle47d05072019-10-18 18:27:2846// Precondition: |header| must already be validated with NLMSG_OK.
[email protected]fb5dead2014-01-23 18:12:2047bool GetAddress(const struct nlmsghdr* header,
Daniel McArdle47d05072019-10-18 18:27:2848 int header_length,
martijnfe8914e2016-03-09 08:33:4449 IPAddress* out,
[email protected]fb5dead2014-01-23 18:12:2050 bool* really_deprecated) {
51 if (really_deprecated)
52 *really_deprecated = false;
Daniel McArdle47d05072019-10-18 18:27:2853
54 // Extract the message and update |header_length| to be the number of
55 // remaining bytes.
[email protected]67172802012-07-16 22:27:2456 const struct ifaddrmsg* msg =
Daniel McArdle69d474462019-12-02 16:36:0357 reinterpret_cast<const struct ifaddrmsg*>(NLMSG_DATA(header));
Daniel McArdle47d05072019-10-18 18:27:2858 header_length -= NLMSG_HDRLEN;
59
[email protected]67172802012-07-16 22:27:2460 size_t address_length = 0;
61 switch (msg->ifa_family) {
62 case AF_INET:
martijnfe8914e2016-03-09 08:33:4463 address_length = IPAddress::kIPv4AddressSize;
[email protected]67172802012-07-16 22:27:2464 break;
65 case AF_INET6:
martijnfe8914e2016-03-09 08:33:4466 address_length = IPAddress::kIPv6AddressSize;
[email protected]67172802012-07-16 22:27:2467 break;
68 default:
69 // Unknown family.
70 return false;
71 }
72 // Use IFA_ADDRESS unless IFA_LOCAL is present. This behavior here is based on
73 // getaddrinfo in glibc (check_pf.c). Judging from kernel implementation of
74 // NETLINK, IPv4 addresses have only the IFA_ADDRESS attribute, while IPv6
75 // have the IFA_LOCAL attribute.
Tsuyoshi Horo291961af2022-06-16 08:51:2776 uint8_t* address = nullptr;
77 uint8_t* local = nullptr;
Daniel McArdle47d05072019-10-18 18:27:2878 int length = IFA_PAYLOAD(header);
79 if (length > header_length) {
80 LOG(ERROR) << "ifaddrmsg length exceeds bounds";
81 return false;
82 }
[email protected]67172802012-07-16 22:27:2483 for (const struct rtattr* attr =
84 reinterpret_cast<const struct rtattr*>(IFA_RTA(msg));
Daniel McArdle47d05072019-10-18 18:27:2885 RTA_OK(attr, length); attr = RTA_NEXT(attr, length)) {
[email protected]67172802012-07-16 22:27:2486 switch (attr->rta_type) {
87 case IFA_ADDRESS:
Daniel McArdle47d05072019-10-18 18:27:2888 if (RTA_PAYLOAD(attr) < address_length) {
89 LOG(ERROR) << "attr does not have enough bytes to read an address";
90 return false;
91 }
martijnfe8914e2016-03-09 08:33:4492 address = reinterpret_cast<uint8_t*>(RTA_DATA(attr));
[email protected]67172802012-07-16 22:27:2493 break;
94 case IFA_LOCAL:
Daniel McArdle47d05072019-10-18 18:27:2895 if (RTA_PAYLOAD(attr) < address_length) {
96 LOG(ERROR) << "attr does not have enough bytes to read an address";
97 return false;
98 }
martijnfe8914e2016-03-09 08:33:4499 local = reinterpret_cast<uint8_t*>(RTA_DATA(attr));
[email protected]67172802012-07-16 22:27:24100 break;
[email protected]fb5dead2014-01-23 18:12:20101 case IFA_CACHEINFO: {
Daniel McArdle53be6a42019-11-27 16:57:39102 if (RTA_PAYLOAD(attr) < sizeof(struct ifa_cacheinfo)) {
103 LOG(ERROR)
104 << "attr does not have enough bytes to read an ifa_cacheinfo";
105 return false;
106 }
107 const struct ifa_cacheinfo* cache_info =
[email protected]fb5dead2014-01-23 18:12:20108 reinterpret_cast<const struct ifa_cacheinfo*>(RTA_DATA(attr));
109 if (really_deprecated)
110 *really_deprecated = (cache_info->ifa_prefered == 0);
111 } break;
[email protected]67172802012-07-16 22:27:24112 default:
113 break;
114 }
115 }
116 if (local)
117 address = local;
118 if (!address)
119 return false;
martijnfe8914e2016-03-09 08:33:44120 *out = IPAddress(address, address_length);
[email protected]67172802012-07-16 22:27:24121 return true;
122}
123
Daniel McArdled499a042019-11-04 18:33:00124// SafelyCastNetlinkMsgData<T> performs a bounds check before casting |header|'s
125// data to a |T*|. When the bounds check fails, returns nullptr.
126template <typename T>
127T* SafelyCastNetlinkMsgData(const struct nlmsghdr* header, int length) {
128 DCHECK(NLMSG_OK(header, static_cast<__u32>(length)));
129 if (length <= 0 || static_cast<size_t>(length) < NLMSG_HDRLEN + sizeof(T))
130 return nullptr;
Daniel McArdle69d474462019-12-02 16:36:03131 return reinterpret_cast<const T*>(NLMSG_DATA(header));
Daniel McArdled499a042019-11-04 18:33:00132}
133
[email protected]67172802012-07-16 22:27:24134} // namespace
135
derekjchow5482d5e2015-01-31 01:04:51136// static
137char* AddressTrackerLinux::GetInterfaceName(int interface_index, char* buf) {
138 memset(buf, 0, IFNAMSIZ);
pauljensen7a0c9f82017-05-17 20:52:00139 base::ScopedFD ioctl_socket = GetSocketForIoctl();
derekjchow5482d5e2015-01-31 01:04:51140 if (!ioctl_socket.is_valid())
141 return buf;
142
143 struct ifreq ifr = {};
144 ifr.ifr_ifindex = interface_index;
145
146 if (ioctl(ioctl_socket.get(), SIOCGIFNAME, &ifr) == 0)
147 strncpy(buf, ifr.ifr_name, IFNAMSIZ - 1);
148 return buf;
149}
150
guoweisf09e9972014-09-22 20:47:43151AddressTrackerLinux::AddressTrackerLinux()
152 : get_interface_name_(GetInterfaceName),
Peter Kasting341e1fb2018-02-24 00:03:01153 address_callback_(base::DoNothing()),
154 link_callback_(base::DoNothing()),
155 tunnel_callback_(base::DoNothing()),
dongseong.hwang425c2692016-02-02 12:02:30156 ignored_interfaces_(),
derekjchow5482d5e2015-01-31 01:04:51157 connection_type_initialized_cv_(&connection_type_lock_),
Tsuyoshi Horo432981d52022-06-09 09:50:13158 tracking_(false) {}
guoweisf09e9972014-09-22 20:47:43159
derekjchowea1725c2015-05-08 03:16:01160AddressTrackerLinux::AddressTrackerLinux(
Anna Malovaede0ba162020-03-03 15:50:08161 const base::RepeatingClosure& address_callback,
162 const base::RepeatingClosure& link_callback,
163 const base::RepeatingClosure& tunnel_callback,
davidben1e912ea2016-04-20 19:17:07164 const std::unordered_set<std::string>& ignored_interfaces)
[email protected]cf71d772014-02-09 10:44:07165 : get_interface_name_(GetInterfaceName),
166 address_callback_(address_callback),
[email protected]d3eada52012-11-29 17:11:55167 link_callback_(link_callback),
[email protected]cf71d772014-02-09 10:44:07168 tunnel_callback_(tunnel_callback),
derekjchowea1725c2015-05-08 03:16:01169 ignored_interfaces_(ignored_interfaces),
derekjchow5482d5e2015-01-31 01:04:51170 connection_type_initialized_cv_(&connection_type_lock_),
Tsuyoshi Horo432981d52022-06-09 09:50:13171 tracking_(true) {
[email protected]d3eada52012-11-29 17:11:55172 DCHECK(!address_callback.is_null());
173 DCHECK(!link_callback.is_null());
[email protected]67172802012-07-16 22:27:24174}
175
Paul Jensen05f0f9782019-04-13 13:33:35176AddressTrackerLinux::~AddressTrackerLinux() = default;
[email protected]67172802012-07-16 22:27:24177
178void AddressTrackerLinux::Init() {
Xiaohan Wang2a6845b2022-01-08 04:40:57179#if BUILDFLAG(IS_ANDROID)
Paul Jensen3a754972020-07-25 13:47:45180 // RTM_GETLINK stopped working in Android 11 (see
181 // https://developer.android.com/preview/privacy/mac-address),
182 // so AddressTrackerLinux should not be used in later versions
183 // of Android. Chromium code doesn't need it past Android P.
184 DCHECK_LT(base::android::BuildInfo::GetInstance()->sdk_int(),
185 base::android::SDK_VERSION_P);
186#endif
Wez2d18a802019-02-01 23:44:50187 netlink_fd_.reset(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE));
188 if (!netlink_fd_.is_valid()) {
[email protected]67172802012-07-16 22:27:24189 PLOG(ERROR) << "Could not create NETLINK socket";
[email protected]d3eada52012-11-29 17:11:55190 AbortAndForceOnline();
[email protected]67172802012-07-16 22:27:24191 return;
192 }
193
guoweisf09e9972014-09-22 20:47:43194 int rv;
195
196 if (tracking_) {
197 // Request notifications.
198 struct sockaddr_nl addr = {};
199 addr.nl_family = AF_NETLINK;
Dan McArdle70968d32021-07-19 22:15:15200 addr.nl_pid = 0; // Let the kernel select a unique value.
guoweisf09e9972014-09-22 20:47:43201 // TODO(szym): Track RTMGRP_LINK as well for ifi_type,
202 // http://crbug.com/113993
203 addr.nl_groups =
204 RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY | RTMGRP_LINK;
Wez2d18a802019-02-01 23:44:50205 rv = bind(netlink_fd_.get(), reinterpret_cast<struct sockaddr*>(&addr),
206 sizeof(addr));
guoweisf09e9972014-09-22 20:47:43207 if (rv < 0) {
208 PLOG(ERROR) << "Could not bind NETLINK socket";
209 AbortAndForceOnline();
210 return;
211 }
[email protected]67172802012-07-16 22:27:24212 }
213
214 // Request dump of addresses.
215 struct sockaddr_nl peer = {};
216 peer.nl_family = AF_NETLINK;
217
218 struct {
219 struct nlmsghdr header;
220 struct rtgenmsg msg;
221 } request = {};
222
[email protected]ca3c13282012-12-03 21:13:29223 request.header.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg));
[email protected]67172802012-07-16 22:27:24224 request.header.nlmsg_type = RTM_GETADDR;
225 request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
Dan McArdle70968d32021-07-19 22:15:15226 request.header.nlmsg_pid = 0; // This field is opaque to netlink.
[email protected]67172802012-07-16 22:27:24227 request.msg.rtgen_family = AF_UNSPEC;
228
Wez2d18a802019-02-01 23:44:50229 rv = HANDLE_EINTR(
230 sendto(netlink_fd_.get(), &request, request.header.nlmsg_len, 0,
231 reinterpret_cast<struct sockaddr*>(&peer), sizeof(peer)));
[email protected]d3eada52012-11-29 17:11:55232 if (rv < 0) {
233 PLOG(ERROR) << "Could not send NETLINK request";
234 AbortAndForceOnline();
235 return;
236 }
237
238 // Consume pending message to populate the AddressMap, but don't notify.
239 // Sending another request without first reading responses results in EBUSY.
240 bool address_changed;
241 bool link_changed;
[email protected]cf71d772014-02-09 10:44:07242 bool tunnel_changed;
243 ReadMessages(&address_changed, &link_changed, &tunnel_changed);
[email protected]d3eada52012-11-29 17:11:55244
245 // Request dump of link state
246 request.header.nlmsg_type = RTM_GETLINK;
247
Wez2d18a802019-02-01 23:44:50248 rv = HANDLE_EINTR(
249 sendto(netlink_fd_.get(), &request, request.header.nlmsg_len, 0,
250 reinterpret_cast<struct sockaddr*>(&peer), sizeof(peer)));
[email protected]67172802012-07-16 22:27:24251 if (rv < 0) {
252 PLOG(ERROR) << "Could not send NETLINK request";
[email protected]d3eada52012-11-29 17:11:55253 AbortAndForceOnline();
[email protected]67172802012-07-16 22:27:24254 return;
255 }
256
[email protected]d3eada52012-11-29 17:11:55257 // Consume pending message to populate links_online_, but don't notify.
[email protected]cf71d772014-02-09 10:44:07258 ReadMessages(&address_changed, &link_changed, &tunnel_changed);
[email protected]d3eada52012-11-29 17:11:55259 {
derekjchow5482d5e2015-01-31 01:04:51260 AddressTrackerAutoLock lock(*this, connection_type_lock_);
261 connection_type_initialized_ = true;
jbriance26007802015-11-06 20:34:34262 connection_type_initialized_cv_.Broadcast();
[email protected]d3eada52012-11-29 17:11:55263 }
[email protected]a0a23c92012-09-05 14:28:26264
guoweisf09e9972014-09-22 20:47:43265 if (tracking_) {
Paul Jensen05f0f9782019-04-13 13:33:35266 watcher_ = base::FileDescriptorWatcher::WatchReadable(
267 netlink_fd_.get(),
268 base::BindRepeating(&AddressTrackerLinux::OnFileCanReadWithoutBlocking,
269 base::Unretained(this)));
[email protected]d3eada52012-11-29 17:11:55270 }
271}
272
Dan McArdle3a2da5a2021-07-16 21:45:47273bool AddressTrackerLinux::DidTrackingInitSucceedForTesting() const {
274 CHECK(tracking_);
275 return watcher_ != nullptr;
276}
277
[email protected]d3eada52012-11-29 17:11:55278void AddressTrackerLinux::AbortAndForceOnline() {
Paul Jensen05f0f9782019-04-13 13:33:35279 watcher_.reset();
Wez2d18a802019-02-01 23:44:50280 netlink_fd_.reset();
derekjchow5482d5e2015-01-31 01:04:51281 AddressTrackerAutoLock lock(*this, connection_type_lock_);
282 current_connection_type_ = NetworkChangeNotifier::CONNECTION_UNKNOWN;
283 connection_type_initialized_ = true;
jbriance26007802015-11-06 20:34:34284 connection_type_initialized_cv_.Broadcast();
[email protected]67172802012-07-16 22:27:24285}
286
287AddressTrackerLinux::AddressMap AddressTrackerLinux::GetAddressMap() const {
guoweisf09e9972014-09-22 20:47:43288 AddressTrackerAutoLock lock(*this, address_map_lock_);
[email protected]d3eada52012-11-29 17:11:55289 return address_map_;
[email protected]67172802012-07-16 22:27:24290}
291
davidben1e912ea2016-04-20 19:17:07292std::unordered_set<int> AddressTrackerLinux::GetOnlineLinks() const {
guoweisf09e9972014-09-22 20:47:43293 AddressTrackerAutoLock lock(*this, online_links_lock_);
294 return online_links_;
295}
296
derekjchowea1725c2015-05-08 03:16:01297bool AddressTrackerLinux::IsInterfaceIgnored(int interface_index) const {
298 if (ignored_interfaces_.empty())
299 return false;
300
301 char buf[IFNAMSIZ] = {0};
302 const char* interface_name = get_interface_name_(interface_index, buf);
303 return ignored_interfaces_.find(interface_name) != ignored_interfaces_.end();
304}
305
[email protected]d3eada52012-11-29 17:11:55306NetworkChangeNotifier::ConnectionType
307AddressTrackerLinux::GetCurrentConnectionType() {
308 // http://crbug.com/125097
Etienne Pierre-dorayc39fa832018-11-08 17:48:18309 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
derekjchow5482d5e2015-01-31 01:04:51310 AddressTrackerAutoLock lock(*this, connection_type_lock_);
311 // Make sure the initial connection type is set before returning.
jbriance26007802015-11-06 20:34:34312 threads_waiting_for_connection_type_initialization_++;
derekjchow5482d5e2015-01-31 01:04:51313 while (!connection_type_initialized_) {
314 connection_type_initialized_cv_.Wait();
[email protected]d3eada52012-11-29 17:11:55315 }
jbriance26007802015-11-06 20:34:34316 threads_waiting_for_connection_type_initialization_--;
derekjchow5482d5e2015-01-31 01:04:51317 return current_connection_type_;
[email protected]d3eada52012-11-29 17:11:55318}
319
320void AddressTrackerLinux::ReadMessages(bool* address_changed,
[email protected]cf71d772014-02-09 10:44:07321 bool* link_changed,
322 bool* tunnel_changed) {
[email protected]d3eada52012-11-29 17:11:55323 *address_changed = false;
324 *link_changed = false;
[email protected]cf71d772014-02-09 10:44:07325 *tunnel_changed = false;
[email protected]67172802012-07-16 22:27:24326 char buffer[4096];
[email protected]d3eada52012-11-29 17:11:55327 bool first_loop = true;
Francois Doray6d622442018-05-31 22:46:32328 {
Anton Bikineev068d2912021-05-15 20:43:52329 absl::optional<base::ScopedBlockingCall> blocking_call;
Etienne Pierre-dorayd98cee72018-08-24 17:55:11330 if (tracking_) {
331 // If the loop below takes a long time to run, a new thread should added
332 // to the current thread pool to ensure forward progress of all tasks.
Etienne Bergeron3d58bbd02019-02-27 18:19:21333 blocking_call.emplace(FROM_HERE, base::BlockingType::MAY_BLOCK);
Etienne Pierre-dorayd98cee72018-08-24 17:55:11334 }
Francois Doray6d622442018-05-31 22:46:32335
336 for (;;) {
Wez2d18a802019-02-01 23:44:50337 int rv = HANDLE_EINTR(recv(netlink_fd_.get(), buffer, sizeof(buffer),
Francois Doray6d622442018-05-31 22:46:32338 // Block the first time through loop.
339 first_loop ? 0 : MSG_DONTWAIT));
340 first_loop = false;
341 if (rv == 0) {
342 LOG(ERROR) << "Unexpected shutdown of NETLINK socket.";
343 return;
344 }
345 if (rv < 0) {
346 if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
347 break;
348 PLOG(ERROR) << "Failed to recv from netlink socket";
349 return;
350 }
351 HandleMessage(buffer, rv, address_changed, link_changed, tunnel_changed);
[email protected]67172802012-07-16 22:27:24352 }
guoweisf09e9972014-09-22 20:47:43353 }
derekjchow5482d5e2015-01-31 01:04:51354 if (*link_changed || *address_changed)
355 UpdateCurrentConnectionType();
[email protected]67172802012-07-16 22:27:24356}
357
Daniel McArdle9fb83692019-10-16 13:04:48358void AddressTrackerLinux::HandleMessage(const char* buffer,
Daniel McArdle47d05072019-10-18 18:27:28359 int length,
[email protected]d3eada52012-11-29 17:11:55360 bool* address_changed,
[email protected]cf71d772014-02-09 10:44:07361 bool* link_changed,
362 bool* tunnel_changed) {
[email protected]67172802012-07-16 22:27:24363 DCHECK(buffer);
Daniel McArdle47d05072019-10-18 18:27:28364 // Note that NLMSG_NEXT decrements |length| to reflect the number of bytes
365 // remaining in |buffer|.
Daniel McArdle9fb83692019-10-16 13:04:48366 for (const struct nlmsghdr* header =
367 reinterpret_cast<const struct nlmsghdr*>(buffer);
Daniel McArdle47d05072019-10-18 18:27:28368 length >= 0 && NLMSG_OK(header, static_cast<__u32>(length));
369 header = NLMSG_NEXT(header, length)) {
370 // The |header| pointer should never precede |buffer|.
371 DCHECK_LE(buffer, reinterpret_cast<const char*>(header));
[email protected]67172802012-07-16 22:27:24372 switch (header->nlmsg_type) {
373 case NLMSG_DONE:
[email protected]d3eada52012-11-29 17:11:55374 return;
375 case NLMSG_ERROR: {
376 const struct nlmsgerr* msg =
Daniel McArdle69d474462019-12-02 16:36:03377 SafelyCastNetlinkMsgData<const struct nlmsgerr>(header, length);
Daniel McArdled499a042019-11-04 18:33:00378 if (msg == nullptr)
379 return;
[email protected]d3eada52012-11-29 17:11:55380 LOG(ERROR) << "Unexpected netlink error " << msg->error << ".";
381 } return;
[email protected]67172802012-07-16 22:27:24382 case RTM_NEWADDR: {
martijnfe8914e2016-03-09 08:33:44383 IPAddress address;
[email protected]fb5dead2014-01-23 18:12:20384 bool really_deprecated;
Daniel McArdle69d474462019-12-02 16:36:03385 const struct ifaddrmsg* msg =
386 SafelyCastNetlinkMsgData<const struct ifaddrmsg>(header, length);
Daniel McArdled499a042019-11-04 18:33:00387 if (msg == nullptr)
388 return;
derekjchowea1725c2015-05-08 03:16:01389 if (IsInterfaceIgnored(msg->ifa_index))
390 break;
Daniel McArdle47d05072019-10-18 18:27:28391 if (GetAddress(header, length, &address, &really_deprecated)) {
Daniel McArdle69d474462019-12-02 16:36:03392 struct ifaddrmsg msg_copy = *msg;
guoweisf09e9972014-09-22 20:47:43393 AddressTrackerAutoLock lock(*this, address_map_lock_);
[email protected]fb5dead2014-01-23 18:12:20394 // Routers may frequently (every few seconds) output the IPv6 ULA
395 // prefix which can cause the linux kernel to frequently output two
396 // back-to-back messages, one without the deprecated flag and one with
397 // the deprecated flag but both with preferred lifetimes of 0. Avoid
Tsuyoshi Horo5c4f4e42022-07-29 05:51:51398 // interpreting this as an actual change by canonicalizing the two
[email protected]fb5dead2014-01-23 18:12:20399 // messages by setting the deprecated flag based on the preferred
400 // lifetime also. http://crbug.com/268042
401 if (really_deprecated)
Daniel McArdle69d474462019-12-02 16:36:03402 msg_copy.ifa_flags |= IFA_F_DEPRECATED;
[email protected]67172802012-07-16 22:27:24403 // Only indicate change if the address is new or ifaddrmsg info has
404 // changed.
jdoerrie22a91d8b92018-10-05 08:43:26405 auto it = address_map_.find(address);
[email protected]d3eada52012-11-29 17:11:55406 if (it == address_map_.end()) {
Daniel McArdle69d474462019-12-02 16:36:03407 address_map_.insert(it, std::make_pair(address, msg_copy));
[email protected]d3eada52012-11-29 17:11:55408 *address_changed = true;
Daniel McArdle69d474462019-12-02 16:36:03409 } else if (memcmp(&it->second, &msg_copy, sizeof(msg_copy))) {
410 it->second = msg_copy;
[email protected]d3eada52012-11-29 17:11:55411 *address_changed = true;
[email protected]67172802012-07-16 22:27:24412 }
413 }
414 } break;
415 case RTM_DELADDR: {
martijnfe8914e2016-03-09 08:33:44416 IPAddress address;
derekjchowea1725c2015-05-08 03:16:01417 const struct ifaddrmsg* msg =
Daniel McArdle69d474462019-12-02 16:36:03418 SafelyCastNetlinkMsgData<const struct ifaddrmsg>(header, length);
Daniel McArdled499a042019-11-04 18:33:00419 if (msg == nullptr)
420 return;
derekjchowea1725c2015-05-08 03:16:01421 if (IsInterfaceIgnored(msg->ifa_index))
422 break;
Daniel McArdle47d05072019-10-18 18:27:28423 if (GetAddress(header, length, &address, nullptr)) {
guoweisf09e9972014-09-22 20:47:43424 AddressTrackerAutoLock lock(*this, address_map_lock_);
[email protected]d3eada52012-11-29 17:11:55425 if (address_map_.erase(address))
426 *address_changed = true;
[email protected]67172802012-07-16 22:27:24427 }
428 } break;
[email protected]d3eada52012-11-29 17:11:55429 case RTM_NEWLINK: {
430 const struct ifinfomsg* msg =
Daniel McArdle69d474462019-12-02 16:36:03431 SafelyCastNetlinkMsgData<const struct ifinfomsg>(header, length);
Daniel McArdled499a042019-11-04 18:33:00432 if (msg == nullptr)
433 return;
derekjchowea1725c2015-05-08 03:16:01434 if (IsInterfaceIgnored(msg->ifi_index))
435 break;
Daniel McArdle47d05072019-10-18 18:27:28436 if (IgnoreWirelessChange(msg, IFLA_PAYLOAD(header))) {
derekjchow72407efa2015-06-20 02:59:43437 VLOG(2) << "Ignoring RTM_NEWLINK message";
438 break;
439 }
[email protected]d3eada52012-11-29 17:11:55440 if (!(msg->ifi_flags & IFF_LOOPBACK) && (msg->ifi_flags & IFF_UP) &&
441 (msg->ifi_flags & IFF_LOWER_UP) && (msg->ifi_flags & IFF_RUNNING)) {
guoweisf09e9972014-09-22 20:47:43442 AddressTrackerAutoLock lock(*this, online_links_lock_);
[email protected]cf71d772014-02-09 10:44:07443 if (online_links_.insert(msg->ifi_index).second) {
[email protected]d3eada52012-11-29 17:11:55444 *link_changed = true;
derekjchow5482d5e2015-01-31 01:04:51445 if (IsTunnelInterface(msg->ifi_index))
[email protected]cf71d772014-02-09 10:44:07446 *tunnel_changed = true;
447 }
[email protected]d3eada52012-11-29 17:11:55448 } else {
guoweisf09e9972014-09-22 20:47:43449 AddressTrackerAutoLock lock(*this, online_links_lock_);
[email protected]cf71d772014-02-09 10:44:07450 if (online_links_.erase(msg->ifi_index)) {
[email protected]d3eada52012-11-29 17:11:55451 *link_changed = true;
derekjchow5482d5e2015-01-31 01:04:51452 if (IsTunnelInterface(msg->ifi_index))
[email protected]cf71d772014-02-09 10:44:07453 *tunnel_changed = true;
454 }
[email protected]d3eada52012-11-29 17:11:55455 }
456 } break;
457 case RTM_DELLINK: {
458 const struct ifinfomsg* msg =
Daniel McArdle69d474462019-12-02 16:36:03459 SafelyCastNetlinkMsgData<const struct ifinfomsg>(header, length);
Daniel McArdled499a042019-11-04 18:33:00460 if (msg == nullptr)
461 return;
derekjchowea1725c2015-05-08 03:16:01462 if (IsInterfaceIgnored(msg->ifi_index))
463 break;
guoweisf09e9972014-09-22 20:47:43464 AddressTrackerAutoLock lock(*this, online_links_lock_);
[email protected]cf71d772014-02-09 10:44:07465 if (online_links_.erase(msg->ifi_index)) {
[email protected]d3eada52012-11-29 17:11:55466 *link_changed = true;
derekjchow5482d5e2015-01-31 01:04:51467 if (IsTunnelInterface(msg->ifi_index))
[email protected]cf71d772014-02-09 10:44:07468 *tunnel_changed = true;
469 }
[email protected]d3eada52012-11-29 17:11:55470 } break;
[email protected]67172802012-07-16 22:27:24471 default:
472 break;
473 }
474 }
[email protected]67172802012-07-16 22:27:24475}
476
Paul Jensen05f0f9782019-04-13 13:33:35477void AddressTrackerLinux::OnFileCanReadWithoutBlocking() {
[email protected]d3eada52012-11-29 17:11:55478 bool address_changed;
479 bool link_changed;
[email protected]cf71d772014-02-09 10:44:07480 bool tunnel_changed;
481 ReadMessages(&address_changed, &link_changed, &tunnel_changed);
[email protected]d3eada52012-11-29 17:11:55482 if (address_changed)
483 address_callback_.Run();
484 if (link_changed)
485 link_callback_.Run();
[email protected]cf71d772014-02-09 10:44:07486 if (tunnel_changed)
487 tunnel_callback_.Run();
[email protected]67172802012-07-16 22:27:24488}
489
derekjchow5482d5e2015-01-31 01:04:51490bool AddressTrackerLinux::IsTunnelInterface(int interface_index) const {
derekjchow5482d5e2015-01-31 01:04:51491 char buf[IFNAMSIZ] = {0};
Miriam Gershensona97831b22018-01-31 16:06:14492 return IsTunnelInterfaceName(get_interface_name_(interface_index, buf));
493}
494
495// static
496bool AddressTrackerLinux::IsTunnelInterfaceName(const char* name) {
497 // Linux kernel drivers/net/tun.c uses "tun" name prefix.
498 return strncmp(name, "tun", 3) == 0;
derekjchow5482d5e2015-01-31 01:04:51499}
500
501void AddressTrackerLinux::UpdateCurrentConnectionType() {
502 AddressTrackerLinux::AddressMap address_map = GetAddressMap();
davidben1e912ea2016-04-20 19:17:07503 std::unordered_set<int> online_links = GetOnlineLinks();
derekjchow5482d5e2015-01-31 01:04:51504
505 // Strip out tunnel interfaces from online_links
jdoerrie22a91d8b92018-10-05 08:43:26506 for (auto it = online_links.cbegin(); it != online_links.cend();) {
derekjchow5482d5e2015-01-31 01:04:51507 if (IsTunnelInterface(*it)) {
jdoerrie22a91d8b92018-10-05 08:43:26508 it = online_links.erase(it);
derekjchow5482d5e2015-01-31 01:04:51509 } else {
510 ++it;
511 }
512 }
513
514 NetworkInterfaceList networks;
515 NetworkChangeNotifier::ConnectionType type =
516 NetworkChangeNotifier::CONNECTION_NONE;
517 if (GetNetworkListImpl(&networks, 0, online_links, address_map,
518 get_interface_name_)) {
519 type = NetworkChangeNotifier::ConnectionTypeFromInterfaceList(networks);
520 } else {
521 type = online_links.empty() ? NetworkChangeNotifier::CONNECTION_NONE
522 : NetworkChangeNotifier::CONNECTION_UNKNOWN;
523 }
524
525 AddressTrackerAutoLock lock(*this, connection_type_lock_);
526 current_connection_type_ = type;
[email protected]cf71d772014-02-09 10:44:07527}
528
Daniel McArdle47d05072019-10-18 18:27:28529int AddressTrackerLinux::GetThreadsWaitingForConnectionTypeInitForTesting() {
jbriance26007802015-11-06 20:34:34530 AddressTrackerAutoLock lock(*this, connection_type_lock_);
531 return threads_waiting_for_connection_type_initialization_;
532}
533
guoweisf09e9972014-09-22 20:47:43534AddressTrackerLinux::AddressTrackerAutoLock::AddressTrackerAutoLock(
535 const AddressTrackerLinux& tracker,
536 base::Lock& lock)
537 : tracker_(tracker), lock_(lock) {
Ali Hijazi55179192022-11-09 16:28:51538 if (tracker_->tracking_) {
539 lock_->Acquire();
guoweisf09e9972014-09-22 20:47:43540 } else {
Ali Hijazi55179192022-11-09 16:28:51541 DCHECK(tracker_->thread_checker_.CalledOnValidThread());
guoweisf09e9972014-09-22 20:47:43542 }
543}
544
545AddressTrackerLinux::AddressTrackerAutoLock::~AddressTrackerAutoLock() {
Ali Hijazi55179192022-11-09 16:28:51546 if (tracker_->tracking_) {
547 lock_->AssertAcquired();
548 lock_->Release();
guoweisf09e9972014-09-22 20:47:43549 }
550}
551
Tsuyoshi Horo4f516be2022-06-14 11:53:13552} // namespace net::internal