| 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 return ip.data(); | |
| 72 } | |
| 73 | |
| 74 // Gets the connection type for interface |ifname| by checking for wireless | |
| 75 // or ethtool extensions. | |
| 76 NetworkChangeNotifier::ConnectionType GetInterfaceConnectionType( | |
| 77 const std::string& ifname) { | |
| 78 base::ScopedFD s(socket(AF_INET, SOCK_STREAM, 0)); | |
| 79 if (!s.is_valid()) | |
| 80 return NetworkChangeNotifier::CONNECTION_UNKNOWN; | |
| 81 | |
| 82 // Test wireless extensions for CONNECTION_WIFI | |
| 83 struct iwreq pwrq = {}; | |
| 84 strncpy(pwrq.ifr_name, ifname.c_str(), IFNAMSIZ - 1); | |
| 85 if (ioctl(s.get(), SIOCGIWNAME, &pwrq) != -1) | |
| 86 return NetworkChangeNotifier::CONNECTION_WIFI; | |
| 87 | |
| 88 #if !defined(OS_ANDROID) | |
| 89 // Test ethtool for CONNECTION_ETHERNET | |
| 90 struct ethtool_cmd ecmd = {}; | |
| 91 ecmd.cmd = ETHTOOL_GSET; | |
| 92 struct ifreq ifr = {}; | |
| 93 ifr.ifr_data = &ecmd; | |
| 94 strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ - 1); | |
| 95 if (ioctl(s.get(), SIOCETHTOOL, &ifr) != -1) | |
| 96 return NetworkChangeNotifier::CONNECTION_ETHERNET; | |
| 97 #endif // !defined(OS_ANDROID) | |
| 98 | |
| 99 return NetworkChangeNotifier::CONNECTION_UNKNOWN; | |
| 100 } | |
| 101 | |
| 102 std::string GetInterfaceSSID(const std::string& ifname) { | |
| 103 base::ScopedFD ioctl_socket(socket(AF_INET, SOCK_DGRAM, 0)); | |
| 104 if (!ioctl_socket.is_valid()) | |
| 105 return ""; | |
| 106 struct iwreq wreq = {}; | |
| 107 strncpy(wreq.ifr_name, ifname.c_str(), IFNAMSIZ - 1); | |
| 108 | |
| 109 char ssid[IW_ESSID_MAX_SIZE + 1] = {0}; | |
| 110 wreq.u.essid.pointer = ssid; | |
| 111 wreq.u.essid.length = IW_ESSID_MAX_SIZE; | |
| 112 if (ioctl(ioctl_socket.get(), SIOCGIWESSID, &wreq) != -1) | |
| 113 return ssid; | |
| 114 return ""; | |
| 115 } | |
| 116 | |
| 117 bool GetNetworkListImpl( | |
| 118 NetworkInterfaceList* networks, | |
| 119 int policy, | |
| 120 const base::hash_set<int>& online_links, | |
| 121 const internal::AddressTrackerLinux::AddressMap& address_map, | |
| 122 GetInterfaceNameFunction get_interface_name) { | |
| 123 std::map<int, std::string> ifnames; | |
| 124 | |
| 125 for (internal::AddressTrackerLinux::AddressMap::const_iterator it = | |
| 126 address_map.begin(); | |
| 127 it != address_map.end(); ++it) { | |
| 128 // Ignore addresses whose links are not online. | |
| 129 if (online_links.find(it->second.ifa_index) == online_links.end()) | |
| 130 continue; | |
| 131 | |
| 132 sockaddr_storage sock_addr; | |
| 133 socklen_t sock_len = sizeof(sockaddr_storage); | |
| 134 | |
| 135 // Convert to sockaddr for next check. | |
| 136 if (!IPEndPoint(it->first, 0) | |
| 137 .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) { | |
| 138 continue; | |
| 139 } | |
| 140 | |
| 141 // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses | |
| 142 if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr))) | |
| 143 continue; | |
| 144 | |
| 145 int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE; | |
| 146 | |
| 147 if (it->second.ifa_family == AF_INET6) { | |
| 148 // Ignore addresses whose attributes are not actionable by | |
| 149 // the application layer. | |
| 150 if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags, | |
| 151 &ip_attributes)) | |
| 152 continue; | |
| 153 } | |
| 154 | |
| 155 // Find the name of this link. | |
| 156 std::map<int, std::string>::const_iterator itname = | |
| 157 ifnames.find(it->second.ifa_index); | |
| 158 std::string ifname; | |
| 159 if (itname == ifnames.end()) { | |
| 160 char buffer[IFNAMSIZ] = {0}; | |
| 161 ifname.assign(get_interface_name(it->second.ifa_index, buffer)); | |
| 162 // Ignore addresses whose interface name can't be retrieved. | |
| 163 if (ifname.empty()) | |
| 164 continue; | |
| 165 ifnames[it->second.ifa_index] = ifname; | |
| 166 } else { | |
| 167 ifname = itname->second; | |
| 168 } | |
| 169 | |
| 170 // Based on the interface name and policy, determine whether we | |
| 171 // should ignore it. | |
| 172 if (ShouldIgnoreInterface(ifname, policy)) | |
| 173 continue; | |
| 174 | |
| 175 NetworkChangeNotifier::ConnectionType type = | |
| 176 GetInterfaceConnectionType(ifname); | |
| 177 | |
| 178 networks->push_back( | |
| 179 NetworkInterface(ifname, ifname, it->second.ifa_index, type, it->first, | |
| 180 it->second.ifa_prefixlen, ip_attributes)); | |
| 181 } | |
| 182 | |
| 183 return true; | |
| 184 } | |
| 185 | |
| 186 std::string GetWifiSSIDFromInterfaceListInternal( | |
| 187 const NetworkInterfaceList& interfaces, | |
| 188 internal::GetInterfaceSSIDFunction get_interface_ssid) { | |
| 189 std::string connected_ssid; | |
| 190 for (size_t i = 0; i < interfaces.size(); ++i) { | |
| 191 if (interfaces[i].type != NetworkChangeNotifier::CONNECTION_WIFI) | |
| 192 return ""; | |
| 193 std::string ssid = get_interface_ssid(interfaces[i].name); | |
| 194 if (i == 0) { | |
| 195 connected_ssid = ssid; | |
| 196 } else if (ssid != connected_ssid) { | |
| 197 return ""; | |
| 198 } | |
| 199 } | |
| 200 return connected_ssid; | |
| 201 } | |
| 202 | |
| 203 } // namespace internal | |
| 204 | |
| 205 bool GetNetworkList(NetworkInterfaceList* networks, int policy) { | |
| 206 if (networks == NULL) | |
| 207 return false; | |
| 208 | |
| 209 internal::AddressTrackerLinux tracker; | |
| 210 tracker.Init(); | |
| 211 | |
| 212 return internal::GetNetworkListImpl( | |
| 213 networks, policy, tracker.GetOnlineLinks(), tracker.GetAddressMap(), | |
| 214 &internal::AddressTrackerLinux::GetInterfaceName); | |
| 215 } | |
| 216 | |
| 217 std::string GetWifiSSID() { | |
| 218 NetworkInterfaceList networks; | |
| 219 if (GetNetworkList(&networks, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES)) { | |
| 220 return internal::GetWifiSSIDFromInterfaceListInternal( | |
| 221 networks, internal::GetInterfaceSSID); | |
| 222 } | |
| 223 return ""; | |
| 224 } | |
| 225 | |
| 226 } // namespace net | |
| OLD | NEW |