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.
5 #include "net/base/net_util.h"
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"
30 typedef DWORD (WINAPI
*WlanOpenHandleFunc
)(
31 DWORD
, VOID
*, DWORD
*, HANDLE
*);
32 typedef DWORD (WINAPI
*WlanEnumInterfacesFunc
)(
33 HANDLE
, VOID
*, WLAN_INTERFACE_INFO_LIST
**);
34 typedef DWORD (WINAPI
*WlanQueryInterfaceFunc
)(
35 HANDLE
, const GUID
*, WLAN_INTF_OPCODE
, VOID
*, DWORD
*, VOID
**,
36 WLAN_OPCODE_VALUE_TYPE
*);
37 typedef VOID (WINAPI
*WlanFreeMemoryFunc
)(VOID
*);
38 typedef DWORD (WINAPI
*WlanCloseHandleFunc
)(HANDLE
, VOID
*);
40 WlanApi() : initialized(false) {
41 // Use an absolute path to load the DLL to avoid DLL preloading attacks.
42 static const wchar_t* const kDLL
= L
"%WINDIR%\\system32\\wlanapi.dll";
43 wchar_t path
[MAX_PATH
] = {0};
44 ExpandEnvironmentStrings(kDLL
, path
, arraysize(path
));
45 module
= ::LoadLibraryEx(path
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
);
49 open_handle_func
= reinterpret_cast<WlanOpenHandleFunc
>(
50 ::GetProcAddress(module
, "WlanOpenHandle"));
51 enum_interfaces_func
= reinterpret_cast<WlanEnumInterfacesFunc
>(
52 ::GetProcAddress(module
, "WlanEnumInterfaces"));
53 query_interface_func
= reinterpret_cast<WlanQueryInterfaceFunc
>(
54 ::GetProcAddress(module
, "WlanQueryInterface"));
55 free_memory_func
= reinterpret_cast<WlanFreeMemoryFunc
>(
56 ::GetProcAddress(module
, "WlanFreeMemory"));
57 close_handle_func
= reinterpret_cast<WlanCloseHandleFunc
>(
58 ::GetProcAddress(module
, "WlanCloseHandle"));
59 initialized
= open_handle_func
&& enum_interfaces_func
&&
60 query_interface_func
&& free_memory_func
&&
65 DWORD
OpenHandle(DWORD client_version
, DWORD
* cur_version
, T
* handle
) const {
67 DWORD result
= open_handle_func(client_version
, NULL
, cur_version
,
69 if (result
!= ERROR_SUCCESS
)
71 handle
->Set(temp_handle
);
76 WlanOpenHandleFunc open_handle_func
;
77 WlanEnumInterfacesFunc enum_interfaces_func
;
78 WlanQueryInterfaceFunc query_interface_func
;
79 WlanFreeMemoryFunc free_memory_func
;
80 WlanCloseHandleFunc close_handle_func
;
88 bool FileURLToFilePath(const GURL
& url
, base::FilePath
* file_path
) {
89 *file_path
= base::FilePath();
90 std::wstring
& file_path_str
= const_cast<std::wstring
&>(file_path
->value());
91 file_path_str
.clear();
97 std::string host
= url
.host();
99 // URL contains no host, the path is the filename. In this case, the path
100 // will probably be preceeded with a slash, as in "/C:/foo.txt", so we
101 // trim out that here.
103 size_t first_non_slash
= path
.find_first_not_of("/\\");
104 if (first_non_slash
!= std::string::npos
&& first_non_slash
> 0)
105 path
.erase(0, first_non_slash
);
107 // URL contains a host: this means it's UNC. We keep the preceeding slash
111 path
.append(url
.path());
116 std::replace(path
.begin(), path
.end(), '/', '\\');
118 // GURL stores strings as percent-encoded UTF-8, this will undo if possible.
119 path
= UnescapeURLComponent(path
,
120 UnescapeRule::SPACES
| UnescapeRule::URL_SPECIAL_CHARS
);
122 if (!IsStringUTF8(path
)) {
123 // Not UTF-8, assume encoding is native codepage and we're done. We know we
124 // are giving the conversion function a nonempty string, and it may fail if
125 // the given string is not in the current encoding and give us an empty
126 // string back. We detect this and report failure.
127 file_path_str
= base::SysNativeMBToWide(path
);
128 return !file_path_str
.empty();
130 file_path_str
.assign(base::UTF8ToWide(path
));
132 // We used to try too hard and see if |path| made up entirely of
133 // the 1st 256 characters in the Unicode was a zero-extended UTF-16.
134 // If so, we converted it to 'Latin-1' and checked if the result was UTF-8.
135 // If the check passed, we converted the result to UTF-8.
136 // Otherwise, we treated the result as the native OS encoding.
137 // However, that led to http://crbug.com/4619 and http://crbug.com/14153
141 bool GetNetworkList(NetworkInterfaceList
* networks
,
142 HostScopeVirtualInterfacePolicy policy
) {
143 // GetAdaptersAddresses() may require IO operations.
144 base::ThreadRestrictions::AssertIOAllowed();
145 bool is_xp
= base::win::GetVersion() < base::win::VERSION_VISTA
;
147 ULONG flags
= is_xp
? GAA_FLAG_INCLUDE_PREFIX
: 0;
148 // First get number of networks.
149 ULONG result
= GetAdaptersAddresses(AF_UNSPEC
, flags
, NULL
, NULL
, &len
);
150 if (result
!= ERROR_BUFFER_OVERFLOW
) {
151 // There are 0 networks.
154 scoped_ptr
<char[]> buf(new char[len
]);
155 IP_ADAPTER_ADDRESSES
*adapters
=
156 reinterpret_cast<IP_ADAPTER_ADDRESSES
*>(buf
.get());
157 result
= GetAdaptersAddresses(AF_UNSPEC
, flags
, NULL
, adapters
, &len
);
158 if (result
!= NO_ERROR
) {
159 LOG(ERROR
) << "GetAdaptersAddresses failed: " << result
;
163 for (IP_ADAPTER_ADDRESSES
*adapter
= adapters
; adapter
!= NULL
;
164 adapter
= adapter
->Next
) {
165 // Ignore the loopback device.
166 if (adapter
->IfType
== IF_TYPE_SOFTWARE_LOOPBACK
) {
170 if (adapter
->OperStatus
!= IfOperStatusUp
) {
174 // Ignore any HOST side vmware adapters with a description like:
175 // VMware Virtual Ethernet Adapter for VMnet1
176 // but don't ignore any GUEST side adapters with a description like:
177 // VMware Accelerated AMD PCNet Adapter #2
178 if (policy
== EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES
&&
179 strstr(adapter
->AdapterName
, "VMnet") != NULL
) {
183 for (IP_ADAPTER_UNICAST_ADDRESS
* address
= adapter
->FirstUnicastAddress
;
184 address
; address
= address
->Next
) {
185 int family
= address
->Address
.lpSockaddr
->sa_family
;
186 if (family
== AF_INET
|| family
== AF_INET6
) {
188 if (endpoint
.FromSockAddr(address
->Address
.lpSockaddr
,
189 address
->Address
.iSockaddrLength
)) {
190 // XP has no OnLinkPrefixLength field.
191 size_t net_prefix
= is_xp
? 0 : address
->OnLinkPrefixLength
;
193 // Prior to Windows Vista the FirstPrefix pointed to the list with
194 // single prefix for each IP address assigned to the adapter.
195 // Order of FirstPrefix does not match order of FirstUnicastAddress,
196 // so we need to find corresponding prefix.
197 for (IP_ADAPTER_PREFIX
* prefix
= adapter
->FirstPrefix
; prefix
;
198 prefix
= prefix
->Next
) {
199 int prefix_family
= prefix
->Address
.lpSockaddr
->sa_family
;
200 IPEndPoint network_endpoint
;
201 if (prefix_family
== family
&&
202 network_endpoint
.FromSockAddr(prefix
->Address
.lpSockaddr
,
203 prefix
->Address
.iSockaddrLength
) &&
204 IPNumberMatchesPrefix(endpoint
.address(),
205 network_endpoint
.address(),
206 prefix
->PrefixLength
)) {
207 net_prefix
= std::max
<size_t>(net_prefix
, prefix
->PrefixLength
);
212 (family
== AF_INET
) ? adapter
->IfIndex
: adapter
->Ipv6IfIndex
;
214 NetworkInterface(adapter
->AdapterName
, index
, endpoint
.address(),
224 WifiPHYLayerProtocol
GetWifiPHYLayerProtocol() {
225 static base::LazyInstance
<WlanApi
>::Leaky lazy_wlanapi
=
226 LAZY_INSTANCE_INITIALIZER
;
228 struct WlanApiHandleTraits
{
229 typedef HANDLE Handle
;
231 static bool CloseHandle(HANDLE handle
) {
232 return lazy_wlanapi
.Get().close_handle_func(handle
, NULL
) ==
235 static bool IsHandleValid(HANDLE handle
) {
236 return base::win::HandleTraits::IsHandleValid(handle
);
238 static HANDLE
NullHandle() {
239 return base::win::HandleTraits::NullHandle();
243 typedef base::win::GenericScopedHandle
<
245 base::win::DummyVerifierTraits
> WlanHandle
;
247 struct WlanApiDeleter
{
248 inline void operator()(void* ptr
) const {
249 lazy_wlanapi
.Get().free_memory_func(ptr
);
253 const WlanApi
& wlanapi
= lazy_wlanapi
.Get();
254 if (!wlanapi
.initialized
)
255 return WIFI_PHY_LAYER_PROTOCOL_NONE
;
258 DWORD cur_version
= 0;
259 const DWORD kMaxClientVersion
= 2;
260 DWORD result
= wlanapi
.OpenHandle(kMaxClientVersion
, &cur_version
, &client
);
261 if (result
!= ERROR_SUCCESS
)
262 return WIFI_PHY_LAYER_PROTOCOL_NONE
;
264 WLAN_INTERFACE_INFO_LIST
* interface_list_ptr
= NULL
;
265 result
= wlanapi
.enum_interfaces_func(client
, NULL
, &interface_list_ptr
);
266 if (result
!= ERROR_SUCCESS
)
267 return WIFI_PHY_LAYER_PROTOCOL_NONE
;
268 scoped_ptr
<WLAN_INTERFACE_INFO_LIST
, WlanApiDeleter
> interface_list(
271 // Assume at most one connected wifi interface.
272 WLAN_INTERFACE_INFO
* info
= NULL
;
273 for (unsigned i
= 0; i
< interface_list
->dwNumberOfItems
; ++i
) {
274 if (interface_list
->InterfaceInfo
[i
].isState
==
275 wlan_interface_state_connected
) {
276 info
= &interface_list
->InterfaceInfo
[i
];
282 return WIFI_PHY_LAYER_PROTOCOL_NONE
;
284 WLAN_CONNECTION_ATTRIBUTES
* conn_info_ptr
;
285 DWORD conn_info_size
= 0;
286 WLAN_OPCODE_VALUE_TYPE op_code
;
287 result
= wlanapi
.query_interface_func(
288 client
, &info
->InterfaceGuid
, wlan_intf_opcode_current_connection
, NULL
,
289 &conn_info_size
, reinterpret_cast<VOID
**>(&conn_info_ptr
), &op_code
);
290 if (result
!= ERROR_SUCCESS
)
291 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN
;
292 scoped_ptr
<WLAN_CONNECTION_ATTRIBUTES
, WlanApiDeleter
> conn_info(
295 switch (conn_info
->wlanAssociationAttributes
.dot11PhyType
) {
296 case dot11_phy_type_fhss
:
297 return WIFI_PHY_LAYER_PROTOCOL_ANCIENT
;
298 case dot11_phy_type_dsss
:
299 return WIFI_PHY_LAYER_PROTOCOL_B
;
300 case dot11_phy_type_irbaseband
:
301 return WIFI_PHY_LAYER_PROTOCOL_ANCIENT
;
302 case dot11_phy_type_ofdm
:
303 return WIFI_PHY_LAYER_PROTOCOL_A
;
304 case dot11_phy_type_hrdsss
:
305 return WIFI_PHY_LAYER_PROTOCOL_B
;
306 case dot11_phy_type_erp
:
307 return WIFI_PHY_LAYER_PROTOCOL_G
;
308 case dot11_phy_type_ht
:
309 return WIFI_PHY_LAYER_PROTOCOL_N
;
311 return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN
;