• 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 #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 
14 #include "base/logging.h"
15 #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 
20 namespace net {
21 
22 namespace {
23 
24 static const char kIfnameEm1[] = "em1";
25 static const char kIfnameVmnet[] = "VMnet";
26 
27 static const unsigned char kIPv6LocalAddr[] = {0, 0, 0, 0, 0, 0, 0, 0,
28                                                0, 0, 0, 0, 0, 0, 0, 1};
29 
30 static const unsigned char kIPv6Addr[] = {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04,
31                                           0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
32                                           0xfe, 0xe5, 0x00, 0xc3};
33 static 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.
FillAdapterAddress(IP_ADAPTER_ADDRESSES * adapter_address,const char * ifname,const IPAddress & ip_address,const IPAddress & ip_netmask,sockaddr_storage sock_addrs[2])41 bool 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 
56   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 
64   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 
TEST(NetworkInterfacesTest,NetworkListTrimmingWindows)99 TEST(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 
TEST(NetworkInterfacesTest,NetworkListExtractMacAddress)199 TEST(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 
TEST(NetworkInterfacesTest,NetworkListExtractMacAddressInvalidLength)223 TEST(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 
read_int_or_bool(DWORD data_size,PVOID data)247 bool 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 
GetWifiOptions()259 int 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 
271   WLAN_INTERFACE_INFO_LIST* interface_list_ptr = nullptr;
272   result =
273       wlanapi.enum_interfaces_func(client.Get(), nullptr, &interface_list_ptr);
274   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,
287                                      nullptr, &data_size, &data, nullptr);
288     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,
297                                           nullptr, &data_size, &data, nullptr);
298     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 
TryChangeWifiOptions(int options)314 void 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 fails on Win Arm64 bots. TODO(https://crbug.com/1425465): Fix on bot.
323 #if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_ARM64)
324 #define MAYBE_SetWifiOptions DISABLED_SetWifiOptions
325 #else
326 #define MAYBE_SetWifiOptions SetWifiOptions
327 #endif
328 // Test SetWifiOptions().
TEST(NetworkInterfacesTest,MAYBE_SetWifiOptions)329 TEST(NetworkInterfacesTest, MAYBE_SetWifiOptions) {
330   TryChangeWifiOptions(0);
331   TryChangeWifiOptions(WIFI_OPTIONS_DISABLE_SCAN);
332   TryChangeWifiOptions(WIFI_OPTIONS_MEDIA_STREAMING_MODE);
333   TryChangeWifiOptions(WIFI_OPTIONS_DISABLE_SCAN |
334                        WIFI_OPTIONS_MEDIA_STREAMING_MODE);
335 }
336 
337 }  // namespace
338 
339 }  // namespace net
340