| // Copyright 2023 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "patchpanel/proto_utils.h" |
| |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <utility> |
| |
| #include <base/functional/callback_helpers.h> |
| #include <chromeos/net-base/http_url.h> |
| #include <chromeos/net-base/ipv4_address.h> |
| #include <chromeos/net-base/ipv6_address.h> |
| #include <chromeos/net-base/mac_address.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <metrics/metrics_library_mock.h> |
| #include <patchpanel/proto_bindings/patchpanel_service.pb.h> |
| |
| #include "patchpanel/address_manager.h" |
| #include "patchpanel/crostini_service.h" |
| |
| namespace patchpanel { |
| |
| class ProtoUtilsTest : public testing::Test { |
| protected: |
| void SetUp() override { addr_mgr_ = std::make_unique<AddressManager>(); } |
| |
| std::unique_ptr<AddressManager> addr_mgr_; |
| }; |
| |
| TEST_F(ProtoUtilsTest, FillTerminaAllocationProto) { |
| const auto termina_ipv4_subnet = |
| *net_base::IPv4CIDR::CreateFromCIDRString("100.115.92.24/30"); |
| const auto termina_ipv4_address = |
| *net_base::IPv4Address::CreateFromString("100.115.92.26"); |
| const auto gateway_ipv4_address = |
| *net_base::IPv4Address::CreateFromString("100.115.92.25"); |
| const auto container_ipv4_subnet = |
| *net_base::IPv4CIDR::CreateFromCIDRString("100.115.92.192/28"); |
| const auto container_ipv4_address = |
| *net_base::IPv4Address::CreateFromString("100.115.92.193"); |
| |
| const uint32_t subnet_index = 0; |
| auto ipv4_subnet = addr_mgr_->AllocateIPv4Subnet( |
| AddressManager::GuestType::kTerminaVM, subnet_index); |
| auto lxd_subnet = |
| addr_mgr_->AllocateIPv4Subnet(AddressManager::GuestType::kLXDContainer); |
| auto termina_device = std::make_unique<CrostiniService::CrostiniDevice>( |
| CrostiniService::VMType::kTermina, "vmtap0", std::move(ipv4_subnet), |
| std::move(lxd_subnet)); |
| |
| TerminaVmStartupResponse proto; |
| FillTerminaAllocationProto(*termina_device, &proto); |
| ASSERT_EQ("vmtap0", proto.tap_device_ifname()); |
| EXPECT_EQ(termina_ipv4_address, |
| net_base::IPv4Address::CreateFromBytes(proto.ipv4_address())); |
| EXPECT_EQ(gateway_ipv4_address, net_base::IPv4Address::CreateFromBytes( |
| proto.gateway_ipv4_address())); |
| EXPECT_EQ(termina_ipv4_subnet.address(), |
| net_base::IPv4Address::CreateFromBytes(proto.ipv4_subnet().addr())); |
| EXPECT_EQ(termina_ipv4_subnet.prefix_length(), |
| proto.ipv4_subnet().prefix_len()); |
| EXPECT_EQ(container_ipv4_address, net_base::IPv4Address::CreateFromBytes( |
| proto.container_ipv4_address())); |
| EXPECT_EQ(container_ipv4_subnet.address(), |
| net_base::IPv4Address::CreateFromBytes( |
| proto.container_ipv4_subnet().addr())); |
| EXPECT_EQ(container_ipv4_subnet.prefix_length(), |
| proto.container_ipv4_subnet().prefix_len()); |
| } |
| |
| TEST_F(ProtoUtilsTest, FillParallelsAllocationProto) { |
| const uint32_t subnet_index = 0; |
| const auto parallels_ipv4_subnet = |
| *net_base::IPv4CIDR::CreateFromCIDRString("100.115.93.0/29"); |
| const auto parallels_ipv4_address = |
| *net_base::IPv4Address::CreateFromString("100.115.93.2"); |
| |
| auto ipv4_subnet = addr_mgr_->AllocateIPv4Subnet( |
| AddressManager::GuestType::kParallelsVM, subnet_index); |
| auto parallels_device = std::make_unique<CrostiniService::CrostiniDevice>( |
| CrostiniService::VMType::kParallels, "vmtap1", std::move(ipv4_subnet), |
| nullptr); |
| |
| ParallelsVmStartupResponse proto; |
| FillParallelsAllocationProto(*parallels_device, &proto); |
| ASSERT_EQ("vmtap1", proto.tap_device_ifname()); |
| EXPECT_EQ(parallels_ipv4_address, |
| net_base::IPv4Address::CreateFromBytes(proto.ipv4_address())); |
| EXPECT_EQ(parallels_ipv4_subnet.address(), |
| net_base::IPv4Address::CreateFromBytes(proto.ipv4_subnet().addr())); |
| EXPECT_EQ(parallels_ipv4_subnet.prefix_length(), |
| proto.ipv4_subnet().prefix_len()); |
| } |
| |
| TEST_F(ProtoUtilsTest, FillBruschettaAllocationProto) { |
| const auto bruschetta_ipv4_subnet = |
| *net_base::IPv4CIDR::CreateFromCIDRString("100.115.93.0/29"); |
| const auto bruschetta_ipv4_address = |
| *net_base::IPv4Address::CreateFromString("100.115.93.2"); |
| const auto gateway_ipv4_address = |
| *net_base::IPv4Address::CreateFromString("100.115.93.1"); |
| auto ipv4_subnet = |
| std::make_unique<Subnet>(bruschetta_ipv4_subnet, base::DoNothing()); |
| |
| // TODO(b/279994478): Add kBruschetta at VMType. |
| CrostiniService::CrostiniDevice bruschetta_device( |
| CrostiniService::VMType::kParallels, "vmtap1", std::move(ipv4_subnet), |
| nullptr); |
| |
| BruschettaVmStartupResponse proto; |
| FillBruschettaAllocationProto(bruschetta_device, &proto); |
| ASSERT_EQ("vmtap1", proto.tap_device_ifname()); |
| EXPECT_EQ(bruschetta_ipv4_address, |
| net_base::IPv4Address::CreateFromBytes(proto.ipv4_address())); |
| EXPECT_EQ(gateway_ipv4_address, net_base::IPv4Address::CreateFromBytes( |
| proto.gateway_ipv4_address())); |
| EXPECT_EQ(bruschetta_ipv4_subnet.address(), |
| net_base::IPv4Address::CreateFromBytes(proto.ipv4_subnet().addr())); |
| EXPECT_EQ(bruschetta_ipv4_subnet.prefix_length(), |
| proto.ipv4_subnet().prefix_len()); |
| } |
| |
| TEST_F(ProtoUtilsTest, FillBorealisAllocationProto) { |
| const auto borealis_ipv4_subnet = |
| *net_base::IPv4CIDR::CreateFromCIDRString("100.115.93.0/29"); |
| const auto borealis_ipv4_address = |
| *net_base::IPv4Address::CreateFromString("100.115.93.2"); |
| const auto gateway_ipv4_address = |
| *net_base::IPv4Address::CreateFromString("100.115.93.1"); |
| auto ipv4_subnet = |
| std::make_unique<Subnet>(borealis_ipv4_subnet, base::DoNothing()); |
| |
| CrostiniService::CrostiniDevice borealis_device( |
| CrostiniService::VMType::kBorealis, "vmtap1", std::move(ipv4_subnet), |
| nullptr); |
| |
| BorealisVmStartupResponse proto; |
| FillBorealisAllocationProto(borealis_device, &proto); |
| ASSERT_EQ("vmtap1", proto.tap_device_ifname()); |
| EXPECT_EQ(borealis_ipv4_address, |
| net_base::IPv4Address::CreateFromBytes(proto.ipv4_address())); |
| EXPECT_EQ(gateway_ipv4_address, net_base::IPv4Address::CreateFromBytes( |
| proto.gateway_ipv4_address())); |
| EXPECT_EQ(borealis_ipv4_subnet.address(), |
| net_base::IPv4Address::CreateFromBytes(proto.ipv4_subnet().addr())); |
| EXPECT_EQ(borealis_ipv4_subnet.prefix_length(), |
| proto.ipv4_subnet().prefix_len()); |
| } |
| |
| TEST_F(ProtoUtilsTest, FillNetworkClientInfoProto) { |
| DownstreamClientInfo info; |
| info.mac_addr = net_base::MacAddress(0x11, 0x22, 0x33, 0x44, 0x55, 0x66); |
| info.ipv4_addr = net_base::IPv4Address(127, 0, 0, 1); |
| info.ipv6_addresses.push_back( |
| *net_base::IPv6Address::CreateFromString("fe80::1")); |
| info.ipv6_addresses.push_back( |
| *net_base::IPv6Address::CreateFromString("fe80::3")); |
| info.hostname = "test_host"; |
| info.vendor_class = "test_vendor_class"; |
| |
| NetworkClientInfo proto; |
| FillNetworkClientInfoProto(info, &proto); |
| |
| EXPECT_EQ(proto.mac_addr(), |
| std::string({0x11, 0x22, 0x33, 0x44, 0x55, 0x66})); |
| EXPECT_EQ(proto.ipv4_addr(), std::string({127, 0, 0, 1})); |
| EXPECT_EQ(proto.ipv6_addresses().size(), 2); |
| EXPECT_EQ(proto.ipv6_addresses()[0], |
| net_base::IPv6Address::CreateFromString("fe80::1")->ToByteString()); |
| EXPECT_EQ(proto.ipv6_addresses()[1], |
| net_base::IPv6Address::CreateFromString("fe80::3")->ToByteString()); |
| EXPECT_EQ(proto.hostname(), "test_host"); |
| EXPECT_EQ(proto.vendor_class(), "test_vendor_class"); |
| } |
| |
| TEST_F(ProtoUtilsTest, DeserializeNetworkConfigEmpty) { |
| patchpanel::NetworkConfig input; |
| |
| const auto output = DeserializeNetworkConfig(input); |
| net_base::NetworkConfig expected_output; |
| EXPECT_EQ(output, expected_output); |
| } |
| |
| TEST_F(ProtoUtilsTest, DeserializeNetworkConfig) { |
| patchpanel::NetworkConfig input; |
| auto* ipv4_address = input.mutable_ipv4_address(); |
| ipv4_address->set_addr({10, 0, 1, 100}); |
| ipv4_address->set_prefix_len(24); |
| input.set_ipv4_gateway({10, 0, 1, 2}); |
| input.set_ipv4_broadcast({10, 0, 1, static_cast<char>(255)}); |
| auto* ipv6_address = input.add_ipv6_addresses(); |
| ipv6_address->set_addr( |
| {0x20, 0x01, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0}); |
| ipv6_address->set_prefix_len(64); |
| ipv6_address = input.add_ipv6_addresses(); |
| ipv6_address->set_addr( |
| {0x20, 0x01, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x20, 0}); |
| ipv6_address->set_prefix_len(56); |
| input.set_ipv6_gateway( |
| {0x20, 0x01, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2}); |
| auto* ipv6_pd = input.add_ipv6_delegated_prefixes(); |
| ipv6_pd->set_addr({0x20, 0x01, 0x3, 0, 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); |
| ipv6_pd->set_prefix_len(96); |
| ipv6_pd = input.add_ipv6_delegated_prefixes(); |
| ipv6_pd->set_addr({0x20, 0x01, 0x3, 0, 0, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); |
| ipv6_pd->set_prefix_len(120); |
| input.set_ipv6_blackhole_route(true); |
| auto* prefix = input.add_excluded_route_prefixes(); |
| prefix->set_addr({0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); |
| prefix->set_prefix_len(128); |
| prefix = input.add_excluded_route_prefixes(); |
| prefix->set_addr({1, 1, 0, 0}); |
| prefix->set_prefix_len(32); |
| prefix = input.add_included_route_prefixes(); |
| prefix->set_addr({0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); |
| prefix->set_prefix_len(120); |
| prefix = input.add_included_route_prefixes(); |
| prefix->set_addr({1, 1, 0, 0}); |
| prefix->set_prefix_len(28); |
| auto* rfc3442_route = input.add_rfc3442_routes(); |
| auto* rfc3442_prefix = rfc3442_route->mutable_prefix(); |
| rfc3442_prefix->set_addr({2, 0, 0, 0}); |
| rfc3442_prefix->set_prefix_len(8); |
| rfc3442_route->set_gateway({10, 0, 1, 3}); |
| auto* pref64 = input.mutable_pref64(); |
| pref64->set_addr({0x00, 0x64, static_cast<char>(0xff), |
| static_cast<char>(0x9b), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0}); |
| pref64->set_prefix_len(96); |
| input.add_dns_servers({8, 8, 8, 8}); |
| input.add_dns_servers({0x20, 0x01, 0x48, 0x60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| static_cast<char>(0x88), static_cast<char>(0x88)}); |
| input.add_dns_search_domains("google.com"); |
| input.set_mtu(1200); |
| input.set_captive_portal_uri("https://portal.net"); |
| |
| const auto output = DeserializeNetworkConfig(input); |
| net_base::NetworkConfig expected_output; |
| expected_output.ipv4_address = |
| *net_base::IPv4CIDR::CreateFromCIDRString("10.0.1.100/24"); |
| expected_output.ipv4_gateway = |
| *net_base::IPv4Address::CreateFromString("10.0.1.2"); |
| expected_output.ipv4_broadcast = |
| *net_base::IPv4Address::CreateFromString("10.0.1.255"); |
| expected_output.ipv6_addresses.push_back( |
| *net_base::IPv6CIDR::CreateFromCIDRString("2001:200::1000/64")); |
| expected_output.ipv6_addresses.push_back( |
| *net_base::IPv6CIDR::CreateFromCIDRString("2001:200::2000/56")); |
| expected_output.ipv6_gateway = |
| *net_base::IPv6Address::CreateFromString("2001:200::2"); |
| expected_output.ipv6_delegated_prefixes.push_back( |
| *net_base::IPv6CIDR::CreateFromCIDRString("2001:300:1::/96")); |
| expected_output.ipv6_delegated_prefixes.push_back( |
| *net_base::IPv6CIDR::CreateFromCIDRString("2001:300:2::/120")); |
| expected_output.ipv6_blackhole_route = true; |
| expected_output.excluded_route_prefixes.push_back( |
| *net_base::IPCIDR::CreateFromCIDRString("2002::/128")); |
| expected_output.excluded_route_prefixes.push_back( |
| *net_base::IPCIDR::CreateFromCIDRString("1.1.0.0/32")); |
| expected_output.included_route_prefixes.push_back( |
| *net_base::IPCIDR::CreateFromCIDRString("2002::/120")); |
| expected_output.included_route_prefixes.push_back( |
| *net_base::IPCIDR::CreateFromCIDRString("1.1.0.0/28")); |
| expected_output.rfc3442_routes.emplace_back( |
| *net_base::IPv4CIDR::CreateFromCIDRString("2.0.0.0/8"), |
| *net_base::IPv4Address::CreateFromString("10.0.1.3")); |
| expected_output.pref64 = |
| *net_base::IPv6CIDR::CreateFromCIDRString("64:ff9b::/96"); |
| expected_output.dns_servers.push_back( |
| *net_base::IPAddress::CreateFromString("8.8.8.8")); |
| expected_output.dns_servers.push_back( |
| *net_base::IPAddress::CreateFromString("2001:4860::8888")); |
| expected_output.dns_search_domains.push_back("google.com"); |
| expected_output.mtu = 1200; |
| expected_output.captive_portal_uri = |
| net_base::HttpUrl::CreateFromString("https://portal.net"); |
| |
| EXPECT_EQ(output, expected_output); |
| } |
| |
| } // namespace patchpanel |