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 "base/win/windows_version.h"
     22 #include "net/base/escape.h"
     23 #include "net/base/ip_endpoint.h"
     24 #include "net/base/net_errors.h"
     25 #include "url/gurl.h"
     26 
     27 namespace net {
     28 
     29 namespace {
     30 
     31 struct WlanApi {
     32   typedef DWORD (WINAPI *WlanOpenHandleFunc)(
     33       DWORD, VOID*, DWORD*, HANDLE*);
     34   typedef DWORD (WINAPI *WlanEnumInterfacesFunc)(
     35       HANDLE, VOID*, WLAN_INTERFACE_INFO_LIST**);
     36   typedef DWORD (WINAPI *WlanQueryInterfaceFunc)(
     37       HANDLE, const GUID*, WLAN_INTF_OPCODE, VOID*, DWORD*, VOID**,
     38       WLAN_OPCODE_VALUE_TYPE*);
     39   typedef VOID (WINAPI *WlanFreeMemoryFunc)(VOID*);
     40   typedef DWORD (WINAPI *WlanCloseHandleFunc)(HANDLE, VOID*);
     41 
     42   WlanApi() : initialized(false) {
     43     // Use an absolute path to load the DLL to avoid DLL preloading attacks.
     44     static const wchar_t* const kDLL = L"%WINDIR%\\system32\\wlanapi.dll";
     45     wchar_t path[MAX_PATH] = {0};
     46     ExpandEnvironmentStrings(kDLL, path, arraysize(path));
     47     module = ::LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
     48     if (!module)
     49       return;
     50 
     51     open_handle_func = reinterpret_cast<WlanOpenHandleFunc>(
     52         ::GetProcAddress(module, "WlanOpenHandle"));
     53     enum_interfaces_func = reinterpret_cast<WlanEnumInterfacesFunc>(
     54         ::GetProcAddress(module, "WlanEnumInterfaces"));
     55     query_interface_func = reinterpret_cast<WlanQueryInterfaceFunc>(
     56         ::GetProcAddress(module, "WlanQueryInterface"));
     57     free_memory_func = reinterpret_cast<WlanFreeMemoryFunc>(
     58         ::GetProcAddress(module, "WlanFreeMemory"));
     59     close_handle_func = reinterpret_cast<WlanCloseHandleFunc>(
     60         ::GetProcAddress(module, "WlanCloseHandle"));
     61     initialized = open_handle_func && enum_interfaces_func &&
     62                   query_interface_func && free_memory_func &&
     63                   close_handle_func;
     64   }
     65 
     66   template <typename T>
     67   DWORD OpenHandle(DWORD client_version, DWORD* cur_version, T* handle) const {
     68     HANDLE temp_handle;
     69     DWORD result = open_handle_func(client_version, NULL, cur_version,
     70                                     &temp_handle);
     71     if (result != ERROR_SUCCESS)
     72       return result;
     73     handle->Set(temp_handle);
     74     return ERROR_SUCCESS;
     75   }
     76 
     77   HMODULE module;
     78   WlanOpenHandleFunc open_handle_func;
     79   WlanEnumInterfacesFunc enum_interfaces_func;
     80   WlanQueryInterfaceFunc query_interface_func;
     81   WlanFreeMemoryFunc free_memory_func;
     82   WlanCloseHandleFunc close_handle_func;
     83   bool initialized;
     84 };
     85 
     86 // Converts Windows defined types to NetworkInterfaceType.
     87 NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(DWORD ifType) {
     88   // Bail out for pre-Vista versions of Windows which are documented to give
     89   // inaccurate results like returning Ethernet for WiFi.
     90   // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366058.aspx
     91   if (base::win::GetVersion() < base::win::VERSION_VISTA)
     92     return NetworkChangeNotifier::CONNECTION_UNKNOWN;
     93 
     94   NetworkChangeNotifier::ConnectionType type =
     95       NetworkChangeNotifier::CONNECTION_UNKNOWN;
     96   if (ifType == IF_TYPE_ETHERNET_CSMACD) {
     97     type = NetworkChangeNotifier::CONNECTION_ETHERNET;
     98   } else if (ifType == IF_TYPE_IEEE80211) {
     99     type = NetworkChangeNotifier::CONNECTION_WIFI;
    100   }
    101   // TODO(mallinath) - Cellular?
    102   return type;
    103 }
    104 
    105 }  // namespace
    106 
    107 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
    108   // GetAdaptersAddresses() may require IO operations.
    109   base::ThreadRestrictions::AssertIOAllowed();
    110   bool is_xp = base::win::GetVersion() < base::win::VERSION_VISTA;
    111   ULONG len = 0;
    112   ULONG flags = is_xp ? GAA_FLAG_INCLUDE_PREFIX : 0;
    113   // First get number of networks.
    114   ULONG result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, NULL, &len);
    115   if (result != ERROR_BUFFER_OVERFLOW) {
    116     // There are 0 networks.
    117     return true;
    118   }
    119   scoped_ptr<char[]> buf(new char[len]);
    120   IP_ADAPTER_ADDRESSES *adapters =
    121       reinterpret_cast<IP_ADAPTER_ADDRESSES *>(buf.get());
    122   result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapters, &len);
    123   if (result != NO_ERROR) {
    124     LOG(ERROR) << "GetAdaptersAddresses failed: " << result;
    125     return false;
    126   }
    127 
    128   // These two variables are used below when this method is asked to pick a
    129   // IPv6 address which has the shortest lifetime.
    130   ULONG ipv6_valid_lifetime = 0;
    131   scoped_ptr<NetworkInterface> ipv6_address;
    132 
    133   for (IP_ADAPTER_ADDRESSES *adapter = adapters; adapter != NULL;
    134        adapter = adapter->Next) {
    135     // Ignore the loopback device.
    136     if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
    137       continue;
    138     }
    139 
    140     if (adapter->OperStatus != IfOperStatusUp) {
    141       continue;
    142     }
    143 
    144     // Ignore any HOST side vmware adapters with a description like:
    145     // VMware Virtual Ethernet Adapter for VMnet1
    146     // but don't ignore any GUEST side adapters with a description like:
    147     // VMware Accelerated AMD PCNet Adapter #2
    148     if (policy == EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES &&
    149         strstr(adapter->AdapterName, "VMnet") != NULL) {
    150       continue;
    151     }
    152 
    153     for (IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress;
    154          address; address = address->Next) {
    155       int family = address->Address.lpSockaddr->sa_family;
    156       if (family == AF_INET || family == AF_INET6) {
    157         IPEndPoint endpoint;
    158         if (endpoint.FromSockAddr(address->Address.lpSockaddr,
    159                                   address->Address.iSockaddrLength)) {
    160           // XP has no OnLinkPrefixLength field.
    161           size_t net_prefix = is_xp ? 0 : address->OnLinkPrefixLength;
    162           if (is_xp) {
    163             // Prior to Windows Vista the FirstPrefix pointed to the list with
    164             // single prefix for each IP address assigned to the adapter.
    165             // Order of FirstPrefix does not match order of FirstUnicastAddress,
    166             // so we need to find corresponding prefix.
    167             for (IP_ADAPTER_PREFIX* prefix = adapter->FirstPrefix; prefix;
    168                  prefix = prefix->Next) {
    169               int prefix_family = prefix->Address.lpSockaddr->sa_family;
    170               IPEndPoint network_endpoint;
    171               if (prefix_family == family &&
    172                   network_endpoint.FromSockAddr(prefix->Address.lpSockaddr,
    173                       prefix->Address.iSockaddrLength) &&
    174                   IPNumberMatchesPrefix(endpoint.address(),
    175                                         network_endpoint.address(),
    176                                         prefix->PrefixLength)) {
    177                 net_prefix = std::max<size_t>(net_prefix, prefix->PrefixLength);
    178               }
    179             }
    180           }
    181           uint32 index =
    182               (family == AF_INET) ? adapter->IfIndex : adapter->Ipv6IfIndex;
    183           // Pick one IPv6 address with least valid lifetime.
    184           // The reason we are checking |ValidLifeftime| as there is no other
    185           // way identifying the interface type. Usually (and most likely) temp
    186           // IPv6 will have a shorter ValidLifetime value then the permanent
    187           // interface.
    188           if (family == AF_INET6 &&
    189               (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE)) {
    190             if (ipv6_valid_lifetime == 0 ||
    191                 ipv6_valid_lifetime > address->ValidLifetime) {
    192               ipv6_valid_lifetime = address->ValidLifetime;
    193               ipv6_address.reset(new NetworkInterface(adapter->AdapterName,
    194                                  base::SysWideToNativeMB(adapter->FriendlyName),
    195                                  index,
    196                                  GetNetworkInterfaceType(adapter->IfType),
    197                                  endpoint.address(),
    198                                  net_prefix));
    199               continue;
    200             }
    201           }
    202           networks->push_back(
    203               NetworkInterface(adapter->AdapterName,
    204                                base::SysWideToNativeMB(adapter->FriendlyName),
    205                                index, GetNetworkInterfaceType(adapter->IfType),
    206                                endpoint.address(), net_prefix));
    207         }
    208       }
    209     }
    210   }
    211 
    212   if (ipv6_address.get()) {
    213     networks->push_back(*(ipv6_address.get()));
    214   }
    215   return true;
    216 }
    217 
    218 WifiPHYLayerProtocol GetWifiPHYLayerProtocol() {
    219   static base::LazyInstance<WlanApi>::Leaky lazy_wlanapi =
    220       LAZY_INSTANCE_INITIALIZER;
    221 
    222   struct WlanApiHandleTraits {
    223     typedef HANDLE Handle;
    224 
    225     static bool CloseHandle(HANDLE handle) {
    226       return lazy_wlanapi.Get().close_handle_func(handle, NULL) ==
    227           ERROR_SUCCESS;
    228     }
    229     static bool IsHandleValid(HANDLE handle) {
    230       return base::win::HandleTraits::IsHandleValid(handle);
    231     }
    232     static HANDLE NullHandle() {
    233       return base::win::HandleTraits::NullHandle();
    234     }
    235   };
    236 
    237   typedef base::win::GenericScopedHandle<
    238       WlanApiHandleTraits,
    239       base::win::DummyVerifierTraits> WlanHandle;
    240 
    241   struct WlanApiDeleter {
    242     inline void operator()(void* ptr) const {
    243       lazy_wlanapi.Get().free_memory_func(ptr);
    244     }
    245   };
    246 
    247   const WlanApi& wlanapi = lazy_wlanapi.Get();
    248   if (!wlanapi.initialized)
    249     return WIFI_PHY_LAYER_PROTOCOL_NONE;
    250 
    251   WlanHandle client;
    252   DWORD cur_version = 0;
    253   const DWORD kMaxClientVersion = 2;
    254   DWORD result = wlanapi.OpenHandle(kMaxClientVersion, &cur_version, &client);
    255   if (result != ERROR_SUCCESS)
    256     return WIFI_PHY_LAYER_PROTOCOL_NONE;
    257 
    258   WLAN_INTERFACE_INFO_LIST* interface_list_ptr = NULL;
    259   result = wlanapi.enum_interfaces_func(client, NULL, &interface_list_ptr);
    260   if (result != ERROR_SUCCESS)
    261     return WIFI_PHY_LAYER_PROTOCOL_NONE;
    262   scoped_ptr<WLAN_INTERFACE_INFO_LIST, WlanApiDeleter> interface_list(
    263       interface_list_ptr);
    264 
    265   // Assume at most one connected wifi interface.
    266   WLAN_INTERFACE_INFO* info = NULL;
    267   for (unsigned i = 0; i < interface_list->dwNumberOfItems; ++i) {
    268     if (interface_list->InterfaceInfo[i].isState ==
    269         wlan_interface_state_connected) {
    270       info = &interface_list->InterfaceInfo[i];
    271       break;
    272     }
    273   }
    274 
    275   if (info == NULL)
    276     return WIFI_PHY_LAYER_PROTOCOL_NONE;
    277 
    278   WLAN_CONNECTION_ATTRIBUTES* conn_info_ptr;
    279   DWORD conn_info_size = 0;
    280   WLAN_OPCODE_VALUE_TYPE op_code;
    281   result = wlanapi.query_interface_func(
    282       client, &info->InterfaceGuid, wlan_intf_opcode_current_connection, NULL,
    283       &conn_info_size, reinterpret_cast<VOID**>(&conn_info_ptr), &op_code);
    284   if (result != ERROR_SUCCESS)
    285     return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
    286   scoped_ptr<WLAN_CONNECTION_ATTRIBUTES, WlanApiDeleter> conn_info(
    287       conn_info_ptr);
    288 
    289   switch (conn_info->wlanAssociationAttributes.dot11PhyType) {
    290     case dot11_phy_type_fhss:
    291       return WIFI_PHY_LAYER_PROTOCOL_ANCIENT;
    292     case dot11_phy_type_dsss:
    293       return WIFI_PHY_LAYER_PROTOCOL_B;
    294     case dot11_phy_type_irbaseband:
    295       return WIFI_PHY_LAYER_PROTOCOL_ANCIENT;
    296     case dot11_phy_type_ofdm:
    297       return WIFI_PHY_LAYER_PROTOCOL_A;
    298     case dot11_phy_type_hrdsss:
    299       return WIFI_PHY_LAYER_PROTOCOL_B;
    300     case dot11_phy_type_erp:
    301       return WIFI_PHY_LAYER_PROTOCOL_G;
    302     case dot11_phy_type_ht:
    303       return WIFI_PHY_LAYER_PROTOCOL_N;
    304     default:
    305       return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
    306   }
    307 }
    308 
    309 }  // namespace net
    310