123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "net/base/network_interfaces_win.h"
- #include <iphlpapi.h>
- #include <objbase.h>
- #include <ostream>
- #include <string>
- #include <unordered_set>
- #include "base/logging.h"
- #include "base/strings/utf_string_conversions.h"
- #include "build/build_config.h"
- #include "net/base/ip_endpoint.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace net {
- namespace {
- static const char kIfnameEm1[] = "em1";
- static const char kIfnameVmnet[] = "VMnet";
- static const unsigned char kIPv6LocalAddr[] = {0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1};
- static const unsigned char kIPv6Addr[] = {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04,
- 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
- 0xfe, 0xe5, 0x00, 0xc3};
- static const unsigned char kIPv6AddrPrefix[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- // Helper function to create a valid IP_ADAPTER_ADDRESSES with reasonable
- // default value. The output is the |adapter_address|. All the rests are input
- // to fill the |adapter_address|. |sock_addrs| are temporary storage used by
- // |adapter_address| once the function is returned.
- bool FillAdapterAddress(IP_ADAPTER_ADDRESSES* adapter_address,
- const char* ifname,
- const IPAddress& ip_address,
- const IPAddress& ip_netmask,
- sockaddr_storage sock_addrs[2]) {
- adapter_address->AdapterName = const_cast<char*>(ifname);
- adapter_address->FriendlyName = const_cast<PWCHAR>(L"interface");
- adapter_address->IfType = IF_TYPE_ETHERNET_CSMACD;
- adapter_address->OperStatus = IfOperStatusUp;
- adapter_address->FirstUnicastAddress->DadState = IpDadStatePreferred;
- adapter_address->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther;
- adapter_address->FirstUnicastAddress->SuffixOrigin = IpSuffixOriginOther;
- adapter_address->FirstUnicastAddress->PreferredLifetime = 100;
- adapter_address->FirstUnicastAddress->ValidLifetime = 1000;
- socklen_t sock_len = sizeof(sockaddr_storage);
- // Convert to sockaddr for next check.
- if (!IPEndPoint(ip_address, 0)
- .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[0]),
- &sock_len)) {
- return false;
- }
- adapter_address->FirstUnicastAddress->Address.lpSockaddr =
- reinterpret_cast<sockaddr*>(&sock_addrs[0]);
- adapter_address->FirstUnicastAddress->Address.iSockaddrLength = sock_len;
- adapter_address->FirstUnicastAddress->OnLinkPrefixLength = 1;
- sock_len = sizeof(sockaddr_storage);
- if (!IPEndPoint(ip_netmask, 0)
- .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[1]),
- &sock_len)) {
- return false;
- }
- adapter_address->FirstPrefix->Address.lpSockaddr =
- reinterpret_cast<sockaddr*>(&sock_addrs[1]);
- adapter_address->FirstPrefix->Address.iSockaddrLength = sock_len;
- adapter_address->FirstPrefix->PrefixLength = 1;
- DCHECK_EQ(sock_addrs[0].ss_family, sock_addrs[1].ss_family);
- if (sock_addrs[0].ss_family == AF_INET6) {
- adapter_address->Ipv6IfIndex = 0;
- } else {
- DCHECK_EQ(sock_addrs[0].ss_family, AF_INET);
- adapter_address->IfIndex = 0;
- }
- return true;
- }
- TEST(NetworkInterfacesTest, NetworkListTrimmingWindows) {
- IPAddress ipv6_local_address(kIPv6LocalAddr);
- IPAddress ipv6_address(kIPv6Addr);
- IPAddress ipv6_prefix(kIPv6AddrPrefix);
- NetworkInterfaceList results;
- sockaddr_storage addresses[2];
- IP_ADAPTER_ADDRESSES adapter_address = {};
- IP_ADAPTER_UNICAST_ADDRESS address = {};
- IP_ADAPTER_PREFIX adapter_prefix = {};
- adapter_address.FirstUnicastAddress = &address;
- adapter_address.FirstPrefix = &adapter_prefix;
- // Address of offline links should be ignored.
- ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
- ipv6_prefix, addresses));
- adapter_address.OperStatus = IfOperStatusDown;
- EXPECT_TRUE(internal::GetNetworkListImpl(
- &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
- EXPECT_EQ(results.size(), 0ul);
- // Address on loopback interface should be trimmed out.
- ASSERT_TRUE(FillAdapterAddress(
- &adapter_address /* adapter_address */, kIfnameEm1 /* ifname */,
- ipv6_local_address /* ip_address */, ipv6_prefix /* ip_netmask */,
- addresses /* sock_addrs */));
- adapter_address.IfType = IF_TYPE_SOFTWARE_LOOPBACK;
- EXPECT_TRUE(internal::GetNetworkListImpl(
- &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
- EXPECT_EQ(results.size(), 0ul);
- // vmware address should return by default.
- ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameVmnet, ipv6_address,
- ipv6_prefix, addresses));
- EXPECT_TRUE(internal::GetNetworkListImpl(
- &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
- EXPECT_EQ(results.size(), 1ul);
- EXPECT_EQ(results[0].name, kIfnameVmnet);
- EXPECT_EQ(results[0].prefix_length, 1ul);
- EXPECT_EQ(results[0].address, ipv6_address);
- EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_NONE);
- results.clear();
- // vmware address should be trimmed out if policy specified so.
- ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameVmnet, ipv6_address,
- ipv6_prefix, addresses));
- EXPECT_TRUE(internal::GetNetworkListImpl(
- &results, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
- EXPECT_EQ(results.size(), 0ul);
- results.clear();
- // Addresses with incomplete DAD should be ignored.
- ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
- ipv6_prefix, addresses));
- adapter_address.FirstUnicastAddress->DadState = IpDadStateTentative;
- EXPECT_TRUE(internal::GetNetworkListImpl(
- &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
- EXPECT_EQ(results.size(), 0ul);
- results.clear();
- // Addresses with allowed attribute IpSuffixOriginRandom should be returned
- // and attributes should be translated correctly to
- // IP_ADDRESS_ATTRIBUTE_TEMPORARY.
- ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
- ipv6_prefix, addresses));
- adapter_address.FirstUnicastAddress->PrefixOrigin =
- IpPrefixOriginRouterAdvertisement;
- adapter_address.FirstUnicastAddress->SuffixOrigin = IpSuffixOriginRandom;
- EXPECT_TRUE(internal::GetNetworkListImpl(
- &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
- EXPECT_EQ(results.size(), 1ul);
- EXPECT_EQ(results[0].name, kIfnameEm1);
- EXPECT_EQ(results[0].prefix_length, 1ul);
- EXPECT_EQ(results[0].address, ipv6_address);
- EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY);
- results.clear();
- // Addresses with preferred lifetime 0 should be returned and
- // attributes should be translated correctly to
- // IP_ADDRESS_ATTRIBUTE_DEPRECATED.
- ASSERT_TRUE(FillAdapterAddress(&adapter_address, kIfnameEm1, ipv6_address,
- ipv6_prefix, addresses));
- adapter_address.FirstUnicastAddress->PreferredLifetime = 0;
- adapter_address.FriendlyName = const_cast<PWCHAR>(L"FriendlyInterfaceName");
- EXPECT_TRUE(internal::GetNetworkListImpl(
- &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &adapter_address));
- EXPECT_EQ(results.size(), 1ul);
- EXPECT_EQ(results[0].friendly_name, "FriendlyInterfaceName");
- EXPECT_EQ(results[0].name, kIfnameEm1);
- EXPECT_EQ(results[0].prefix_length, 1ul);
- EXPECT_EQ(results[0].address, ipv6_address);
- EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED);
- results.clear();
- }
- bool read_int_or_bool(DWORD data_size, PVOID data) {
- switch (data_size) {
- case 1:
- return !!*reinterpret_cast<uint8_t*>(data);
- case 4:
- return !!*reinterpret_cast<uint32_t*>(data);
- default:
- LOG(FATAL) << "That is not a type I know!";
- return false;
- }
- }
- int GetWifiOptions() {
- const internal::WlanApi& wlanapi = internal::WlanApi::GetInstance();
- if (!wlanapi.initialized)
- return -1;
- internal::WlanHandle client;
- DWORD cur_version = 0;
- const DWORD kMaxClientVersion = 2;
- DWORD result = wlanapi.OpenHandle(kMaxClientVersion, &cur_version, &client);
- if (result != ERROR_SUCCESS)
- return -1;
- WLAN_INTERFACE_INFO_LIST* interface_list_ptr = nullptr;
- result =
- wlanapi.enum_interfaces_func(client.Get(), nullptr, &interface_list_ptr);
- if (result != ERROR_SUCCESS)
- return -1;
- std::unique_ptr<WLAN_INTERFACE_INFO_LIST, internal::WlanApiDeleter>
- interface_list(interface_list_ptr);
- for (unsigned i = 0; i < interface_list->dwNumberOfItems; ++i) {
- WLAN_INTERFACE_INFO* info = &interface_list->InterfaceInfo[i];
- DWORD data_size;
- PVOID data;
- int options = 0;
- result =
- wlanapi.query_interface_func(client.Get(), &info->InterfaceGuid,
- wlan_intf_opcode_background_scan_enabled,
- nullptr, &data_size, &data, nullptr);
- if (result != ERROR_SUCCESS)
- continue;
- if (!read_int_or_bool(data_size, data)) {
- options |= WIFI_OPTIONS_DISABLE_SCAN;
- }
- internal::WlanApi::GetInstance().free_memory_func(data);
- result = wlanapi.query_interface_func(client.Get(), &info->InterfaceGuid,
- wlan_intf_opcode_media_streaming_mode,
- nullptr, &data_size, &data, nullptr);
- if (result != ERROR_SUCCESS)
- continue;
- if (read_int_or_bool(data_size, data)) {
- options |= WIFI_OPTIONS_MEDIA_STREAMING_MODE;
- }
- internal::WlanApi::GetInstance().free_memory_func(data);
- // Just the the options from the first succesful
- // interface.
- return options;
- }
- // No wifi interface found.
- return -1;
- }
- void TryChangeWifiOptions(int options) {
- int previous_options = GetWifiOptions();
- std::unique_ptr<ScopedWifiOptions> scoped_options = SetWifiOptions(options);
- EXPECT_EQ(previous_options | options, GetWifiOptions());
- scoped_options.reset();
- EXPECT_EQ(previous_options, GetWifiOptions());
- }
- // Test SetWifiOptions().
- TEST(NetworkInterfacesTest, SetWifiOptions) {
- TryChangeWifiOptions(0);
- TryChangeWifiOptions(WIFI_OPTIONS_DISABLE_SCAN);
- TryChangeWifiOptions(WIFI_OPTIONS_MEDIA_STREAMING_MODE);
- TryChangeWifiOptions(WIFI_OPTIONS_DISABLE_SCAN |
- WIFI_OPTIONS_MEDIA_STREAMING_MODE);
- }
- } // namespace
- } // namespace net
|