summaryrefslogtreecommitdiff
path: root/chromium/net/base/address_tracker_linux.h
blob: c993318ed74618c1a542f8927289b946546b74e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_BASE_ADDRESS_TRACKER_LINUX_H_
#define NET_BASE_ADDRESS_TRACKER_LINUX_H_

#include <sys/socket.h>  // Needed to include netlink.
// Mask superfluous definition of |struct net|. This is fixed in Linux 2.6.38.
#define net net_kernel
#include <linux/rtnetlink.h>
#undef net
#include <stddef.h>

#include <map>
#include <memory>
#include <string>
#include <unordered_set>

#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/files/file_descriptor_watcher_posix.h"
#include "base/files/scoped_file.h"
#include "base/gtest_prod_util.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "net/base/ip_address.h"
#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"

namespace net {
namespace internal {

// Keeps track of network interface addresses using rtnetlink. Used by
// NetworkChangeNotifier to provide signals to registered IPAddressObservers.
class NET_EXPORT_PRIVATE AddressTrackerLinux {
 public:
  typedef std::map<IPAddress, struct ifaddrmsg> AddressMap;

  // Non-tracking version constructor: it takes a snapshot of the
  // current system configuration. Once Init() returns, the
  // configuration is available through GetOnlineLinks() and
  // GetAddressMap().
  AddressTrackerLinux();

  // Tracking version constructor: it will run |address_callback| when
  // the AddressMap changes, |link_callback| when the list of online
  // links changes, and |tunnel_callback| when the list of online
  // tunnels changes.
  // |ignored_interfaces| is the list of interfaces to ignore.  Changes to an
  // ignored interface will not cause any callback to be run. An ignored
  // interface will not have entries in GetAddressMap() and GetOnlineLinks().
  // NOTE: Only ignore interfaces not used to connect to the internet. Adding
  // interfaces used to connect to the internet can cause critical network
  // changed signals to be lost allowing incorrect stale state to persist.
  AddressTrackerLinux(
      const base::RepeatingClosure& address_callback,
      const base::RepeatingClosure& link_callback,
      const base::RepeatingClosure& tunnel_callback,
      const std::unordered_set<std::string>& ignored_interfaces);
  virtual ~AddressTrackerLinux();

  // In tracking mode, it starts watching the system configuration for
  // changes. The current thread must have a MessageLoopForIO. In
  // non-tracking mode, once Init() returns, a snapshot of the system
  // configuration is available through GetOnlineLinks() and
  // GetAddressMap().
  void Init();

  AddressMap GetAddressMap() const;

  // Returns set of interface indicies for online interfaces.
  std::unordered_set<int> GetOnlineLinks() const;

  // Implementation of NetworkChangeNotifierLinux::GetCurrentConnectionType().
  // Safe to call from any thread, but will block until Init() has completed.
  NetworkChangeNotifier::ConnectionType GetCurrentConnectionType();

  // Returns the name for the interface with interface index |interface_index|.
  // |buf| should be a pointer to an array of size IFNAMSIZ. The returned
  // pointer will point to |buf|. This function acts like if_indextoname which
  // cannot be used as net/if.h cannot be mixed with linux/if.h. We'll stick
  // with exclusively talking to the kernel and not the C library.
  static char* GetInterfaceName(int interface_index, char* buf);

  // Does |name| refer to a tunnel interface?
  static bool IsTunnelInterfaceName(const char* name);

 private:
  friend class AddressTrackerLinuxTest;
  FRIEND_TEST_ALL_PREFIXES(AddressTrackerLinuxNetlinkTest,
                           TestInitializeTwoTrackers);
  FRIEND_TEST_ALL_PREFIXES(AddressTrackerLinuxNetlinkTest,
                           TestInitializeTwoTrackersInPidNamespaces);
  friend int ChildProcessInitializeTrackerForTesting();

  // In tracking mode, holds |lock| while alive. In non-tracking mode,
  // enforces single-threaded access.
  class AddressTrackerAutoLock {
   public:
    AddressTrackerAutoLock(const AddressTrackerLinux& tracker,
                           base::Lock& lock);
    AddressTrackerAutoLock(const AddressTrackerAutoLock&) = delete;
    AddressTrackerAutoLock& operator=(const AddressTrackerAutoLock&) = delete;
    ~AddressTrackerAutoLock();

   private:
    const AddressTrackerLinux& tracker_;
    base::Lock& lock_;
  };

  // A function that returns the name of an interface given the interface index
  // in |interface_index|. |ifname| should be a buffer of size IFNAMSIZ. The
  // function should return a pointer to |ifname|.
  typedef char* (*GetInterfaceNameFunction)(int interface_index, char* ifname);

  // Sets |*address_changed| to indicate whether |address_map_| changed and
  // sets |*link_changed| to indicate if |online_links_| changed and sets
  // |*tunnel_changed| to indicate if |online_links_| changed with regards to a
  // tunnel interface while reading messages from |netlink_fd_|.
  void ReadMessages(bool* address_changed,
                    bool* link_changed,
                    bool* tunnel_changed);

  // Sets |*address_changed| to true if |address_map_| changed, sets
  // |*link_changed| to true if |online_links_| changed, sets |*tunnel_changed|
  // to true if |online_links_| changed with regards to a tunnel interface while
  // reading the message from |buffer|.
  void HandleMessage(const char* buffer,
                     int length,
                     bool* address_changed,
                     bool* link_changed,
                     bool* tunnel_changed);

  // Call when some part of initialization failed; forces online and unblocks.
  void AbortAndForceOnline();

  // Called by |watcher_| when |netlink_fd_| can be read without blocking.
  void OnFileCanReadWithoutBlocking();

  // Does |interface_index| refer to a tunnel interface?
  bool IsTunnelInterface(int interface_index) const;

  // Is interface with index |interface_index| in list of ignored interfaces?
  bool IsInterfaceIgnored(int interface_index) const;

  // Updates current_connection_type_ based on the network list.
  void UpdateCurrentConnectionType();

  // Used by AddressTrackerLinuxTest, returns the number of threads waiting
  // for |connection_type_initialized_cv_|.
  int GetThreadsWaitingForConnectionTypeInitForTesting();

  // Used by AddressTrackerLinuxNetlinkTest, returns true iff `Init` succeeded.
  // Undefined for non-tracking mode.
  bool DidTrackingInitSucceedForTesting() const;

  // Gets the name of an interface given the interface index |interface_index|.
  // May return empty string if it fails but should not return NULL. This is
  // overridden by tests.
  GetInterfaceNameFunction get_interface_name_;

  base::RepeatingClosure address_callback_;
  base::RepeatingClosure link_callback_;
  base::RepeatingClosure tunnel_callback_;

  // Note that |watcher_| must be inactive when |netlink_fd_| is closed.
  base::ScopedFD netlink_fd_;
  std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher_;

  mutable base::Lock address_map_lock_;
  AddressMap address_map_;

  // Set of interface indices for links that are currently online.
  mutable base::Lock online_links_lock_;
  std::unordered_set<int> online_links_;

  // Set of interface names that should be ignored.
  const std::unordered_set<std::string> ignored_interfaces_;

  base::Lock connection_type_lock_;
  bool connection_type_initialized_;
  base::ConditionVariable connection_type_initialized_cv_;
  NetworkChangeNotifier::ConnectionType current_connection_type_;
  bool tracking_;
  int threads_waiting_for_connection_type_initialization_;

  // Used to verify single-threaded access in non-tracking mode.
  base::ThreadChecker thread_checker_;
};

}  // namespace internal
}  // namespace net

#endif  // NET_BASE_ADDRESS_TRACKER_LINUX_H_