1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef NET_BASE_ADDRESS_TRACKER_LINUX_H_
6 #define NET_BASE_ADDRESS_TRACKER_LINUX_H_
7 
8 #include <sys/socket.h>  // Needed to include netlink.
9 // Mask superfluous definition of |struct net|. This is fixed in Linux 2.6.38.
10 #include <stddef.h>
11 
12 #include <map>
13 #include <memory>
14 #include <string>
15 #include <unordered_set>
16 
17 #include "base/callback.h"
18 #include "base/compiler_specific.h"
19 #include "base/files/file_descriptor_watcher_posix.h"
20 #include "base/files/scoped_file.h"
21 #include "base/synchronization/condition_variable.h"
22 #include "base/synchronization/lock.h"
23 #include "base/threading/thread_checker.h"
24 #include "net/base/ip_address.h"
25 #include "net/base/net_export.h"
26 #include "net/base/network_change_notifier.h"
27 
28 namespace net {
29 namespace internal {
30 
31 // Keeps track of network interface addresses using rtnetlink. Used by
32 // NetworkChangeNotifier to provide signals to registered IPAddressObservers.
33 class NET_EXPORT_PRIVATE AddressTrackerLinux {
34  public:
35   typedef std::map<IPAddress, struct ifaddrmsg> AddressMap;
36 
37   // Non-tracking version constructor: it takes a snapshot of the
38   // current system configuration. Once Init() returns, the
39   // configuration is available through GetOnlineLinks() and
40   // GetAddressMap().
41   AddressTrackerLinux();
42 
43   // Tracking version constructor: it will run |address_callback| when
44   // the AddressMap changes, |link_callback| when the list of online
45   // links changes, and |tunnel_callback| when the list of online
46   // tunnels changes.
47   // |ignored_interfaces| is the list of interfaces to ignore.  Changes to an
48   // ignored interface will not cause any callback to be run. An ignored
49   // interface will not have entries in GetAddressMap() and GetOnlineLinks().
50   // NOTE: Only ignore interfaces not used to connect to the internet. Adding
51   // interfaces used to connect to the internet can cause critical network
52   // changed signals to be lost allowing incorrect stale state to persist.
53   AddressTrackerLinux(
54       const base::RepeatingClosure& address_callback,
55       const base::RepeatingClosure& link_callback,
56       const base::RepeatingClosure& tunnel_callback,
57       const std::unordered_set<std::string>& ignored_interfaces);
58   virtual ~AddressTrackerLinux();
59 
60   // In tracking mode, it starts watching the system configuration for
61   // changes. The current thread must have a MessageLoopForIO. In
62   // non-tracking mode, once Init() returns, a snapshot of the system
63   // configuration is available through GetOnlineLinks() and
64   // GetAddressMap().
65   void Init();
66 
67   AddressMap GetAddressMap() const;
68 
69   // Returns set of interface indicies for online interfaces.
70   std::unordered_set<int> GetOnlineLinks() const;
71 
72   // Implementation of NetworkChangeNotifierLinux::GetCurrentConnectionType().
73   // Safe to call from any thread, but will block until Init() has completed.
74   NetworkChangeNotifier::ConnectionType GetCurrentConnectionType();
75 
76   // Returns the name for the interface with interface index |interface_index|.
77   // |buf| should be a pointer to an array of size IFNAMSIZ. The returned
78   // pointer will point to |buf|. This function acts like if_indextoname which
79   // cannot be used as net/if.h cannot be mixed with linux/if.h. We'll stick
80   // with exclusively talking to the kernel and not the C library.
81   static char* GetInterfaceName(int interface_index, char* buf);
82 
83   // Does |name| refer to a tunnel interface?
84   static bool IsTunnelInterfaceName(const char* name);
85 
86  private:
87   friend class AddressTrackerLinuxTest;
88 
89   // In tracking mode, holds |lock| while alive. In non-tracking mode,
90   // enforces single-threaded access.
91   class AddressTrackerAutoLock {
92    public:
93     AddressTrackerAutoLock(const AddressTrackerLinux& tracker,
94                            base::Lock& lock);
95     AddressTrackerAutoLock(const AddressTrackerAutoLock&) = delete;
96     AddressTrackerAutoLock& operator=(const AddressTrackerAutoLock&) = delete;
97     ~AddressTrackerAutoLock();
98 
99    private:
100     const AddressTrackerLinux& tracker_;
101     base::Lock& lock_;
102   };
103 
104   // A function that returns the name of an interface given the interface index
105   // in |interface_index|. |ifname| should be a buffer of size IFNAMSIZ. The
106   // function should return a pointer to |ifname|.
107   typedef char* (*GetInterfaceNameFunction)(int interface_index, char* ifname);
108 
109   // Sets |*address_changed| to indicate whether |address_map_| changed and
110   // sets |*link_changed| to indicate if |online_links_| changed and sets
111   // |*tunnel_changed| to indicate if |online_links_| changed with regards to a
112   // tunnel interface while reading messages from |netlink_fd_|.
113   void ReadMessages(bool* address_changed,
114                     bool* link_changed,
115                     bool* tunnel_changed);
116 
117   // Sets |*address_changed| to true if |address_map_| changed, sets
118   // |*link_changed| to true if |online_links_| changed, sets |*tunnel_changed|
119   // to true if |online_links_| changed with regards to a tunnel interface while
120   // reading the message from |buffer|.
121   void HandleMessage(const char* buffer,
122                      int length,
123                      bool* address_changed,
124                      bool* link_changed,
125                      bool* tunnel_changed);
126 
127   // Call when some part of initialization failed; forces online and unblocks.
128   void AbortAndForceOnline();
129 
130   // Called by |watcher_| when |netlink_fd_| can be read without blocking.
131   void OnFileCanReadWithoutBlocking();
132 
133   // Does |interface_index| refer to a tunnel interface?
134   bool IsTunnelInterface(int interface_index) const;
135 
136   // Is interface with index |interface_index| in list of ignored interfaces?
137   bool IsInterfaceIgnored(int interface_index) const;
138 
139   // Updates current_connection_type_ based on the network list.
140   void UpdateCurrentConnectionType();
141 
142   // Used by AddressTrackerLinuxTest, returns the number of threads waiting
143   // for |connection_type_initialized_cv_|.
144   int GetThreadsWaitingForConnectionTypeInitForTesting();
145 
146   // Gets the name of an interface given the interface index |interface_index|.
147   // May return empty string if it fails but should not return NULL. This is
148   // overridden by tests.
149   GetInterfaceNameFunction get_interface_name_;
150 
151   base::RepeatingClosure address_callback_;
152   base::RepeatingClosure link_callback_;
153   base::RepeatingClosure tunnel_callback_;
154 
155   // Note that |watcher_| must be inactive when |netlink_fd_| is closed.
156   base::ScopedFD netlink_fd_;
157   std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher_;
158 
159   mutable base::Lock address_map_lock_;
160   AddressMap address_map_;
161 
162   // Set of interface indices for links that are currently online.
163   mutable base::Lock online_links_lock_;
164   std::unordered_set<int> online_links_;
165 
166   // Set of interface names that should be ignored.
167   const std::unordered_set<std::string> ignored_interfaces_;
168 
169   base::Lock connection_type_lock_;
170   bool connection_type_initialized_;
171   base::ConditionVariable connection_type_initialized_cv_;
172   NetworkChangeNotifier::ConnectionType current_connection_type_;
173   bool tracking_;
174   int threads_waiting_for_connection_type_initialization_;
175 
176   // Used to verify single-threaded access in non-tracking mode.
177   base::ThreadChecker thread_checker_;
178 };
179 
180 }  // namespace internal
181 }  // namespace net
182 
183 #endif  // NET_BASE_ADDRESS_TRACKER_LINUX_H_
184