Home | History | Annotate | Download | only in base
      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