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