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 // This is a small utility that watches for and logs network changes.
6 // It prints out the current network connection type and proxy configuration
7 // upon startup and then prints out changes as they happen.
8 // It's useful for testing NetworkChangeNotifier and ProxyConfigService.
9 // The only command line option supported is --ignore-netif which is followed
10 // by a comma seperated list of network interfaces to ignore when computing
11 // connection type; this option is only supported on linux.
12
13 #include <memory>
14 #include <string>
15 #include <unordered_set>
16
17 #include "base/at_exit.h"
18 #include "base/command_line.h"
19 #include "base/compiler_specific.h"
20 #include "base/json/json_writer.h"
21 #include "base/logging.h"
22 #include "base/message_loop/message_pump_type.h"
23 #include "base/run_loop.h"
24 #include "base/strings/string_split.h"
25 #include "base/task/single_thread_task_executor.h"
26 #include "base/task/thread_pool/thread_pool_instance.h"
27 #include "base/values.h"
28 #include "build/build_config.h"
29 #include "build/chromeos_buildflags.h"
30 #include "net/base/network_change_notifier.h"
31 #include "net/proxy_resolution/proxy_config.h"
32 #include "net/proxy_resolution/proxy_config_service.h"
33 #include "net/proxy_resolution/proxy_config_with_annotation.h"
34
35 #if BUILDFLAG(IS_LINUX)
36 #include "net/base/network_change_notifier_linux.h"
37 #endif
38
39 #if BUILDFLAG(IS_APPLE)
40 #include "base/apple/scoped_nsautorelease_pool.h"
41 #endif
42
43 namespace {
44
45 // TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
46 // of lacros-chrome is complete.
47 #if BUILDFLAG(IS_LINUX)
48 // Flag to specifies which network interfaces to ignore. Interfaces should
49 // follow as a comma seperated list.
50 const char kIgnoreNetifFlag[] = "ignore-netif";
51 #endif
52
53 // Conversions from various network-related types to string.
54
ConnectionTypeToString(net::NetworkChangeNotifier::ConnectionType type)55 const char* ConnectionTypeToString(
56 net::NetworkChangeNotifier::ConnectionType type) {
57 switch (type) {
58 case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
59 return "CONNECTION_UNKNOWN";
60 case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
61 return "CONNECTION_ETHERNET";
62 case net::NetworkChangeNotifier::CONNECTION_WIFI:
63 return "CONNECTION_WIFI";
64 case net::NetworkChangeNotifier::CONNECTION_2G:
65 return "CONNECTION_2G";
66 case net::NetworkChangeNotifier::CONNECTION_3G:
67 return "CONNECTION_3G";
68 case net::NetworkChangeNotifier::CONNECTION_4G:
69 return "CONNECTION_4G";
70 case net::NetworkChangeNotifier::CONNECTION_5G:
71 return "CONNECTION_5G";
72 case net::NetworkChangeNotifier::CONNECTION_NONE:
73 return "CONNECTION_NONE";
74 case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
75 return "CONNECTION_BLUETOOTH";
76 default:
77 return "CONNECTION_UNEXPECTED";
78 }
79 }
80
ProxyConfigToString(const net::ProxyConfig & config)81 std::string ProxyConfigToString(const net::ProxyConfig& config) {
82 base::Value config_value = config.ToValue();
83 std::string str;
84 base::JSONWriter::Write(config_value, &str);
85 return str;
86 }
87
ConfigAvailabilityToString(net::ProxyConfigService::ConfigAvailability availability)88 const char* ConfigAvailabilityToString(
89 net::ProxyConfigService::ConfigAvailability availability) {
90 switch (availability) {
91 case net::ProxyConfigService::CONFIG_PENDING:
92 return "CONFIG_PENDING";
93 case net::ProxyConfigService::CONFIG_VALID:
94 return "CONFIG_VALID";
95 case net::ProxyConfigService::CONFIG_UNSET:
96 return "CONFIG_UNSET";
97 default:
98 return "CONFIG_UNEXPECTED";
99 }
100 }
101
102 // The main observer class that logs network events.
103 class NetWatcher :
104 public net::NetworkChangeNotifier::IPAddressObserver,
105 public net::NetworkChangeNotifier::ConnectionTypeObserver,
106 public net::NetworkChangeNotifier::DNSObserver,
107 public net::NetworkChangeNotifier::NetworkChangeObserver,
108 public net::ProxyConfigService::Observer {
109 public:
110 NetWatcher() = default;
111
112 NetWatcher(const NetWatcher&) = delete;
113 NetWatcher& operator=(const NetWatcher&) = delete;
114
115 ~NetWatcher() override = default;
116
117 // net::NetworkChangeNotifier::IPAddressObserver implementation.
OnIPAddressChanged()118 void OnIPAddressChanged() override { LOG(INFO) << "OnIPAddressChanged()"; }
119
120 // net::NetworkChangeNotifier::ConnectionTypeObserver implementation.
OnConnectionTypeChanged(net::NetworkChangeNotifier::ConnectionType type)121 void OnConnectionTypeChanged(
122 net::NetworkChangeNotifier::ConnectionType type) override {
123 LOG(INFO) << "OnConnectionTypeChanged("
124 << ConnectionTypeToString(type) << ")";
125 }
126
127 // net::NetworkChangeNotifier::DNSObserver implementation.
OnDNSChanged()128 void OnDNSChanged() override { LOG(INFO) << "OnDNSChanged()"; }
129
130 // net::NetworkChangeNotifier::NetworkChangeObserver implementation.
OnNetworkChanged(net::NetworkChangeNotifier::ConnectionType type)131 void OnNetworkChanged(
132 net::NetworkChangeNotifier::ConnectionType type) override {
133 LOG(INFO) << "OnNetworkChanged("
134 << ConnectionTypeToString(type) << ")";
135 }
136
137 // net::ProxyConfigService::Observer implementation.
OnProxyConfigChanged(const net::ProxyConfigWithAnnotation & config,net::ProxyConfigService::ConfigAvailability availability)138 void OnProxyConfigChanged(
139 const net::ProxyConfigWithAnnotation& config,
140 net::ProxyConfigService::ConfigAvailability availability) override {
141 LOG(INFO) << "OnProxyConfigChanged(" << ProxyConfigToString(config.value())
142 << ", " << ConfigAvailabilityToString(availability) << ")";
143 }
144 };
145
146 } // namespace
147
main(int argc,char * argv[])148 int main(int argc, char* argv[]) {
149 #if BUILDFLAG(IS_APPLE)
150 base::apple::ScopedNSAutoreleasePool pool;
151 #endif
152 base::AtExitManager exit_manager;
153 base::CommandLine::Init(argc, argv);
154 logging::LoggingSettings settings;
155 settings.logging_dest =
156 logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
157 logging::InitLogging(settings);
158
159 // Just make the main task executor the network loop.
160 base::SingleThreadTaskExecutor io_task_executor(base::MessagePumpType::IO);
161
162 base::ThreadPoolInstance::CreateAndStartWithDefaultParams("NetWatcher");
163
164 NetWatcher net_watcher;
165
166 #if BUILDFLAG(IS_LINUX)
167 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
168 std::string ignored_netifs_str =
169 command_line->GetSwitchValueASCII(kIgnoreNetifFlag);
170 std::unordered_set<std::string> ignored_interfaces;
171 if (!ignored_netifs_str.empty()) {
172 for (const std::string& ignored_netif :
173 base::SplitString(ignored_netifs_str, ",", base::TRIM_WHITESPACE,
174 base::SPLIT_WANT_ALL)) {
175 LOG(INFO) << "Ignoring: " << ignored_netif;
176 ignored_interfaces.insert(ignored_netif);
177 }
178 }
179 auto network_change_notifier =
180 std::make_unique<net::NetworkChangeNotifierLinux>(ignored_interfaces);
181 #else
182 std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier(
183 net::NetworkChangeNotifier::CreateIfNeeded());
184 #endif
185
186 // Use the network loop as the file loop also.
187 std::unique_ptr<net::ProxyConfigService> proxy_config_service(
188 net::ProxyConfigService::CreateSystemProxyConfigService(
189 io_task_executor.task_runner()));
190
191 // Uses |network_change_notifier|.
192 net::NetworkChangeNotifier::AddIPAddressObserver(&net_watcher);
193 net::NetworkChangeNotifier::AddConnectionTypeObserver(&net_watcher);
194 net::NetworkChangeNotifier::AddDNSObserver(&net_watcher);
195 net::NetworkChangeNotifier::AddNetworkChangeObserver(&net_watcher);
196
197 proxy_config_service->AddObserver(&net_watcher);
198
199 LOG(INFO) << "Initial connection type: "
200 << ConnectionTypeToString(
201 net::NetworkChangeNotifier::GetConnectionType());
202
203 {
204 net::ProxyConfigWithAnnotation config;
205 const net::ProxyConfigService::ConfigAvailability availability =
206 proxy_config_service->GetLatestProxyConfig(&config);
207 LOG(INFO) << "Initial proxy config: " << ProxyConfigToString(config.value())
208 << ", " << ConfigAvailabilityToString(availability);
209 }
210
211 LOG(INFO) << "Watching for network events...";
212
213 // Start watching for events.
214 base::RunLoop().Run();
215
216 proxy_config_service->RemoveObserver(&net_watcher);
217
218 // Uses |network_change_notifier|.
219 net::NetworkChangeNotifier::RemoveDNSObserver(&net_watcher);
220 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(&net_watcher);
221 net::NetworkChangeNotifier::RemoveIPAddressObserver(&net_watcher);
222 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(&net_watcher);
223
224 return 0;
225 }
226