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