| // Copyright 2019 The Chromium OS 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 "patchpanel/datapath.h" |
| |
| #include <linux/if_tun.h> |
| #include <net/if.h> |
| #include <sys/ioctl.h> |
| |
| #include <utility> |
| #include <vector> |
| |
| #include <base/bind.h> |
| #include <base/bind_helpers.h> |
| #include <base/strings/string_util.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "patchpanel/mock_firewall.h" |
| #include "patchpanel/net_util.h" |
| |
| using testing::_; |
| using testing::ElementsAre; |
| using testing::Return; |
| using testing::StrEq; |
| |
| namespace patchpanel { |
| namespace { |
| |
| // TODO(hugobenichi) Centralize this constant definition |
| constexpr pid_t kTestPID = -2; |
| |
| std::vector<ioctl_req_t> ioctl_reqs; |
| std::vector<std::pair<std::string, struct rtentry>> ioctl_rtentry_args; |
| |
| // Capture all ioctls and succeed. |
| int ioctl_req_cap(int fd, ioctl_req_t req, ...) { |
| ioctl_reqs.push_back(req); |
| return 0; |
| } |
| |
| // Capture ioctls for SIOCADDRT and SIOCDELRT and succeed. |
| int ioctl_rtentry_cap(int fd, ioctl_req_t req, struct rtentry* arg) { |
| ioctl_reqs.push_back(req); |
| ioctl_rtentry_args.push_back({"", *arg}); |
| // Copy the string poited by rtentry.rt_dev because Add/DeleteIPv4Route pass |
| // this value to ioctl() on the stack. |
| if (arg->rt_dev) { |
| auto& cap = ioctl_rtentry_args.back(); |
| cap.first = std::string(arg->rt_dev); |
| cap.second.rt_dev = (char*)cap.first.c_str(); |
| } |
| return 0; |
| } |
| |
| } // namespace |
| |
| class MockProcessRunner : public MinijailedProcessRunner { |
| public: |
| MockProcessRunner() = default; |
| ~MockProcessRunner() = default; |
| |
| MOCK_METHOD1(WriteSentinelToContainer, int(pid_t pid)); |
| MOCK_METHOD3(brctl, |
| int(const std::string& cmd, |
| const std::vector<std::string>& argv, |
| bool log_failures)); |
| MOCK_METHOD4(chown, |
| int(const std::string& uid, |
| const std::string& gid, |
| const std::string& file, |
| bool log_failures)); |
| MOCK_METHOD4(ip, |
| int(const std::string& obj, |
| const std::string& cmd, |
| const std::vector<std::string>& args, |
| bool log_failures)); |
| MOCK_METHOD4(ip6, |
| int(const std::string& obj, |
| const std::string& cmd, |
| const std::vector<std::string>& args, |
| bool log_failures)); |
| MOCK_METHOD4(iptables, |
| int(const std::string& table, |
| const std::vector<std::string>& argv, |
| bool log_failures, |
| std::string* output)); |
| MOCK_METHOD4(ip6tables, |
| int(const std::string& table, |
| const std::vector<std::string>& argv, |
| bool log_failures, |
| std::string* output)); |
| MOCK_METHOD2(modprobe_all, |
| int(const std::vector<std::string>& modules, bool log_failures)); |
| MOCK_METHOD3(sysctl_w, |
| int(const std::string& key, |
| const std::string& value, |
| bool log_failures)); |
| MOCK_METHOD3(ip_netns_attach, |
| int(const std::string& netns_name, |
| pid_t netns_pid, |
| bool log_failures)); |
| MOCK_METHOD2(ip_netns_delete, |
| int(const std::string& netns_name, bool log_failures)); |
| }; |
| |
| TEST(DatapathTest, IpFamily) { |
| EXPECT_EQ(IpFamily::Dual, IpFamily::IPv4 | IpFamily::IPv6); |
| EXPECT_EQ(IpFamily::Dual & IpFamily::IPv4, IpFamily::IPv4); |
| EXPECT_EQ(IpFamily::Dual & IpFamily::IPv6, IpFamily::IPv6); |
| EXPECT_NE(IpFamily::Dual, IpFamily::IPv4); |
| EXPECT_NE(IpFamily::Dual, IpFamily::IPv6); |
| EXPECT_NE(IpFamily::IPv4, IpFamily::IPv6); |
| } |
| |
| TEST(DatapathTest, Start) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| // Asserts for sysctl modifications |
| EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv4.ip_forward"), StrEq("1"), true)); |
| EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv4.ip_local_port_range"), |
| StrEq("32768 47103"), true)); |
| EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv6.conf.all.forwarding"), |
| StrEq("1"), true)); |
| // Asserts for AddSNATMarkRules |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-m", "mark", "--mark", "1/1", "-m", |
| "state", "--state", "INVALID", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-m", "mark", "--mark", |
| "1/1", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("nat"), |
| ElementsAre("-A", "POSTROUTING", "-m", "mark", "--mark", |
| "1/1", "-j", "MASQUERADE", "-w"), |
| true, nullptr)); |
| // Asserts for AddForwardEstablishedRule |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-m", "state", "--state", |
| "ESTABLISHED,RELATED", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| // Asserts for AddSourceIPv4DropRule() calls. |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-I", "OUTPUT", "-o", "eth+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-I", "OUTPUT", "-o", "wlan+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-I", "OUTPUT", "-o", "mlan+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-I", "OUTPUT", "-o", "usb+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-I", "OUTPUT", "-o", "wwan+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-I", "OUTPUT", "-o", "rmnet+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| // Asserts for AddOutboundIPv4SNATMark("vmtap+") |
| EXPECT_CALL(runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "vmtap+", "-j", |
| "MARK", "--set-mark", "1/1", "-w"), |
| true, nullptr)); |
| // Asserts for OUTPUT CONNMARK restore rule |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "OUTPUT", "-j", "CONNMARK", |
| "--restore-mark", "--mask", |
| "0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "OUTPUT", "-j", "CONNMARK", |
| "--restore-mark", "--mask", |
| "0xffff0000", "-w"), |
| true, nullptr)); |
| // Asserts for apply_local_source_mark chain |
| EXPECT_CALL(runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-N", "apply_local_source_mark", "-w"), true, |
| nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-F", "apply_local_source_mark", "-w"), true, |
| nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "OUTPUT", "-j", |
| "apply_local_source_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "chronos", "-j", "MARK", "--set-mark", |
| "0x00008100/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", |
| "-m", "owner", "--uid-owner", |
| "debugd", "-j", "MARK", "--set-mark", |
| "0x00008200/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", |
| "owner", "--uid-owner", "cups", "-j", "MARK", |
| "--set-mark", "0x00008200/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "kerberosd", "-j", "MARK", |
| "--set-mark", "0x00008400/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "kerberosd-exec", "-j", "MARK", |
| "--set-mark", "0x00008400/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "tlsdate", "-j", "MARK", "--set-mark", |
| "0x00008400/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "pluginvm", "-j", "MARK", |
| "--set-mark", "0x00008200/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "fuse-smbfs", "-j", "MARK", |
| "--set-mark", "0x00008400/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "cgroup", |
| "--cgroup", "0x00010001", "-j", "MARK", "--set-mark", |
| "0x00000300/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "mark", |
| "--mark", "0x0/0x00003f00", "-j", "MARK", |
| "--set-mark", "0x00000400/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-N", "apply_local_source_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-F", "apply_local_source_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "OUTPUT", "-j", |
| "apply_local_source_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "debugd", "-j", "MARK", "--set-mark", |
| "0x00008200/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "chronos", "-j", "MARK", |
| "--set-mark", "0x00008100/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", |
| "-m", "owner", "--uid-owner", |
| "cups", "-j", "MARK", "--set-mark", |
| "0x00008200/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "kerberosd", "-j", "MARK", |
| "--set-mark", "0x00008400/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "kerberosd-exec", "-j", "MARK", |
| "--set-mark", "0x00008400/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "tlsdate", "-j", "MARK", |
| "--set-mark", "0x00008400/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "pluginvm", "-j", "MARK", |
| "--set-mark", "0x00008200/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "owner", |
| "--uid-owner", "fuse-smbfs", "-j", "MARK", |
| "--set-mark", "0x00008400/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "cgroup", |
| "--cgroup", "0x00010001", "-j", "MARK", |
| "--set-mark", "0x00000300/0x0000ff00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_local_source_mark", "-m", "mark", |
| "--mark", "0x0/0x00003f00", "-j", "MARK", |
| "--set-mark", "0x00000400/0x00003f00", "-w"), |
| true, nullptr)); |
| // Asserts for apply_vpn_mark chain |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-N", "apply_vpn_mark", "-w"), true, |
| nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-F", "apply_vpn_mark", "-w"), true, |
| nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "OUTPUT", "-m", "mark", |
| "--mark", "0x00008000/0x0000c000", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_vpn_mark", "-m", "mark", |
| "!", "--mark", "0x0/0xffff0000", |
| "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-N", "apply_vpn_mark", "-w"), true, |
| nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-F", "apply_vpn_mark", "-w"), true, |
| nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "OUTPUT", "-m", "mark", |
| "--mark", "0x00008000/0x0000c000", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_vpn_mark", "-m", "mark", "!", "--mark", |
| "0x0/0xffff0000", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| |
| Datapath datapath(&runner, &firewall); |
| datapath.Start(); |
| } |
| |
| TEST(DatapathTest, Stop) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| // Asserts for sysctl modifications |
| EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv4.ip_local_port_range"), |
| StrEq("32768 61000"), true)); |
| EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv6.conf.all.forwarding"), |
| StrEq("0"), true)); |
| EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv4.ip_forward"), StrEq("0"), true)); |
| // Asserts for RemoveOutboundIPv4SNATMark("vmtap+") |
| EXPECT_CALL(runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "vmtap+", "-j", |
| "MARK", "--set-mark", "1/1", "-w"), |
| true, nullptr)); |
| // Asserts for RemoveForwardEstablishedRule |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-m", "state", "--state", |
| "ESTABLISHED,RELATED", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| // Asserts for RemoveSNATMarkRules |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-m", "mark", "--mark", "1/1", "-m", |
| "state", "--state", "INVALID", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-m", "mark", "--mark", |
| "1/1", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("nat"), |
| ElementsAre("-D", "POSTROUTING", "-m", "mark", "--mark", |
| "1/1", "-j", "MASQUERADE", "-w"), |
| true, nullptr)); |
| // Asserts for RemoveSourceIPv4DropRule() calls. |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "OUTPUT", "-o", "eth+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "OUTPUT", "-o", "wlan+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "OUTPUT", "-o", "mlan+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "OUTPUT", "-o", "usb+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "OUTPUT", "-o", "wwan+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "OUTPUT", "-o", "rmnet+", "-s", |
| "100.115.92.0/23", "-j", "DROP", "-w"), |
| true, nullptr)); |
| // Asserts for apply_local_source_mark chain |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "OUTPUT", "-j", |
| "apply_local_source_mark", "-w"), |
| true, nullptr)); |
| // Asserts for OUTPUT CONNMARK restore rule |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "OUTPUT", "-j", "CONNMARK", |
| "--restore-mark", "--mask", |
| "0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "OUTPUT", "-j", "CONNMARK", |
| "--restore-mark", "--mask", |
| "0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-F", "apply_local_source_mark", "-w"), true, |
| nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-X", "apply_local_source_mark", "-w"), true, |
| nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "OUTPUT", "-j", |
| "apply_local_source_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-F", "apply_local_source_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-X", "apply_local_source_mark", "-w"), |
| true, nullptr)); |
| // Asserts for apply_vpn_mark chain |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "OUTPUT", "-m", "mark", |
| "--mark", "0x00008000/0x0000c000", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-F", "apply_vpn_mark", "-w"), true, |
| nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-X", "apply_vpn_mark", "-w"), true, |
| nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "OUTPUT", "-m", "mark", |
| "--mark", "0x00008000/0x0000c000", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-F", "apply_vpn_mark", "-w"), true, |
| nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-X", "apply_vpn_mark", "-w"), true, |
| nullptr)); |
| |
| Datapath datapath(&runner, &firewall); |
| datapath.Stop(); |
| } |
| |
| TEST(DatapathTest, AddTAP) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| Datapath datapath(&runner, &firewall, ioctl_req_cap); |
| MacAddress mac = {1, 2, 3, 4, 5, 6}; |
| Subnet subnet(Ipv4Addr(100, 115, 92, 4), 30, base::DoNothing()); |
| auto addr = subnet.AllocateAtOffset(0); |
| auto ifname = datapath.AddTAP("foo0", &mac, addr.get(), ""); |
| EXPECT_EQ(ifname, "foo0"); |
| std::vector<ioctl_req_t> expected = { |
| TUNSETIFF, TUNSETPERSIST, SIOCSIFADDR, SIOCSIFNETMASK, |
| SIOCSIFHWADDR, SIOCGIFFLAGS, SIOCSIFFLAGS}; |
| EXPECT_EQ(ioctl_reqs, expected); |
| ioctl_reqs.clear(); |
| ioctl_rtentry_args.clear(); |
| } |
| |
| TEST(DatapathTest, AddTAPWithOwner) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| Datapath datapath(&runner, &firewall, ioctl_req_cap); |
| MacAddress mac = {1, 2, 3, 4, 5, 6}; |
| Subnet subnet(Ipv4Addr(100, 115, 92, 4), 30, base::DoNothing()); |
| auto addr = subnet.AllocateAtOffset(0); |
| auto ifname = datapath.AddTAP("foo0", &mac, addr.get(), "root"); |
| EXPECT_EQ(ifname, "foo0"); |
| std::vector<ioctl_req_t> expected = { |
| TUNSETIFF, TUNSETPERSIST, TUNSETOWNER, SIOCSIFADDR, |
| SIOCSIFNETMASK, SIOCSIFHWADDR, SIOCGIFFLAGS, SIOCSIFFLAGS}; |
| EXPECT_EQ(ioctl_reqs, expected); |
| ioctl_reqs.clear(); |
| ioctl_rtentry_args.clear(); |
| } |
| |
| TEST(DatapathTest, AddTAPNoAddrs) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| Datapath datapath(&runner, &firewall, ioctl_req_cap); |
| auto ifname = datapath.AddTAP("foo0", nullptr, nullptr, ""); |
| EXPECT_EQ(ifname, "foo0"); |
| std::vector<ioctl_req_t> expected = {TUNSETIFF, TUNSETPERSIST, SIOCGIFFLAGS, |
| SIOCSIFFLAGS}; |
| EXPECT_EQ(ioctl_reqs, expected); |
| ioctl_reqs.clear(); |
| ioctl_rtentry_args.clear(); |
| } |
| |
| TEST(DatapathTest, RemoveTAP) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, ip(StrEq("tuntap"), StrEq("del"), |
| ElementsAre("foo0", "mode", "tap"), true)); |
| Datapath datapath(&runner, &firewall); |
| datapath.RemoveTAP("foo0"); |
| } |
| |
| TEST(DatapathTest, NetnsAttachName) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, ip_netns_delete(StrEq("netns_foo"), false)); |
| EXPECT_CALL(runner, ip_netns_attach(StrEq("netns_foo"), 1234, true)); |
| Datapath datapath(&runner, &firewall); |
| EXPECT_TRUE(datapath.NetnsAttachName("netns_foo", 1234)); |
| } |
| |
| TEST(DatapathTest, NetnsDeleteName) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, ip_netns_delete(StrEq("netns_foo"), true)); |
| Datapath datapath(&runner, &firewall); |
| EXPECT_TRUE(datapath.NetnsDeleteName("netns_foo")); |
| } |
| |
| TEST(DatapathTest, AddBridge) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| Datapath datapath(&runner, &firewall); |
| EXPECT_CALL(runner, brctl(StrEq("addbr"), ElementsAre("br"), true)); |
| EXPECT_CALL( |
| runner, |
| ip(StrEq("addr"), StrEq("add"), |
| ElementsAre("1.1.1.1/30", "brd", "1.1.1.3", "dev", "br"), true)); |
| EXPECT_CALL(runner, |
| ip(StrEq("link"), StrEq("set"), ElementsAre("br", "up"), true)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "br", "-j", |
| "MARK", "--set-mark", "1/1", "-w"), |
| true, nullptr)); |
| datapath.AddBridge("br", Ipv4Addr(1, 1, 1, 1), 30); |
| } |
| |
| TEST(DatapathTest, ConnectVethPair) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, ip(StrEq("link"), StrEq("add"), |
| ElementsAre("veth_foo", "type", "veth", "peer", "name", |
| "peer_foo", "netns", "netns_foo"), |
| true)); |
| EXPECT_CALL(runner, ip(StrEq("addr"), StrEq("add"), |
| ElementsAre("100.115.92.169/30", "brd", |
| "100.115.92.171", "dev", "peer_foo"), |
| true)) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"), |
| ElementsAre("dev", "peer_foo", "up", "addr", |
| "01:02:03:04:05:06", "multicast", "on"), |
| true)) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"), |
| ElementsAre("veth_foo", "up"), true)); |
| Datapath datapath(&runner, &firewall); |
| EXPECT_TRUE(datapath.ConnectVethPair(kTestPID, "netns_foo", "veth_foo", |
| "peer_foo", {1, 2, 3, 4, 5, 6}, |
| Ipv4Addr(100, 115, 92, 169), 30, true)); |
| } |
| |
| TEST(DatapathTest, AddVirtualInterfacePair) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, ip(StrEq("link"), StrEq("add"), |
| ElementsAre("veth_foo", "type", "veth", "peer", "name", |
| "peer_foo", "netns", "netns_foo"), |
| true)); |
| Datapath datapath(&runner, &firewall); |
| EXPECT_TRUE( |
| datapath.AddVirtualInterfacePair("netns_foo", "veth_foo", "peer_foo")); |
| } |
| |
| TEST(DatapathTest, ToggleInterface) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, |
| ip(StrEq("link"), StrEq("set"), ElementsAre("foo", "up"), true)); |
| EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"), |
| ElementsAre("bar", "down"), true)); |
| Datapath datapath(&runner, &firewall); |
| EXPECT_TRUE(datapath.ToggleInterface("foo", true)); |
| EXPECT_TRUE(datapath.ToggleInterface("bar", false)); |
| } |
| |
| TEST(DatapathTest, ConfigureInterface) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL( |
| runner, |
| ip(StrEq("addr"), StrEq("add"), |
| ElementsAre("1.1.1.1/30", "brd", "1.1.1.3", "dev", "foo"), true)) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"), |
| ElementsAre("dev", "foo", "up", "addr", |
| "02:02:02:02:02:02", "multicast", "on"), |
| true)) |
| .WillOnce(Return(0)); |
| |
| Datapath datapath(&runner, &firewall); |
| MacAddress mac_addr = {2, 2, 2, 2, 2, 2}; |
| EXPECT_TRUE(datapath.ConfigureInterface("foo", mac_addr, Ipv4Addr(1, 1, 1, 1), |
| 30, true, true)); |
| } |
| |
| TEST(DatapathTest, RemoveInterface) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, |
| ip(StrEq("link"), StrEq("delete"), ElementsAre("foo"), false)); |
| Datapath datapath(&runner, &firewall); |
| datapath.RemoveInterface("foo"); |
| } |
| |
| TEST(DatapathTest, RemoveBridge) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "br", "-j", |
| "MARK", "--set-mark", "1/1", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| ip(StrEq("link"), StrEq("set"), ElementsAre("br", "down"), true)); |
| EXPECT_CALL(runner, brctl(StrEq("delbr"), ElementsAre("br"), true)); |
| Datapath datapath(&runner, &firewall); |
| datapath.RemoveBridge("br"); |
| } |
| |
| TEST(DatapathTest, AddRemoveSourceIPv4DropRule) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-I", "OUTPUT", "-o", "eth+", "-s", |
| "100.115.92.0/24", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "OUTPUT", "-o", "eth+", "-s", |
| "100.115.92.0/24", "-j", "DROP", "-w"), |
| true, nullptr)); |
| Datapath datapath(&runner, &firewall); |
| datapath.AddSourceIPv4DropRule("eth+", "100.115.92.0/24"); |
| datapath.RemoveSourceIPv4DropRule("eth+", "100.115.92.0/24"); |
| } |
| |
| TEST(DatapathTest, StartRoutingNamespace) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| MacAddress mac = {1, 2, 3, 4, 5, 6}; |
| |
| EXPECT_CALL(runner, ip_netns_delete(StrEq("netns_foo"), false)); |
| EXPECT_CALL(runner, ip_netns_attach(StrEq("netns_foo"), kTestPID, true)); |
| EXPECT_CALL(runner, ip(StrEq("link"), StrEq("add"), |
| ElementsAre("arc_ns0", "type", "veth", "peer", "name", |
| "veth0", "netns", "netns_foo"), |
| true)); |
| EXPECT_CALL(runner, ip(StrEq("addr"), StrEq("add"), |
| ElementsAre("100.115.92.130/30", "brd", |
| "100.115.92.131", "dev", "veth0"), |
| true)) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"), |
| ElementsAre("dev", "veth0", "up", "addr", |
| "01:02:03:04:05:06", "multicast", "off"), |
| true)) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"), |
| ElementsAre("arc_ns0", "up"), true)); |
| EXPECT_CALL(runner, ip(StrEq("addr"), StrEq("add"), |
| ElementsAre("100.115.92.129/30", "brd", |
| "100.115.92.131", "dev", "arc_ns0"), |
| true)) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"), |
| ElementsAre("dev", "arc_ns0", "up", "addr", |
| "01:02:03:04:05:06", "multicast", "off"), |
| true)) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-o", "arc_ns0", |
| "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-i", "arc_ns0", |
| "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arc_ns0", "-j", |
| "MARK", "--set-mark", "1/1", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arc_ns0", |
| "-j", "MARK", "--set-mark", |
| "0x00000200/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arc_ns0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arc_ns0", |
| "-j", "MARK", "--set-mark", |
| "0x00000200/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arc_ns0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arc_ns0", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arc_ns0", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| |
| ConnectedNamespace nsinfo = {}; |
| nsinfo.pid = kTestPID; |
| nsinfo.netns_name = "netns_foo"; |
| nsinfo.source = TrafficSource::USER; |
| nsinfo.outbound_ifname = ""; |
| nsinfo.route_on_vpn = true; |
| nsinfo.host_ifname = "arc_ns0"; |
| nsinfo.peer_ifname = "veth0"; |
| nsinfo.peer_subnet = std::make_unique<Subnet>(Ipv4Addr(100, 115, 92, 128), 30, |
| base::DoNothing()); |
| nsinfo.peer_mac_addr = mac; |
| Datapath datapath(&runner, &firewall, (ioctl_t)ioctl_rtentry_cap); |
| datapath.StartRoutingNamespace(nsinfo); |
| ioctl_reqs.clear(); |
| ioctl_rtentry_args.clear(); |
| } |
| |
| TEST(DatapathTest, StopRoutingNamespace) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-o", "arc_ns0", |
| "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-i", "arc_ns0", |
| "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arc_ns0", "-j", |
| "MARK", "--set-mark", "1/1", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arc_ns0", |
| "-j", "MARK", "--set-mark", |
| "0x00000200/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arc_ns0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arc_ns0", |
| "-j", "MARK", "--set-mark", |
| "0x00000200/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arc_ns0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arc_ns0", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arc_ns0", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip_netns_delete(StrEq("netns_foo"), true)); |
| EXPECT_CALL(runner, ip(StrEq("link"), StrEq("delete"), ElementsAre("arc_ns0"), |
| false)); |
| |
| ConnectedNamespace nsinfo = {}; |
| nsinfo.pid = kTestPID; |
| nsinfo.netns_name = "netns_foo"; |
| nsinfo.source = TrafficSource::USER; |
| nsinfo.outbound_ifname = ""; |
| nsinfo.route_on_vpn = true; |
| nsinfo.host_ifname = "arc_ns0"; |
| nsinfo.peer_ifname = "veth0"; |
| nsinfo.peer_subnet = std::make_unique<Subnet>(Ipv4Addr(100, 115, 92, 128), 30, |
| base::DoNothing()); |
| Datapath datapath(&runner, &firewall); |
| datapath.StopRoutingNamespace(nsinfo); |
| } |
| |
| TEST(DatapathTest, StartRoutingDevice_Arc) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-A", "PREROUTING", "-i", "eth0", |
| "-m", "socket", "--nowildcard", "-j", |
| "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-A", "PREROUTING", "-i", "eth0", |
| "-p", "tcp", "-j", "DNAT", |
| "--to-destination", "1.2.3.4", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-A", "PREROUTING", "-i", "eth0", |
| "-p", "udp", "-j", "DNAT", |
| "--to-destination", "1.2.3.4", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-i", "eth0", "-o", |
| "arc_eth0", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-i", "arc_eth0", |
| "-o", "eth0", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arc_eth0", |
| "-j", "MARK", "--set-mark", |
| "0x00002000/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arc_eth0", |
| "-j", "MARK", "--set-mark", |
| "0x03ea0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arc_eth0", "-j", "MARK", |
| "--set-mark", "0x00002000/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arc_eth0", "-j", "MARK", |
| "--set-mark", "0x03ea0000/0xffff0000", "-w"), |
| true, nullptr)); |
| |
| Datapath datapath(&runner, &firewall); |
| datapath.SetIfnameIndex("eth0", 2); |
| datapath.StartRoutingDevice("eth0", "arc_eth0", Ipv4Addr(1, 2, 3, 4), |
| TrafficSource::ARC, false); |
| } |
| |
| TEST(DatapathTest, StartRoutingDevice_CrosVM) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-o", "vmtap0", |
| "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-i", "vmtap0", |
| "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "vmtap0", |
| "-j", "MARK", "--set-mark", |
| "0x00002100/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "vmtap0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "vmtap0", |
| "-j", "MARK", "--set-mark", |
| "0x00002100/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "vmtap0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "vmtap0", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "vmtap0", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| |
| Datapath datapath(&runner, &firewall); |
| datapath.StartRoutingDevice("", "vmtap0", Ipv4Addr(1, 2, 3, 4), |
| TrafficSource::CROSVM, true); |
| } |
| |
| TEST(DatapathTest, StopRoutingDevice_Arc) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-D", "PREROUTING", "-i", "eth0", |
| "-m", "socket", "--nowildcard", "-j", |
| "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-D", "PREROUTING", "-i", "eth0", |
| "-p", "tcp", "-j", "DNAT", |
| "--to-destination", "1.2.3.4", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-D", "PREROUTING", "-i", "eth0", |
| "-p", "udp", "-j", "DNAT", |
| "--to-destination", "1.2.3.4", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-i", "eth0", "-o", |
| "arc_eth0", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-i", "arc_eth0", |
| "-o", "eth0", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arc_eth0", |
| "-j", "MARK", "--set-mark", |
| "0x00002000/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arc_eth0", |
| "-j", "MARK", "--set-mark", |
| "0x03ea0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arc_eth0", "-j", "MARK", |
| "--set-mark", "0x00002000/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL( |
| runner, |
| ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arc_eth0", "-j", "MARK", |
| "--set-mark", "0x03ea0000/0xffff0000", "-w"), |
| true, nullptr)); |
| |
| Datapath datapath(&runner, &firewall); |
| datapath.SetIfnameIndex("eth0", 2); |
| datapath.StopRoutingDevice("eth0", "arc_eth0", Ipv4Addr(1, 2, 3, 4), |
| TrafficSource::ARC, true); |
| } |
| |
| TEST(DatapathTest, StopRoutingDevice_CrosVM) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-o", "vmtap0", |
| "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-i", "vmtap0", |
| "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "vmtap0", |
| "-j", "MARK", "--set-mark", |
| "0x00002100/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "vmtap0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "vmtap0", |
| "-j", "MARK", "--set-mark", |
| "0x00002100/0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "vmtap0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "vmtap0", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "vmtap0", |
| "-j", "apply_vpn_mark", "-w"), |
| true, nullptr)); |
| |
| Datapath datapath(&runner, &firewall); |
| datapath.StopRoutingDevice("", "vmtap0", Ipv4Addr(1, 2, 3, 4), |
| TrafficSource::CROSVM, true); |
| } |
| |
| TEST(DatapathTest, StartStopIpForwarding) { |
| struct { |
| IpFamily family; |
| std::string iif; |
| std::string oif; |
| std::vector<std::string> start_args; |
| std::vector<std::string> stop_args; |
| bool result; |
| } testcases[] = { |
| {IpFamily::IPv4, "", "", {}, {}, false}, |
| {IpFamily::NONE, "foo", "bar", {}, {}, false}, |
| {IpFamily::IPv4, |
| "foo", |
| "bar", |
| {"-A", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| {"-D", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| true}, |
| {IpFamily::IPv4, |
| "", |
| "bar", |
| {"-A", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| {"-D", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| true}, |
| {IpFamily::IPv4, |
| "foo", |
| "", |
| {"-A", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"}, |
| {"-D", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"}, |
| true}, |
| {IpFamily::IPv6, |
| "foo", |
| "bar", |
| {"-A", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| {"-D", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| true}, |
| {IpFamily::IPv6, |
| "", |
| "bar", |
| {"-A", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| {"-D", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| true}, |
| {IpFamily::IPv6, |
| "foo", |
| "", |
| {"-A", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"}, |
| {"-D", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"}, |
| true}, |
| {IpFamily::Dual, |
| "foo", |
| "bar", |
| {"-A", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| {"-D", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| true}, |
| {IpFamily::Dual, |
| "", |
| "bar", |
| {"-A", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| {"-D", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"}, |
| true}, |
| {IpFamily::Dual, |
| "foo", |
| "", |
| {"-A", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"}, |
| {"-D", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"}, |
| true}, |
| }; |
| |
| for (const auto& tt : testcases) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| if (tt.result) { |
| if (tt.family & IpFamily::IPv4) { |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), tt.start_args, true, nullptr)) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), tt.stop_args, true, nullptr)) |
| .WillOnce(Return(0)); |
| } |
| if (tt.family & IpFamily::IPv6) { |
| EXPECT_CALL(runner, |
| ip6tables(StrEq("filter"), tt.start_args, true, nullptr)) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(runner, |
| ip6tables(StrEq("filter"), tt.stop_args, true, nullptr)) |
| .WillOnce(Return(0)); |
| } |
| } |
| Datapath datapath(&runner, &firewall); |
| |
| EXPECT_EQ(tt.result, datapath.StartIpForwarding(tt.family, tt.iif, tt.oif)); |
| EXPECT_EQ(tt.result, datapath.StopIpForwarding(tt.family, tt.iif, tt.oif)); |
| } |
| } |
| |
| TEST(DatapathTest, StartStopConnectionPinning) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| |
| // Setup |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "POSTROUTING", "-o", "eth0", |
| "-j", "CONNMARK", "--set-mark", |
| "0x03eb0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "POSTROUTING", "-o", "eth0", |
| "-j", "CONNMARK", "--set-mark", |
| "0x03eb0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "POSTROUTING", "-o", "eth0", |
| "-j", "CONNMARK", "--save-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "POSTROUTING", "-o", "eth0", |
| "-j", "CONNMARK", "--save-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "eth0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "eth0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| // Teardown |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "POSTROUTING", "-o", "eth0", |
| "-j", "CONNMARK", "--set-mark", |
| "0x03eb0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "POSTROUTING", "-o", "eth0", |
| "-j", "CONNMARK", "--set-mark", |
| "0x03eb0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "POSTROUTING", "-o", "eth0", |
| "-j", "CONNMARK", "--save-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "POSTROUTING", "-o", "eth0", |
| "-j", "CONNMARK", "--save-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "eth0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "eth0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| |
| Datapath datapath(&runner, &firewall); |
| datapath.SetIfnameIndex("eth0", 3); |
| datapath.StartConnectionPinning("eth0"); |
| datapath.StopConnectionPinning("eth0"); |
| } |
| |
| TEST(DatapathTest, StartStopVpnRouting_NoVirtualDevices) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| |
| // Setup |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "POSTROUTING", "-o", "arcbr0", |
| "-j", "CONNMARK", "--set-mark", |
| "0x03ed0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-A", "apply_vpn_mark", "-j", "MARK", |
| "--set-mark", "0x03ed0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "POSTROUTING", "-o", "arcbr0", |
| "-j", "CONNMARK", "--set-mark", |
| "0x03ed0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "apply_vpn_mark", "-j", |
| "MARK", "--set-mark", |
| "0x03ed0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "POSTROUTING", "-o", "arcbr0", |
| "-j", "CONNMARK", "--save-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "POSTROUTING", "-o", "arcbr0", |
| "-j", "CONNMARK", "--save-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arcbr0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-A", "PREROUTING", "-i", "arcbr0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| // Teardown |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "POSTROUTING", "-o", "arcbr0", |
| "-j", "CONNMARK", "--set-mark", |
| "0x03ed0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("mangle"), |
| ElementsAre("-D", "apply_vpn_mark", "-j", "MARK", |
| "--set-mark", "0x03ed0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "POSTROUTING", "-o", "arcbr0", |
| "-j", "CONNMARK", "--set-mark", |
| "0x03ed0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "apply_vpn_mark", "-j", |
| "MARK", "--set-mark", |
| "0x03ed0000/0xffff0000", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "POSTROUTING", "-o", "arcbr0", |
| "-j", "CONNMARK", "--save-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "POSTROUTING", "-o", "arcbr0", |
| "-j", "CONNMARK", "--save-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arcbr0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("mangle"), |
| ElementsAre("-D", "PREROUTING", "-i", "arcbr0", |
| "-j", "CONNMARK", "--restore-mark", |
| "--mask", "0x00003f00", "-w"), |
| true, nullptr)); |
| |
| Datapath datapath(&runner, &firewall); |
| datapath.SetIfnameIndex("arcbr0", 5); |
| datapath.StartVpnRouting("arcbr0"); |
| datapath.StopVpnRouting("arcbr0"); |
| } |
| |
| TEST(DatapathTest, AddInboundIPv4DNAT) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-A", "PREROUTING", "-i", "eth0", |
| "-m", "socket", "--nowildcard", "-j", |
| "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-A", "PREROUTING", "-i", "eth0", |
| "-p", "tcp", "-j", "DNAT", |
| "--to-destination", "1.2.3.4", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-A", "PREROUTING", "-i", "eth0", |
| "-p", "udp", "-j", "DNAT", |
| "--to-destination", "1.2.3.4", "-w"), |
| true, nullptr)); |
| Datapath datapath(&runner, &firewall); |
| datapath.AddInboundIPv4DNAT("eth0", "1.2.3.4"); |
| } |
| |
| TEST(DatapathTest, RemoveInboundIPv4DNAT) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-D", "PREROUTING", "-i", "eth0", |
| "-m", "socket", "--nowildcard", "-j", |
| "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-D", "PREROUTING", "-i", "eth0", |
| "-p", "tcp", "-j", "DNAT", |
| "--to-destination", "1.2.3.4", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, iptables(StrEq("nat"), |
| ElementsAre("-D", "PREROUTING", "-i", "eth0", |
| "-p", "udp", "-j", "DNAT", |
| "--to-destination", "1.2.3.4", "-w"), |
| true, nullptr)); |
| Datapath datapath(&runner, &firewall); |
| datapath.RemoveInboundIPv4DNAT("eth0", "1.2.3.4"); |
| } |
| |
| TEST(DatapathTest, MaskInterfaceFlags) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| Datapath datapath(&runner, &firewall, ioctl_req_cap); |
| |
| bool result = datapath.MaskInterfaceFlags("foo0", IFF_DEBUG); |
| EXPECT_TRUE(result); |
| std::vector<ioctl_req_t> expected = {SIOCGIFFLAGS, SIOCSIFFLAGS}; |
| EXPECT_EQ(ioctl_reqs, expected); |
| ioctl_reqs.clear(); |
| ioctl_rtentry_args.clear(); |
| } |
| |
| TEST(DatapathTest, AddIPv6Forwarding) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| // Return 1 on iptables -C to simulate rule not existing case |
| EXPECT_CALL(runner, ip6tables(StrEq("filter"), |
| ElementsAre("-C", "FORWARD", "-i", "eth0", "-o", |
| "arc_eth0", "-j", "ACCEPT", "-w"), |
| false, nullptr)) |
| .WillOnce(Return(1)); |
| EXPECT_CALL(runner, ip6tables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-i", "eth0", "-o", |
| "arc_eth0", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("filter"), |
| ElementsAre("-C", "FORWARD", "-i", "arc_eth0", |
| "-o", "eth0", "-j", "ACCEPT", "-w"), |
| false, nullptr)) |
| .WillOnce(Return(1)); |
| EXPECT_CALL(runner, ip6tables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-i", "arc_eth0", |
| "-o", "eth0", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| Datapath datapath(&runner, &firewall); |
| datapath.AddIPv6Forwarding("eth0", "arc_eth0"); |
| } |
| |
| TEST(DatapathTest, AddIPv6ForwardingRuleExists) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, ip6tables(StrEq("filter"), |
| ElementsAre("-C", "FORWARD", "-i", "eth0", "-o", |
| "arc_eth0", "-j", "ACCEPT", "-w"), |
| false, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("filter"), |
| ElementsAre("-C", "FORWARD", "-i", "arc_eth0", |
| "-o", "eth0", "-j", "ACCEPT", "-w"), |
| false, nullptr)); |
| Datapath datapath(&runner, &firewall); |
| datapath.AddIPv6Forwarding("eth0", "arc_eth0"); |
| } |
| |
| TEST(DatapathTest, RemoveIPv6Forwarding) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, ip6tables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-i", "eth0", "-o", |
| "arc_eth0", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, ip6tables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-i", "arc_eth0", |
| "-o", "eth0", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| Datapath datapath(&runner, &firewall); |
| datapath.RemoveIPv6Forwarding("eth0", "arc_eth0"); |
| } |
| |
| TEST(DatapathTest, AddIPv6HostRoute) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL(runner, |
| ip6(StrEq("route"), StrEq("replace"), |
| ElementsAre("2001:da8:e00::1234/128", "dev", "eth0"), true)); |
| Datapath datapath(&runner, &firewall); |
| datapath.AddIPv6HostRoute("eth0", "2001:da8:e00::1234", 128); |
| } |
| |
| TEST(DatapathTest, AddIPv4Route) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| Datapath datapath(&runner, &firewall, (ioctl_t)ioctl_rtentry_cap); |
| |
| datapath.AddIPv4Route(Ipv4Addr(192, 168, 1, 1), Ipv4Addr(100, 115, 93, 0), |
| Ipv4Addr(255, 255, 255, 0)); |
| datapath.DeleteIPv4Route(Ipv4Addr(192, 168, 1, 1), Ipv4Addr(100, 115, 93, 0), |
| Ipv4Addr(255, 255, 255, 0)); |
| datapath.AddIPv4Route("eth0", Ipv4Addr(100, 115, 92, 8), |
| Ipv4Addr(255, 255, 255, 252)); |
| datapath.DeleteIPv4Route("eth0", Ipv4Addr(100, 115, 92, 8), |
| Ipv4Addr(255, 255, 255, 252)); |
| |
| std::vector<ioctl_req_t> expected_reqs = {SIOCADDRT, SIOCDELRT, SIOCADDRT, |
| SIOCDELRT}; |
| EXPECT_EQ(expected_reqs, ioctl_reqs); |
| |
| std::string route1 = |
| "{rt_dst: {family: AF_INET, port: 0, addr: 100.115.93.0}, rt_genmask: " |
| "{family: AF_INET, port: 0, addr: 255.255.255.0}, rt_gateway: {family: " |
| "AF_INET, port: 0, addr: 192.168.1.1}, rt_dev: null, rt_flags: RTF_UP | " |
| "RTF_GATEWAY}"; |
| std::string route2 = |
| "{rt_dst: {family: AF_INET, port: 0, addr: 100.115.92.8}, rt_genmask: " |
| "{family: AF_INET, port: 0, addr: 255.255.255.252}, rt_gateway: {unset}, " |
| "rt_dev: eth0, rt_flags: RTF_UP | RTF_GATEWAY}"; |
| std::vector<std::string> captured_routes; |
| for (const auto& route : ioctl_rtentry_args) { |
| std::ostringstream stream; |
| stream << route.second; |
| captured_routes.emplace_back(stream.str()); |
| } |
| EXPECT_EQ(route1, captured_routes[0]); |
| EXPECT_EQ(route1, captured_routes[1]); |
| EXPECT_EQ(route2, captured_routes[2]); |
| EXPECT_EQ(route2, captured_routes[3]); |
| ioctl_reqs.clear(); |
| ioctl_rtentry_args.clear(); |
| } |
| |
| TEST(DatapathTest, AddSNATMarkRules) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-m", "mark", "--mark", "1/1", "-m", |
| "state", "--state", "INVALID", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-A", "FORWARD", "-m", "mark", "--mark", |
| "1/1", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("nat"), |
| ElementsAre("-A", "POSTROUTING", "-m", "mark", "--mark", |
| "1/1", "-j", "MASQUERADE", "-w"), |
| true, nullptr)); |
| Datapath datapath(&runner, &firewall); |
| datapath.AddSNATMarkRules(); |
| } |
| |
| TEST(DatapathTest, RemoveSNATMarkRules) { |
| MockProcessRunner runner; |
| MockFirewall firewall; |
| EXPECT_CALL( |
| runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-m", "mark", "--mark", "1/1", "-m", |
| "state", "--state", "INVALID", "-j", "DROP", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("filter"), |
| ElementsAre("-D", "FORWARD", "-m", "mark", "--mark", |
| "1/1", "-j", "ACCEPT", "-w"), |
| true, nullptr)); |
| EXPECT_CALL(runner, |
| iptables(StrEq("nat"), |
| ElementsAre("-D", "POSTROUTING", "-m", "mark", "--mark", |
| "1/1", "-j", "MASQUERADE", "-w"), |
| true, nullptr)); |
| Datapath datapath(&runner, &firewall); |
| datapath.RemoveSNATMarkRules(); |
| } |
| |
| TEST(DatapathTest, ArcVethHostName) { |
| EXPECT_EQ("vetheth0", ArcVethHostName("eth0")); |
| EXPECT_EQ("vethrmnet0", ArcVethHostName("rmnet0")); |
| EXPECT_EQ("vethrmnet_data0", ArcVethHostName("rmnet_data0")); |
| EXPECT_EQ("vethifnamsiz_i0", ArcVethHostName("ifnamsiz_ifnam0")); |
| auto ifname = ArcVethHostName("exceeds_ifnamesiz_checkanyway"); |
| EXPECT_EQ("vethexceeds_ify", ifname); |
| EXPECT_LT(ifname.length(), IFNAMSIZ); |
| } |
| |
| TEST(DatapathTest, ArcBridgeName) { |
| EXPECT_EQ("arc_eth0", ArcBridgeName("eth0")); |
| EXPECT_EQ("arc_rmnet0", ArcBridgeName("rmnet0")); |
| EXPECT_EQ("arc_rmnet_data0", ArcBridgeName("rmnet_data0")); |
| EXPECT_EQ("arc_ifnamsiz_i0", ArcBridgeName("ifnamsiz_ifnam0")); |
| auto ifname = ArcBridgeName("exceeds_ifnamesiz_checkanyway"); |
| EXPECT_EQ("arc_exceeds_ify", ifname); |
| EXPECT_LT(ifname.length(), IFNAMSIZ); |
| } |
| |
| } // namespace patchpanel |