blob: 65d944213a4bafa9902e43d68a755006537a7e5a [file] [log] [blame]
// Copyright 2017 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/firewall.h"
#include <string>
#include <string_view>
#include <vector>
#include <base/strings/string_split.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "patchpanel/datapath.h"
#include "patchpanel/iptables.h"
#include "patchpanel/mock_process_runner.h"
using testing::_;
using testing::DoAll;
using testing::ElementsAreArray;
using testing::Mock;
using testing::Return;
using testing::SaveArg;
using testing::StrEq;
namespace patchpanel {
TEST(FirewallTest, AddAcceptRules_InvalidPorts) {
MockProcessRunner runner;
Firewall firewall(&runner);
runner.ExpectNoCallIptables();
EXPECT_FALSE(firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 0, "iface"));
EXPECT_FALSE(firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 0, "iface"));
EXPECT_FALSE(
firewall.DeleteAcceptRules(ModifyPortRuleRequest::TCP, 0, "iface"));
EXPECT_FALSE(
firewall.DeleteAcceptRules(ModifyPortRuleRequest::UDP, 0, "iface"));
}
TEST(FirewallTest, AddAcceptRules_ValidInterfaceName) {
MockProcessRunner runner;
Firewall firewall(&runner);
runner.ExpectCallIptables(
IpFamily::kDual,
"filter -I ingress_port_firewall -p tcp --dport 80 -i "
"shortname -j ACCEPT -w");
EXPECT_TRUE(
firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80, "shortname"));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kDual,
"filter -I ingress_port_firewall -p udp --dport 53 -i "
"shortname -j ACCEPT -w");
EXPECT_TRUE(
firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53, "shortname"));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kDual,
"filter -I ingress_port_firewall -p tcp --dport 80 -i "
"middle-dash -j ACCEPT -w");
EXPECT_TRUE(
firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80, "middle-dash"));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kDual,
"filter -I ingress_port_firewall -p udp --dport 53 -i "
"middle-dash -j ACCEPT -w");
EXPECT_TRUE(
firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53, "middle-dash"));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kDual,
"filter -I ingress_port_firewall -p tcp --dport 80 -i "
"middle.dot -j ACCEPT -w");
EXPECT_TRUE(
firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80, "middle.dot"));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kDual,
"filter -I ingress_port_firewall -p udp --dport 53 -i "
"middle.dot -j ACCEPT -w");
EXPECT_TRUE(
firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53, "middle.dot"));
Mock::VerifyAndClearExpectations(&runner);
}
TEST(FirewallTest, AddAcceptRules_IptablesFails) {
MockProcessRunner runner;
Firewall firewall(&runner);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -I ingress_port_firewall -p tcp --dport 80 -i iface -j ACCEPT -w",
/*call_times=*/1, /*output=*/"", /*empty_chain=*/false,
/*return_value=*/1);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -I ingress_port_firewall -p udp --dport 53 -i iface -j ACCEPT -w",
/*call_times=*/1, /*output=*/"", /*empty_chain=*/false,
/*return_value=*/1);
runner.ExpectNoCallIptables(IpFamily::kIPv6);
// Punch hole for TCP port 80, should fail.
ASSERT_FALSE(
firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80, "iface"));
// Punch hole for UDP port 53, should fail.
ASSERT_FALSE(
firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53, "iface"));
}
TEST(FirewallTest, AddAcceptRules_Ip6tablesFails) {
MockProcessRunner runner;
Firewall firewall(&runner);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -I ingress_port_firewall -p tcp --dport 80 -i iface "
"-j ACCEPT -w");
// Mock that failed to accept IPv6 rules for TCP.
runner.ExpectCallIptables(
IpFamily::kIPv6,
"filter -I ingress_port_firewall -p tcp --dport 80 -i iface "
"-j ACCEPT -w",
/*call_times=*/1, /*output=*/"", /*empty_chain=*/false,
/*return_value=*/1);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -D ingress_port_firewall -p tcp --dport 80 -i iface "
"-j ACCEPT -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -I ingress_port_firewall -p udp --dport 53 -i iface "
"-j ACCEPT -w");
// Mock that failed to accept IPv6 rules for UDP.
runner.ExpectCallIptables(
IpFamily::kIPv6,
"filter -I ingress_port_firewall -p udp --dport 53 -i iface "
"-j ACCEPT -w",
/*call_times=*/1, /*output=*/"", /*empty_chain=*/false,
/*return_value=*/1);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -D ingress_port_firewall -p udp --dport 53 -i iface "
"-j ACCEPT -w");
// Punch hole for TCP port 80, should fail because 'ip6tables' fails.
ASSERT_FALSE(
firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80, "iface"));
// Punch hole for UDP port 53, should fail because 'ip6tables' fails.
ASSERT_FALSE(
firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53, "iface"));
}
TEST(FirewallTest, AddLoopbackLockdownRules_InvalidPort) {
MockProcessRunner runner;
Firewall firewall(&runner);
runner.ExpectNoCallIptables();
// Try to lock down TCP port 0, port 0 is not a valid port.
EXPECT_FALSE(
firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 0));
// Try to lock down UDP port 0, port 0 is not a valid port.
EXPECT_FALSE(
firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::UDP, 0));
}
TEST(FirewallTest, AddLoopbackLockdownRules_Success) {
MockProcessRunner runner;
Firewall firewall(&runner);
runner.ExpectCallIptables(
IpFamily::kDual,
"filter -I egress_port_firewall -p tcp --dport 80 -o lo -m owner ! "
"--uid-owner chronos -j REJECT -w");
ASSERT_TRUE(
firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 80));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kDual,
"filter -I egress_port_firewall -p udp --dport 53 -o lo -m owner ! "
"--uid-owner chronos -j REJECT -w");
ASSERT_TRUE(
firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::UDP, 53));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kDual,
"filter -I egress_port_firewall -p tcp --dport 1234 -o lo -m owner ! "
"--uid-owner chronos -j REJECT -w");
ASSERT_TRUE(
firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 1234));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kDual,
"filter -I egress_port_firewall -p tcp --dport 8080 -o lo -m owner ! "
"--uid-owner chronos -j REJECT -w");
ASSERT_TRUE(
firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 8080));
Mock::VerifyAndClearExpectations(&runner);
}
TEST(FirewallTest, AddLoopbackLockdownRules_IptablesFails) {
MockProcessRunner runner;
Firewall firewall(&runner);
runner.ExpectCallIptables(IpFamily::kIPv4,
"filter -I egress_port_firewall -p tcp --dport 80 "
"-o lo -m owner ! --uid-owner chronos -j REJECT -w",
/*call_times=*/1, /*output=*/"",
/*empty_chain=*/false, /*return_value=*/1);
runner.ExpectCallIptables(IpFamily::kIPv4,
"filter -I egress_port_firewall -p udp --dport 53 "
"-o lo -m owner ! --uid-owner chronos -j REJECT -w",
/*call_times=*/1, /*output=*/"",
/*empty_chain=*/false, /*return_value=*/1);
runner.ExpectNoCallIptables(IpFamily::kIPv6);
// Lock down TCP port 80, should fail.
ASSERT_FALSE(
firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 80));
// Lock down UDP port 53, should fail.
ASSERT_FALSE(
firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::UDP, 53));
}
TEST(FirewallTest, AddLoopbackLockdownRules_Ip6tablesFails) {
MockProcessRunner runner;
Firewall firewall(&runner);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -I egress_port_firewall -p tcp --dport 80 -o lo -m owner ! "
"--uid-owner chronos -j REJECT -w");
runner.ExpectCallIptables(
IpFamily::kIPv6,
"filter -I egress_port_firewall -p tcp --dport 80 -o lo -m owner ! "
"--uid-owner chronos -j REJECT -w",
/*call_times=*/1, /*output=*/"", /*empty_chain=*/false,
/*return_value=*/1);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -D egress_port_firewall -p tcp --dport 80 -o lo -m owner ! "
"--uid-owner chronos -j REJECT -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -I egress_port_firewall -p udp --dport 53 -o lo -m owner ! "
"--uid-owner chronos -j REJECT -w");
runner.ExpectCallIptables(
IpFamily::kIPv6,
"filter -I egress_port_firewall -p udp --dport 53 -o lo -m owner ! "
"--uid-owner chronos -j REJECT -w",
/*call_times=*/1, /*output=*/"", /*empty_chain=*/false,
/*return_value=*/1);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -D egress_port_firewall -p udp --dport 53 -o lo -m owner ! "
"--uid-owner chronos -j REJECT -w");
// Lock down TCP port 80, should fail because 'ip6tables' fails.
ASSERT_FALSE(
firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 80));
// Lock down UDP port 53, should fail because 'ip6tables' fails.
ASSERT_FALSE(
firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::UDP, 53));
}
TEST(FirewallTest, AddIpv4ForwardRules_InvalidArguments) {
MockProcessRunner runner;
Firewall firewall(&runner);
// Empty input interface. No iptables commands are issued.
runner.ExpectNoCallIptables();
ASSERT_FALSE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 80, "",
net_base::IPv4Address(100, 115, 92, 5), 8080));
ASSERT_FALSE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 80, "",
net_base::IPv4Address(100, 115, 92, 5), 8080));
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 80, "",
net_base::IPv4Address(100, 115, 92, 5), 8080));
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 80, "",
net_base::IPv4Address(100, 115, 92, 5), 8080));
Mock::VerifyAndClearExpectations(&runner);
// Empty interface. No iptables commands are issued.
runner.ExpectNoCallIptables();
ASSERT_FALSE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 80, "",
net_base::IPv4Address(100, 115, 92, 5), 8080));
ASSERT_FALSE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 80, "",
net_base::IPv4Address(100, 115, 92, 5), 8080));
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 80, "",
net_base::IPv4Address(100, 115, 92, 5), 8080));
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 80, "",
net_base::IPv4Address(100, 115, 92, 5), 8080));
Mock::VerifyAndClearExpectations(&runner);
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 80, "",
net_base::IPv4Address(100, 115, 92, 5), 8080));
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 80, "",
net_base::IPv4Address(100, 115, 92, 5), 8080));
Mock::VerifyAndClearExpectations(&runner);
// Trying to delete an IPv4 forward rule with an invalid input port will
// still trigger an explicit iptables -D command for the associated FORWARD
// ACCEPT rule. Two such commands are expected.
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -D FORWARD -i iface -p tcp -d 100.115.92.5 --dport "
"8080 -j ACCEPT -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -D FORWARD -i iface -p udp -d 100.115.92.5 --dport "
"8080 -j ACCEPT -w");
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 0, "iface",
net_base::IPv4Address(100, 115, 92, 5), 8080));
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 0, "iface",
net_base::IPv4Address(100, 115, 92, 5), 8080));
Mock::VerifyAndClearExpectations(&runner);
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 0, "iface",
net_base::IPv4Address(100, 115, 92, 5), 8080));
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 0, "iface",
net_base::IPv4Address(100, 115, 92, 5), 8080));
Mock::VerifyAndClearExpectations(&runner);
// Invalid output dst port. No iptables commands are issused.
runner.ExpectNoCallIptables();
ASSERT_FALSE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 80, "iface",
net_base::IPv4Address(100, 115, 92, 5), 0));
ASSERT_FALSE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 80, "iface",
net_base::IPv4Address(100, 115, 92, 5), 0));
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 80, "iface",
net_base::IPv4Address(100, 115, 92, 5), 0));
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 80, "iface",
net_base::IPv4Address(100, 115, 92, 5), 0));
Mock::VerifyAndClearExpectations(&runner);
}
TEST(FirewallTest, AddIpv4ForwardRules_IptablesFails) {
MockProcessRunner runner;
Firewall firewall(&runner);
// AddIpv4ForwardRule: Firewall should return at the first failure and issue
// only a single command.
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -I ingress_port_forwarding -i iface -p tcp --dport 80 -j DNAT "
"--to-destination 100.115.92.6:8080 -w",
/*call_times=*/1, /*output=*/"", /*empty_chain=*/false,
/*return_value=*/1);
runner.ExpectNoCallIptables(IpFamily::kIPv6);
ASSERT_FALSE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 80, "iface",
net_base::IPv4Address(100, 115, 92, 6), 8080));
Mock::VerifyAndClearExpectations(&runner);
}
TEST(FirewallTest, AddIpv4ForwardRules_IptablesPartialFailure) {
MockProcessRunner runner;
Firewall firewall(&runner);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -I ingress_port_forwarding -i iface -p udp --dport 80 -j DNAT "
"--to-destination 100.115.92.6:8080 -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -A FORWARD -i iface -p udp -d 100.115.92.6 --dport "
"8080 -j ACCEPT -w",
/*call_times=*/1, /*output=*/"", /*empty_chain=*/false,
/*return_value=*/1);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -D ingress_port_forwarding -i iface -p udp --dport 80 -j DNAT "
"--to-destination 100.115.92.6:8080 -w");
runner.ExpectNoCallIptables(IpFamily::kIPv6);
ASSERT_FALSE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 80, "iface",
net_base::IPv4Address(100, 115, 92, 6), 8080));
Mock::VerifyAndClearExpectations(&runner);
}
TEST(FirewallTest, DeleteIpv4ForwardRules_IptablesFails) {
MockProcessRunner runner;
Firewall firewall(&runner);
// DeleteIpv4ForwardRule: Firewall should try to delete both the DNAT rule
// and the FORWARD rule regardless of iptables failures.
// Verify_iptables(runner, "nat -D ingress_port_forwarding -i iface -p tcp
// --dport 80 -j DNAT --to-destination 100.115.92.6:8080 -w");
// Verify_iptables(runner, "filter -D FORWARD -i iface -p tcp -d
// 100.115.92.6 --dport 8080 -j ACCEPT -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -D ingress_port_forwarding -i iface -p tcp --dport 80 -j DNAT "
"--to-destination 100.115.92.6:8080 -w",
1);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -D FORWARD -i iface -p tcp -d 100.115.92.6 --dport "
"8080 -j ACCEPT -w",
/*call_times=*/1, /*output=*/"", /*empty_chain=*/false,
/*return_value=*/1);
runner.ExpectNoCallIptables(IpFamily::kIPv6);
ASSERT_FALSE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 80, "iface",
net_base::IPv4Address(100, 115, 92, 6), 8080));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -D ingress_port_forwarding -i iface -p udp --dport 80 -j DNAT "
"--to-destination 100.115.92.6:8080 -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -D FORWARD -i iface -p udp -d 100.115.92.6 --dport "
"8080 -j ACCEPT -w");
runner.ExpectNoCallIptables(IpFamily::kIPv6);
ASSERT_TRUE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 80, "iface",
net_base::IPv4Address(100, 115, 92, 6), 8080));
Mock::VerifyAndClearExpectations(&runner);
}
TEST(FirewallTest, AddIpv4ForwardRules_ValidRules) {
MockProcessRunner runner;
Firewall firewall(&runner);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -I ingress_port_forwarding -i wlan0 -p tcp --dport 80 -j DNAT "
"--to-destination 100.115.92.2:8080 -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -A FORWARD -i wlan0 -p tcp -d 100.115.92.2 --dport "
"8080 -j ACCEPT -w");
ASSERT_TRUE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 80, "wlan0",
net_base::IPv4Address(100, 115, 92, 2), 8080));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -I ingress_port_forwarding -i vmtap0 -p tcp -d 100.115.92.2 --dport "
"5555 -j DNAT --to-destination 127.0.0.1:5550 -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -A FORWARD -i vmtap0 -p tcp -d 127.0.0.1 --dport "
"5550 -j ACCEPT -w");
ASSERT_TRUE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::TCP, net_base::IPv4Address(100, 115, 92, 2), 5555,
"vmtap0", net_base::IPv4Address(127, 0, 0, 1), 5550));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -I ingress_port_forwarding -i eth0 -p udp --dport 5353 -j DNAT "
"--to-destination 192.168.1.1:5353 -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -A FORWARD -i eth0 -p udp -d 192.168.1.1 --dport "
"5353 -j ACCEPT -w");
ASSERT_TRUE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 5353, "eth0",
net_base::IPv4Address(192, 168, 1, 1), 5353));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -D ingress_port_forwarding -i mlan0 -p tcp --dport 5000 -j DNAT "
"--to-destination 10.0.0.24:5001 -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -D FORWARD -i mlan0 -p tcp -d 10.0.0.24 --dport 5001 "
"-j ACCEPT -w");
ASSERT_TRUE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 5000, "mlan0",
net_base::IPv4Address(10, 0, 0, 24), 5001));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -D ingress_port_forwarding -i vmtap0 -p tcp -d 100.115.92.2 --dport "
"5555 -j DNAT --to-destination 127.0.0.1:5550 -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -D FORWARD -i vmtap0 -p tcp -d 127.0.0.1 --dport "
"5550 -j ACCEPT -w");
ASSERT_TRUE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::TCP, net_base::IPv4Address(100, 115, 92, 2), 5555,
"vmtap0", net_base::IPv4Address(127, 0, 0, 1), 5550));
Mock::VerifyAndClearExpectations(&runner);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -D ingress_port_forwarding -i eth1 -p udp --dport 443 -j DNAT "
"--to-destination 1.2.3.4:443 -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -D FORWARD -i eth1 -p udp -d 1.2.3.4 --dport 443 -j ACCEPT -w");
ASSERT_TRUE(firewall.DeleteIpv4ForwardRule(
ModifyPortRuleRequest::UDP, std::nullopt, 443, "eth1",
net_base::IPv4Address(1, 2, 3, 4), 443));
}
TEST(FirewallTest, AddIpv4ForwardRules_PartialFailure) {
MockProcessRunner runner;
Firewall firewall(&runner);
// When the second issued FORWARD command fails, expect a delete command to
// cleanup the ingress_port_forwarding command that succeeded.
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -I ingress_port_forwarding -i wlan0 -p tcp --dport 80 -j DNAT "
"--to-destination 100.115.92.2:8080 -w");
runner.ExpectCallIptables(
IpFamily::kIPv4,
"filter -A FORWARD -i wlan0 -p tcp -d 100.115.92.2 --dport "
"8080 -j ACCEPT -w",
/*call_times=*/1, /*output=*/"", /*empty_chain=*/false,
/*return_value=*/1);
runner.ExpectCallIptables(
IpFamily::kIPv4,
"nat -D ingress_port_forwarding -i wlan0 -p tcp --dport 80 -j DNAT "
"--to-destination 100.115.92.2:8080 -w");
ASSERT_FALSE(firewall.AddIpv4ForwardRule(
ModifyPortRuleRequest::TCP, std::nullopt, 80, "wlan0",
net_base::IPv4Address(100, 115, 92, 2), 8080));
}
} // namespace patchpanel