PageRenderTime 27ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/net/base/network_interfaces_linux.cc

http://github.com/chromium/chromium
C++ | 236 lines | 171 code | 39 blank | 26 comment | 37 complexity | fddd072a1cbe91925d67b9be6643d1cc MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, BSD-2-Clause, LGPL-2.1, MPL-2.0, 0BSD, EPL-1.0, MPL-2.0-no-copyleft-exception, GPL-2.0, BitTorrent-1.0, CPL-1.0, LGPL-3.0, Unlicense, BSD-3-Clause, CC0-1.0, JSON, MIT, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0
  1. // Copyright (c) 2014 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 "net/base/network_interfaces_linux.h"
  5. #include <memory>
  6. #if !defined(OS_ANDROID)
  7. #include <linux/ethtool.h>
  8. #endif // !defined(OS_ANDROID)
  9. #include <linux/if.h>
  10. #include <linux/sockios.h>
  11. #include <linux/wireless.h>
  12. #include <set>
  13. #include <sys/ioctl.h>
  14. #include <sys/types.h>
  15. #include "base/files/file_path.h"
  16. #include "base/files/scoped_file.h"
  17. #include "base/strings/string_number_conversions.h"
  18. #include "base/strings/string_tokenizer.h"
  19. #include "base/strings/string_util.h"
  20. #include "base/threading/thread_restrictions.h"
  21. #include "net/base/address_tracker_linux.h"
  22. #include "net/base/escape.h"
  23. #include "net/base/ip_endpoint.h"
  24. #include "net/base/net_errors.h"
  25. #include "net/base/network_interfaces_posix.h"
  26. #include "url/gurl.h"
  27. #if defined(OS_ANDROID)
  28. #include "net/android/network_library.h"
  29. #endif
  30. namespace net {
  31. namespace {
  32. // When returning true, the platform native IPv6 address attributes were
  33. // successfully converted to net IP address attributes. Otherwise, returning
  34. // false and the caller should drop the IP address which can't be used by the
  35. // application layer.
  36. bool TryConvertNativeToNetIPAttributes(int native_attributes,
  37. int* net_attributes) {
  38. // For Linux/ChromeOS/Android, we disallow addresses with attributes
  39. // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these
  40. // are still progressing through duplicated address detection (DAD)
  41. // and shouldn't be used by the application layer until DAD process
  42. // is completed.
  43. if (native_attributes & (
  44. #if !defined(OS_ANDROID)
  45. IFA_F_OPTIMISTIC | IFA_F_DADFAILED |
  46. #endif // !OS_ANDROID
  47. IFA_F_TENTATIVE)) {
  48. return false;
  49. }
  50. if (native_attributes & IFA_F_TEMPORARY) {
  51. *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
  52. }
  53. if (native_attributes & IFA_F_DEPRECATED) {
  54. *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
  55. }
  56. return true;
  57. }
  58. } // namespace
  59. namespace internal {
  60. // Gets the connection type for interface |ifname| by checking for wireless
  61. // or ethtool extensions.
  62. NetworkChangeNotifier::ConnectionType GetInterfaceConnectionType(
  63. const std::string& ifname) {
  64. base::ScopedFD s = GetSocketForIoctl();
  65. if (!s.is_valid())
  66. return NetworkChangeNotifier::CONNECTION_UNKNOWN;
  67. // Test wireless extensions for CONNECTION_WIFI
  68. struct iwreq pwrq = {};
  69. strncpy(pwrq.ifr_name, ifname.c_str(), IFNAMSIZ - 1);
  70. if (ioctl(s.get(), SIOCGIWNAME, &pwrq) != -1)
  71. return NetworkChangeNotifier::CONNECTION_WIFI;
  72. #if !defined(OS_ANDROID)
  73. // Test ethtool for CONNECTION_ETHERNET
  74. struct ethtool_cmd ecmd = {};
  75. ecmd.cmd = ETHTOOL_GSET;
  76. struct ifreq ifr = {};
  77. ifr.ifr_data = &ecmd;
  78. strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ - 1);
  79. if (ioctl(s.get(), SIOCETHTOOL, &ifr) != -1)
  80. return NetworkChangeNotifier::CONNECTION_ETHERNET;
  81. #endif // !defined(OS_ANDROID)
  82. return NetworkChangeNotifier::CONNECTION_UNKNOWN;
  83. }
  84. std::string GetInterfaceSSID(const std::string& ifname) {
  85. base::ScopedFD ioctl_socket = GetSocketForIoctl();
  86. if (!ioctl_socket.is_valid())
  87. return std::string();
  88. struct iwreq wreq = {};
  89. strncpy(wreq.ifr_name, ifname.c_str(), IFNAMSIZ - 1);
  90. char ssid[IW_ESSID_MAX_SIZE + 1] = {0};
  91. wreq.u.essid.pointer = ssid;
  92. wreq.u.essid.length = IW_ESSID_MAX_SIZE;
  93. if (ioctl(ioctl_socket.get(), SIOCGIWESSID, &wreq) != -1)
  94. return ssid;
  95. return std::string();
  96. }
  97. bool GetNetworkListImpl(
  98. NetworkInterfaceList* networks,
  99. int policy,
  100. const std::unordered_set<int>& online_links,
  101. const internal::AddressTrackerLinux::AddressMap& address_map,
  102. GetInterfaceNameFunction get_interface_name) {
  103. std::map<int, std::string> ifnames;
  104. for (auto it = address_map.begin(); it != address_map.end(); ++it) {
  105. // Ignore addresses whose links are not online.
  106. if (online_links.find(it->second.ifa_index) == online_links.end())
  107. continue;
  108. sockaddr_storage sock_addr;
  109. socklen_t sock_len = sizeof(sockaddr_storage);
  110. // Convert to sockaddr for next check.
  111. if (!IPEndPoint(it->first, 0)
  112. .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) {
  113. continue;
  114. }
  115. // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
  116. if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr)))
  117. continue;
  118. int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
  119. if (it->second.ifa_family == AF_INET6) {
  120. // Ignore addresses whose attributes are not actionable by
  121. // the application layer.
  122. if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags,
  123. &ip_attributes))
  124. continue;
  125. }
  126. // Find the name of this link.
  127. std::map<int, std::string>::const_iterator itname =
  128. ifnames.find(it->second.ifa_index);
  129. std::string ifname;
  130. if (itname == ifnames.end()) {
  131. char buffer[IFNAMSIZ] = {0};
  132. ifname.assign(get_interface_name(it->second.ifa_index, buffer));
  133. // Ignore addresses whose interface name can't be retrieved.
  134. if (ifname.empty())
  135. continue;
  136. ifnames[it->second.ifa_index] = ifname;
  137. } else {
  138. ifname = itname->second;
  139. }
  140. // Based on the interface name and policy, determine whether we
  141. // should ignore it.
  142. if (ShouldIgnoreInterface(ifname, policy))
  143. continue;
  144. NetworkChangeNotifier::ConnectionType type =
  145. GetInterfaceConnectionType(ifname);
  146. networks->push_back(
  147. NetworkInterface(ifname, ifname, it->second.ifa_index, type, it->first,
  148. it->second.ifa_prefixlen, ip_attributes));
  149. }
  150. return true;
  151. }
  152. std::string GetWifiSSIDFromInterfaceListInternal(
  153. const NetworkInterfaceList& interfaces,
  154. internal::GetInterfaceSSIDFunction get_interface_ssid) {
  155. std::string connected_ssid;
  156. for (size_t i = 0; i < interfaces.size(); ++i) {
  157. if (interfaces[i].type != NetworkChangeNotifier::CONNECTION_WIFI)
  158. return std::string();
  159. std::string ssid = get_interface_ssid(interfaces[i].name);
  160. if (i == 0) {
  161. connected_ssid = ssid;
  162. } else if (ssid != connected_ssid) {
  163. return std::string();
  164. }
  165. }
  166. return connected_ssid;
  167. }
  168. base::ScopedFD GetSocketForIoctl() {
  169. base::ScopedFD ioctl_socket(socket(AF_INET6, SOCK_DGRAM, 0));
  170. if (ioctl_socket.is_valid())
  171. return ioctl_socket;
  172. return base::ScopedFD(socket(AF_INET, SOCK_DGRAM, 0));
  173. }
  174. } // namespace internal
  175. bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
  176. if (networks == NULL)
  177. return false;
  178. internal::AddressTrackerLinux tracker;
  179. tracker.Init();
  180. return internal::GetNetworkListImpl(
  181. networks, policy, tracker.GetOnlineLinks(), tracker.GetAddressMap(),
  182. &internal::AddressTrackerLinux::GetInterfaceName);
  183. }
  184. std::string GetWifiSSID() {
  185. // On Android, obtain the SSID using the Android-specific APIs.
  186. #if defined(OS_ANDROID)
  187. return android::GetWifiSSID();
  188. #else
  189. NetworkInterfaceList networks;
  190. if (GetNetworkList(&networks, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES)) {
  191. return internal::GetWifiSSIDFromInterfaceListInternal(
  192. networks, internal::GetInterfaceSSID);
  193. }
  194. return std::string();
  195. #endif
  196. }
  197. } // namespace net