blob: 618ba6891317df60ded60dde6e2e58a8e72cce61 [file] [log] [blame]
// Copyright 2020 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 "chrome/browser/ash/crostini/crostini_port_forwarder.h"
#include "base/callback_helpers.h"
#include "base/run_loop.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/dbus/cicerone/cicerone_client.h"
#include "chromeos/dbus/concierge/concierge_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/permission_broker/fake_permission_broker_client.h"
#include "chromeos/dbus/seneschal/seneschal_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_(ContainerId::GetDefault()),
other_container_id_(ContainerId("other", "other")),
inactive_container_id_(ContainerId("inactive", "inactive")) {}
~CrostiniPortForwarderTest() override {}
void SetUp() override {
chromeos::DBusThreadManager::Initialize();
chromeos::CiceroneClient::InitializeFake();
chromeos::ConciergeClient::InitializeFake();
chromeos::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();
chromeos::SeneschalClient::Shutdown();
chromeos::ConciergeClient::Shutdown();
chromeos::CiceroneClient::Shutdown();
chromeos::DBusThreadManager::Shutdown();
}
protected:
class MockPortObserver : public CrostiniPortForwarder::Observer {
public:
MOCK_METHOD(void,
OnActivePortsChanged,
(const base::ListValue& activePorts),
(override));
};
Profile* profile() { return profile_.get(); }
CrostiniPortForwarder::PortRuleKey GetPortKey(int port_number,
Protocol protocol_type,
ContainerId 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) {
absl::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().FindIntKey(crostini::kPortNumberKey).value());
EXPECT_EQ(static_cast<int>(key.protocol_type),
pref.value().FindIntKey(crostini::kPortProtocolKey).value());
EXPECT_EQ(key.container_id.vm_name,
*pref.value().FindStringKey(crostini::kPortVmNameKey));
EXPECT_EQ(key.container_id.container_name,
*pref.value().FindStringKey(crostini::kPortContainerNameKey));
EXPECT_EQ(label, *pref.value().FindStringKey(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) {
bool success = false;
base::RunLoop run_loop;
crostini_port_forwarder_->AddPort(
port.container_id, port.port_number, port.protocol_type, "",
base::BindOnce(&TestingCallback, base::Unretained(&success),
run_loop.QuitClosure()));
run_loop.Run();
return success;
}
bool ActivatePortFromKey(CrostiniPortForwarder::PortRuleKey port) {
bool success = false;
base::RunLoop run_loop;
crostini_port_forwarder_->ActivatePort(
port.container_id, port.port_number, port.protocol_type,
base::BindOnce(&TestingCallback, base::Unretained(&success),
run_loop.QuitClosure()));
run_loop.Run();
return success;
}
bool RemovePortFromKey(CrostiniPortForwarder::PortRuleKey port) {
bool success = false;
base::RunLoop run_loop;
crostini_port_forwarder_->RemovePort(
port.container_id, port.port_number, port.protocol_type,
base::BindOnce(&TestingCallback, base::Unretained(&success),
run_loop.QuitClosure()));
run_loop.Run();
return success;
}
bool DeactivatePortFromKey(CrostiniPortForwarder::PortRuleKey port) {
bool success = false;
base::RunLoop run_loop;
crostini_port_forwarder_->DeactivatePort(
port.container_id, port.port_number, port.protocol_type,
base::BindOnce(&TestingCallback, base::Unretained(&success),
run_loop.QuitClosure()));
run_loop.Run();
return success;
}
ContainerId default_container_id_;
ContainerId other_container_id_;
ContainerId inactive_container_id_;
testing::NiceMock<MockPortObserver> mock_observer_;
std::unique_ptr<CrostiniTestHelper> test_helper_;
std::unique_ptr<TestingProfile> profile_;
std::unique_ptr<CrostiniPortForwarder> crostini_port_forwarder_;
content::BrowserTaskEnvironment task_environment_;
private:
DISALLOW_COPY_AND_ASSIGN(CrostiniPortForwarderTest);
};
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) {
ContainerId 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) {
ContainerId 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) {
ContainerId 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::ListValue forwarded_ports = crostini_port_forwarder_->GetActivePorts();
EXPECT_EQ(forwarded_ports.GetList().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.GetList()[i].FindPath("port_number")),
base::Value(ports_to_add.at(reverse_index).port_number));
EXPECT_EQ(*(forwarded_ports.GetList()[i].FindPath("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());
// 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);
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);
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