// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/crostini/crostini_port_forwarder.h"
#include "base/test/test_future.h"
#include "chrome/browser/ash/crostini/crostini_manager.h"
#include "chrome/browser/ash/crostini/crostini_test_helper.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/ash/components/dbus/chunneld/chunneld_client.h"
#include "chromeos/ash/components/dbus/cicerone/cicerone_client.h"
#include "chromeos/ash/components/dbus/concierge/concierge_client.h"
#include "chromeos/ash/components/dbus/seneschal/seneschal_client.h"
#include "chromeos/ash/components/network/network_handler_test_helper.h"
#include "chromeos/dbus/permission_broker/fake_permission_broker_client.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::Mock;
using testing::Return;
void TestingCallback(bool* out, base::OnceClosure closure, bool in) {
*out = in;
std::move(closure).Run();
}
namespace crostini {
using Protocol = CrostiniPortForwarder::Protocol;
class CrostiniPortForwarderTest : public testing::Test {
public:
CrostiniPortForwarderTest()
: default_container_id_(DefaultContainerId()),
other_container_id_(
guest_os::GuestId(kCrostiniDefaultVmType, "other", "other")),
inactive_container_id_(
guest_os::GuestId(kCrostiniDefaultVmType, "inactive", "inactive")) {
network_handler_helper_ = std::make_unique<ash::NetworkHandlerTestHelper>();
network_handler_helper_->AddDefaultProfiles();
network_handler_helper_->ResetDevicesAndServices();
}
CrostiniPortForwarderTest(const CrostiniPortForwarderTest&) = delete;
CrostiniPortForwarderTest& operator=(const CrostiniPortForwarderTest&) =
delete;
~CrostiniPortForwarderTest() override = default;
void SetUp() override {
ash::ChunneldClient::InitializeFake();
ash::CiceroneClient::InitializeFake();
ash::ConciergeClient::InitializeFake();
ash::SeneschalClient::InitializeFake();
chromeos::PermissionBrokerClient::InitializeFake();
profile_ = std::make_unique<TestingProfile>();
CrostiniManager::GetForProfile(profile())->AddRunningVmForTesting(
kCrostiniDefaultVmName);
CrostiniManager::GetForProfile(profile())->AddRunningContainerForTesting(
kCrostiniDefaultVmName,
ContainerInfo(kCrostiniDefaultContainerName, kCrostiniDefaultUsername,
"home/testuser1", "CONTAINER_IP_ADDRESS"));
test_helper_ = std::make_unique<CrostiniTestHelper>(profile_.get());
crostini_port_forwarder_ =
std::make_unique<CrostiniPortForwarder>(profile());
crostini_port_forwarder_->AddObserver(&mock_observer_);
}
void TearDown() override {
chromeos::PermissionBrokerClient::Shutdown();
crostini_port_forwarder_->RemoveObserver(&mock_observer_);
crostini_port_forwarder_.reset();
test_helper_.reset();
profile_.reset();
ash::SeneschalClient::Shutdown();
ash::ConciergeClient::Shutdown();
ash::CiceroneClient::Shutdown();
ash::ChunneldClient::Shutdown();
}
protected:
class MockPortObserver : public CrostiniPortForwarder::Observer {
public:
MOCK_METHOD(void,
OnActivePortsChanged,
(const base::Value::List& activePorts),
(override));
MOCK_METHOD(void,
OnActiveNetworkChanged,
(const base::Value& interface, const base::Value& ipAddress),
(override));
};
Profile* profile() { return profile_.get(); }
CrostiniPortForwarder::PortRuleKey GetPortKey(
int port_number,
Protocol protocol_type,
guest_os::GuestId container_id) {
return {
.port_number = static_cast<uint16_t>(port_number),
.protocol_type = protocol_type,
.container_id = container_id,
};
}
void MakePermissionBrokerPortForwardingExpectation(int port_number,
Protocol protocol,
bool exists,
const char* interface) {
switch (protocol) {
case Protocol::TCP:
EXPECT_EQ(
chromeos::FakePermissionBrokerClient::Get()->HasTcpPortForward(
port_number, interface),
exists);
break;
case Protocol::UDP:
EXPECT_EQ(
chromeos::FakePermissionBrokerClient::Get()->HasUdpPortForward(
port_number, interface),
exists);
break;
}
}
void MakePortPreferenceExpectation(CrostiniPortForwarder::PortRuleKey key,
bool exists,
std::string label) {
std::optional<base::Value> pref =
crostini_port_forwarder_->ReadPortPreferenceForTesting(key);
EXPECT_EQ(exists, pref.has_value());
if (!exists) {
return;
}
EXPECT_EQ(key.port_number,
pref.value().GetDict().FindInt(crostini::kPortNumberKey).value());
EXPECT_EQ(
static_cast<int>(key.protocol_type),
pref.value().GetDict().FindInt(crostini::kPortProtocolKey).value());
EXPECT_EQ(key.container_id, guest_os::GuestId(pref.value()));
EXPECT_EQ(label,
*pref.value().GetDict().FindString(crostini::kPortLabelKey));
}
void MakePortExistenceExpectation(CrostiniPortForwarder::PortRuleKey port,
std::string label,
bool expected_pref,
bool expected_permission) {
MakePortPreferenceExpectation(port, /*exists=*/expected_pref,
/*label=*/label);
MakePermissionBrokerPortForwardingExpectation(
/*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
/*exists=*/expected_permission,
/*interface=*/crostini::kDefaultInterfaceToForward);
}
bool AddPortFromKey(CrostiniPortForwarder::PortRuleKey port) {
base::test::TestFuture<bool> result_future;
crostini_port_forwarder_->AddPort(port.container_id, port.port_number,
port.protocol_type, "",
result_future.GetCallback());
return result_future.Get();
}
bool ActivatePortFromKey(CrostiniPortForwarder::PortRuleKey port) {
base::test::TestFuture<bool> result_future;
crostini_port_forwarder_->ActivatePort(port.container_id, port.port_number,
port.protocol_type,
result_future.GetCallback());
return result_future.Get();
}
bool RemovePortFromKey(CrostiniPortForwarder::PortRuleKey port) {
base::test::TestFuture<bool> result_future;
crostini_port_forwarder_->RemovePort(port.container_id, port.port_number,
port.protocol_type,
result_future.GetCallback());
return result_future.Get();
}
bool DeactivatePortFromKey(CrostiniPortForwarder::PortRuleKey port) {
base::test::TestFuture<bool> result_future;
crostini_port_forwarder_->DeactivatePort(
port.container_id, port.port_number, port.protocol_type,
result_future.GetCallback());
return result_future.Get();
}
guest_os::GuestId default_container_id_;
guest_os::GuestId other_container_id_;
guest_os::GuestId inactive_container_id_;
testing::NiceMock<MockPortObserver> mock_observer_;
std::unique_ptr<ash::NetworkHandlerTestHelper> network_handler_helper_;
std::unique_ptr<CrostiniTestHelper> test_helper_;
std::unique_ptr<TestingProfile> profile_;
std::unique_ptr<CrostiniPortForwarder> crostini_port_forwarder_;
content::BrowserTaskEnvironment task_environment_;
};
TEST_F(CrostiniPortForwarderTest, AddPort) {
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_add = {
GetPortKey(5000, Protocol::TCP, default_container_id_),
GetPortKey(5000, Protocol::UDP, default_container_id_),
GetPortKey(5001, Protocol::UDP, default_container_id_)};
EXPECT_CALL(mock_observer_, OnActivePortsChanged).Times(ports_to_add.size());
// Add ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_TRUE(AddPortFromKey(port));
MakePortExistenceExpectation(port, "", true, true);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
3U);
// Adding ports fails as they already exist.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", true, true);
EXPECT_FALSE(AddPortFromKey(port));
MakePortExistenceExpectation(port, "", true, true);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
3U);
}
TEST_F(CrostiniPortForwarderTest, RemovePort) {
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_add = {
GetPortKey(5000, Protocol::TCP, default_container_id_),
GetPortKey(5000, Protocol::UDP, default_container_id_),
GetPortKey(5001, Protocol::UDP, default_container_id_)};
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_remove = {
GetPortKey(5000, Protocol::TCP, default_container_id_),
GetPortKey(5001, Protocol::UDP, default_container_id_)};
std::vector<CrostiniPortForwarder::PortRuleKey> missing_ports_to_remove = {
GetPortKey(5005, Protocol::TCP, default_container_id_),
GetPortKey(5006, Protocol::UDP, default_container_id_)};
EXPECT_CALL(mock_observer_, OnActivePortsChanged)
.Times(ports_to_add.size() + ports_to_remove.size());
// Add ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_TRUE(AddPortFromKey(port));
MakePortExistenceExpectation(port, "", true, true);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
3U);
// Remove ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_remove) {
MakePortExistenceExpectation(port, "", true, true);
EXPECT_TRUE(RemovePortFromKey(port));
MakePortExistenceExpectation(port, "", false, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
1U);
// Removing ports fails due to them not existing in prefs.
for (CrostiniPortForwarder::PortRuleKey& port : missing_ports_to_remove) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_FALSE(RemovePortFromKey(port));
MakePortExistenceExpectation(port, "", false, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
1U);
}
TEST_F(CrostiniPortForwarderTest, DeactivatePort) {
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_add = {
GetPortKey(5000, Protocol::TCP, default_container_id_),
GetPortKey(5000, Protocol::UDP, default_container_id_),
GetPortKey(5001, Protocol::UDP, default_container_id_)};
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_deactivate = {
GetPortKey(5000, Protocol::TCP, default_container_id_),
GetPortKey(5001, Protocol::UDP, default_container_id_)};
std::vector<CrostiniPortForwarder::PortRuleKey> missing_ports_to_deactivate =
{GetPortKey(5005, Protocol::TCP, default_container_id_),
GetPortKey(5006, Protocol::UDP, default_container_id_)};
EXPECT_CALL(mock_observer_, OnActivePortsChanged)
.Times(ports_to_add.size() + ports_to_deactivate.size() * 2);
// Add ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_TRUE(AddPortFromKey(port));
MakePortExistenceExpectation(port, "", true, true);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
3U);
// Deactivate ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_deactivate) {
MakePortExistenceExpectation(port, "", true, true);
EXPECT_TRUE(DeactivatePortFromKey(port));
MakePortExistenceExpectation(port, "", true, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
1U);
// Deactivating ports fail due to the ports already being deactivated.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_deactivate) {
MakePortExistenceExpectation(port, "", true, false);
EXPECT_FALSE(DeactivatePortFromKey(port));
MakePortExistenceExpectation(port, "", true, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
1U);
// Deactivating ports fails due to the ports not existing in the prefs.
for (CrostiniPortForwarder::PortRuleKey& port : missing_ports_to_deactivate) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_FALSE(DeactivatePortFromKey(port));
MakePortExistenceExpectation(port, "", false, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
1U);
}
TEST_F(CrostiniPortForwarderTest, ActivatePort) {
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_add = {
GetPortKey(5000, Protocol::TCP, default_container_id_),
GetPortKey(5000, Protocol::UDP, default_container_id_),
GetPortKey(5001, Protocol::UDP, default_container_id_)};
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_deactivate = {
GetPortKey(5000, Protocol::TCP, default_container_id_),
GetPortKey(5000, Protocol::UDP, default_container_id_),
GetPortKey(5001, Protocol::UDP, default_container_id_)};
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_activate = {
GetPortKey(5000, Protocol::TCP, default_container_id_),
GetPortKey(5001, Protocol::UDP, default_container_id_)};
std::vector<CrostiniPortForwarder::PortRuleKey> missing_ports_to_activate = {
GetPortKey(5005, Protocol::TCP, default_container_id_),
GetPortKey(5006, Protocol::TCP, default_container_id_),
GetPortKey(5007, Protocol::TCP, default_container_id_)};
EXPECT_CALL(mock_observer_, OnActivePortsChanged)
.Times(ports_to_add.size() + ports_to_deactivate.size() +
ports_to_activate.size());
// Add ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_TRUE(AddPortFromKey(port));
MakePortExistenceExpectation(port, "", true, true);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
3U);
// Deactivate ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_deactivate) {
MakePortExistenceExpectation(port, "", true, true);
EXPECT_TRUE(DeactivatePortFromKey(port));
MakePortExistenceExpectation(port, "", true, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
0U);
// Activate ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_activate) {
MakePortExistenceExpectation(port, "", true, false);
EXPECT_TRUE(ActivatePortFromKey(port));
MakePortExistenceExpectation(port, "", true, true);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
2U);
// Activating ports fails due to ports already being active.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_activate) {
MakePortExistenceExpectation(port, "", true, true);
EXPECT_FALSE(ActivatePortFromKey(port));
MakePortExistenceExpectation(port, "", true, true);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
2U);
// Activating ports fails due to missing prefs.
for (CrostiniPortForwarder::PortRuleKey& port : missing_ports_to_activate) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_FALSE(ActivatePortFromKey(port));
MakePortExistenceExpectation(port, "", false, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
2U);
}
TEST_F(CrostiniPortForwarderTest, InactiveContainerHandling) {
std::vector<CrostiniPortForwarder::PortRuleKey> ports_for_inactive_container =
{GetPortKey(5000, Protocol::TCP, inactive_container_id_),
GetPortKey(5000, Protocol::UDP, inactive_container_id_),
GetPortKey(5001, Protocol::UDP, inactive_container_id_)};
EXPECT_CALL(mock_observer_, OnActivePortsChanged)
.Times(ports_for_inactive_container.size() * 4);
// Add ports, fails due to an inactive container.
for (CrostiniPortForwarder::PortRuleKey& port :
ports_for_inactive_container) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_FALSE(AddPortFromKey(port));
MakePortExistenceExpectation(port, "", true, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
0U);
// Activate ports, fails due to an inactive container.
for (CrostiniPortForwarder::PortRuleKey& port :
ports_for_inactive_container) {
MakePortExistenceExpectation(port, "", true, false);
EXPECT_FALSE(ActivatePortFromKey(port));
MakePortExistenceExpectation(port, "", true, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
0U);
// Deactivate ports, fails due to an inactive container.
for (CrostiniPortForwarder::PortRuleKey& port :
ports_for_inactive_container) {
MakePortExistenceExpectation(port, "", true, false);
EXPECT_FALSE(DeactivatePortFromKey(port));
MakePortExistenceExpectation(port, "", true, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
0U);
// Remove ports, fails due to an inactive container.
for (CrostiniPortForwarder::PortRuleKey& port :
ports_for_inactive_container) {
MakePortExistenceExpectation(port, "", true, false);
EXPECT_FALSE(RemovePortFromKey(port));
MakePortExistenceExpectation(port, "", false, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
0U);
}
TEST_F(CrostiniPortForwarderTest, DeactivateAllPorts) {
guest_os::GuestId container_id = default_container_id_;
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_add = {
GetPortKey(5000, Protocol::TCP, container_id),
GetPortKey(5000, Protocol::UDP, container_id),
GetPortKey(5001, Protocol::UDP, container_id)};
EXPECT_CALL(mock_observer_, OnActivePortsChanged)
.Times(ports_to_add.size() + 2);
crostini_port_forwarder_->DeactivateAllActivePorts(container_id);
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
0U);
// Add ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_TRUE(AddPortFromKey(port));
MakePortExistenceExpectation(port, "", true, true);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
3U);
// Deactivate all ports.
crostini_port_forwarder_->DeactivateAllActivePorts(container_id);
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", true, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
0U);
}
TEST_F(CrostiniPortForwarderTest, RemoveAllPorts) {
guest_os::GuestId container_id = default_container_id_;
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_add = {
GetPortKey(5000, Protocol::TCP, container_id),
GetPortKey(5000, Protocol::UDP, container_id),
GetPortKey(5001, Protocol::UDP, container_id)};
EXPECT_CALL(mock_observer_, OnActivePortsChanged)
.Times(ports_to_add.size() + 2);
// Remove all ports (ensuring that things don't break when there are
// no ports to remove).
crostini_port_forwarder_->RemoveAllPorts(container_id);
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
0U);
// Add ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_TRUE(AddPortFromKey(port));
MakePortExistenceExpectation(port, "", true, true);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
3U);
// Remove all ports.
crostini_port_forwarder_->RemoveAllPorts(container_id);
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", false, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
0U);
}
TEST_F(CrostiniPortForwarderTest, GetActivePorts) {
guest_os::GuestId container_id = default_container_id_;
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_add = {
GetPortKey(5000, Protocol::TCP, container_id),
GetPortKey(5000, Protocol::UDP, container_id),
GetPortKey(5001, Protocol::UDP, container_id)};
// Add ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_TRUE(AddPortFromKey(port));
MakePortExistenceExpectation(port, "", true, true);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
3U);
// Get active ports.
base::Value::List forwarded_ports =
crostini_port_forwarder_->GetActivePorts();
EXPECT_EQ(forwarded_ports.size(), ports_to_add.size());
for (unsigned int i = 0; i < ports_to_add.size(); i++) {
unsigned int reverse_index = ports_to_add.size() - i - 1;
EXPECT_EQ(*(forwarded_ports[i].GetDict().Find("port_number")),
base::Value(ports_to_add.at(reverse_index).port_number));
EXPECT_EQ(*(forwarded_ports[i].GetDict().Find("protocol_type")),
base::Value(static_cast<int>(
ports_to_add.at(reverse_index).protocol_type)));
}
}
TEST_F(CrostiniPortForwarderTest, ActiveNetworksChanged) {
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_add = {
GetPortKey(5000, Protocol::TCP, default_container_id_),
GetPortKey(5000, Protocol::UDP, default_container_id_),
GetPortKey(5001, Protocol::UDP, default_container_id_)};
const char eth_interface[] = "eth0";
EXPECT_CALL(mock_observer_, OnActivePortsChanged).Times(ports_to_add.size());
EXPECT_CALL(mock_observer_, OnActiveNetworkChanged).Times(2);
// Add ports
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_TRUE(AddPortFromKey(port));
MakePortPreferenceExpectation(port, /*exists=*/true,
/*label=*/"");
MakePermissionBrokerPortForwardingExpectation(
/*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
/*exists=*/true, /*interface=*/crostini::kDefaultInterfaceToForward);
MakePermissionBrokerPortForwardingExpectation(
/*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
/*exists=*/false, /*interface=*/eth_interface);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
3U);
// Request to update interface to kDefaultInterfaceToForward, no change
// required as ports are already being forwarded on kDefaultInterfaceToForward
// by default.
crostini_port_forwarder_->ActiveNetworksChanged(
crostini::kDefaultInterfaceToForward, "127.0.0.1");
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortPreferenceExpectation(port, /*exists=*/true,
/*label=*/"");
MakePermissionBrokerPortForwardingExpectation(
/*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
/*exists=*/true, /*interface=*/crostini::kDefaultInterfaceToForward);
MakePermissionBrokerPortForwardingExpectation(
/*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
/*exists=*/false, /*interface=*/eth_interface);
}
// Request to update interface to "", invalid request, no change required.
crostini_port_forwarder_->ActiveNetworksChanged("", "");
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortPreferenceExpectation(port, /*exists=*/true,
/*label=*/"");
MakePermissionBrokerPortForwardingExpectation(
/*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
/*exists=*/true, /*interface=*/crostini::kDefaultInterfaceToForward);
MakePermissionBrokerPortForwardingExpectation(
/*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
/*exists=*/false, /*interface=*/eth_interface);
}
// Request to update interface to eth_interface, ports are updated to use
// the eth_interface and no longer use what they were using before
// (kDefaultInterfaceToForward).
crostini_port_forwarder_->ActiveNetworksChanged(eth_interface, "10.1.1.1");
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortPreferenceExpectation(port, /*exists=*/true,
/*label=*/"");
// Deactivating forwarding on the previous interface is handled in Chromeos
// and by the lifelines used to track port rules. Until the port is released
// in Chromeos, both interfaces will be used.
MakePermissionBrokerPortForwardingExpectation(
/*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
/*exists=*/true, /*interface=*/crostini::kDefaultInterfaceToForward);
MakePermissionBrokerPortForwardingExpectation(
/*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
/*exists=*/true, /*interface=*/eth_interface);
}
// Request to update interface to kDefaultInterfaceToForward with an IPv6
// address. Needs a new interface because this is only called when interfaces
// changes.
crostini_port_forwarder_->ActiveNetworksChanged(kDefaultInterfaceToForward,
"2001:db8:0:1");
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortPreferenceExpectation(port, /*exists=*/true,
/*label=*/"");
// Deactivating forwarding on the previous interface is handled in Chromeos
// and by the lifelines used to track port rules. Until the port is released
// in Chromeos, both interfaces will be used.
MakePermissionBrokerPortForwardingExpectation(
/*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
/*exists=*/true, /*interface=*/crostini::kDefaultInterfaceToForward);
MakePermissionBrokerPortForwardingExpectation(
/*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
/*exists=*/true, /*interface=*/eth_interface);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
3U);
}
TEST_F(CrostiniPortForwarderTest, HandlingOfflinePermissionBroker) {
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_add = {
GetPortKey(5000, Protocol::TCP, default_container_id_),
GetPortKey(5000, Protocol::UDP, default_container_id_),
GetPortKey(5001, Protocol::UDP, default_container_id_)};
std::vector<CrostiniPortForwarder::PortRuleKey> ports_to_deactivate = {
GetPortKey(5001, Protocol::UDP, default_container_id_)};
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
0U);
// Add ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
MakePortExistenceExpectation(port, "", false, false);
EXPECT_TRUE(AddPortFromKey(port));
MakePortExistenceExpectation(port, "", true, true);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
3U);
// Deactivate ports.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_deactivate) {
MakePortExistenceExpectation(port, "", true, true);
EXPECT_TRUE(DeactivatePortFromKey(port));
MakePortExistenceExpectation(port, "", true, false);
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
2U);
// Shut PermissionBrokerClient down.
chromeos::PermissionBrokerClient::Shutdown();
// Activating ports fails, due to permission broker being inaccessible.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
EXPECT_FALSE(ActivatePortFromKey(port));
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
2U);
// Deactivating ports fails, due to permission broker being inaccessible.
for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
EXPECT_FALSE(DeactivatePortFromKey(port));
}
EXPECT_EQ(crostini_port_forwarder_->GetNumberOfForwardedPortsForTesting(),
0U);
// Re-initialize otherwise Shutdown in TearDown phase will break.
chromeos::PermissionBrokerClient::InitializeFake();
}
} // namespace crostini