// 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_getifaddrs.h" #include #include "build/build_config.h" #include "net/base/ip_endpoint.h" #include "testing/gtest/include/gtest/gtest.h" #include #include #include namespace net { namespace { class IPAttributesGetterTest : public internal::IPAttributesGetter { public: IPAttributesGetterTest() = default; // internal::IPAttributesGetter interface. bool IsInitialized() const override { return true; } bool GetAddressAttributes(const ifaddrs* if_addr, int* attributes) override { *attributes = attributes_; return true; } NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType( const ifaddrs* if_addr) override { return NetworkChangeNotifier::CONNECTION_UNKNOWN; } void set_attributes(int attributes) { attributes_ = attributes; } private: int attributes_ = 0; }; // Helper function to create a single valid ifaddrs bool FillIfaddrs(ifaddrs* interfaces, const char* ifname, uint flags, const IPAddress& ip_address, const IPAddress& ip_netmask, sockaddr_storage sock_addrs[2]) { interfaces->ifa_next = nullptr; interfaces->ifa_name = const_cast(ifname); interfaces->ifa_flags = flags; socklen_t sock_len = sizeof(sockaddr_storage); // Convert to sockaddr for next check. if (!IPEndPoint(ip_address, 0) .ToSockAddr(reinterpret_cast(&sock_addrs[0]), &sock_len)) { return false; } interfaces->ifa_addr = reinterpret_cast(&sock_addrs[0]); sock_len = sizeof(sockaddr_storage); if (!IPEndPoint(ip_netmask, 0) .ToSockAddr(reinterpret_cast(&sock_addrs[1]), &sock_len)) { return false; } interfaces->ifa_netmask = reinterpret_cast(&sock_addrs[1]); return true; } 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}; // The following 3 addresses need to be changed together. IPv6Addr is the IPv6 // address. IPv6Netmask is the mask address with as many leading bits set to 1 // as the prefix length. IPv6AddrPrefix needs to match IPv6Addr with the same // number of bits as the prefix length. 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 kIPv6Netmask[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; TEST(NetworkInterfacesTest, IfaddrsToNetworkInterfaceList) { IPAddress ipv6_local_address(kIPv6LocalAddr); IPAddress ipv6_address(kIPv6Addr); IPAddress ipv6_netmask(kIPv6Netmask); NetworkInterfaceList results; IPAttributesGetterTest ip_attributes_getter; sockaddr_storage addresses[2]; ifaddrs interface; // Address of offline links should be ignored. ASSERT_TRUE(FillIfaddrs(&interface, kIfnameEm1, IFF_UP, ipv6_address, ipv6_netmask, addresses)); EXPECT_TRUE(internal::IfaddrsToNetworkInterfaceList( INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface, &ip_attributes_getter, &results)); EXPECT_EQ(results.size(), 0ul); // Local address should be trimmed out. ASSERT_TRUE(FillIfaddrs(&interface, kIfnameEm1, IFF_RUNNING, ipv6_local_address, ipv6_netmask, addresses)); EXPECT_TRUE(internal::IfaddrsToNetworkInterfaceList( INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface, &ip_attributes_getter, &results)); EXPECT_EQ(results.size(), 0ul); // vmware address should return by default. ASSERT_TRUE(FillIfaddrs(&interface, kIfnameVmnet, IFF_RUNNING, ipv6_address, ipv6_netmask, addresses)); EXPECT_TRUE(internal::IfaddrsToNetworkInterfaceList( INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface, &ip_attributes_getter, &results)); 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); results.clear(); // vmware address should be trimmed out if policy specified so. ASSERT_TRUE(FillIfaddrs(&interface, kIfnameVmnet, IFF_RUNNING, ipv6_address, ipv6_netmask, addresses)); EXPECT_TRUE(internal::IfaddrsToNetworkInterfaceList( EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface, &ip_attributes_getter, &results)); EXPECT_EQ(results.size(), 0ul); results.clear(); // Addresses with banned attributes should be ignored. ip_attributes_getter.set_attributes(IP_ADDRESS_ATTRIBUTE_ANYCAST); ASSERT_TRUE(FillIfaddrs(&interface, kIfnameEm1, IFF_RUNNING, ipv6_address, ipv6_netmask, addresses)); EXPECT_TRUE(internal::IfaddrsToNetworkInterfaceList( INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface, &ip_attributes_getter, &results)); EXPECT_EQ(results.size(), 0ul); results.clear(); // Addresses with allowed attribute IFA_F_TEMPORARY should be returned and // attributes should be translated correctly. ip_attributes_getter.set_attributes(IP_ADDRESS_ATTRIBUTE_TEMPORARY); ASSERT_TRUE(FillIfaddrs(&interface, kIfnameEm1, IFF_RUNNING, ipv6_address, ipv6_netmask, addresses)); EXPECT_TRUE(internal::IfaddrsToNetworkInterfaceList( INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface, &ip_attributes_getter, &results)); 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 allowed attribute IFA_F_DEPRECATED should be returned and // attributes should be translated correctly. ip_attributes_getter.set_attributes(IP_ADDRESS_ATTRIBUTE_DEPRECATED); ASSERT_TRUE(FillIfaddrs(&interface, kIfnameEm1, IFF_RUNNING, ipv6_address, ipv6_netmask, addresses)); EXPECT_TRUE(internal::IfaddrsToNetworkInterfaceList( INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface, &ip_attributes_getter, &results)); 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_DEPRECATED); results.clear(); } } // namespace } // namespace net