blob: c80950ae5e5c26b0730b060edd225ed0d1f8a84c [file] [log] [blame]
Garrick Evansf0ab7132019-06-18 14:50:42 +09001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Garrick Evans3388a032020-03-24 11:25:55 +09005#include "patchpanel/datapath.h"
Garrick Evansf0ab7132019-06-18 14:50:42 +09006
Garrick Evansc7ae82c2019-09-04 16:25:10 +09007#include <linux/if_tun.h>
Taoyu Li90c13912019-11-26 17:56:54 +09008#include <net/if.h>
Garrick Evansc7ae82c2019-09-04 16:25:10 +09009#include <sys/ioctl.h>
10
Garrick Evansf0ab7132019-06-18 14:50:42 +090011#include <utility>
12#include <vector>
13
Garrick Evansc7ae82c2019-09-04 16:25:10 +090014#include <base/bind.h>
Qijiang Fane90b8792020-03-09 16:15:41 +090015#include <base/bind_helpers.h>
Garrick Evansf0ab7132019-06-18 14:50:42 +090016#include <base/strings/string_util.h>
Garrick Evans8e8e3472020-01-23 14:03:50 +090017#include <gmock/gmock.h>
Garrick Evansf0ab7132019-06-18 14:50:42 +090018#include <gtest/gtest.h>
19
Garrick Evans3388a032020-03-24 11:25:55 +090020#include "patchpanel/net_util.h"
Garrick Evansf0ab7132019-06-18 14:50:42 +090021
Garrick Evans8e8e3472020-01-23 14:03:50 +090022using testing::_;
23using testing::ElementsAre;
24using testing::Return;
25using testing::StrEq;
26
Garrick Evans3388a032020-03-24 11:25:55 +090027namespace patchpanel {
Garrick Evansc7ae82c2019-09-04 16:25:10 +090028namespace {
29
Hugo Benichi76675592020-04-08 14:29:57 +090030// TODO(hugobenichi) Centralize this constant definition
31constexpr pid_t kTestPID = -2;
32
Hugo Benichie8758b52020-04-03 14:49:01 +090033std::vector<ioctl_req_t> ioctl_reqs;
34std::vector<std::pair<std::string, struct rtentry>> ioctl_rtentry_args;
Garrick Evansc7ae82c2019-09-04 16:25:10 +090035
36// Capture all ioctls and succeed.
Taoyu Li90c13912019-11-26 17:56:54 +090037int ioctl_req_cap(int fd, ioctl_req_t req, ...) {
Hugo Benichie8758b52020-04-03 14:49:01 +090038 ioctl_reqs.push_back(req);
39 return 0;
40}
41
42// Capture ioctls for SIOCADDRT and SIOCDELRT and succeed.
43int ioctl_rtentry_cap(int fd, ioctl_req_t req, struct rtentry* arg) {
44 ioctl_reqs.push_back(req);
45 ioctl_rtentry_args.push_back({"", *arg});
46 // Copy the string poited by rtentry.rt_dev because Add/DeleteIPv4Route pass
47 // this value to ioctl() on the stack.
48 if (arg->rt_dev) {
49 auto& cap = ioctl_rtentry_args.back();
50 cap.first = std::string(arg->rt_dev);
51 cap.second.rt_dev = (char*)cap.first.c_str();
52 }
Garrick Evansc7ae82c2019-09-04 16:25:10 +090053 return 0;
54}
55
56} // namespace
57
Garrick Evans8e8e3472020-01-23 14:03:50 +090058class MockProcessRunner : public MinijailedProcessRunner {
59 public:
60 MockProcessRunner() = default;
61 ~MockProcessRunner() = default;
62
Garrick Evans2470caa2020-03-04 14:15:41 +090063 MOCK_METHOD1(WriteSentinelToContainer, int(pid_t pid));
Garrick Evans8e8e3472020-01-23 14:03:50 +090064 MOCK_METHOD3(brctl,
65 int(const std::string& cmd,
66 const std::vector<std::string>& argv,
67 bool log_failures));
68 MOCK_METHOD4(chown,
69 int(const std::string& uid,
70 const std::string& gid,
71 const std::string& file,
72 bool log_failures));
Garrick Evans8e8e3472020-01-23 14:03:50 +090073 MOCK_METHOD4(ip,
74 int(const std::string& obj,
75 const std::string& cmd,
76 const std::vector<std::string>& args,
77 bool log_failures));
78 MOCK_METHOD4(ip6,
79 int(const std::string& obj,
80 const std::string& cmd,
81 const std::vector<std::string>& args,
82 bool log_failures));
Jie Jiangcf5ce9c2020-07-14 17:22:03 +090083 MOCK_METHOD4(iptables,
Garrick Evans8e8e3472020-01-23 14:03:50 +090084 int(const std::string& table,
85 const std::vector<std::string>& argv,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +090086 bool log_failures,
87 std::string* output));
88 MOCK_METHOD4(ip6tables,
Garrick Evans8e8e3472020-01-23 14:03:50 +090089 int(const std::string& table,
90 const std::vector<std::string>& argv,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +090091 bool log_failures,
92 std::string* output));
Garrick Evans8e8e3472020-01-23 14:03:50 +090093 MOCK_METHOD2(modprobe_all,
94 int(const std::vector<std::string>& modules, bool log_failures));
95 MOCK_METHOD3(sysctl_w,
96 int(const std::string& key,
97 const std::string& value,
98 bool log_failures));
Hugo Benichi33860d72020-07-09 16:34:01 +090099 MOCK_METHOD3(ip_netns_attach,
100 int(const std::string& netns_name,
101 pid_t netns_pid,
102 bool log_failures));
103 MOCK_METHOD2(ip_netns_delete,
104 int(const std::string& netns_name, bool log_failures));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900105};
106
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900107TEST(DatapathTest, AddTAP) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900108 MockProcessRunner runner;
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900109 Datapath datapath(&runner, ioctl_req_cap);
110 MacAddress mac = {1, 2, 3, 4, 5, 6};
Qijiang Fane90b8792020-03-09 16:15:41 +0900111 Subnet subnet(Ipv4Addr(100, 115, 92, 4), 30, base::DoNothing());
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900112 auto addr = subnet.AllocateAtOffset(0);
Garrick Evans4f9f5572019-11-26 10:25:16 +0900113 auto ifname = datapath.AddTAP("foo0", &mac, addr.get(), "");
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900114 EXPECT_EQ(ifname, "foo0");
Hugo Benichie8758b52020-04-03 14:49:01 +0900115 std::vector<ioctl_req_t> expected = {
116 TUNSETIFF, TUNSETPERSIST, SIOCSIFADDR, SIOCSIFNETMASK,
117 SIOCSIFHWADDR, SIOCGIFFLAGS, SIOCSIFFLAGS};
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900118 EXPECT_EQ(ioctl_reqs, expected);
119 ioctl_reqs.clear();
120}
121
122TEST(DatapathTest, AddTAPWithOwner) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900123 MockProcessRunner runner;
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900124 Datapath datapath(&runner, ioctl_req_cap);
125 MacAddress mac = {1, 2, 3, 4, 5, 6};
Qijiang Fane90b8792020-03-09 16:15:41 +0900126 Subnet subnet(Ipv4Addr(100, 115, 92, 4), 30, base::DoNothing());
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900127 auto addr = subnet.AllocateAtOffset(0);
Garrick Evans4f9f5572019-11-26 10:25:16 +0900128 auto ifname = datapath.AddTAP("foo0", &mac, addr.get(), "root");
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900129 EXPECT_EQ(ifname, "foo0");
Hugo Benichie8758b52020-04-03 14:49:01 +0900130 std::vector<ioctl_req_t> expected = {
131 TUNSETIFF, TUNSETPERSIST, TUNSETOWNER, SIOCSIFADDR,
132 SIOCSIFNETMASK, SIOCSIFHWADDR, SIOCGIFFLAGS, SIOCSIFFLAGS};
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900133 EXPECT_EQ(ioctl_reqs, expected);
134 ioctl_reqs.clear();
135}
136
Garrick Evans621ed262019-11-13 12:28:43 +0900137TEST(DatapathTest, AddTAPNoAddrs) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900138 MockProcessRunner runner;
Garrick Evans621ed262019-11-13 12:28:43 +0900139 Datapath datapath(&runner, ioctl_req_cap);
Garrick Evans4f9f5572019-11-26 10:25:16 +0900140 auto ifname = datapath.AddTAP("foo0", nullptr, nullptr, "");
Garrick Evans621ed262019-11-13 12:28:43 +0900141 EXPECT_EQ(ifname, "foo0");
Hugo Benichie8758b52020-04-03 14:49:01 +0900142 std::vector<ioctl_req_t> expected = {TUNSETIFF, TUNSETPERSIST, SIOCGIFFLAGS,
143 SIOCSIFFLAGS};
Garrick Evans621ed262019-11-13 12:28:43 +0900144 EXPECT_EQ(ioctl_reqs, expected);
145 ioctl_reqs.clear();
146}
147
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900148TEST(DatapathTest, RemoveTAP) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900149 MockProcessRunner runner;
150 EXPECT_CALL(runner, ip(StrEq("tuntap"), StrEq("del"),
151 ElementsAre("foo0", "mode", "tap"), true));
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900152 Datapath datapath(&runner);
153 datapath.RemoveTAP("foo0");
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900154}
Garrick Evansf0ab7132019-06-18 14:50:42 +0900155
Hugo Benichi33860d72020-07-09 16:34:01 +0900156TEST(DatapathTest, NetnsAttachName) {
157 MockProcessRunner runner;
158 EXPECT_CALL(runner, ip_netns_delete(StrEq("netns_foo"), false));
159 EXPECT_CALL(runner, ip_netns_attach(StrEq("netns_foo"), 1234, true));
160 Datapath datapath(&runner);
161 EXPECT_TRUE(datapath.NetnsAttachName("netns_foo", 1234));
162}
163
164TEST(DatapathTest, NetnsDeleteName) {
165 MockProcessRunner runner;
166 EXPECT_CALL(runner, ip_netns_delete(StrEq("netns_foo"), true));
167 Datapath datapath(&runner);
168 EXPECT_TRUE(datapath.NetnsDeleteName("netns_foo"));
169}
170
Garrick Evans8a949dc2019-07-18 16:17:53 +0900171TEST(DatapathTest, AddBridge) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900172 MockProcessRunner runner;
Garrick Evans8a949dc2019-07-18 16:17:53 +0900173 Datapath datapath(&runner);
Garrick Evans8e8e3472020-01-23 14:03:50 +0900174 EXPECT_CALL(runner, brctl(StrEq("addbr"), ElementsAre("br"), true));
Garrick Evans6f4fa3a2020-02-10 16:15:09 +0900175 EXPECT_CALL(
176 runner,
177 ip(StrEq("addr"), StrEq("add"),
178 ElementsAre("1.1.1.1/30", "brd", "1.1.1.3", "dev", "br"), true));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900179 EXPECT_CALL(runner,
180 ip(StrEq("link"), StrEq("set"), ElementsAre("br", "up"), true));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900181 EXPECT_CALL(runner, iptables(StrEq("mangle"),
182 ElementsAre("-A", "PREROUTING", "-i", "br", "-j",
183 "MARK", "--set-mark", "1", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900184 true, nullptr));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900185 datapath.AddBridge("br", Ipv4Addr(1, 1, 1, 1), 30);
Garrick Evans8a949dc2019-07-18 16:17:53 +0900186}
187
Hugo Benichi76675592020-04-08 14:29:57 +0900188TEST(DatapathTest, ConnectVethPair) {
189 MockProcessRunner runner;
190 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("add"),
191 ElementsAre("veth_foo", "type", "veth", "peer", "name",
Hugo Benichi33860d72020-07-09 16:34:01 +0900192 "peer_foo", "netns", "netns_foo"),
Hugo Benichi76675592020-04-08 14:29:57 +0900193 true));
194 EXPECT_CALL(runner, ip(StrEq("addr"), StrEq("add"),
195 ElementsAre("100.115.92.169/30", "brd",
196 "100.115.92.171", "dev", "peer_foo"),
197 true))
198 .WillOnce(Return(0));
199 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
200 ElementsAre("dev", "peer_foo", "up", "addr",
201 "01:02:03:04:05:06", "multicast", "on"),
202 true))
203 .WillOnce(Return(0));
Hugo Benichi76675592020-04-08 14:29:57 +0900204 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
205 ElementsAre("veth_foo", "up"), true));
206 Datapath datapath(&runner);
Hugo Benichi33860d72020-07-09 16:34:01 +0900207 EXPECT_TRUE(datapath.ConnectVethPair(kTestPID, "netns_foo", "veth_foo",
208 "peer_foo", {1, 2, 3, 4, 5, 6},
Hugo Benichi76675592020-04-08 14:29:57 +0900209 Ipv4Addr(100, 115, 92, 169), 30, true));
210}
211
Garrick Evans2470caa2020-03-04 14:15:41 +0900212TEST(DatapathTest, AddVirtualInterfacePair) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900213 MockProcessRunner runner;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900214 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("add"),
215 ElementsAre("veth_foo", "type", "veth", "peer", "name",
Hugo Benichi33860d72020-07-09 16:34:01 +0900216 "peer_foo", "netns", "netns_foo"),
Garrick Evans8e8e3472020-01-23 14:03:50 +0900217 true));
Garrick Evans2470caa2020-03-04 14:15:41 +0900218 Datapath datapath(&runner);
Hugo Benichi33860d72020-07-09 16:34:01 +0900219 EXPECT_TRUE(
220 datapath.AddVirtualInterfacePair("netns_foo", "veth_foo", "peer_foo"));
Garrick Evans2470caa2020-03-04 14:15:41 +0900221}
222
223TEST(DatapathTest, ToggleInterface) {
224 MockProcessRunner runner;
225 EXPECT_CALL(runner,
226 ip(StrEq("link"), StrEq("set"), ElementsAre("foo", "up"), true));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900227 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
Garrick Evans2470caa2020-03-04 14:15:41 +0900228 ElementsAre("bar", "down"), true));
229 Datapath datapath(&runner);
230 EXPECT_TRUE(datapath.ToggleInterface("foo", true));
231 EXPECT_TRUE(datapath.ToggleInterface("bar", false));
232}
233
234TEST(DatapathTest, ConfigureInterface) {
235 MockProcessRunner runner;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900236 EXPECT_CALL(
237 runner,
Garrick Evans2470caa2020-03-04 14:15:41 +0900238 ip(StrEq("addr"), StrEq("add"),
239 ElementsAre("1.1.1.1/30", "brd", "1.1.1.3", "dev", "foo"), true))
240 .WillOnce(Return(0));
241 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
242 ElementsAre("dev", "foo", "up", "addr",
243 "02:02:02:02:02:02", "multicast", "on"),
244 true))
245 .WillOnce(Return(0));
246
Garrick Evans54861622019-07-19 09:05:09 +0900247 Datapath datapath(&runner);
Garrick Evans2470caa2020-03-04 14:15:41 +0900248 MacAddress mac_addr = {2, 2, 2, 2, 2, 2};
249 EXPECT_TRUE(datapath.ConfigureInterface("foo", mac_addr, Ipv4Addr(1, 1, 1, 1),
250 30, true, true));
Garrick Evans54861622019-07-19 09:05:09 +0900251}
252
253TEST(DatapathTest, RemoveInterface) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900254 MockProcessRunner runner;
255 EXPECT_CALL(runner,
256 ip(StrEq("link"), StrEq("delete"), ElementsAre("foo"), false));
Garrick Evans54861622019-07-19 09:05:09 +0900257 Datapath datapath(&runner);
258 datapath.RemoveInterface("foo");
Garrick Evans54861622019-07-19 09:05:09 +0900259}
260
Garrick Evans8a949dc2019-07-18 16:17:53 +0900261TEST(DatapathTest, RemoveBridge) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900262 MockProcessRunner runner;
263 EXPECT_CALL(runner, iptables(StrEq("mangle"),
264 ElementsAre("-D", "PREROUTING", "-i", "br", "-j",
265 "MARK", "--set-mark", "1", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900266 true, nullptr));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900267 EXPECT_CALL(runner,
268 ip(StrEq("link"), StrEq("set"), ElementsAre("br", "down"), true));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900269 EXPECT_CALL(runner, brctl(StrEq("delbr"), ElementsAre("br"), true));
Garrick Evans8a949dc2019-07-18 16:17:53 +0900270 Datapath datapath(&runner);
271 datapath.RemoveBridge("br");
Garrick Evans8a949dc2019-07-18 16:17:53 +0900272}
273
Garrick Evansf0ab7132019-06-18 14:50:42 +0900274TEST(DatapathTest, AddLegacyIPv4DNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900275 MockProcessRunner runner;
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900276 EXPECT_CALL(runner,
277 iptables(StrEq("nat"), ElementsAre("-N", "dnat_arc", "-w"), true,
278 nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900279 EXPECT_CALL(runner, iptables(StrEq("nat"),
280 ElementsAre("-A", "dnat_arc", "-j", "DNAT",
281 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900282 true, nullptr));
283 EXPECT_CALL(runner, iptables(StrEq("nat"), ElementsAre("-N", "try_arc", "-w"),
284 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900285 EXPECT_CALL(runner,
286 iptables(StrEq("nat"),
287 ElementsAre("-A", "PREROUTING", "-m", "socket",
288 "--nowildcard", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900289 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900290 EXPECT_CALL(runner, iptables(StrEq("nat"),
291 ElementsAre("-A", "PREROUTING", "-p", "tcp",
292 "-j", "try_arc", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900293 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900294 EXPECT_CALL(runner, iptables(StrEq("nat"),
295 ElementsAre("-A", "PREROUTING", "-p", "udp",
296 "-j", "try_arc", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900297 true, nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900298 Datapath datapath(&runner);
299 datapath.AddLegacyIPv4DNAT("1.2.3.4");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900300}
301
302TEST(DatapathTest, RemoveLegacyIPv4DNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900303 MockProcessRunner runner;
304 EXPECT_CALL(runner, iptables(StrEq("nat"),
305 ElementsAre("-D", "PREROUTING", "-p", "udp",
306 "-j", "try_arc", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900307 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900308 EXPECT_CALL(runner, iptables(StrEq("nat"),
309 ElementsAre("-D", "PREROUTING", "-p", "tcp",
310 "-j", "try_arc", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900311 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900312 EXPECT_CALL(runner,
313 iptables(StrEq("nat"),
314 ElementsAre("-D", "PREROUTING", "-m", "socket",
315 "--nowildcard", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900316 true, nullptr));
317 EXPECT_CALL(runner, iptables(StrEq("nat"), ElementsAre("-F", "try_arc", "-w"),
318 true, nullptr));
319 EXPECT_CALL(runner, iptables(StrEq("nat"), ElementsAre("-X", "try_arc", "-w"),
320 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900321 EXPECT_CALL(runner,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900322 iptables(StrEq("nat"), ElementsAre("-F", "dnat_arc", "-w"), true,
323 nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900324 EXPECT_CALL(runner,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900325 iptables(StrEq("nat"), ElementsAre("-X", "dnat_arc", "-w"), true,
326 nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900327 Datapath datapath(&runner);
328 datapath.RemoveLegacyIPv4DNAT();
Garrick Evansf0ab7132019-06-18 14:50:42 +0900329}
330
Garrick Evans54861622019-07-19 09:05:09 +0900331TEST(DatapathTest, AddLegacyIPv4InboundDNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900332 MockProcessRunner runner;
333 EXPECT_CALL(runner, iptables(StrEq("nat"),
334 ElementsAre("-A", "try_arc", "-i", "wlan0", "-j",
335 "dnat_arc", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900336 true, nullptr));
Garrick Evans54861622019-07-19 09:05:09 +0900337 Datapath datapath(&runner);
338 datapath.AddLegacyIPv4InboundDNAT("wlan0");
Garrick Evans54861622019-07-19 09:05:09 +0900339}
340
341TEST(DatapathTest, RemoveLegacyIPv4InboundDNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900342 MockProcessRunner runner;
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900343 EXPECT_CALL(runner, iptables(StrEq("nat"), ElementsAre("-F", "try_arc", "-w"),
344 true, nullptr));
Garrick Evans54861622019-07-19 09:05:09 +0900345 Datapath datapath(&runner);
346 datapath.RemoveLegacyIPv4InboundDNAT();
Garrick Evans54861622019-07-19 09:05:09 +0900347}
348
Garrick Evansf0ab7132019-06-18 14:50:42 +0900349TEST(DatapathTest, AddInboundIPv4DNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900350 MockProcessRunner runner;
351 EXPECT_CALL(runner, iptables(StrEq("nat"),
352 ElementsAre("-A", "PREROUTING", "-i", "eth0",
353 "-m", "socket", "--nowildcard", "-j",
354 "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900355 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900356 EXPECT_CALL(runner, iptables(StrEq("nat"),
357 ElementsAre("-A", "PREROUTING", "-i", "eth0",
358 "-p", "tcp", "-j", "DNAT",
359 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900360 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900361 EXPECT_CALL(runner, iptables(StrEq("nat"),
362 ElementsAre("-A", "PREROUTING", "-i", "eth0",
363 "-p", "udp", "-j", "DNAT",
364 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900365 true, nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900366 Datapath datapath(&runner);
367 datapath.AddInboundIPv4DNAT("eth0", "1.2.3.4");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900368}
369
370TEST(DatapathTest, RemoveInboundIPv4DNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900371 MockProcessRunner runner;
372 EXPECT_CALL(runner, iptables(StrEq("nat"),
373 ElementsAre("-D", "PREROUTING", "-i", "eth0",
374 "-m", "socket", "--nowildcard", "-j",
375 "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900376 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900377 EXPECT_CALL(runner, iptables(StrEq("nat"),
378 ElementsAre("-D", "PREROUTING", "-i", "eth0",
379 "-p", "tcp", "-j", "DNAT",
380 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900381 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900382 EXPECT_CALL(runner, iptables(StrEq("nat"),
383 ElementsAre("-D", "PREROUTING", "-i", "eth0",
384 "-p", "udp", "-j", "DNAT",
385 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900386 true, nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900387 Datapath datapath(&runner);
388 datapath.RemoveInboundIPv4DNAT("eth0", "1.2.3.4");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900389}
390
391TEST(DatapathTest, AddOutboundIPv4) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900392 MockProcessRunner runner;
393 EXPECT_CALL(runner, iptables(StrEq("filter"),
394 ElementsAre("-A", "FORWARD", "-o", "eth0", "-j",
395 "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900396 true, nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900397 Datapath datapath(&runner);
398 datapath.AddOutboundIPv4("eth0");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900399}
400
401TEST(DatapathTest, RemoveInboundIPv4) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900402 MockProcessRunner runner;
403 EXPECT_CALL(runner, iptables(StrEq("filter"),
404 ElementsAre("-D", "FORWARD", "-o", "eth0", "-j",
405 "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900406 true, nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900407 Datapath datapath(&runner);
408 datapath.RemoveOutboundIPv4("eth0");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900409}
410
Garrick Evans664a82f2019-12-17 12:18:05 +0900411TEST(DatapathTest, MaskInterfaceFlags) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900412 MockProcessRunner runner;
Taoyu Li90c13912019-11-26 17:56:54 +0900413 Datapath datapath(&runner, ioctl_req_cap);
Garrick Evans664a82f2019-12-17 12:18:05 +0900414 bool result = datapath.MaskInterfaceFlags("foo0", IFF_DEBUG);
Taoyu Li90c13912019-11-26 17:56:54 +0900415 EXPECT_TRUE(result);
Hugo Benichie8758b52020-04-03 14:49:01 +0900416 std::vector<ioctl_req_t> expected = {SIOCGIFFLAGS, SIOCSIFFLAGS};
Taoyu Li90c13912019-11-26 17:56:54 +0900417 EXPECT_EQ(ioctl_reqs, expected);
418 ioctl_reqs.clear();
419}
420
421TEST(DatapathTest, AddIPv6Forwarding) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900422 MockProcessRunner runner;
Taoyu Lica49c832019-12-06 17:56:43 +0900423 // Return 1 on iptables -C to simulate rule not existing case
Garrick Evans8e8e3472020-01-23 14:03:50 +0900424 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
425 ElementsAre("-C", "FORWARD", "-i", "eth0", "-o",
426 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900427 false, nullptr))
Garrick Evans8e8e3472020-01-23 14:03:50 +0900428 .WillOnce(Return(1));
429 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
430 ElementsAre("-A", "FORWARD", "-i", "eth0", "-o",
431 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900432 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900433 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
434 ElementsAre("-C", "FORWARD", "-i", "arc_eth0",
435 "-o", "eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900436 false, nullptr))
Garrick Evans8e8e3472020-01-23 14:03:50 +0900437 .WillOnce(Return(1));
438 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
439 ElementsAre("-A", "FORWARD", "-i", "arc_eth0",
440 "-o", "eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900441 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900442 Datapath datapath(&runner);
Taoyu Li90c13912019-11-26 17:56:54 +0900443 datapath.AddIPv6Forwarding("eth0", "arc_eth0");
Taoyu Li90c13912019-11-26 17:56:54 +0900444}
445
Taoyu Lica49c832019-12-06 17:56:43 +0900446TEST(DatapathTest, AddIPv6ForwardingRuleExists) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900447 MockProcessRunner runner;
448 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
449 ElementsAre("-C", "FORWARD", "-i", "eth0", "-o",
450 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900451 false, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900452 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
453 ElementsAre("-C", "FORWARD", "-i", "arc_eth0",
454 "-o", "eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900455 false, nullptr));
Taoyu Lica49c832019-12-06 17:56:43 +0900456 Datapath datapath(&runner);
457 datapath.AddIPv6Forwarding("eth0", "arc_eth0");
Taoyu Lica49c832019-12-06 17:56:43 +0900458}
459
Taoyu Li90c13912019-11-26 17:56:54 +0900460TEST(DatapathTest, RemoveIPv6Forwarding) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900461 MockProcessRunner runner;
462 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
463 ElementsAre("-D", "FORWARD", "-i", "eth0", "-o",
464 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900465 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900466 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
467 ElementsAre("-D", "FORWARD", "-i", "arc_eth0",
468 "-o", "eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900469 true, nullptr));
Taoyu Li90c13912019-11-26 17:56:54 +0900470 Datapath datapath(&runner);
471 datapath.RemoveIPv6Forwarding("eth0", "arc_eth0");
Taoyu Li90c13912019-11-26 17:56:54 +0900472}
473
Taoyu Lieb6cc8f2019-12-09 15:53:04 +0900474TEST(DatapathTest, AddIPv6HostRoute) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900475 MockProcessRunner runner;
476 EXPECT_CALL(runner,
477 ip6(StrEq("route"), StrEq("replace"),
478 ElementsAre("2001:da8:e00::1234/128", "dev", "eth0"), true));
Taoyu Lieb6cc8f2019-12-09 15:53:04 +0900479 Datapath datapath(&runner);
480 datapath.AddIPv6HostRoute("eth0", "2001:da8:e00::1234", 128);
Taoyu Lieb6cc8f2019-12-09 15:53:04 +0900481}
482
Hugo Benichie8758b52020-04-03 14:49:01 +0900483TEST(DatapathTest, AddIPv4Route) {
484 MockProcessRunner runner;
485 Datapath datapath(&runner, (ioctl_t)ioctl_rtentry_cap);
486
487 datapath.AddIPv4Route(Ipv4Addr(192, 168, 1, 1), Ipv4Addr(100, 115, 93, 0),
488 Ipv4Addr(255, 255, 255, 0));
489 datapath.DeleteIPv4Route(Ipv4Addr(192, 168, 1, 1), Ipv4Addr(100, 115, 93, 0),
490 Ipv4Addr(255, 255, 255, 0));
491 datapath.AddIPv4Route("eth0", Ipv4Addr(100, 115, 92, 8),
492 Ipv4Addr(255, 255, 255, 252));
493 datapath.DeleteIPv4Route("eth0", Ipv4Addr(100, 115, 92, 8),
494 Ipv4Addr(255, 255, 255, 252));
495
496 std::vector<ioctl_req_t> expected_reqs = {SIOCADDRT, SIOCDELRT, SIOCADDRT,
497 SIOCDELRT};
498 EXPECT_EQ(expected_reqs, ioctl_reqs);
499 ioctl_reqs.clear();
500
501 std::string route1 =
502 "{rt_dst: {family: AF_INET, port: 0, addr: 100.115.93.0}, rt_genmask: "
503 "{family: AF_INET, port: 0, addr: 255.255.255.0}, rt_gateway: {family: "
504 "AF_INET, port: 0, addr: 192.168.1.1}, rt_dev: null, rt_flags: RTF_UP | "
505 "RTF_GATEWAY}";
506 std::string route2 =
507 "{rt_dst: {family: AF_INET, port: 0, addr: 100.115.92.8}, rt_genmask: "
508 "{family: AF_INET, port: 0, addr: 255.255.255.252}, rt_gateway: {unset}, "
509 "rt_dev: eth0, rt_flags: RTF_UP | RTF_GATEWAY}";
510 std::vector<std::string> captured_routes;
511 for (const auto& route : ioctl_rtentry_args) {
512 std::ostringstream stream;
513 stream << route.second;
514 captured_routes.emplace_back(stream.str());
515 }
516 ioctl_rtentry_args.clear();
517 EXPECT_EQ(route1, captured_routes[0]);
518 EXPECT_EQ(route1, captured_routes[1]);
519 EXPECT_EQ(route2, captured_routes[2]);
520 EXPECT_EQ(route2, captured_routes[3]);
521}
522
Garrick Evansd291af62020-05-25 10:39:06 +0900523TEST(DatapathTest, AddSNATMarkRules) {
524 MockProcessRunner runner;
Taoyu Li79871c92020-07-02 16:09:39 +0900525 EXPECT_CALL(
526 runner,
527 iptables(StrEq("filter"),
528 ElementsAre("-A", "FORWARD", "-m", "mark", "--mark", "1", "-m",
529 "state", "--state", "INVALID", "-j", "DROP", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900530 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900531 EXPECT_CALL(runner, iptables(StrEq("filter"),
532 ElementsAre("-A", "FORWARD", "-m", "mark",
533 "--mark", "1", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900534 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900535 EXPECT_CALL(runner,
536 iptables(StrEq("nat"),
537 ElementsAre("-A", "POSTROUTING", "-m", "mark", "--mark",
538 "1", "-j", "MASQUERADE", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900539 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900540 Datapath datapath(&runner);
541 datapath.AddSNATMarkRules();
542}
543
544TEST(DatapathTest, RemoveSNATMarkRules) {
545 MockProcessRunner runner;
Taoyu Li79871c92020-07-02 16:09:39 +0900546 EXPECT_CALL(
547 runner,
548 iptables(StrEq("filter"),
549 ElementsAre("-D", "FORWARD", "-m", "mark", "--mark", "1", "-m",
550 "state", "--state", "INVALID", "-j", "DROP", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900551 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900552 EXPECT_CALL(runner, iptables(StrEq("filter"),
553 ElementsAre("-D", "FORWARD", "-m", "mark",
554 "--mark", "1", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900555 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900556 EXPECT_CALL(runner,
557 iptables(StrEq("nat"),
558 ElementsAre("-D", "POSTROUTING", "-m", "mark", "--mark",
559 "1", "-j", "MASQUERADE", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900560 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900561 Datapath datapath(&runner);
562 datapath.RemoveSNATMarkRules();
563}
564
565TEST(DatapathTest, AddForwardEstablishedRule) {
566 MockProcessRunner runner;
567 EXPECT_CALL(runner,
568 iptables(StrEq("filter"),
569 ElementsAre("-A", "FORWARD", "-m", "state", "--state",
570 "ESTABLISHED,RELATED", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900571 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900572 Datapath datapath(&runner);
573 datapath.AddForwardEstablishedRule();
574}
575
576TEST(DatapathTest, RemoveForwardEstablishedRule) {
577 MockProcessRunner runner;
578 EXPECT_CALL(runner,
579 iptables(StrEq("filter"),
580 ElementsAre("-D", "FORWARD", "-m", "state", "--state",
581 "ESTABLISHED,RELATED", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900582 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900583 Datapath datapath(&runner);
584 datapath.RemoveForwardEstablishedRule();
585}
586
Garrick Evansff6e37f2020-05-25 10:54:47 +0900587TEST(DatapathTest, AddInterfaceSNAT) {
588 MockProcessRunner runner;
589 EXPECT_CALL(runner, iptables(StrEq("nat"),
590 ElementsAre("-A", "POSTROUTING", "-o", "wwan+",
591 "-j", "MASQUERADE", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900592 true, nullptr));
Garrick Evansff6e37f2020-05-25 10:54:47 +0900593 Datapath datapath(&runner);
594 datapath.AddInterfaceSNAT("wwan+");
595}
596
597TEST(DatapathTest, RemoveInterfaceSNAT) {
598 MockProcessRunner runner;
599 EXPECT_CALL(runner, iptables(StrEq("nat"),
600 ElementsAre("-D", "POSTROUTING", "-o", "wwan+",
601 "-j", "MASQUERADE", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900602 true, nullptr));
Garrick Evansff6e37f2020-05-25 10:54:47 +0900603 Datapath datapath(&runner);
604 datapath.RemoveInterfaceSNAT("wwan+");
605}
606
Garrick Evans2f581a02020-05-11 10:43:35 +0900607TEST(DatapathTest, ArcVethHostName) {
608 EXPECT_EQ("vetheth0", ArcVethHostName("eth0"));
609 EXPECT_EQ("vethrmnet0", ArcVethHostName("rmnet0"));
610 EXPECT_EQ("vethrmnet_data0", ArcVethHostName("rmnet_data0"));
611 EXPECT_EQ("vethifnamsiz_i0", ArcVethHostName("ifnamsiz_ifnam0"));
612 auto ifname = ArcVethHostName("exceeds_ifnamesiz_checkanyway");
613 EXPECT_EQ("vethexceeds_ify", ifname);
614 EXPECT_LT(ifname.length(), IFNAMSIZ);
615}
616
Garrick Evans8a067562020-05-11 12:47:30 +0900617TEST(DatapathTest, ArcBridgeName) {
618 EXPECT_EQ("arc_eth0", ArcBridgeName("eth0"));
619 EXPECT_EQ("arc_rmnet0", ArcBridgeName("rmnet0"));
620 EXPECT_EQ("arc_rmnet_data0", ArcBridgeName("rmnet_data0"));
621 EXPECT_EQ("arc_ifnamsiz_i0", ArcBridgeName("ifnamsiz_ifnam0"));
622 auto ifname = ArcBridgeName("exceeds_ifnamesiz_checkanyway");
623 EXPECT_EQ("arc_exceeds_ify", ifname);
624 EXPECT_LT(ifname.length(), IFNAMSIZ);
625}
626
Garrick Evans3388a032020-03-24 11:25:55 +0900627} // namespace patchpanel