networking_log.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. // Copyright 2021 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. #include "ash/system/diagnostics/networking_log.h"
  5. #include <sstream>
  6. #include <utility>
  7. #include "base/check.h"
  8. #include "base/containers/contains.h"
  9. #include "base/i18n/time_formatting.h"
  10. #include "base/notreached.h"
  11. #include "base/strings/string_number_conversions.h"
  12. #include "base/strings/string_util.h"
  13. #include "base/strings/stringprintf.h"
  14. #include "base/strings/utf_string_conversions.h"
  15. #include "base/time/time.h"
  16. namespace ash {
  17. namespace diagnostics {
  18. namespace {
  19. const char kNewline[] = "\n";
  20. // NetworkingInfo constants:
  21. const char kNetworkingInfoSectionName[] = "--- Network Info ---";
  22. const char kNetworkEventsSectionName[] = "--- Network Events ---";
  23. const char kNetworkNameTitle[] = "Name: ";
  24. const char kNetworkTypeTitle[] = "Type: ";
  25. const char kNetworkStateTitle[] = "State: ";
  26. const char kActiveTitle[] = "Active: ";
  27. const char kMacAddressTitle[] = "MAC Address: ";
  28. // CellularStateProperties constants:
  29. const char kCellularIccidTitle[] = "ICCID: ";
  30. const char kCellularEidTitle[] = "EID: ";
  31. const char kCellularNetworkTechnologyTitle[] = "Technology: ";
  32. const char kCellularRoamingTitle[] = "Roaming: ";
  33. const char kCellularRoamingStateTitle[] = "Roaming State: ";
  34. const char kCellularSignalStrengthTitle[] = "Signal Strength: ";
  35. const char kCellularSimLockedTitle[] = "SIM Locked: ";
  36. const char kCellularLockTypeTitle[] = "SIM Lock Type: ";
  37. // EthernetStateProperties constants:
  38. const char kEthernetAuthenticationTitle[] = "Authentication: ";
  39. // WiFiStateProperties constants:
  40. const char kWifiSignalStrengthTitle[] = "Signal Strength: ";
  41. const char kWifiFrequencyTitle[] = "Frequency: ";
  42. const char kWifiSsidTitle[] = "SSID: ";
  43. const char kWifiBssidTitle[] = "BSSID: ";
  44. const char kSecurityTitle[] = "Security: ";
  45. // IpConfigProperties constants:
  46. const char kNameServersTitle[] = "Name Servers: ";
  47. const char kGatewayTitle[] = "Gateway: ";
  48. const char kIPAddressTitle[] = "IP Address: ";
  49. const char kSubnetMaskTitle[] = "Subnet Mask: ";
  50. // Event log entries
  51. const char kEventLogFilename[] = "network_events.log";
  52. const char kNetworkAddedEventTemplate[] =
  53. "%s network [%s] started in state %s\n";
  54. const char kNetworkRemovedEventTemplate[] = "%s network [%s] removed\n";
  55. const char kNetworkStateChangedEventTemplate[] =
  56. "%s network [%s] changed state from %s to %s\n";
  57. const char kJoinedWiFiEventTemplate[] =
  58. "%s network [%s] joined SSID '%s' on access point [%s]\n";
  59. const char kLeftWiFiEventTemplate[] = "%s network [%s] left SSID '%s'\n";
  60. const char kAccessPointRoamingEventTemplate[] =
  61. "%s network [%s] on SSID '%s' roamed from access point [%s] to [%s]\n";
  62. std::string GetSubnetMask(int prefix) {
  63. uint32_t mask = (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF;
  64. std::vector<uint32_t> pieces = {mask >> 24, (mask >> 16) & 0xFF,
  65. (mask >> 8) & 0xFF, mask & 0xFF};
  66. std::vector<std::string> vec;
  67. for (const auto& piece : pieces) {
  68. vec.push_back(base::NumberToString(piece));
  69. }
  70. return base::JoinString(vec, ".");
  71. }
  72. std::string GetSecurityType(mojom::SecurityType type) {
  73. switch (type) {
  74. case mojom::SecurityType::kNone:
  75. return "None";
  76. case mojom::SecurityType::kWep8021x:
  77. case mojom::SecurityType::kWpaEap:
  78. return "EAP";
  79. case mojom::SecurityType::kWepPsk:
  80. return "WEP";
  81. case mojom::SecurityType::kWpaPsk:
  82. return "PSK (WPA or RSN)";
  83. }
  84. }
  85. std::string GetSsid(const mojom::NetworkPtr& network) {
  86. DCHECK(network->type == mojom::NetworkType::kWiFi);
  87. return network->type_properties ? network->type_properties->get_wifi()->ssid
  88. : "";
  89. }
  90. std::string GetBssid(const mojom::NetworkPtr& network) {
  91. DCHECK(network->type == mojom::NetworkType::kWiFi);
  92. return network->type_properties ? network->type_properties->get_wifi()->bssid
  93. : "";
  94. }
  95. bool HasJoinedWiFiNetwork(const mojom::NetworkPtr& old_state,
  96. const mojom::NetworkPtr& new_state) {
  97. const std::string old_ssid = GetSsid(old_state);
  98. return old_ssid.empty() && (old_ssid != GetSsid(new_state));
  99. }
  100. bool HasLeftWiFiNetwork(const mojom::NetworkPtr& old_state,
  101. const mojom::NetworkPtr& new_state) {
  102. const std::string new_ssid = GetSsid(new_state);
  103. return new_ssid.empty() && (new_ssid != GetSsid(old_state));
  104. }
  105. bool HasRoamedAccessPoint(const mojom::NetworkPtr& old_state,
  106. const mojom::NetworkPtr& new_state) {
  107. const std::string new_ssid = GetSsid(new_state);
  108. return !new_ssid.empty() && (new_ssid == GetSsid(old_state)) &&
  109. (GetBssid(old_state) != GetBssid(new_state));
  110. }
  111. void AddWifiInfoToLog(const mojom::NetworkTypeProperties& type_props,
  112. std::stringstream& output) {
  113. output << kWifiSignalStrengthTitle << type_props.get_wifi()->signal_strength
  114. << kNewline << kWifiFrequencyTitle << type_props.get_wifi()->frequency
  115. << kNewline << kWifiSsidTitle << type_props.get_wifi()->ssid
  116. << kNewline << kWifiBssidTitle << type_props.get_wifi()->bssid
  117. << kNewline << kSecurityTitle
  118. << GetSecurityType(type_props.get_wifi()->security) << kNewline;
  119. }
  120. std::string GetBoolAsString(bool value) {
  121. return value ? "True" : "False";
  122. }
  123. std::string GetCellularRoamingState(mojom::RoamingState state) {
  124. switch (state) {
  125. case mojom::RoamingState::kNone:
  126. return "None";
  127. case mojom::RoamingState::kHome:
  128. return "Home";
  129. case mojom::RoamingState::kRoaming:
  130. return "Roaming";
  131. }
  132. }
  133. std::string GetCellularLockType(mojom::LockType lock_type) {
  134. switch (lock_type) {
  135. case mojom::LockType::kNone:
  136. return "None";
  137. case mojom::LockType::kSimPin:
  138. return "sim-pin";
  139. case mojom::LockType::kSimPuk:
  140. return "sim-puk";
  141. }
  142. }
  143. void AddCellularInfoToLog(const mojom::NetworkTypeProperties& type_props,
  144. std::stringstream& output) {
  145. output << kCellularIccidTitle << type_props.get_cellular()->iccid << kNewline
  146. << kCellularEidTitle << type_props.get_cellular()->eid << kNewline
  147. << kCellularNetworkTechnologyTitle
  148. << type_props.get_cellular()->network_technology << kNewline
  149. << kCellularRoamingTitle
  150. << GetBoolAsString(type_props.get_cellular()->roaming) << kNewline
  151. << kCellularRoamingStateTitle
  152. << GetCellularRoamingState(type_props.get_cellular()->roaming_state)
  153. << kNewline << kCellularSignalStrengthTitle
  154. << type_props.get_cellular()->signal_strength << kNewline
  155. << kCellularSimLockedTitle
  156. << GetBoolAsString(type_props.get_cellular()->sim_locked) << kNewline
  157. << kCellularLockTypeTitle
  158. << GetCellularLockType(type_props.get_cellular()->lock_type)
  159. << kNewline;
  160. }
  161. std::string GetEthernetAuthenticationType(mojom::AuthenticationType type) {
  162. switch (type) {
  163. case mojom::AuthenticationType::kNone:
  164. return "None";
  165. case mojom::AuthenticationType::k8021x:
  166. return "EAP";
  167. }
  168. }
  169. void AddEthernetInfoToLog(const mojom::NetworkTypeProperties& type_props,
  170. std::stringstream& output) {
  171. output << kEthernetAuthenticationTitle
  172. << GetEthernetAuthenticationType(
  173. type_props.get_ethernet()->authentication)
  174. << kNewline;
  175. }
  176. void AddTypePropertiesToLog(const mojom::NetworkTypeProperties& type_props,
  177. mojom::NetworkType type,
  178. std::stringstream& output) {
  179. switch (type) {
  180. case mojom::NetworkType::kWiFi:
  181. AddWifiInfoToLog(type_props, output);
  182. break;
  183. case mojom::NetworkType::kCellular:
  184. AddCellularInfoToLog(type_props, output);
  185. break;
  186. case mojom::NetworkType::kEthernet:
  187. AddEthernetInfoToLog(type_props, output);
  188. break;
  189. case mojom::NetworkType::kUnsupported:
  190. NOTREACHED();
  191. break;
  192. }
  193. }
  194. void AddIPConfigPropertiesToLog(const mojom::IPConfigProperties& ip_config,
  195. std::stringstream& output) {
  196. output << kGatewayTitle << ip_config.gateway.value_or("") << kNewline;
  197. output << kIPAddressTitle << ip_config.ip_address.value_or("") << kNewline;
  198. auto name_servers = base::JoinString(
  199. ip_config.name_servers.value_or(std::vector<std::string>()), ", ");
  200. output << kNameServersTitle << name_servers << kNewline;
  201. // A routing prefix can not be 0, 0 indicates an unset value.
  202. auto subnet_mask = ip_config.routing_prefix != 0
  203. ? GetSubnetMask(ip_config.routing_prefix)
  204. : "";
  205. output << kSubnetMaskTitle << subnet_mask << kNewline;
  206. }
  207. std::string GetNetworkStateString(mojom::NetworkState state) {
  208. switch (state) {
  209. case mojom::NetworkState::kOnline:
  210. return "Online";
  211. case mojom::NetworkState::kConnected:
  212. return "Connected";
  213. case mojom::NetworkState::kConnecting:
  214. return "Connecting";
  215. case mojom::NetworkState::kNotConnected:
  216. return "Not Connected";
  217. case mojom::NetworkState::kDisabled:
  218. return "Disabled";
  219. case mojom::NetworkState::kPortal:
  220. return "Portal";
  221. }
  222. }
  223. std::string GetNetworkType(mojom::NetworkType type) {
  224. switch (type) {
  225. case mojom::NetworkType::kWiFi:
  226. return "WiFi";
  227. case mojom::NetworkType::kCellular:
  228. return "Cellular";
  229. case mojom::NetworkType::kEthernet:
  230. return "Ethernet";
  231. case mojom::NetworkType::kUnsupported:
  232. NOTREACHED();
  233. return "";
  234. }
  235. }
  236. } // namespace
  237. NetworkingLog::NetworkingLog(const base::FilePath& log_base_path)
  238. : event_log_(log_base_path.Append(kEventLogFilename)) {}
  239. NetworkingLog::~NetworkingLog() = default;
  240. std::string NetworkingLog::GetNetworkInfo() const {
  241. std::stringstream output;
  242. output << kNetworkingInfoSectionName << kNewline;
  243. for (const auto& pair : latest_network_states_) {
  244. const mojom::NetworkPtr& network = pair.second;
  245. output << kNewline << kNetworkNameTitle << network->name << kNewline
  246. << kNetworkTypeTitle << GetNetworkType(network->type) << kNewline
  247. << kNetworkStateTitle << GetNetworkStateString(network->state)
  248. << kNewline << kActiveTitle
  249. << (network->observer_guid == active_guid_ ? "True" : "False")
  250. << kNewline << kMacAddressTitle << network->mac_address.value_or("")
  251. << kNewline;
  252. if (network->type_properties) {
  253. AddTypePropertiesToLog(*network->type_properties, network->type, output);
  254. }
  255. if (network->ip_config) {
  256. AddIPConfigPropertiesToLog(*network->ip_config, output);
  257. }
  258. }
  259. return output.str();
  260. }
  261. std::string NetworkingLog::GetNetworkEvents() const {
  262. return std::string(kNetworkEventsSectionName) + kNewline + kNewline +
  263. event_log_.GetContents();
  264. }
  265. void NetworkingLog::UpdateNetworkList(
  266. const std::vector<std::string>& observer_guids,
  267. std::string active_guid) {
  268. // If a network is no longer valid, remove it from the map.
  269. for (auto iter = latest_network_states_.begin();
  270. iter != latest_network_states_.end();) {
  271. if (!base::Contains(observer_guids, iter->first)) {
  272. LogNetworkRemoved(iter->second);
  273. iter = latest_network_states_.erase(iter);
  274. continue;
  275. }
  276. ++iter;
  277. }
  278. active_guid_ = active_guid;
  279. }
  280. void NetworkingLog::UpdateNetworkState(mojom::NetworkPtr network) {
  281. if (network.is_null()) {
  282. LOG(ERROR) << "Network to log update is null";
  283. return;
  284. }
  285. if (!base::Contains(latest_network_states_, network->observer_guid)) {
  286. LogNetworkAdded(network);
  287. latest_network_states_.emplace(network->observer_guid, std::move(network));
  288. return;
  289. }
  290. LogNetworkChanges(network);
  291. latest_network_states_[network->observer_guid] = std::move(network);
  292. }
  293. void NetworkingLog::LogEvent(const std::string& event_string) {
  294. const std::string datetime =
  295. base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(base::Time::Now()));
  296. event_log_.Append(datetime + " - " + event_string);
  297. }
  298. void NetworkingLog::LogNetworkAdded(const mojom::NetworkPtr& network) {
  299. const std::string line = base::StringPrintf(
  300. kNetworkAddedEventTemplate, GetNetworkType(network->type).c_str(),
  301. network->mac_address.value_or("").c_str(),
  302. GetNetworkStateString(network->state).c_str());
  303. LogEvent(line);
  304. }
  305. void NetworkingLog::LogNetworkRemoved(const mojom::NetworkPtr& network) {
  306. if (network.is_null()) {
  307. LOG(ERROR) << "Network to log removal is null";
  308. return;
  309. }
  310. const std::string line = base::StringPrintf(
  311. kNetworkRemovedEventTemplate, GetNetworkType(network->type).c_str(),
  312. network->mac_address.value_or("").c_str());
  313. LogEvent(line);
  314. }
  315. void NetworkingLog::LogNetworkChanges(const mojom::NetworkPtr& new_state) {
  316. DCHECK(base::Contains(latest_network_states_, new_state->observer_guid));
  317. const mojom::NetworkPtr& old_state =
  318. latest_network_states_.at(new_state->observer_guid);
  319. if (new_state->type == mojom::NetworkType::kWiFi) {
  320. if (HasJoinedWiFiNetwork(old_state, new_state)) {
  321. LogJoinedWiFiNetwork(new_state);
  322. } else if (HasLeftWiFiNetwork(old_state, new_state)) {
  323. LogLeftWiFiNetwork(new_state, GetSsid(old_state));
  324. } else if (HasRoamedAccessPoint(old_state, new_state)) {
  325. LogWiFiRoamedAccessPoint(new_state, GetBssid(old_state));
  326. }
  327. }
  328. if (old_state->state != new_state->state) {
  329. LogNetworkStateChanged(old_state, new_state);
  330. }
  331. }
  332. void NetworkingLog::LogNetworkStateChanged(const mojom::NetworkPtr& old_state,
  333. const mojom::NetworkPtr& new_state) {
  334. const std::string line =
  335. base::StringPrintf(kNetworkStateChangedEventTemplate,
  336. GetNetworkType(new_state->type).c_str(),
  337. new_state->mac_address.value_or("").c_str(),
  338. GetNetworkStateString(old_state->state).c_str(),
  339. GetNetworkStateString(new_state->state).c_str());
  340. LogEvent(line);
  341. }
  342. void NetworkingLog::LogJoinedWiFiNetwork(const mojom::NetworkPtr& network) {
  343. const std::string line = base::StringPrintf(
  344. kJoinedWiFiEventTemplate, GetNetworkType(network->type).c_str(),
  345. network->mac_address.value_or("").c_str(), GetSsid(network).c_str(),
  346. GetBssid(network).c_str());
  347. LogEvent(line);
  348. }
  349. void NetworkingLog::LogLeftWiFiNetwork(const mojom::NetworkPtr& network,
  350. const std::string& old_ssid) {
  351. const std::string line = base::StringPrintf(
  352. kLeftWiFiEventTemplate, GetNetworkType(network->type).c_str(),
  353. network->mac_address.value_or("").c_str(), old_ssid.c_str());
  354. LogEvent(line);
  355. }
  356. void NetworkingLog::LogWiFiRoamedAccessPoint(const mojom::NetworkPtr& network,
  357. const std::string& old_bssid) {
  358. const std::string line = base::StringPrintf(
  359. kAccessPointRoamingEventTemplate, GetNetworkType(network->type).c_str(),
  360. network->mac_address.value_or("").c_str(), GetSsid(network).c_str(),
  361. old_bssid.c_str(), GetBssid(network).c_str());
  362. LogEvent(line);
  363. }
  364. } // namespace diagnostics
  365. } // namespace ash