1 // Copyright (c) 2012 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.h" 6 7 #include <iphlpapi.h> 8 #include <wlanapi.h> 9 10 #include <algorithm> 11 12 #include "base/files/file_path.h" 13 #include "base/lazy_instance.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/strings/string_piece.h" 16 #include "base/strings/string_util.h" 17 #include "base/strings/sys_string_conversions.h" 18 #include "base/strings/utf_string_conversions.h" 19 #include "base/threading/thread_restrictions.h" 20 #include "base/win/scoped_handle.h" 21 #include "net/base/escape.h" 22 #include "net/base/ip_endpoint.h" 23 #include "net/base/net_errors.h" 24 #include "url/gurl.h" 25 26 namespace { 27 28 struct WlanApi { 29 typedef DWORD (WINAPI *WlanOpenHandleFunc)( 30 DWORD, VOID*, DWORD*, HANDLE*); 31 typedef DWORD (WINAPI *WlanEnumInterfacesFunc)( 32 HANDLE, VOID*, WLAN_INTERFACE_INFO_LIST**); 33 typedef DWORD (WINAPI *WlanQueryInterfaceFunc)( 34 HANDLE, const GUID*, WLAN_INTF_OPCODE, VOID*, DWORD*, VOID**, 35 WLAN_OPCODE_VALUE_TYPE*); 36 typedef VOID (WINAPI *WlanFreeMemoryFunc)(VOID*); 37 typedef DWORD (WINAPI *WlanCloseHandleFunc)(HANDLE, VOID*); 38 39 WlanApi() : initialized(false) { 40 // Use an absolute path to load the DLL to avoid DLL preloading attacks. 41 static const wchar_t* const kDLL = L"%WINDIR%\\system32\\wlanapi.dll"; 42 wchar_t path[MAX_PATH] = {0}; 43 ExpandEnvironmentStrings(kDLL, path, arraysize(path)); 44 module = ::LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); 45 if (!module) 46 return; 47 48 open_handle_func = reinterpret_cast<WlanOpenHandleFunc>( 49 ::GetProcAddress(module, "WlanOpenHandle")); 50 enum_interfaces_func = reinterpret_cast<WlanEnumInterfacesFunc>( 51 ::GetProcAddress(module, "WlanEnumInterfaces")); 52 query_interface_func = reinterpret_cast<WlanQueryInterfaceFunc>( 53 ::GetProcAddress(module, "WlanQueryInterface")); 54 free_memory_func = reinterpret_cast<WlanFreeMemoryFunc>( 55 ::GetProcAddress(module, "WlanFreeMemory")); 56 close_handle_func = reinterpret_cast<WlanCloseHandleFunc>( 57 ::GetProcAddress(module, "WlanCloseHandle")); 58 initialized = open_handle_func && enum_interfaces_func && 59 query_interface_func && free_memory_func && 60 close_handle_func; 61 } 62 63 HMODULE module; 64 WlanOpenHandleFunc open_handle_func; 65 WlanEnumInterfacesFunc enum_interfaces_func; 66 WlanQueryInterfaceFunc query_interface_func; 67 WlanFreeMemoryFunc free_memory_func; 68 WlanCloseHandleFunc close_handle_func; 69 bool initialized; 70 }; 71 72 } // namespace 73 74 namespace net { 75 76 bool FileURLToFilePath(const GURL& url, base::FilePath* file_path) { 77 *file_path = base::FilePath(); 78 std::wstring& file_path_str = const_cast<std::wstring&>(file_path->value()); 79 file_path_str.clear(); 80 81 if (!url.is_valid()) 82 return false; 83 84 std::string path; 85 std::string host = url.host(); 86 if (host.empty()) { 87 // URL contains no host, the path is the filename. In this case, the path 88 // will probably be preceeded with a slash, as in "/C:/foo.txt", so we 89 // trim out that here. 90 path = url.path(); 91 size_t first_non_slash = path.find_first_not_of("/\\"); 92 if (first_non_slash != std::string::npos && first_non_slash > 0) 93 path.erase(0, first_non_slash); 94 } else { 95 // URL contains a host: this means it's UNC. We keep the preceeding slash 96 // on the path. 97 path = "\\\\"; 98 path.append(host); 99 path.append(url.path()); 100 } 101 102 if (path.empty()) 103 return false; 104 std::replace(path.begin(), path.end(), '/', '\\'); 105 106 // GURL stores strings as percent-encoded UTF-8, this will undo if possible. 107 path = UnescapeURLComponent(path, 108 UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS); 109 110 if (!IsStringUTF8(path)) { 111 // Not UTF-8, assume encoding is native codepage and we're done. We know we 112 // are giving the conversion function a nonempty string, and it may fail if 113 // the given string is not in the current encoding and give us an empty 114 // string back. We detect this and report failure. 115 file_path_str = base::SysNativeMBToWide(path); 116 return !file_path_str.empty(); 117 } 118 file_path_str.assign(UTF8ToWide(path)); 119 120 // We used to try too hard and see if |path| made up entirely of 121 // the 1st 256 characters in the Unicode was a zero-extended UTF-16. 122 // If so, we converted it to 'Latin-1' and checked if the result was UTF-8. 123 // If the check passed, we converted the result to UTF-8. 124 // Otherwise, we treated the result as the native OS encoding. 125 // However, that led to http://crbug.com/4619 and http://crbug.com/14153 126 return true; 127 } 128 129 bool GetNetworkList(NetworkInterfaceList* networks) { 130 // GetAdaptersAddresses() may require IO operations. 131 base::ThreadRestrictions::AssertIOAllowed(); 132 133 IP_ADAPTER_ADDRESSES info_temp; 134 ULONG len = 0; 135 136 // First get number of networks. 137 ULONG result = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, &info_temp, &len); 138 if (result != ERROR_BUFFER_OVERFLOW) { 139 // There are 0 networks. 140 return true; 141 } 142 143 scoped_ptr<char[]> buf(new char[len]); 144 IP_ADAPTER_ADDRESSES *adapters = 145 reinterpret_cast<IP_ADAPTER_ADDRESSES *>(buf.get()); 146 result = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapters, &len); 147 if (result != NO_ERROR) { 148 LOG(ERROR) << "GetAdaptersAddresses failed: " << result; 149 return false; 150 } 151 152 for (IP_ADAPTER_ADDRESSES *adapter = adapters; adapter != NULL; 153 adapter = adapter->Next) { 154 // Ignore the loopback device. 155 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) { 156 continue; 157 } 158 159 if (adapter->OperStatus != IfOperStatusUp) { 160 continue; 161 } 162 163 IP_ADAPTER_UNICAST_ADDRESS* address; 164 for (address = adapter->FirstUnicastAddress; address != NULL; 165 address = address->Next) { 166 int family = address->Address.lpSockaddr->sa_family; 167 if (family == AF_INET || family == AF_INET6) { 168 IPEndPoint endpoint; 169 if (endpoint.FromSockAddr(address->Address.lpSockaddr, 170 address->Address.iSockaddrLength)) { 171 std::string name = adapter->AdapterName; 172 networks->push_back(NetworkInterface(name, endpoint.address())); 173 } 174 } 175 } 176 } 177 178 return true; 179 } 180 181 WifiPHYLayerProtocol GetWifiPHYLayerProtocol() { 182 static base::LazyInstance<WlanApi>::Leaky lazy_wlanapi = 183 LAZY_INSTANCE_INITIALIZER; 184 185 struct WlanApiHandleTraits { 186 typedef HANDLE Handle; 187 188 static bool CloseHandle(HANDLE handle) { 189 return lazy_wlanapi.Get().close_handle_func(handle, NULL) == 190 ERROR_SUCCESS; 191 } 192 static bool IsHandleValid(HANDLE handle) { 193 return base::win::HandleTraits::IsHandleValid(handle); 194 } 195 static HANDLE NullHandle() { 196 return base::win::HandleTraits::NullHandle(); 197 } 198 }; 199 200 typedef base::win::GenericScopedHandle< 201 WlanApiHandleTraits, 202 base::win::DummyVerifierTraits> WlanHandle; 203 204 struct WlanApiDeleter { 205 inline void operator()(void* ptr) const { 206 lazy_wlanapi.Get().free_memory_func(ptr); 207 } 208 }; 209 210 const WlanApi& wlanapi = lazy_wlanapi.Get(); 211 if (!wlanapi.initialized) 212 return WIFI_PHY_LAYER_PROTOCOL_NONE; 213 214 WlanHandle client; 215 DWORD cur_version = 0; 216 const DWORD kMaxClientVersion = 2; 217 DWORD result = wlanapi.open_handle_func(kMaxClientVersion, NULL, &cur_version, 218 client.Receive()); 219 if (result != ERROR_SUCCESS) 220 return WIFI_PHY_LAYER_PROTOCOL_NONE; 221 222 WLAN_INTERFACE_INFO_LIST* interface_list_ptr = NULL; 223 result = wlanapi.enum_interfaces_func(client, NULL, &interface_list_ptr); 224 if (result != ERROR_SUCCESS) 225 return WIFI_PHY_LAYER_PROTOCOL_NONE; 226 scoped_ptr<WLAN_INTERFACE_INFO_LIST, WlanApiDeleter> interface_list( 227 interface_list_ptr); 228 229 // Assume at most one connected wifi interface. 230 WLAN_INTERFACE_INFO* info = NULL; 231 for (unsigned i = 0; i < interface_list->dwNumberOfItems; ++i) { 232 if (interface_list->InterfaceInfo[i].isState == 233 wlan_interface_state_connected) { 234 info = &interface_list->InterfaceInfo[i]; 235 break; 236 } 237 } 238 239 if (info == NULL) 240 return WIFI_PHY_LAYER_PROTOCOL_NONE; 241 242 WLAN_CONNECTION_ATTRIBUTES* conn_info_ptr; 243 DWORD conn_info_size = 0; 244 WLAN_OPCODE_VALUE_TYPE op_code; 245 result = wlanapi.query_interface_func( 246 client, &info->InterfaceGuid, wlan_intf_opcode_current_connection, NULL, 247 &conn_info_size, reinterpret_cast<VOID**>(&conn_info_ptr), &op_code); 248 if (result != ERROR_SUCCESS) 249 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN; 250 scoped_ptr<WLAN_CONNECTION_ATTRIBUTES, WlanApiDeleter> conn_info( 251 conn_info_ptr); 252 253 switch (conn_info->wlanAssociationAttributes.dot11PhyType) { 254 case dot11_phy_type_fhss: 255 return WIFI_PHY_LAYER_PROTOCOL_ANCIENT; 256 case dot11_phy_type_dsss: 257 return WIFI_PHY_LAYER_PROTOCOL_B; 258 case dot11_phy_type_irbaseband: 259 return WIFI_PHY_LAYER_PROTOCOL_ANCIENT; 260 case dot11_phy_type_ofdm: 261 return WIFI_PHY_LAYER_PROTOCOL_A; 262 case dot11_phy_type_hrdsss: 263 return WIFI_PHY_LAYER_PROTOCOL_B; 264 case dot11_phy_type_erp: 265 return WIFI_PHY_LAYER_PROTOCOL_G; 266 case dot11_phy_type_ht: 267 return WIFI_PHY_LAYER_PROTOCOL_N; 268 default: 269 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN; 270 } 271 } 272 273 } // namespace net 274