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