1 // Copyright 2017 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/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/strings/utf_string_conversions.h"
15 #include "build/build_config.h"
16 #include "net/base/ip_endpoint.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 namespace net {
20 
21 namespace {
22 
23 static const char kIfnameEm1[] = "em1";
24 static const char kIfnameVmnet[] = "VMnet";
25 
26 static const unsigned char kIPv6LocalAddr[] = {0, 0, 0, 0, 0, 0, 0, 0,
27                                                0, 0, 0, 0, 0, 0, 0, 1};
28 
29 static const unsigned char kIPv6Addr[] = {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04,
30                                           0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
31                                           0xfe, 0xe5, 0x00, 0xc3};
32 static const unsigned char kIPv6AddrPrefix[] = {
33     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
35 
36 // Helper function to create a valid IP_ADAPTER_ADDRESSES with reasonable
37 // default value. The output is the |adapter_address|. All the rests are input
38 // to fill the |adapter_address|. |sock_addrs| are temporary storage used by
39 // |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])40 bool FillAdapterAddress(IP_ADAPTER_ADDRESSES* adapter_address,
41                         const char* ifname,
42                         const IPAddress& ip_address,
43                         const IPAddress& ip_netmask,
44                         sockaddr_storage sock_addrs[2]) {
45   adapter_address->AdapterName = const_cast<char*>(ifname);
46   adapter_address->FriendlyName = const_cast<PWCHAR>(L"interface");
47   adapter_address->IfType = IF_TYPE_ETHERNET_CSMACD;
48   adapter_address->OperStatus = IfOperStatusUp;
49   adapter_address->FirstUnicastAddress->DadState = IpDadStatePreferred;
50   adapter_address->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther;
51   adapter_address->FirstUnicastAddress->SuffixOrigin = IpSuffixOriginOther;
52   adapter_address->FirstUnicastAddress->PreferredLifetime = 100;
53   adapter_address->FirstUnicastAddress->ValidLifetime = 1000;
54 
55   socklen_t sock_len = sizeof(sockaddr_storage);
56 
57   // Convert to sockaddr for next check.
58   if (!IPEndPoint(ip_address, 0)
59            .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[0]),
60                        &sock_len)) {
61     return false;
62   }
63   adapter_address->FirstUnicastAddress->Address.lpSockaddr =
64       reinterpret_cast<sockaddr*>(&sock_addrs[0]);
65   adapter_address->FirstUnicastAddress->Address.iSockaddrLength = sock_len;
66   adapter_address->FirstUnicastAddress->OnLinkPrefixLength = 1;
67 
68   sock_len = sizeof(sockaddr_storage);
69   if (!IPEndPoint(ip_netmask, 0)
70            .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[1]),
71                        &sock_len)) {
72     return false;
73   }
74   adapter_address->FirstPrefix->Address.lpSockaddr =
75       reinterpret_cast<sockaddr*>(&sock_addrs[1]);
76   adapter_address->FirstPrefix->Address.iSockaddrLength = sock_len;
77   adapter_address->FirstPrefix->PrefixLength = 1;
78 
79   DCHECK_EQ(sock_addrs[0].ss_family, sock_addrs[1].ss_family);
80   if (sock_addrs[0].ss_family == AF_INET6) {
81     adapter_address->Ipv6IfIndex = 0;
82   } else {
83     DCHECK_EQ(sock_addrs[0].ss_family, AF_INET);
84     adapter_address->IfIndex = 0;
85   }
86 
87   return true;
88 }
89 
TEST(NetworkInterfacesTest,NetworkListTrimmingWindows)90 TEST(NetworkInterfacesTest, NetworkListTrimmingWindows) {
91   IPAddress ipv6_local_address(kIPv6LocalAddr);
92   IPAddress ipv6_address(kIPv6Addr);
93   IPAddress ipv6_prefix(kIPv6AddrPrefix);
94 
95   NetworkInterfaceList results;
96   sockaddr_storage addresses[2];
97   IP_ADAPTER_ADDRESSES adapter_address = {};
98   IP_ADAPTER_UNICAST_ADDRESS address = {};
99   IP_ADAPTER_PREFIX adapter_prefix = {};
100   adapter_address.FirstUnicastAddress = &address;
101   adapter_address.FirstPrefix = &adapter_prefix;
102 
103   // Address of offline links should be ignored.
104   ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
105                                  ipv6_prefix, addresses));
106   adapter_address.OperStatus = IfOperStatusDown;
107 
108   EXPECT_TRUE(internal::GetNetworkListImpl(
109       &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
110 
111   EXPECT_EQ(results.size(), 0ul);
112 
113   // Address on loopback interface should be trimmed out.
114   ASSERT_TRUE(FillAdapterAddress(
115       &adapter_address /* adapter_address */, kIfnameEm1 /* ifname */,
116       ipv6_local_address /* ip_address */, ipv6_prefix /* ip_netmask */,
117       addresses /* sock_addrs */));
118   adapter_address.IfType = IF_TYPE_SOFTWARE_LOOPBACK;
119 
120   EXPECT_TRUE(internal::GetNetworkListImpl(
121       &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
122   EXPECT_EQ(results.size(), 0ul);
123 
124   // vmware address should return by default.
125   ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameVmnet, ipv6_address,
126                                  ipv6_prefix, addresses));
127   EXPECT_TRUE(internal::GetNetworkListImpl(
128       &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
129   EXPECT_EQ(results.size(), 1ul);
130   EXPECT_EQ(results[0].name, kIfnameVmnet);
131   EXPECT_EQ(results[0].prefix_length, 1ul);
132   EXPECT_EQ(results[0].address, ipv6_address);
133   EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_NONE);
134   results.clear();
135 
136   // vmware address should be trimmed out if policy specified so.
137   ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameVmnet, ipv6_address,
138                                  ipv6_prefix, addresses));
139   EXPECT_TRUE(internal::GetNetworkListImpl(
140       &results, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
141   EXPECT_EQ(results.size(), 0ul);
142   results.clear();
143 
144   // Addresses with incomplete DAD should be ignored.
145   ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
146                                  ipv6_prefix, addresses));
147   adapter_address.FirstUnicastAddress->DadState = IpDadStateTentative;
148 
149   EXPECT_TRUE(internal::GetNetworkListImpl(
150       &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
151   EXPECT_EQ(results.size(), 0ul);
152   results.clear();
153 
154   // Addresses with allowed attribute IpSuffixOriginRandom should be returned
155   // and attributes should be translated correctly to
156   // IP_ADDRESS_ATTRIBUTE_TEMPORARY.
157   ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
158                                  ipv6_prefix, addresses));
159   adapter_address.FirstUnicastAddress->PrefixOrigin =
160       IpPrefixOriginRouterAdvertisement;
161   adapter_address.FirstUnicastAddress->SuffixOrigin = IpSuffixOriginRandom;
162 
163   EXPECT_TRUE(internal::GetNetworkListImpl(
164       &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
165   EXPECT_EQ(results.size(), 1ul);
166   EXPECT_EQ(results[0].name, kIfnameEm1);
167   EXPECT_EQ(results[0].prefix_length, 1ul);
168   EXPECT_EQ(results[0].address, ipv6_address);
169   EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY);
170   results.clear();
171 
172   // Addresses with preferred lifetime 0 should be returned and
173   // attributes should be translated correctly to
174   // IP_ADDRESS_ATTRIBUTE_DEPRECATED.
175   ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
176                                  ipv6_prefix, addresses));
177   adapter_address.FirstUnicastAddress->PreferredLifetime = 0;
178   adapter_address.FriendlyName = const_cast<PWCHAR>(L"FriendlyInterfaceName");
179   EXPECT_TRUE(internal::GetNetworkListImpl(
180       &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
181   EXPECT_EQ(results.size(), 1ul);
182   EXPECT_EQ(results[0].friendly_name, "FriendlyInterfaceName");
183   EXPECT_EQ(results[0].name, kIfnameEm1);
184   EXPECT_EQ(results[0].prefix_length, 1ul);
185   EXPECT_EQ(results[0].address, ipv6_address);
186   EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED);
187   results.clear();
188 }
189 
read_int_or_bool(DWORD data_size,PVOID data)190 bool read_int_or_bool(DWORD data_size, PVOID data) {
191   switch (data_size) {
192     case 1:
193       return !!*reinterpret_cast<uint8_t*>(data);
194     case 4:
195       return !!*reinterpret_cast<uint32_t*>(data);
196     default:
197       LOG(FATAL) << "That is not a type I know!";
198       return false;
199   }
200 }
201 
GetWifiOptions()202 int GetWifiOptions() {
203   const internal::WlanApi& wlanapi = internal::WlanApi::GetInstance();
204   if (!wlanapi.initialized)
205     return -1;
206 
207   internal::WlanHandle client;
208   DWORD cur_version = 0;
209   const DWORD kMaxClientVersion = 2;
210   DWORD result = wlanapi.OpenHandle(kMaxClientVersion, &cur_version, &client);
211   if (result != ERROR_SUCCESS)
212     return -1;
213 
214   WLAN_INTERFACE_INFO_LIST* interface_list_ptr = nullptr;
215   result =
216       wlanapi.enum_interfaces_func(client.Get(), nullptr, &interface_list_ptr);
217   if (result != ERROR_SUCCESS)
218     return -1;
219   std::unique_ptr<WLAN_INTERFACE_INFO_LIST, internal::WlanApiDeleter>
220       interface_list(interface_list_ptr);
221 
222   for (unsigned i = 0; i < interface_list->dwNumberOfItems; ++i) {
223     WLAN_INTERFACE_INFO* info = &interface_list->InterfaceInfo[i];
224     DWORD data_size;
225     PVOID data;
226     int options = 0;
227     result =
228         wlanapi.query_interface_func(client.Get(), &info->InterfaceGuid,
229                                      wlan_intf_opcode_background_scan_enabled,
230                                      nullptr, &data_size, &data, nullptr);
231     if (result != ERROR_SUCCESS)
232       continue;
233     if (!read_int_or_bool(data_size, data)) {
234       options |= WIFI_OPTIONS_DISABLE_SCAN;
235     }
236     internal::WlanApi::GetInstance().free_memory_func(data);
237 
238     result = wlanapi.query_interface_func(client.Get(), &info->InterfaceGuid,
239                                           wlan_intf_opcode_media_streaming_mode,
240                                           nullptr, &data_size, &data, nullptr);
241     if (result != ERROR_SUCCESS)
242       continue;
243     if (read_int_or_bool(data_size, data)) {
244       options |= WIFI_OPTIONS_MEDIA_STREAMING_MODE;
245     }
246     internal::WlanApi::GetInstance().free_memory_func(data);
247 
248     // Just the the options from the first succesful
249     // interface.
250     return options;
251   }
252 
253   // No wifi interface found.
254   return -1;
255 }
256 
TryChangeWifiOptions(int options)257 void TryChangeWifiOptions(int options) {
258   int previous_options = GetWifiOptions();
259   std::unique_ptr<ScopedWifiOptions> scoped_options = SetWifiOptions(options);
260   EXPECT_EQ(previous_options | options, GetWifiOptions());
261   scoped_options.reset();
262   EXPECT_EQ(previous_options, GetWifiOptions());
263 }
264 
265 // Test SetWifiOptions().
TEST(NetworkInterfacesTest,SetWifiOptions)266 TEST(NetworkInterfacesTest, SetWifiOptions) {
267   TryChangeWifiOptions(0);
268   TryChangeWifiOptions(WIFI_OPTIONS_DISABLE_SCAN);
269   TryChangeWifiOptions(WIFI_OPTIONS_MEDIA_STREAMING_MODE);
270   TryChangeWifiOptions(WIFI_OPTIONS_DISABLE_SCAN |
271                        WIFI_OPTIONS_MEDIA_STREAMING_MODE);
272 }
273 
274 }  // namespace
275 
276 }  // namespace net
277