blob: b5120115ed5dc4ea671b8a5e519c0c3ae50f11cf [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_METHOD2(RestoreDefaultNamespace,
64 int(const std::string& ifname, pid_t pid));
65 MOCK_METHOD1(WriteSentinelToContainer, int(pid_t pid));
Garrick Evans8e8e3472020-01-23 14:03:50 +090066 MOCK_METHOD3(brctl,
67 int(const std::string& cmd,
68 const std::vector<std::string>& argv,
69 bool log_failures));
70 MOCK_METHOD4(chown,
71 int(const std::string& uid,
72 const std::string& gid,
73 const std::string& file,
74 bool log_failures));
Garrick Evans8e8e3472020-01-23 14:03:50 +090075 MOCK_METHOD4(ip,
76 int(const std::string& obj,
77 const std::string& cmd,
78 const std::vector<std::string>& args,
79 bool log_failures));
80 MOCK_METHOD4(ip6,
81 int(const std::string& obj,
82 const std::string& cmd,
83 const std::vector<std::string>& args,
84 bool log_failures));
Jie Jiangcf5ce9c2020-07-14 17:22:03 +090085 MOCK_METHOD4(iptables,
Garrick Evans8e8e3472020-01-23 14:03:50 +090086 int(const std::string& table,
87 const std::vector<std::string>& argv,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +090088 bool log_failures,
89 std::string* output));
90 MOCK_METHOD4(ip6tables,
Garrick Evans8e8e3472020-01-23 14:03:50 +090091 int(const std::string& table,
92 const std::vector<std::string>& argv,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +090093 bool log_failures,
94 std::string* output));
Garrick Evans8e8e3472020-01-23 14:03:50 +090095 MOCK_METHOD2(modprobe_all,
96 int(const std::vector<std::string>& modules, bool log_failures));
97 MOCK_METHOD3(sysctl_w,
98 int(const std::string& key,
99 const std::string& value,
100 bool log_failures));
101};
102
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900103TEST(DatapathTest, AddTAP) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900104 MockProcessRunner runner;
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900105 Datapath datapath(&runner, ioctl_req_cap);
106 MacAddress mac = {1, 2, 3, 4, 5, 6};
Qijiang Fane90b8792020-03-09 16:15:41 +0900107 Subnet subnet(Ipv4Addr(100, 115, 92, 4), 30, base::DoNothing());
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900108 auto addr = subnet.AllocateAtOffset(0);
Garrick Evans4f9f5572019-11-26 10:25:16 +0900109 auto ifname = datapath.AddTAP("foo0", &mac, addr.get(), "");
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900110 EXPECT_EQ(ifname, "foo0");
Hugo Benichie8758b52020-04-03 14:49:01 +0900111 std::vector<ioctl_req_t> expected = {
112 TUNSETIFF, TUNSETPERSIST, SIOCSIFADDR, SIOCSIFNETMASK,
113 SIOCSIFHWADDR, SIOCGIFFLAGS, SIOCSIFFLAGS};
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900114 EXPECT_EQ(ioctl_reqs, expected);
115 ioctl_reqs.clear();
116}
117
118TEST(DatapathTest, AddTAPWithOwner) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900119 MockProcessRunner runner;
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900120 Datapath datapath(&runner, ioctl_req_cap);
121 MacAddress mac = {1, 2, 3, 4, 5, 6};
Qijiang Fane90b8792020-03-09 16:15:41 +0900122 Subnet subnet(Ipv4Addr(100, 115, 92, 4), 30, base::DoNothing());
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900123 auto addr = subnet.AllocateAtOffset(0);
Garrick Evans4f9f5572019-11-26 10:25:16 +0900124 auto ifname = datapath.AddTAP("foo0", &mac, addr.get(), "root");
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900125 EXPECT_EQ(ifname, "foo0");
Hugo Benichie8758b52020-04-03 14:49:01 +0900126 std::vector<ioctl_req_t> expected = {
127 TUNSETIFF, TUNSETPERSIST, TUNSETOWNER, SIOCSIFADDR,
128 SIOCSIFNETMASK, SIOCSIFHWADDR, SIOCGIFFLAGS, SIOCSIFFLAGS};
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900129 EXPECT_EQ(ioctl_reqs, expected);
130 ioctl_reqs.clear();
131}
132
Garrick Evans621ed262019-11-13 12:28:43 +0900133TEST(DatapathTest, AddTAPNoAddrs) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900134 MockProcessRunner runner;
Garrick Evans621ed262019-11-13 12:28:43 +0900135 Datapath datapath(&runner, ioctl_req_cap);
Garrick Evans4f9f5572019-11-26 10:25:16 +0900136 auto ifname = datapath.AddTAP("foo0", nullptr, nullptr, "");
Garrick Evans621ed262019-11-13 12:28:43 +0900137 EXPECT_EQ(ifname, "foo0");
Hugo Benichie8758b52020-04-03 14:49:01 +0900138 std::vector<ioctl_req_t> expected = {TUNSETIFF, TUNSETPERSIST, SIOCGIFFLAGS,
139 SIOCSIFFLAGS};
Garrick Evans621ed262019-11-13 12:28:43 +0900140 EXPECT_EQ(ioctl_reqs, expected);
141 ioctl_reqs.clear();
142}
143
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900144TEST(DatapathTest, RemoveTAP) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900145 MockProcessRunner runner;
146 EXPECT_CALL(runner, ip(StrEq("tuntap"), StrEq("del"),
147 ElementsAre("foo0", "mode", "tap"), true));
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900148 Datapath datapath(&runner);
149 datapath.RemoveTAP("foo0");
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900150}
Garrick Evansf0ab7132019-06-18 14:50:42 +0900151
Garrick Evans8a949dc2019-07-18 16:17:53 +0900152TEST(DatapathTest, AddBridge) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900153 MockProcessRunner runner;
Garrick Evans8a949dc2019-07-18 16:17:53 +0900154 Datapath datapath(&runner);
Garrick Evans8e8e3472020-01-23 14:03:50 +0900155 EXPECT_CALL(runner, brctl(StrEq("addbr"), ElementsAre("br"), true));
Garrick Evans6f4fa3a2020-02-10 16:15:09 +0900156 EXPECT_CALL(
157 runner,
158 ip(StrEq("addr"), StrEq("add"),
159 ElementsAre("1.1.1.1/30", "brd", "1.1.1.3", "dev", "br"), true));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900160 EXPECT_CALL(runner,
161 ip(StrEq("link"), StrEq("set"), ElementsAre("br", "up"), true));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900162 EXPECT_CALL(runner, iptables(StrEq("mangle"),
163 ElementsAre("-A", "PREROUTING", "-i", "br", "-j",
164 "MARK", "--set-mark", "1", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900165 true, nullptr));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900166 datapath.AddBridge("br", Ipv4Addr(1, 1, 1, 1), 30);
Garrick Evans8a949dc2019-07-18 16:17:53 +0900167}
168
Hugo Benichi76675592020-04-08 14:29:57 +0900169TEST(DatapathTest, ConnectVethPair) {
170 MockProcessRunner runner;
171 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("add"),
172 ElementsAre("veth_foo", "type", "veth", "peer", "name",
173 "peer_foo"),
174 true));
175 EXPECT_CALL(runner, ip(StrEq("addr"), StrEq("add"),
176 ElementsAre("100.115.92.169/30", "brd",
177 "100.115.92.171", "dev", "peer_foo"),
178 true))
179 .WillOnce(Return(0));
180 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
181 ElementsAre("dev", "peer_foo", "up", "addr",
182 "01:02:03:04:05:06", "multicast", "on"),
183 true))
184 .WillOnce(Return(0));
185 EXPECT_CALL(runner, RestoreDefaultNamespace(StrEq("veth_foo"), kTestPID));
186 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
187 ElementsAre("veth_foo", "up"), true));
188 Datapath datapath(&runner);
189 EXPECT_TRUE(datapath.ConnectVethPair(kTestPID, "veth_foo", "peer_foo",
190 {1, 2, 3, 4, 5, 6},
191 Ipv4Addr(100, 115, 92, 169), 30, true));
192}
193
Garrick Evans2470caa2020-03-04 14:15:41 +0900194TEST(DatapathTest, AddVirtualInterfacePair) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900195 MockProcessRunner runner;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900196 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("add"),
197 ElementsAre("veth_foo", "type", "veth", "peer", "name",
198 "peer_foo"),
199 true));
Garrick Evans2470caa2020-03-04 14:15:41 +0900200 Datapath datapath(&runner);
201 EXPECT_TRUE(datapath.AddVirtualInterfacePair("veth_foo", "peer_foo"));
202}
203
204TEST(DatapathTest, ToggleInterface) {
205 MockProcessRunner runner;
206 EXPECT_CALL(runner,
207 ip(StrEq("link"), StrEq("set"), ElementsAre("foo", "up"), true));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900208 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
Garrick Evans2470caa2020-03-04 14:15:41 +0900209 ElementsAre("bar", "down"), true));
210 Datapath datapath(&runner);
211 EXPECT_TRUE(datapath.ToggleInterface("foo", true));
212 EXPECT_TRUE(datapath.ToggleInterface("bar", false));
213}
214
215TEST(DatapathTest, ConfigureInterface) {
216 MockProcessRunner runner;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900217 EXPECT_CALL(
218 runner,
Garrick Evans2470caa2020-03-04 14:15:41 +0900219 ip(StrEq("addr"), StrEq("add"),
220 ElementsAre("1.1.1.1/30", "brd", "1.1.1.3", "dev", "foo"), true))
221 .WillOnce(Return(0));
222 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
223 ElementsAre("dev", "foo", "up", "addr",
224 "02:02:02:02:02:02", "multicast", "on"),
225 true))
226 .WillOnce(Return(0));
227
Garrick Evans54861622019-07-19 09:05:09 +0900228 Datapath datapath(&runner);
Garrick Evans2470caa2020-03-04 14:15:41 +0900229 MacAddress mac_addr = {2, 2, 2, 2, 2, 2};
230 EXPECT_TRUE(datapath.ConfigureInterface("foo", mac_addr, Ipv4Addr(1, 1, 1, 1),
231 30, true, true));
Garrick Evans54861622019-07-19 09:05:09 +0900232}
233
234TEST(DatapathTest, RemoveInterface) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900235 MockProcessRunner runner;
236 EXPECT_CALL(runner,
237 ip(StrEq("link"), StrEq("delete"), ElementsAre("foo"), false));
Garrick Evans54861622019-07-19 09:05:09 +0900238 Datapath datapath(&runner);
239 datapath.RemoveInterface("foo");
Garrick Evans54861622019-07-19 09:05:09 +0900240}
241
Garrick Evans8a949dc2019-07-18 16:17:53 +0900242TEST(DatapathTest, RemoveBridge) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900243 MockProcessRunner runner;
244 EXPECT_CALL(runner, iptables(StrEq("mangle"),
245 ElementsAre("-D", "PREROUTING", "-i", "br", "-j",
246 "MARK", "--set-mark", "1", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900247 true, nullptr));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900248 EXPECT_CALL(runner,
249 ip(StrEq("link"), StrEq("set"), ElementsAre("br", "down"), true));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900250 EXPECT_CALL(runner, brctl(StrEq("delbr"), ElementsAre("br"), true));
Garrick Evans8a949dc2019-07-18 16:17:53 +0900251 Datapath datapath(&runner);
252 datapath.RemoveBridge("br");
Garrick Evans8a949dc2019-07-18 16:17:53 +0900253}
254
Garrick Evansf0ab7132019-06-18 14:50:42 +0900255TEST(DatapathTest, AddLegacyIPv4DNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900256 MockProcessRunner runner;
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900257 EXPECT_CALL(runner,
258 iptables(StrEq("nat"), ElementsAre("-N", "dnat_arc", "-w"), true,
259 nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900260 EXPECT_CALL(runner, iptables(StrEq("nat"),
261 ElementsAre("-A", "dnat_arc", "-j", "DNAT",
262 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900263 true, nullptr));
264 EXPECT_CALL(runner, iptables(StrEq("nat"), ElementsAre("-N", "try_arc", "-w"),
265 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900266 EXPECT_CALL(runner,
267 iptables(StrEq("nat"),
268 ElementsAre("-A", "PREROUTING", "-m", "socket",
269 "--nowildcard", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900270 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900271 EXPECT_CALL(runner, iptables(StrEq("nat"),
272 ElementsAre("-A", "PREROUTING", "-p", "tcp",
273 "-j", "try_arc", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900274 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900275 EXPECT_CALL(runner, iptables(StrEq("nat"),
276 ElementsAre("-A", "PREROUTING", "-p", "udp",
277 "-j", "try_arc", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900278 true, nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900279 Datapath datapath(&runner);
280 datapath.AddLegacyIPv4DNAT("1.2.3.4");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900281}
282
283TEST(DatapathTest, RemoveLegacyIPv4DNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900284 MockProcessRunner runner;
285 EXPECT_CALL(runner, iptables(StrEq("nat"),
286 ElementsAre("-D", "PREROUTING", "-p", "udp",
287 "-j", "try_arc", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900288 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900289 EXPECT_CALL(runner, iptables(StrEq("nat"),
290 ElementsAre("-D", "PREROUTING", "-p", "tcp",
291 "-j", "try_arc", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900292 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900293 EXPECT_CALL(runner,
294 iptables(StrEq("nat"),
295 ElementsAre("-D", "PREROUTING", "-m", "socket",
296 "--nowildcard", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900297 true, nullptr));
298 EXPECT_CALL(runner, iptables(StrEq("nat"), ElementsAre("-F", "try_arc", "-w"),
299 true, nullptr));
300 EXPECT_CALL(runner, iptables(StrEq("nat"), ElementsAre("-X", "try_arc", "-w"),
301 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900302 EXPECT_CALL(runner,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900303 iptables(StrEq("nat"), ElementsAre("-F", "dnat_arc", "-w"), true,
304 nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900305 EXPECT_CALL(runner,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900306 iptables(StrEq("nat"), ElementsAre("-X", "dnat_arc", "-w"), true,
307 nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900308 Datapath datapath(&runner);
309 datapath.RemoveLegacyIPv4DNAT();
Garrick Evansf0ab7132019-06-18 14:50:42 +0900310}
311
Garrick Evans54861622019-07-19 09:05:09 +0900312TEST(DatapathTest, AddLegacyIPv4InboundDNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900313 MockProcessRunner runner;
314 EXPECT_CALL(runner, iptables(StrEq("nat"),
315 ElementsAre("-A", "try_arc", "-i", "wlan0", "-j",
316 "dnat_arc", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900317 true, nullptr));
Garrick Evans54861622019-07-19 09:05:09 +0900318 Datapath datapath(&runner);
319 datapath.AddLegacyIPv4InboundDNAT("wlan0");
Garrick Evans54861622019-07-19 09:05:09 +0900320}
321
322TEST(DatapathTest, RemoveLegacyIPv4InboundDNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900323 MockProcessRunner runner;
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900324 EXPECT_CALL(runner, iptables(StrEq("nat"), ElementsAre("-F", "try_arc", "-w"),
325 true, nullptr));
Garrick Evans54861622019-07-19 09:05:09 +0900326 Datapath datapath(&runner);
327 datapath.RemoveLegacyIPv4InboundDNAT();
Garrick Evans54861622019-07-19 09:05:09 +0900328}
329
Garrick Evansf0ab7132019-06-18 14:50:42 +0900330TEST(DatapathTest, AddInboundIPv4DNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900331 MockProcessRunner runner;
332 EXPECT_CALL(runner, iptables(StrEq("nat"),
333 ElementsAre("-A", "PREROUTING", "-i", "eth0",
334 "-m", "socket", "--nowildcard", "-j",
335 "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900336 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900337 EXPECT_CALL(runner, iptables(StrEq("nat"),
338 ElementsAre("-A", "PREROUTING", "-i", "eth0",
339 "-p", "tcp", "-j", "DNAT",
340 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900341 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900342 EXPECT_CALL(runner, iptables(StrEq("nat"),
343 ElementsAre("-A", "PREROUTING", "-i", "eth0",
344 "-p", "udp", "-j", "DNAT",
345 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900346 true, nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900347 Datapath datapath(&runner);
348 datapath.AddInboundIPv4DNAT("eth0", "1.2.3.4");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900349}
350
351TEST(DatapathTest, RemoveInboundIPv4DNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900352 MockProcessRunner runner;
353 EXPECT_CALL(runner, iptables(StrEq("nat"),
354 ElementsAre("-D", "PREROUTING", "-i", "eth0",
355 "-m", "socket", "--nowildcard", "-j",
356 "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900357 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900358 EXPECT_CALL(runner, iptables(StrEq("nat"),
359 ElementsAre("-D", "PREROUTING", "-i", "eth0",
360 "-p", "tcp", "-j", "DNAT",
361 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900362 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900363 EXPECT_CALL(runner, iptables(StrEq("nat"),
364 ElementsAre("-D", "PREROUTING", "-i", "eth0",
365 "-p", "udp", "-j", "DNAT",
366 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900367 true, nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900368 Datapath datapath(&runner);
369 datapath.RemoveInboundIPv4DNAT("eth0", "1.2.3.4");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900370}
371
372TEST(DatapathTest, AddOutboundIPv4) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900373 MockProcessRunner runner;
374 EXPECT_CALL(runner, iptables(StrEq("filter"),
375 ElementsAre("-A", "FORWARD", "-o", "eth0", "-j",
376 "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900377 true, nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900378 Datapath datapath(&runner);
379 datapath.AddOutboundIPv4("eth0");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900380}
381
382TEST(DatapathTest, RemoveInboundIPv4) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900383 MockProcessRunner runner;
384 EXPECT_CALL(runner, iptables(StrEq("filter"),
385 ElementsAre("-D", "FORWARD", "-o", "eth0", "-j",
386 "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900387 true, nullptr));
Garrick Evansf0ab7132019-06-18 14:50:42 +0900388 Datapath datapath(&runner);
389 datapath.RemoveOutboundIPv4("eth0");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900390}
391
Garrick Evans664a82f2019-12-17 12:18:05 +0900392TEST(DatapathTest, MaskInterfaceFlags) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900393 MockProcessRunner runner;
Taoyu Li90c13912019-11-26 17:56:54 +0900394 Datapath datapath(&runner, ioctl_req_cap);
Garrick Evans664a82f2019-12-17 12:18:05 +0900395 bool result = datapath.MaskInterfaceFlags("foo0", IFF_DEBUG);
Taoyu Li90c13912019-11-26 17:56:54 +0900396 EXPECT_TRUE(result);
Hugo Benichie8758b52020-04-03 14:49:01 +0900397 std::vector<ioctl_req_t> expected = {SIOCGIFFLAGS, SIOCSIFFLAGS};
Taoyu Li90c13912019-11-26 17:56:54 +0900398 EXPECT_EQ(ioctl_reqs, expected);
399 ioctl_reqs.clear();
400}
401
402TEST(DatapathTest, AddIPv6Forwarding) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900403 MockProcessRunner runner;
Taoyu Lica49c832019-12-06 17:56:43 +0900404 // Return 1 on iptables -C to simulate rule not existing case
Garrick Evans8e8e3472020-01-23 14:03:50 +0900405 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
406 ElementsAre("-C", "FORWARD", "-i", "eth0", "-o",
407 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900408 false, nullptr))
Garrick Evans8e8e3472020-01-23 14:03:50 +0900409 .WillOnce(Return(1));
410 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
411 ElementsAre("-A", "FORWARD", "-i", "eth0", "-o",
412 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900413 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900414 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
415 ElementsAre("-C", "FORWARD", "-i", "arc_eth0",
416 "-o", "eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900417 false, nullptr))
Garrick Evans8e8e3472020-01-23 14:03:50 +0900418 .WillOnce(Return(1));
419 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
420 ElementsAre("-A", "FORWARD", "-i", "arc_eth0",
421 "-o", "eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900422 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900423 Datapath datapath(&runner);
Taoyu Li90c13912019-11-26 17:56:54 +0900424 datapath.AddIPv6Forwarding("eth0", "arc_eth0");
Taoyu Li90c13912019-11-26 17:56:54 +0900425}
426
Taoyu Lica49c832019-12-06 17:56:43 +0900427TEST(DatapathTest, AddIPv6ForwardingRuleExists) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900428 MockProcessRunner runner;
429 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
430 ElementsAre("-C", "FORWARD", "-i", "eth0", "-o",
431 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900432 false, 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));
Taoyu Lica49c832019-12-06 17:56:43 +0900437 Datapath datapath(&runner);
438 datapath.AddIPv6Forwarding("eth0", "arc_eth0");
Taoyu Lica49c832019-12-06 17:56:43 +0900439}
440
Taoyu Li90c13912019-11-26 17:56:54 +0900441TEST(DatapathTest, RemoveIPv6Forwarding) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900442 MockProcessRunner runner;
443 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
444 ElementsAre("-D", "FORWARD", "-i", "eth0", "-o",
445 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900446 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900447 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
448 ElementsAre("-D", "FORWARD", "-i", "arc_eth0",
449 "-o", "eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900450 true, nullptr));
Taoyu Li90c13912019-11-26 17:56:54 +0900451 Datapath datapath(&runner);
452 datapath.RemoveIPv6Forwarding("eth0", "arc_eth0");
Taoyu Li90c13912019-11-26 17:56:54 +0900453}
454
Taoyu Lieb6cc8f2019-12-09 15:53:04 +0900455TEST(DatapathTest, AddIPv6HostRoute) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900456 MockProcessRunner runner;
457 EXPECT_CALL(runner,
458 ip6(StrEq("route"), StrEq("replace"),
459 ElementsAre("2001:da8:e00::1234/128", "dev", "eth0"), true));
Taoyu Lieb6cc8f2019-12-09 15:53:04 +0900460 Datapath datapath(&runner);
461 datapath.AddIPv6HostRoute("eth0", "2001:da8:e00::1234", 128);
Taoyu Lieb6cc8f2019-12-09 15:53:04 +0900462}
463
Hugo Benichie8758b52020-04-03 14:49:01 +0900464TEST(DatapathTest, AddIPv4Route) {
465 MockProcessRunner runner;
466 Datapath datapath(&runner, (ioctl_t)ioctl_rtentry_cap);
467
468 datapath.AddIPv4Route(Ipv4Addr(192, 168, 1, 1), Ipv4Addr(100, 115, 93, 0),
469 Ipv4Addr(255, 255, 255, 0));
470 datapath.DeleteIPv4Route(Ipv4Addr(192, 168, 1, 1), Ipv4Addr(100, 115, 93, 0),
471 Ipv4Addr(255, 255, 255, 0));
472 datapath.AddIPv4Route("eth0", Ipv4Addr(100, 115, 92, 8),
473 Ipv4Addr(255, 255, 255, 252));
474 datapath.DeleteIPv4Route("eth0", Ipv4Addr(100, 115, 92, 8),
475 Ipv4Addr(255, 255, 255, 252));
476
477 std::vector<ioctl_req_t> expected_reqs = {SIOCADDRT, SIOCDELRT, SIOCADDRT,
478 SIOCDELRT};
479 EXPECT_EQ(expected_reqs, ioctl_reqs);
480 ioctl_reqs.clear();
481
482 std::string route1 =
483 "{rt_dst: {family: AF_INET, port: 0, addr: 100.115.93.0}, rt_genmask: "
484 "{family: AF_INET, port: 0, addr: 255.255.255.0}, rt_gateway: {family: "
485 "AF_INET, port: 0, addr: 192.168.1.1}, rt_dev: null, rt_flags: RTF_UP | "
486 "RTF_GATEWAY}";
487 std::string route2 =
488 "{rt_dst: {family: AF_INET, port: 0, addr: 100.115.92.8}, rt_genmask: "
489 "{family: AF_INET, port: 0, addr: 255.255.255.252}, rt_gateway: {unset}, "
490 "rt_dev: eth0, rt_flags: RTF_UP | RTF_GATEWAY}";
491 std::vector<std::string> captured_routes;
492 for (const auto& route : ioctl_rtentry_args) {
493 std::ostringstream stream;
494 stream << route.second;
495 captured_routes.emplace_back(stream.str());
496 }
497 ioctl_rtentry_args.clear();
498 EXPECT_EQ(route1, captured_routes[0]);
499 EXPECT_EQ(route1, captured_routes[1]);
500 EXPECT_EQ(route2, captured_routes[2]);
501 EXPECT_EQ(route2, captured_routes[3]);
502}
503
Garrick Evansd291af62020-05-25 10:39:06 +0900504TEST(DatapathTest, AddSNATMarkRules) {
505 MockProcessRunner runner;
Taoyu Li79871c92020-07-02 16:09:39 +0900506 EXPECT_CALL(
507 runner,
508 iptables(StrEq("filter"),
509 ElementsAre("-A", "FORWARD", "-m", "mark", "--mark", "1", "-m",
510 "state", "--state", "INVALID", "-j", "DROP", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900511 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900512 EXPECT_CALL(runner, iptables(StrEq("filter"),
513 ElementsAre("-A", "FORWARD", "-m", "mark",
514 "--mark", "1", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900515 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900516 EXPECT_CALL(runner,
517 iptables(StrEq("nat"),
518 ElementsAre("-A", "POSTROUTING", "-m", "mark", "--mark",
519 "1", "-j", "MASQUERADE", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900520 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900521 Datapath datapath(&runner);
522 datapath.AddSNATMarkRules();
523}
524
525TEST(DatapathTest, RemoveSNATMarkRules) {
526 MockProcessRunner runner;
Taoyu Li79871c92020-07-02 16:09:39 +0900527 EXPECT_CALL(
528 runner,
529 iptables(StrEq("filter"),
530 ElementsAre("-D", "FORWARD", "-m", "mark", "--mark", "1", "-m",
531 "state", "--state", "INVALID", "-j", "DROP", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900532 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900533 EXPECT_CALL(runner, iptables(StrEq("filter"),
534 ElementsAre("-D", "FORWARD", "-m", "mark",
535 "--mark", "1", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900536 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900537 EXPECT_CALL(runner,
538 iptables(StrEq("nat"),
539 ElementsAre("-D", "POSTROUTING", "-m", "mark", "--mark",
540 "1", "-j", "MASQUERADE", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900541 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900542 Datapath datapath(&runner);
543 datapath.RemoveSNATMarkRules();
544}
545
546TEST(DatapathTest, AddForwardEstablishedRule) {
547 MockProcessRunner runner;
548 EXPECT_CALL(runner,
549 iptables(StrEq("filter"),
550 ElementsAre("-A", "FORWARD", "-m", "state", "--state",
551 "ESTABLISHED,RELATED", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900552 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900553 Datapath datapath(&runner);
554 datapath.AddForwardEstablishedRule();
555}
556
557TEST(DatapathTest, RemoveForwardEstablishedRule) {
558 MockProcessRunner runner;
559 EXPECT_CALL(runner,
560 iptables(StrEq("filter"),
561 ElementsAre("-D", "FORWARD", "-m", "state", "--state",
562 "ESTABLISHED,RELATED", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900563 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +0900564 Datapath datapath(&runner);
565 datapath.RemoveForwardEstablishedRule();
566}
567
Garrick Evansff6e37f2020-05-25 10:54:47 +0900568TEST(DatapathTest, AddInterfaceSNAT) {
569 MockProcessRunner runner;
570 EXPECT_CALL(runner, iptables(StrEq("nat"),
571 ElementsAre("-A", "POSTROUTING", "-o", "wwan+",
572 "-j", "MASQUERADE", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900573 true, nullptr));
Garrick Evansff6e37f2020-05-25 10:54:47 +0900574 Datapath datapath(&runner);
575 datapath.AddInterfaceSNAT("wwan+");
576}
577
578TEST(DatapathTest, RemoveInterfaceSNAT) {
579 MockProcessRunner runner;
580 EXPECT_CALL(runner, iptables(StrEq("nat"),
581 ElementsAre("-D", "POSTROUTING", "-o", "wwan+",
582 "-j", "MASQUERADE", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900583 true, nullptr));
Garrick Evansff6e37f2020-05-25 10:54:47 +0900584 Datapath datapath(&runner);
585 datapath.RemoveInterfaceSNAT("wwan+");
586}
587
Garrick Evans2f581a02020-05-11 10:43:35 +0900588TEST(DatapathTest, ArcVethHostName) {
589 EXPECT_EQ("vetheth0", ArcVethHostName("eth0"));
590 EXPECT_EQ("vethrmnet0", ArcVethHostName("rmnet0"));
591 EXPECT_EQ("vethrmnet_data0", ArcVethHostName("rmnet_data0"));
592 EXPECT_EQ("vethifnamsiz_i0", ArcVethHostName("ifnamsiz_ifnam0"));
593 auto ifname = ArcVethHostName("exceeds_ifnamesiz_checkanyway");
594 EXPECT_EQ("vethexceeds_ify", ifname);
595 EXPECT_LT(ifname.length(), IFNAMSIZ);
596}
597
Garrick Evans8a067562020-05-11 12:47:30 +0900598TEST(DatapathTest, ArcBridgeName) {
599 EXPECT_EQ("arc_eth0", ArcBridgeName("eth0"));
600 EXPECT_EQ("arc_rmnet0", ArcBridgeName("rmnet0"));
601 EXPECT_EQ("arc_rmnet_data0", ArcBridgeName("rmnet_data0"));
602 EXPECT_EQ("arc_ifnamsiz_i0", ArcBridgeName("ifnamsiz_ifnam0"));
603 auto ifname = ArcBridgeName("exceeds_ifnamesiz_checkanyway");
604 EXPECT_EQ("arc_exceeds_ify", ifname);
605 EXPECT_LT(ifname.length(), IFNAMSIZ);
606}
607
Garrick Evans3388a032020-03-24 11:25:55 +0900608} // namespace patchpanel