network_interfaces_linux.cc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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. #include "build/build_config.h"
  7. #if !BUILDFLAG(IS_ANDROID)
  8. #include <linux/ethtool.h>
  9. #endif // !BUILDFLAG(IS_ANDROID)
  10. #include <linux/if.h>
  11. #include <linux/sockios.h>
  12. #include <linux/wireless.h>
  13. #include <set>
  14. #include <sys/ioctl.h>
  15. #include <sys/types.h>
  16. #include "base/files/file_path.h"
  17. #include "base/files/scoped_file.h"
  18. #include "base/strings/escape.h"
  19. #include "base/strings/string_number_conversions.h"
  20. #include "base/strings/string_tokenizer.h"
  21. #include "base/strings/string_util.h"
  22. #include "base/threading/thread_restrictions.h"
  23. #include "build/build_config.h"
  24. #include "net/base/address_tracker_linux.h"
  25. #include "net/base/ip_endpoint.h"
  26. #include "net/base/net_errors.h"
  27. #include "net/base/network_interfaces_posix.h"
  28. #include "url/gurl.h"
  29. #if BUILDFLAG(IS_ANDROID)
  30. #include "base/android/build_info.h"
  31. #include "base/strings/string_piece.h"
  32. #include "net/android/network_library.h"
  33. #include "net/base/network_interfaces_getifaddrs.h"
  34. #endif
  35. namespace net {
  36. namespace {
  37. // When returning true, the platform native IPv6 address attributes were
  38. // successfully converted to net IP address attributes. Otherwise, returning
  39. // false and the caller should drop the IP address which can't be used by the
  40. // application layer.
  41. bool TryConvertNativeToNetIPAttributes(int native_attributes,
  42. int* net_attributes) {
  43. // For Linux/ChromeOS/Android, we disallow addresses with attributes
  44. // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these
  45. // are still progressing through duplicated address detection (DAD)
  46. // and shouldn't be used by the application layer until DAD process
  47. // is completed.
  48. if (native_attributes & (
  49. #if !BUILDFLAG(IS_ANDROID)
  50. IFA_F_OPTIMISTIC | IFA_F_DADFAILED |
  51. #endif // !BUILDFLAG(IS_ANDROID)
  52. IFA_F_TENTATIVE)) {
  53. return false;
  54. }
  55. if (native_attributes & IFA_F_TEMPORARY) {
  56. *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
  57. }
  58. if (native_attributes & IFA_F_DEPRECATED) {
  59. *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
  60. }
  61. return true;
  62. }
  63. } // namespace
  64. namespace internal {
  65. // Gets the connection type for interface |ifname| by checking for wireless
  66. // or ethtool extensions.
  67. NetworkChangeNotifier::ConnectionType GetInterfaceConnectionType(
  68. const std::string& ifname) {
  69. base::ScopedFD s = GetSocketForIoctl();
  70. if (!s.is_valid())
  71. return NetworkChangeNotifier::CONNECTION_UNKNOWN;
  72. // Test wireless extensions for CONNECTION_WIFI
  73. struct iwreq pwrq = {};
  74. strncpy(pwrq.ifr_name, ifname.c_str(), IFNAMSIZ - 1);
  75. if (ioctl(s.get(), SIOCGIWNAME, &pwrq) != -1)
  76. return NetworkChangeNotifier::CONNECTION_WIFI;
  77. #if !BUILDFLAG(IS_ANDROID)
  78. // Test ethtool for CONNECTION_ETHERNET
  79. struct ethtool_cmd ecmd = {};
  80. ecmd.cmd = ETHTOOL_GSET;
  81. struct ifreq ifr = {};
  82. ifr.ifr_data = &ecmd;
  83. strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ - 1);
  84. if (ioctl(s.get(), SIOCETHTOOL, &ifr) != -1)
  85. return NetworkChangeNotifier::CONNECTION_ETHERNET;
  86. #endif // !BUILDFLAG(IS_ANDROID)
  87. return NetworkChangeNotifier::CONNECTION_UNKNOWN;
  88. }
  89. std::string GetInterfaceSSID(const std::string& ifname) {
  90. base::ScopedFD ioctl_socket = GetSocketForIoctl();
  91. if (!ioctl_socket.is_valid())
  92. return std::string();
  93. struct iwreq wreq = {};
  94. strncpy(wreq.ifr_name, ifname.c_str(), IFNAMSIZ - 1);
  95. char ssid[IW_ESSID_MAX_SIZE + 1] = {0};
  96. wreq.u.essid.pointer = ssid;
  97. wreq.u.essid.length = IW_ESSID_MAX_SIZE;
  98. if (ioctl(ioctl_socket.get(), SIOCGIWESSID, &wreq) != -1)
  99. return ssid;
  100. return std::string();
  101. }
  102. bool GetNetworkListImpl(
  103. NetworkInterfaceList* networks,
  104. int policy,
  105. const std::unordered_set<int>& online_links,
  106. const internal::AddressTrackerLinux::AddressMap& address_map,
  107. GetInterfaceNameFunction get_interface_name) {
  108. std::map<int, std::string> ifnames;
  109. for (const auto& it : address_map) {
  110. // Ignore addresses whose links are not online.
  111. if (online_links.find(it.second.ifa_index) == online_links.end())
  112. continue;
  113. sockaddr_storage sock_addr;
  114. socklen_t sock_len = sizeof(sockaddr_storage);
  115. // Convert to sockaddr for next check.
  116. if (!IPEndPoint(it.first, 0)
  117. .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) {
  118. continue;
  119. }
  120. // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
  121. if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr)))
  122. continue;
  123. int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
  124. if (it.second.ifa_family == AF_INET6) {
  125. // Ignore addresses whose attributes are not actionable by
  126. // the application layer.
  127. if (!TryConvertNativeToNetIPAttributes(it.second.ifa_flags,
  128. &ip_attributes))
  129. continue;
  130. }
  131. // Find the name of this link.
  132. std::map<int, std::string>::const_iterator itname =
  133. ifnames.find(it.second.ifa_index);
  134. std::string ifname;
  135. if (itname == ifnames.end()) {
  136. char buffer[IFNAMSIZ] = {0};
  137. ifname.assign(get_interface_name(it.second.ifa_index, buffer));
  138. // Ignore addresses whose interface name can't be retrieved.
  139. if (ifname.empty())
  140. continue;
  141. ifnames[it.second.ifa_index] = ifname;
  142. } else {
  143. ifname = itname->second;
  144. }
  145. // Based on the interface name and policy, determine whether we
  146. // should ignore it.
  147. if (ShouldIgnoreInterface(ifname, policy))
  148. continue;
  149. NetworkChangeNotifier::ConnectionType type =
  150. GetInterfaceConnectionType(ifname);
  151. networks->push_back(
  152. NetworkInterface(ifname, ifname, it.second.ifa_index, type, it.first,
  153. it.second.ifa_prefixlen, ip_attributes));
  154. }
  155. return true;
  156. }
  157. std::string GetWifiSSIDFromInterfaceListInternal(
  158. const NetworkInterfaceList& interfaces,
  159. internal::GetInterfaceSSIDFunction get_interface_ssid) {
  160. std::string connected_ssid;
  161. for (size_t i = 0; i < interfaces.size(); ++i) {
  162. if (interfaces[i].type != NetworkChangeNotifier::CONNECTION_WIFI)
  163. return std::string();
  164. std::string ssid = get_interface_ssid(interfaces[i].name);
  165. if (i == 0) {
  166. connected_ssid = ssid;
  167. } else if (ssid != connected_ssid) {
  168. return std::string();
  169. }
  170. }
  171. return connected_ssid;
  172. }
  173. base::ScopedFD GetSocketForIoctl() {
  174. base::ScopedFD ioctl_socket(socket(AF_INET6, SOCK_DGRAM, 0));
  175. if (ioctl_socket.is_valid())
  176. return ioctl_socket;
  177. return base::ScopedFD(socket(AF_INET, SOCK_DGRAM, 0));
  178. }
  179. } // namespace internal
  180. bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
  181. if (networks == nullptr)
  182. return false;
  183. #if BUILDFLAG(IS_ANDROID)
  184. // On Android 11 RTM_GETLINK (used by AddressTrackerLinux) no longer works as
  185. // per https://developer.android.com/preview/privacy/mac-address so instead
  186. // use getifaddrs() which is supported since Android N.
  187. base::android::BuildInfo* build_info =
  188. base::android::BuildInfo::GetInstance();
  189. if (build_info->sdk_int() >= base::android::SDK_VERSION_NOUGAT) {
  190. // Some Samsung devices with MediaTek processors are with
  191. // a buggy getifaddrs() implementation,
  192. // so use a Chromium's own implementation to workaround.
  193. // See https://crbug.com/1240237 for more context.
  194. bool use_alternative_getifaddrs =
  195. base::StringPiece(build_info->brand()) == "samsung" &&
  196. base::StartsWith(build_info->hardware(), "mt");
  197. bool ret = internal::GetNetworkListUsingGetifaddrs(
  198. networks, policy, use_alternative_getifaddrs);
  199. // Use GetInterfaceConnectionType() to sharpen up interface types.
  200. for (NetworkInterface& network : *networks)
  201. network.type = internal::GetInterfaceConnectionType(network.name);
  202. return ret;
  203. }
  204. #endif
  205. internal::AddressTrackerLinux tracker;
  206. tracker.Init();
  207. return internal::GetNetworkListImpl(
  208. networks, policy, tracker.GetOnlineLinks(), tracker.GetAddressMap(),
  209. &internal::AddressTrackerLinux::GetInterfaceName);
  210. }
  211. std::string GetWifiSSID() {
  212. // On Android, obtain the SSID using the Android-specific APIs.
  213. #if BUILDFLAG(IS_ANDROID)
  214. return android::GetWifiSSID();
  215. #else
  216. NetworkInterfaceList networks;
  217. if (GetNetworkList(&networks, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES)) {
  218. return internal::GetWifiSSIDFromInterfaceListInternal(
  219. networks, internal::GetInterfaceSSID);
  220. }
  221. return std::string();
  222. #endif
  223. }
  224. } // namespace net