blob: 75a73ea4f5c6577210034d9c686e4c4e0ba4db5d [file] [log] [blame]
Avi Drissman64595482022-09-14 20:52:291// Copyright 2017 The Chromium Authors
Sergey Ulanov5bb07d32017-07-12 04:14:542// 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/network_interfaces_win.h"
6
7#include <iphlpapi.h>
8#include <objbase.h>
9
10#include <ostream>
11#include <string>
12#include <unordered_set>
13
Hans Wennborg725d0432020-06-18 13:54:1614#include "base/logging.h"
Sergey Ulanov5bb07d32017-07-12 04:14:5415#include "base/strings/utf_string_conversions.h"
16#include "build/build_config.h"
17#include "net/base/ip_endpoint.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20namespace net {
21
22namespace {
23
24static const char kIfnameEm1[] = "em1";
25static const char kIfnameVmnet[] = "VMnet";
26
27static const unsigned char kIPv6LocalAddr[] = {0, 0, 0, 0, 0, 0, 0, 0,
28 0, 0, 0, 0, 0, 0, 0, 1};
29
30static const unsigned char kIPv6Addr[] = {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04,
31 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
32 0xfe, 0xe5, 0x00, 0xc3};
33static const unsigned char kIPv6AddrPrefix[] = {
34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
36
37// Helper function to create a valid IP_ADAPTER_ADDRESSES with reasonable
38// default value. The output is the |adapter_address|. All the rests are input
39// to fill the |adapter_address|. |sock_addrs| are temporary storage used by
40// |adapter_address| once the function is returned.
41bool FillAdapterAddress(IP_ADAPTER_ADDRESSES* adapter_address,
42 const char* ifname,
43 const IPAddress& ip_address,
44 const IPAddress& ip_netmask,
45 sockaddr_storage sock_addrs[2]) {
46 adapter_address->AdapterName = const_cast<char*>(ifname);
47 adapter_address->FriendlyName = const_cast<PWCHAR>(L"interface");
48 adapter_address->IfType = IF_TYPE_ETHERNET_CSMACD;
49 adapter_address->OperStatus = IfOperStatusUp;
50 adapter_address->FirstUnicastAddress->DadState = IpDadStatePreferred;
51 adapter_address->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther;
52 adapter_address->FirstUnicastAddress->SuffixOrigin = IpSuffixOriginOther;
53 adapter_address->FirstUnicastAddress->PreferredLifetime = 100;
54 adapter_address->FirstUnicastAddress->ValidLifetime = 1000;
55
Erik Oveliusb51918572022-09-02 18:52:1256 DCHECK(sizeof(adapter_address->PhysicalAddress) > 5);
57 // Generate 06:05:04:03:02:01
58 adapter_address->PhysicalAddressLength = 6;
59 for (unsigned long i = 0; i < adapter_address->PhysicalAddressLength; i++) {
60 adapter_address->PhysicalAddress[i] =
61 adapter_address->PhysicalAddressLength - i;
62 }
63
Sergey Ulanov5bb07d32017-07-12 04:14:5464 socklen_t sock_len = sizeof(sockaddr_storage);
65
66 // Convert to sockaddr for next check.
67 if (!IPEndPoint(ip_address, 0)
68 .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[0]),
69 &sock_len)) {
70 return false;
71 }
72 adapter_address->FirstUnicastAddress->Address.lpSockaddr =
73 reinterpret_cast<sockaddr*>(&sock_addrs[0]);
74 adapter_address->FirstUnicastAddress->Address.iSockaddrLength = sock_len;
75 adapter_address->FirstUnicastAddress->OnLinkPrefixLength = 1;
76
77 sock_len = sizeof(sockaddr_storage);
78 if (!IPEndPoint(ip_netmask, 0)
79 .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[1]),
80 &sock_len)) {
81 return false;
82 }
83 adapter_address->FirstPrefix->Address.lpSockaddr =
84 reinterpret_cast<sockaddr*>(&sock_addrs[1]);
85 adapter_address->FirstPrefix->Address.iSockaddrLength = sock_len;
86 adapter_address->FirstPrefix->PrefixLength = 1;
87
88 DCHECK_EQ(sock_addrs[0].ss_family, sock_addrs[1].ss_family);
89 if (sock_addrs[0].ss_family == AF_INET6) {
90 adapter_address->Ipv6IfIndex = 0;
91 } else {
92 DCHECK_EQ(sock_addrs[0].ss_family, AF_INET);
93 adapter_address->IfIndex = 0;
94 }
95
96 return true;
97}
98
99TEST(NetworkInterfacesTest, NetworkListTrimmingWindows) {
100 IPAddress ipv6_local_address(kIPv6LocalAddr);
101 IPAddress ipv6_address(kIPv6Addr);
102 IPAddress ipv6_prefix(kIPv6AddrPrefix);
103
104 NetworkInterfaceList results;
105 sockaddr_storage addresses[2];
106 IP_ADAPTER_ADDRESSES adapter_address = {};
107 IP_ADAPTER_UNICAST_ADDRESS address = {};
108 IP_ADAPTER_PREFIX adapter_prefix = {};
109 adapter_address.FirstUnicastAddress = &address;
110 adapter_address.FirstPrefix = &adapter_prefix;
111
112 // Address of offline links should be ignored.
113 ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
114 ipv6_prefix, addresses));
115 adapter_address.OperStatus = IfOperStatusDown;
116
117 EXPECT_TRUE(internal::GetNetworkListImpl(
118 &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
119
120 EXPECT_EQ(results.size(), 0ul);
121
122 // Address on loopback interface should be trimmed out.
123 ASSERT_TRUE(FillAdapterAddress(
124 &adapter_address /* adapter_address */, kIfnameEm1 /* ifname */,
125 ipv6_local_address /* ip_address */, ipv6_prefix /* ip_netmask */,
126 addresses /* sock_addrs */));
127 adapter_address.IfType = IF_TYPE_SOFTWARE_LOOPBACK;
128
129 EXPECT_TRUE(internal::GetNetworkListImpl(
130 &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
131 EXPECT_EQ(results.size(), 0ul);
132
133 // vmware address should return by default.
134 ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameVmnet, ipv6_address,
135 ipv6_prefix, addresses));
136 EXPECT_TRUE(internal::GetNetworkListImpl(
137 &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
138 EXPECT_EQ(results.size(), 1ul);
139 EXPECT_EQ(results[0].name, kIfnameVmnet);
140 EXPECT_EQ(results[0].prefix_length, 1ul);
141 EXPECT_EQ(results[0].address, ipv6_address);
142 EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_NONE);
143 results.clear();
144
145 // vmware address should be trimmed out if policy specified so.
146 ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameVmnet, ipv6_address,
147 ipv6_prefix, addresses));
148 EXPECT_TRUE(internal::GetNetworkListImpl(
149 &results, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
150 EXPECT_EQ(results.size(), 0ul);
151 results.clear();
152
153 // Addresses with incomplete DAD should be ignored.
154 ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
155 ipv6_prefix, addresses));
156 adapter_address.FirstUnicastAddress->DadState = IpDadStateTentative;
157
158 EXPECT_TRUE(internal::GetNetworkListImpl(
159 &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
160 EXPECT_EQ(results.size(), 0ul);
161 results.clear();
162
163 // Addresses with allowed attribute IpSuffixOriginRandom should be returned
164 // and attributes should be translated correctly to
165 // IP_ADDRESS_ATTRIBUTE_TEMPORARY.
166 ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
167 ipv6_prefix, addresses));
168 adapter_address.FirstUnicastAddress->PrefixOrigin =
169 IpPrefixOriginRouterAdvertisement;
170 adapter_address.FirstUnicastAddress->SuffixOrigin = IpSuffixOriginRandom;
171
172 EXPECT_TRUE(internal::GetNetworkListImpl(
173 &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
174 EXPECT_EQ(results.size(), 1ul);
175 EXPECT_EQ(results[0].name, kIfnameEm1);
176 EXPECT_EQ(results[0].prefix_length, 1ul);
177 EXPECT_EQ(results[0].address, ipv6_address);
178 EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY);
179 results.clear();
180
181 // Addresses with preferred lifetime 0 should be returned and
182 // attributes should be translated correctly to
183 // IP_ADDRESS_ATTRIBUTE_DEPRECATED.
184 ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
185 ipv6_prefix, addresses));
186 adapter_address.FirstUnicastAddress->PreferredLifetime = 0;
187 adapter_address.FriendlyName = const_cast<PWCHAR>(L"FriendlyInterfaceName");
188 EXPECT_TRUE(internal::GetNetworkListImpl(
189 &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
190 EXPECT_EQ(results.size(), 1ul);
191 EXPECT_EQ(results[0].friendly_name, "FriendlyInterfaceName");
192 EXPECT_EQ(results[0].name, kIfnameEm1);
193 EXPECT_EQ(results[0].prefix_length, 1ul);
194 EXPECT_EQ(results[0].address, ipv6_address);
195 EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED);
196 results.clear();
197}
198
Erik Oveliusb51918572022-09-02 18:52:12199TEST(NetworkInterfacesTest, NetworkListExtractMacAddress) {
200 IPAddress ipv6_local_address(kIPv6LocalAddr);
201 IPAddress ipv6_address(kIPv6Addr);
202 IPAddress ipv6_prefix(kIPv6AddrPrefix);
203
204 NetworkInterfaceList results;
205 sockaddr_storage addresses[2];
206 IP_ADAPTER_ADDRESSES adapter_address = {};
207 IP_ADAPTER_UNICAST_ADDRESS address = {};
208 IP_ADAPTER_PREFIX adapter_prefix = {};
209 adapter_address.FirstUnicastAddress = &address;
210 adapter_address.FirstPrefix = &adapter_prefix;
211
212 ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
213 ipv6_prefix, addresses));
214
215 Eui48MacAddress expected_mac_address = {0x6, 0x5, 0x4, 0x3, 0x2, 0x1};
216
217 EXPECT_TRUE(internal::GetNetworkListImpl(
218 &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
219 ASSERT_EQ(results.size(), 1ul);
220 ASSERT_EQ(results[0].mac_address, expected_mac_address);
221}
222
223TEST(NetworkInterfacesTest, NetworkListExtractMacAddressInvalidLength) {
224 IPAddress ipv6_local_address(kIPv6LocalAddr);
225 IPAddress ipv6_address(kIPv6Addr);
226 IPAddress ipv6_prefix(kIPv6AddrPrefix);
227
228 NetworkInterfaceList results;
229 sockaddr_storage addresses[2];
230 IP_ADAPTER_ADDRESSES adapter_address = {};
231 IP_ADAPTER_UNICAST_ADDRESS address = {};
232 IP_ADAPTER_PREFIX adapter_prefix = {};
233 adapter_address.FirstUnicastAddress = &address;
234 adapter_address.FirstPrefix = &adapter_prefix;
235
236 ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
237 ipv6_prefix, addresses));
238 // Not EUI-48 Mac address, so it is not extracted.
239 adapter_address.PhysicalAddressLength = 8;
240
241 EXPECT_TRUE(internal::GetNetworkListImpl(
242 &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
243 ASSERT_EQ(results.size(), 1ul);
244 EXPECT_FALSE(results[0].mac_address.has_value());
245}
246
Sergey Ulanov5bb07d32017-07-12 04:14:54247bool read_int_or_bool(DWORD data_size, PVOID data) {
248 switch (data_size) {
249 case 1:
250 return !!*reinterpret_cast<uint8_t*>(data);
251 case 4:
252 return !!*reinterpret_cast<uint32_t*>(data);
253 default:
254 LOG(FATAL) << "That is not a type I know!";
255 return false;
256 }
257}
258
259int GetWifiOptions() {
260 const internal::WlanApi& wlanapi = internal::WlanApi::GetInstance();
261 if (!wlanapi.initialized)
262 return -1;
263
264 internal::WlanHandle client;
265 DWORD cur_version = 0;
266 const DWORD kMaxClientVersion = 2;
267 DWORD result = wlanapi.OpenHandle(kMaxClientVersion, &cur_version, &client);
268 if (result != ERROR_SUCCESS)
269 return -1;
270
Raul Tambre94493c652019-03-11 17:18:35271 WLAN_INTERFACE_INFO_LIST* interface_list_ptr = nullptr;
Sergey Ulanov5bb07d32017-07-12 04:14:54272 result =
Raul Tambre94493c652019-03-11 17:18:35273 wlanapi.enum_interfaces_func(client.Get(), nullptr, &interface_list_ptr);
Sergey Ulanov5bb07d32017-07-12 04:14:54274 if (result != ERROR_SUCCESS)
275 return -1;
276 std::unique_ptr<WLAN_INTERFACE_INFO_LIST, internal::WlanApiDeleter>
277 interface_list(interface_list_ptr);
278
279 for (unsigned i = 0; i < interface_list->dwNumberOfItems; ++i) {
280 WLAN_INTERFACE_INFO* info = &interface_list->InterfaceInfo[i];
281 DWORD data_size;
282 PVOID data;
283 int options = 0;
284 result =
285 wlanapi.query_interface_func(client.Get(), &info->InterfaceGuid,
286 wlan_intf_opcode_background_scan_enabled,
Raul Tambre94493c652019-03-11 17:18:35287 nullptr, &data_size, &data, nullptr);
Sergey Ulanov5bb07d32017-07-12 04:14:54288 if (result != ERROR_SUCCESS)
289 continue;
290 if (!read_int_or_bool(data_size, data)) {
291 options |= WIFI_OPTIONS_DISABLE_SCAN;
292 }
293 internal::WlanApi::GetInstance().free_memory_func(data);
294
295 result = wlanapi.query_interface_func(client.Get(), &info->InterfaceGuid,
296 wlan_intf_opcode_media_streaming_mode,
Raul Tambre94493c652019-03-11 17:18:35297 nullptr, &data_size, &data, nullptr);
Sergey Ulanov5bb07d32017-07-12 04:14:54298 if (result != ERROR_SUCCESS)
299 continue;
300 if (read_int_or_bool(data_size, data)) {
301 options |= WIFI_OPTIONS_MEDIA_STREAMING_MODE;
302 }
303 internal::WlanApi::GetInstance().free_memory_func(data);
304
305 // Just the the options from the first succesful
306 // interface.
307 return options;
308 }
309
310 // No wifi interface found.
311 return -1;
312}
313
314void TryChangeWifiOptions(int options) {
315 int previous_options = GetWifiOptions();
316 std::unique_ptr<ScopedWifiOptions> scoped_options = SetWifiOptions(options);
317 EXPECT_EQ(previous_options | options, GetWifiOptions());
318 scoped_options.reset();
319 EXPECT_EQ(previous_options, GetWifiOptions());
320}
321
322// Test SetWifiOptions().
323TEST(NetworkInterfacesTest, SetWifiOptions) {
324 TryChangeWifiOptions(0);
325 TryChangeWifiOptions(WIFI_OPTIONS_DISABLE_SCAN);
326 TryChangeWifiOptions(WIFI_OPTIONS_MEDIA_STREAMING_MODE);
327 TryChangeWifiOptions(WIFI_OPTIONS_DISABLE_SCAN |
328 WIFI_OPTIONS_MEDIA_STREAMING_MODE);
329}
330
331} // namespace
332
333} // namespace net