blob: f113363a0a693458cb68b73b001aebe1402c540c [file] [log] [blame]
// 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