blob: fe98f8f4396a63d63be269506bbc20523ba9be2a [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
Jason Jeremy Imana7273a32020-08-04 11:25:31 +090020#include "patchpanel/mock_firewall.h"
Garrick Evans3388a032020-03-24 11:25:55 +090021#include "patchpanel/net_util.h"
Garrick Evansf0ab7132019-06-18 14:50:42 +090022
Garrick Evans8e8e3472020-01-23 14:03:50 +090023using testing::_;
24using testing::ElementsAre;
25using testing::Return;
26using testing::StrEq;
27
Garrick Evans3388a032020-03-24 11:25:55 +090028namespace patchpanel {
Garrick Evansc7ae82c2019-09-04 16:25:10 +090029namespace {
30
Hugo Benichi76675592020-04-08 14:29:57 +090031// TODO(hugobenichi) Centralize this constant definition
32constexpr pid_t kTestPID = -2;
33
Hugo Benichie8758b52020-04-03 14:49:01 +090034std::vector<ioctl_req_t> ioctl_reqs;
35std::vector<std::pair<std::string, struct rtentry>> ioctl_rtentry_args;
Garrick Evansc7ae82c2019-09-04 16:25:10 +090036
37// Capture all ioctls and succeed.
Taoyu Li90c13912019-11-26 17:56:54 +090038int ioctl_req_cap(int fd, ioctl_req_t req, ...) {
Hugo Benichie8758b52020-04-03 14:49:01 +090039 ioctl_reqs.push_back(req);
40 return 0;
41}
42
43// Capture ioctls for SIOCADDRT and SIOCDELRT and succeed.
44int ioctl_rtentry_cap(int fd, ioctl_req_t req, struct rtentry* arg) {
45 ioctl_reqs.push_back(req);
46 ioctl_rtentry_args.push_back({"", *arg});
47 // Copy the string poited by rtentry.rt_dev because Add/DeleteIPv4Route pass
48 // this value to ioctl() on the stack.
49 if (arg->rt_dev) {
50 auto& cap = ioctl_rtentry_args.back();
51 cap.first = std::string(arg->rt_dev);
52 cap.second.rt_dev = (char*)cap.first.c_str();
53 }
Garrick Evansc7ae82c2019-09-04 16:25:10 +090054 return 0;
55}
56
57} // namespace
58
Garrick Evans8e8e3472020-01-23 14:03:50 +090059class MockProcessRunner : public MinijailedProcessRunner {
60 public:
61 MockProcessRunner() = default;
62 ~MockProcessRunner() = default;
63
Garrick Evans2470caa2020-03-04 14:15:41 +090064 MOCK_METHOD1(WriteSentinelToContainer, int(pid_t pid));
Garrick Evans8e8e3472020-01-23 14:03:50 +090065 MOCK_METHOD3(brctl,
66 int(const std::string& cmd,
67 const std::vector<std::string>& argv,
68 bool log_failures));
69 MOCK_METHOD4(chown,
70 int(const std::string& uid,
71 const std::string& gid,
72 const std::string& file,
73 bool log_failures));
Garrick Evans8e8e3472020-01-23 14:03:50 +090074 MOCK_METHOD4(ip,
75 int(const std::string& obj,
76 const std::string& cmd,
77 const std::vector<std::string>& args,
78 bool log_failures));
79 MOCK_METHOD4(ip6,
80 int(const std::string& obj,
81 const std::string& cmd,
82 const std::vector<std::string>& args,
83 bool log_failures));
Jie Jiangcf5ce9c2020-07-14 17:22:03 +090084 MOCK_METHOD4(iptables,
Garrick Evans8e8e3472020-01-23 14:03:50 +090085 int(const std::string& table,
86 const std::vector<std::string>& argv,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +090087 bool log_failures,
88 std::string* output));
89 MOCK_METHOD4(ip6tables,
Garrick Evans8e8e3472020-01-23 14:03:50 +090090 int(const std::string& table,
91 const std::vector<std::string>& argv,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +090092 bool log_failures,
93 std::string* output));
Garrick Evans8e8e3472020-01-23 14:03:50 +090094 MOCK_METHOD2(modprobe_all,
95 int(const std::vector<std::string>& modules, bool log_failures));
96 MOCK_METHOD3(sysctl_w,
97 int(const std::string& key,
98 const std::string& value,
99 bool log_failures));
Hugo Benichi33860d72020-07-09 16:34:01 +0900100 MOCK_METHOD3(ip_netns_attach,
101 int(const std::string& netns_name,
102 pid_t netns_pid,
103 bool log_failures));
104 MOCK_METHOD2(ip_netns_delete,
105 int(const std::string& netns_name, bool log_failures));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900106};
107
Hugo Benichid82d8832020-08-14 10:05:03 +0900108TEST(DatapathTest, IpFamily) {
109 EXPECT_EQ(IpFamily::Dual, IpFamily::IPv4 | IpFamily::IPv6);
110 EXPECT_EQ(IpFamily::Dual & IpFamily::IPv4, IpFamily::IPv4);
111 EXPECT_EQ(IpFamily::Dual & IpFamily::IPv6, IpFamily::IPv6);
112 EXPECT_NE(IpFamily::Dual, IpFamily::IPv4);
113 EXPECT_NE(IpFamily::Dual, IpFamily::IPv6);
114 EXPECT_NE(IpFamily::IPv4, IpFamily::IPv6);
115}
116
Hugo Benichibf811c62020-09-07 17:30:45 +0900117TEST(DatapathTest, Start) {
118 MockProcessRunner runner;
119 MockFirewall firewall;
120 // Asserts for sysctl modifications
121 EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv4.ip_forward"), StrEq("1"), true));
122 EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv4.ip_local_port_range"),
123 StrEq("32768 47103"), true));
124 EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv6.conf.all.forwarding"),
125 StrEq("1"), true));
126 // Asserts for AddSNATMarkRules
127 EXPECT_CALL(
128 runner,
129 iptables(StrEq("filter"),
130 ElementsAre("-A", "FORWARD", "-m", "mark", "--mark", "1/1", "-m",
131 "state", "--state", "INVALID", "-j", "DROP", "-w"),
132 true, nullptr));
133 EXPECT_CALL(runner,
134 iptables(StrEq("filter"),
135 ElementsAre("-A", "FORWARD", "-m", "mark", "--mark",
136 "1/1", "-j", "ACCEPT", "-w"),
137 true, nullptr));
138 EXPECT_CALL(runner,
139 iptables(StrEq("nat"),
140 ElementsAre("-A", "POSTROUTING", "-m", "mark", "--mark",
141 "1/1", "-j", "MASQUERADE", "-w"),
142 true, nullptr));
143 // Asserts for AddForwardEstablishedRule
144 EXPECT_CALL(runner,
145 iptables(StrEq("filter"),
146 ElementsAre("-A", "FORWARD", "-m", "state", "--state",
147 "ESTABLISHED,RELATED", "-j", "ACCEPT", "-w"),
148 true, nullptr));
149 // Asserts for AddSourceIPv4DropRule() calls.
150 EXPECT_CALL(runner,
151 iptables(StrEq("filter"),
152 ElementsAre("-I", "OUTPUT", "-o", "eth+", "-s",
153 "100.115.92.0/23", "-j", "DROP", "-w"),
154 true, nullptr));
155 EXPECT_CALL(runner,
156 iptables(StrEq("filter"),
157 ElementsAre("-I", "OUTPUT", "-o", "wlan+", "-s",
158 "100.115.92.0/23", "-j", "DROP", "-w"),
159 true, nullptr));
160 EXPECT_CALL(runner,
161 iptables(StrEq("filter"),
162 ElementsAre("-I", "OUTPUT", "-o", "mlan+", "-s",
163 "100.115.92.0/23", "-j", "DROP", "-w"),
164 true, nullptr));
165 EXPECT_CALL(runner,
166 iptables(StrEq("filter"),
167 ElementsAre("-I", "OUTPUT", "-o", "usb+", "-s",
168 "100.115.92.0/23", "-j", "DROP", "-w"),
169 true, nullptr));
170 EXPECT_CALL(runner,
171 iptables(StrEq("filter"),
172 ElementsAre("-I", "OUTPUT", "-o", "wwan+", "-s",
173 "100.115.92.0/23", "-j", "DROP", "-w"),
174 true, nullptr));
175 EXPECT_CALL(runner,
176 iptables(StrEq("filter"),
177 ElementsAre("-I", "OUTPUT", "-o", "rmnet+", "-s",
178 "100.115.92.0/23", "-j", "DROP", "-w"),
179 true, nullptr));
180 // Asserts for AddOutboundIPv4SNATMark("vmtap+")
181 EXPECT_CALL(runner,
182 iptables(StrEq("mangle"),
183 ElementsAre("-A", "PREROUTING", "-i", "vmtap+", "-j",
184 "MARK", "--set-mark", "1/1", "-w"),
185 true, nullptr));
186
187 Datapath datapath(&runner, &firewall);
188 datapath.Start();
189}
190
191TEST(DatapathTest, Stop) {
192 MockProcessRunner runner;
193 MockFirewall firewall;
194 // Asserts for sysctl modifications
195 EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv4.ip_local_port_range"),
196 StrEq("32768 61000"), true));
197 EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv6.conf.all.forwarding"),
198 StrEq("0"), true));
199 EXPECT_CALL(runner, sysctl_w(StrEq("net.ipv4.ip_forward"), StrEq("0"), true));
200 // Asserts for RemoveOutboundIPv4SNATMark("vmtap+")
201 EXPECT_CALL(runner,
202 iptables(StrEq("mangle"),
203 ElementsAre("-D", "PREROUTING", "-i", "vmtap+", "-j",
204 "MARK", "--set-mark", "1/1", "-w"),
205 true, nullptr));
206 // Asserts for RemoveForwardEstablishedRule
207 EXPECT_CALL(runner,
208 iptables(StrEq("filter"),
209 ElementsAre("-D", "FORWARD", "-m", "state", "--state",
210 "ESTABLISHED,RELATED", "-j", "ACCEPT", "-w"),
211 true, nullptr));
212 // Asserts for RemoveSNATMarkRules
213 EXPECT_CALL(
214 runner,
215 iptables(StrEq("filter"),
216 ElementsAre("-D", "FORWARD", "-m", "mark", "--mark", "1/1", "-m",
217 "state", "--state", "INVALID", "-j", "DROP", "-w"),
218 true, nullptr));
219 EXPECT_CALL(runner,
220 iptables(StrEq("filter"),
221 ElementsAre("-D", "FORWARD", "-m", "mark", "--mark",
222 "1/1", "-j", "ACCEPT", "-w"),
223 true, nullptr));
224 EXPECT_CALL(runner,
225 iptables(StrEq("nat"),
226 ElementsAre("-D", "POSTROUTING", "-m", "mark", "--mark",
227 "1/1", "-j", "MASQUERADE", "-w"),
228 true, nullptr));
229 // Asserts for RemoveSourceIPv4DropRule() calls.
230 EXPECT_CALL(runner,
231 iptables(StrEq("filter"),
232 ElementsAre("-D", "OUTPUT", "-o", "eth+", "-s",
233 "100.115.92.0/23", "-j", "DROP", "-w"),
234 true, nullptr));
235 EXPECT_CALL(runner,
236 iptables(StrEq("filter"),
237 ElementsAre("-D", "OUTPUT", "-o", "wlan+", "-s",
238 "100.115.92.0/23", "-j", "DROP", "-w"),
239 true, nullptr));
240 EXPECT_CALL(runner,
241 iptables(StrEq("filter"),
242 ElementsAre("-D", "OUTPUT", "-o", "mlan+", "-s",
243 "100.115.92.0/23", "-j", "DROP", "-w"),
244 true, nullptr));
245 EXPECT_CALL(runner,
246 iptables(StrEq("filter"),
247 ElementsAre("-D", "OUTPUT", "-o", "usb+", "-s",
248 "100.115.92.0/23", "-j", "DROP", "-w"),
249 true, nullptr));
250 EXPECT_CALL(runner,
251 iptables(StrEq("filter"),
252 ElementsAre("-D", "OUTPUT", "-o", "wwan+", "-s",
253 "100.115.92.0/23", "-j", "DROP", "-w"),
254 true, nullptr));
255 EXPECT_CALL(runner,
256 iptables(StrEq("filter"),
257 ElementsAre("-D", "OUTPUT", "-o", "rmnet+", "-s",
258 "100.115.92.0/23", "-j", "DROP", "-w"),
259 true, nullptr));
260
261 Datapath datapath(&runner, &firewall);
262 datapath.Stop();
263}
264
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900265TEST(DatapathTest, AddTAP) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900266 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900267 MockFirewall firewall;
268 Datapath datapath(&runner, &firewall, ioctl_req_cap);
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900269 MacAddress mac = {1, 2, 3, 4, 5, 6};
Qijiang Fane90b8792020-03-09 16:15:41 +0900270 Subnet subnet(Ipv4Addr(100, 115, 92, 4), 30, base::DoNothing());
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900271 auto addr = subnet.AllocateAtOffset(0);
Garrick Evans4f9f5572019-11-26 10:25:16 +0900272 auto ifname = datapath.AddTAP("foo0", &mac, addr.get(), "");
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900273 EXPECT_EQ(ifname, "foo0");
Hugo Benichie8758b52020-04-03 14:49:01 +0900274 std::vector<ioctl_req_t> expected = {
275 TUNSETIFF, TUNSETPERSIST, SIOCSIFADDR, SIOCSIFNETMASK,
276 SIOCSIFHWADDR, SIOCGIFFLAGS, SIOCSIFFLAGS};
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900277 EXPECT_EQ(ioctl_reqs, expected);
278 ioctl_reqs.clear();
Hugo Benichi7c342672020-09-08 09:18:14 +0900279 ioctl_rtentry_args.clear();
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900280}
281
282TEST(DatapathTest, AddTAPWithOwner) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900283 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900284 MockFirewall firewall;
285 Datapath datapath(&runner, &firewall, ioctl_req_cap);
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900286 MacAddress mac = {1, 2, 3, 4, 5, 6};
Qijiang Fane90b8792020-03-09 16:15:41 +0900287 Subnet subnet(Ipv4Addr(100, 115, 92, 4), 30, base::DoNothing());
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900288 auto addr = subnet.AllocateAtOffset(0);
Garrick Evans4f9f5572019-11-26 10:25:16 +0900289 auto ifname = datapath.AddTAP("foo0", &mac, addr.get(), "root");
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900290 EXPECT_EQ(ifname, "foo0");
Hugo Benichie8758b52020-04-03 14:49:01 +0900291 std::vector<ioctl_req_t> expected = {
292 TUNSETIFF, TUNSETPERSIST, TUNSETOWNER, SIOCSIFADDR,
293 SIOCSIFNETMASK, SIOCSIFHWADDR, SIOCGIFFLAGS, SIOCSIFFLAGS};
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900294 EXPECT_EQ(ioctl_reqs, expected);
295 ioctl_reqs.clear();
Hugo Benichi7c342672020-09-08 09:18:14 +0900296 ioctl_rtentry_args.clear();
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900297}
298
Garrick Evans621ed262019-11-13 12:28:43 +0900299TEST(DatapathTest, AddTAPNoAddrs) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900300 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900301 MockFirewall firewall;
302 Datapath datapath(&runner, &firewall, ioctl_req_cap);
Garrick Evans4f9f5572019-11-26 10:25:16 +0900303 auto ifname = datapath.AddTAP("foo0", nullptr, nullptr, "");
Garrick Evans621ed262019-11-13 12:28:43 +0900304 EXPECT_EQ(ifname, "foo0");
Hugo Benichie8758b52020-04-03 14:49:01 +0900305 std::vector<ioctl_req_t> expected = {TUNSETIFF, TUNSETPERSIST, SIOCGIFFLAGS,
306 SIOCSIFFLAGS};
Garrick Evans621ed262019-11-13 12:28:43 +0900307 EXPECT_EQ(ioctl_reqs, expected);
308 ioctl_reqs.clear();
Hugo Benichi7c342672020-09-08 09:18:14 +0900309 ioctl_rtentry_args.clear();
Garrick Evans621ed262019-11-13 12:28:43 +0900310}
311
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900312TEST(DatapathTest, RemoveTAP) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900313 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900314 MockFirewall firewall;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900315 EXPECT_CALL(runner, ip(StrEq("tuntap"), StrEq("del"),
316 ElementsAre("foo0", "mode", "tap"), true));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900317 Datapath datapath(&runner, &firewall);
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900318 datapath.RemoveTAP("foo0");
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900319}
Garrick Evansf0ab7132019-06-18 14:50:42 +0900320
Hugo Benichi33860d72020-07-09 16:34:01 +0900321TEST(DatapathTest, NetnsAttachName) {
322 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900323 MockFirewall firewall;
Hugo Benichi33860d72020-07-09 16:34:01 +0900324 EXPECT_CALL(runner, ip_netns_delete(StrEq("netns_foo"), false));
325 EXPECT_CALL(runner, ip_netns_attach(StrEq("netns_foo"), 1234, true));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900326 Datapath datapath(&runner, &firewall);
Hugo Benichi33860d72020-07-09 16:34:01 +0900327 EXPECT_TRUE(datapath.NetnsAttachName("netns_foo", 1234));
328}
329
330TEST(DatapathTest, NetnsDeleteName) {
331 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900332 MockFirewall firewall;
Hugo Benichi33860d72020-07-09 16:34:01 +0900333 EXPECT_CALL(runner, ip_netns_delete(StrEq("netns_foo"), true));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900334 Datapath datapath(&runner, &firewall);
Hugo Benichi33860d72020-07-09 16:34:01 +0900335 EXPECT_TRUE(datapath.NetnsDeleteName("netns_foo"));
336}
337
Garrick Evans8a949dc2019-07-18 16:17:53 +0900338TEST(DatapathTest, AddBridge) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900339 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900340 MockFirewall firewall;
341 Datapath datapath(&runner, &firewall);
Garrick Evans8e8e3472020-01-23 14:03:50 +0900342 EXPECT_CALL(runner, brctl(StrEq("addbr"), ElementsAre("br"), true));
Garrick Evans6f4fa3a2020-02-10 16:15:09 +0900343 EXPECT_CALL(
344 runner,
345 ip(StrEq("addr"), StrEq("add"),
346 ElementsAre("1.1.1.1/30", "brd", "1.1.1.3", "dev", "br"), true));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900347 EXPECT_CALL(runner,
348 ip(StrEq("link"), StrEq("set"), ElementsAre("br", "up"), true));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900349 EXPECT_CALL(runner, iptables(StrEq("mangle"),
350 ElementsAre("-A", "PREROUTING", "-i", "br", "-j",
Hugo Benichi6c445322020-08-12 16:46:19 +0900351 "MARK", "--set-mark", "1/1", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900352 true, nullptr));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900353 datapath.AddBridge("br", Ipv4Addr(1, 1, 1, 1), 30);
Garrick Evans8a949dc2019-07-18 16:17:53 +0900354}
355
Hugo Benichi76675592020-04-08 14:29:57 +0900356TEST(DatapathTest, ConnectVethPair) {
357 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900358 MockFirewall firewall;
Hugo Benichi76675592020-04-08 14:29:57 +0900359 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("add"),
360 ElementsAre("veth_foo", "type", "veth", "peer", "name",
Hugo Benichi33860d72020-07-09 16:34:01 +0900361 "peer_foo", "netns", "netns_foo"),
Hugo Benichi76675592020-04-08 14:29:57 +0900362 true));
363 EXPECT_CALL(runner, ip(StrEq("addr"), StrEq("add"),
364 ElementsAre("100.115.92.169/30", "brd",
365 "100.115.92.171", "dev", "peer_foo"),
366 true))
367 .WillOnce(Return(0));
368 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
369 ElementsAre("dev", "peer_foo", "up", "addr",
370 "01:02:03:04:05:06", "multicast", "on"),
371 true))
372 .WillOnce(Return(0));
Hugo Benichi76675592020-04-08 14:29:57 +0900373 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
374 ElementsAre("veth_foo", "up"), true));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900375 Datapath datapath(&runner, &firewall);
Hugo Benichi33860d72020-07-09 16:34:01 +0900376 EXPECT_TRUE(datapath.ConnectVethPair(kTestPID, "netns_foo", "veth_foo",
377 "peer_foo", {1, 2, 3, 4, 5, 6},
Hugo Benichi76675592020-04-08 14:29:57 +0900378 Ipv4Addr(100, 115, 92, 169), 30, true));
379}
380
Garrick Evans2470caa2020-03-04 14:15:41 +0900381TEST(DatapathTest, AddVirtualInterfacePair) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900382 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900383 MockFirewall firewall;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900384 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("add"),
385 ElementsAre("veth_foo", "type", "veth", "peer", "name",
Hugo Benichi33860d72020-07-09 16:34:01 +0900386 "peer_foo", "netns", "netns_foo"),
Garrick Evans8e8e3472020-01-23 14:03:50 +0900387 true));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900388 Datapath datapath(&runner, &firewall);
Hugo Benichi33860d72020-07-09 16:34:01 +0900389 EXPECT_TRUE(
390 datapath.AddVirtualInterfacePair("netns_foo", "veth_foo", "peer_foo"));
Garrick Evans2470caa2020-03-04 14:15:41 +0900391}
392
393TEST(DatapathTest, ToggleInterface) {
394 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900395 MockFirewall firewall;
Garrick Evans2470caa2020-03-04 14:15:41 +0900396 EXPECT_CALL(runner,
397 ip(StrEq("link"), StrEq("set"), ElementsAre("foo", "up"), true));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900398 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
Garrick Evans2470caa2020-03-04 14:15:41 +0900399 ElementsAre("bar", "down"), true));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900400 Datapath datapath(&runner, &firewall);
Garrick Evans2470caa2020-03-04 14:15:41 +0900401 EXPECT_TRUE(datapath.ToggleInterface("foo", true));
402 EXPECT_TRUE(datapath.ToggleInterface("bar", false));
403}
404
405TEST(DatapathTest, ConfigureInterface) {
406 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900407 MockFirewall firewall;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900408 EXPECT_CALL(
409 runner,
Garrick Evans2470caa2020-03-04 14:15:41 +0900410 ip(StrEq("addr"), StrEq("add"),
411 ElementsAre("1.1.1.1/30", "brd", "1.1.1.3", "dev", "foo"), true))
412 .WillOnce(Return(0));
413 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
414 ElementsAre("dev", "foo", "up", "addr",
415 "02:02:02:02:02:02", "multicast", "on"),
416 true))
417 .WillOnce(Return(0));
418
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900419 Datapath datapath(&runner, &firewall);
Garrick Evans2470caa2020-03-04 14:15:41 +0900420 MacAddress mac_addr = {2, 2, 2, 2, 2, 2};
421 EXPECT_TRUE(datapath.ConfigureInterface("foo", mac_addr, Ipv4Addr(1, 1, 1, 1),
422 30, true, true));
Garrick Evans54861622019-07-19 09:05:09 +0900423}
424
425TEST(DatapathTest, RemoveInterface) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900426 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900427 MockFirewall firewall;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900428 EXPECT_CALL(runner,
429 ip(StrEq("link"), StrEq("delete"), ElementsAre("foo"), false));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900430 Datapath datapath(&runner, &firewall);
Garrick Evans54861622019-07-19 09:05:09 +0900431 datapath.RemoveInterface("foo");
Garrick Evans54861622019-07-19 09:05:09 +0900432}
433
Garrick Evans8a949dc2019-07-18 16:17:53 +0900434TEST(DatapathTest, RemoveBridge) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900435 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900436 MockFirewall firewall;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900437 EXPECT_CALL(runner, iptables(StrEq("mangle"),
438 ElementsAre("-D", "PREROUTING", "-i", "br", "-j",
Hugo Benichi6c445322020-08-12 16:46:19 +0900439 "MARK", "--set-mark", "1/1", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900440 true, nullptr));
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900441 EXPECT_CALL(runner,
442 ip(StrEq("link"), StrEq("set"), ElementsAre("br", "down"), true));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900443 EXPECT_CALL(runner, brctl(StrEq("delbr"), ElementsAre("br"), true));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900444 Datapath datapath(&runner, &firewall);
Garrick Evans8a949dc2019-07-18 16:17:53 +0900445 datapath.RemoveBridge("br");
Garrick Evans8a949dc2019-07-18 16:17:53 +0900446}
447
Hugo Benichi321f23b2020-09-25 15:42:05 +0900448TEST(DatapathTest, AddRemoveSourceIPv4DropRule) {
449 MockProcessRunner runner;
450 MockFirewall firewall;
451 EXPECT_CALL(runner,
452 iptables(StrEq("filter"),
453 ElementsAre("-I", "OUTPUT", "-o", "eth+", "-s",
454 "100.115.92.0/24", "-j", "DROP", "-w"),
455 true, nullptr));
456 EXPECT_CALL(runner,
457 iptables(StrEq("filter"),
458 ElementsAre("-D", "OUTPUT", "-o", "eth+", "-s",
459 "100.115.92.0/24", "-j", "DROP", "-w"),
460 true, nullptr));
461 Datapath datapath(&runner, &firewall);
462 datapath.AddSourceIPv4DropRule("eth+", "100.115.92.0/24");
463 datapath.RemoveSourceIPv4DropRule("eth+", "100.115.92.0/24");
464}
465
Hugo Benichi7c342672020-09-08 09:18:14 +0900466TEST(DatapathTest, StartRoutingNamespace) {
467 MockProcessRunner runner;
468 MockFirewall firewall;
469 MacAddress mac = {1, 2, 3, 4, 5, 6};
470
471 EXPECT_CALL(runner, ip_netns_delete(StrEq("netns_foo"), false));
472 EXPECT_CALL(runner, ip_netns_attach(StrEq("netns_foo"), kTestPID, true));
473 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("add"),
474 ElementsAre("arc_ns0", "type", "veth", "peer", "name",
475 "veth0", "netns", "netns_foo"),
476 true));
477 EXPECT_CALL(runner, ip(StrEq("addr"), StrEq("add"),
478 ElementsAre("100.115.92.130/30", "brd",
479 "100.115.92.131", "dev", "veth0"),
480 true))
481 .WillOnce(Return(0));
482 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
483 ElementsAre("dev", "veth0", "up", "addr",
484 "01:02:03:04:05:06", "multicast", "off"),
485 true))
486 .WillOnce(Return(0));
487 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
488 ElementsAre("arc_ns0", "up"), true));
489 EXPECT_CALL(runner, ip(StrEq("addr"), StrEq("add"),
490 ElementsAre("100.115.92.129/30", "brd",
491 "100.115.92.131", "dev", "arc_ns0"),
492 true))
493 .WillOnce(Return(0));
494 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("set"),
495 ElementsAre("dev", "arc_ns0", "up", "addr",
496 "01:02:03:04:05:06", "multicast", "off"),
497 true))
498 .WillOnce(Return(0));
499 EXPECT_CALL(runner, iptables(StrEq("filter"),
500 ElementsAre("-A", "FORWARD", "-o", "arc_ns0",
501 "-j", "ACCEPT", "-w"),
502 true, nullptr));
503 EXPECT_CALL(runner,
504 iptables(StrEq("mangle"),
505 ElementsAre("-A", "PREROUTING", "-i", "arc_ns0", "-j",
506 "MARK", "--set-mark", "1/1", "-w"),
507 true, nullptr));
508
509 Datapath datapath(&runner, &firewall, (ioctl_t)ioctl_rtentry_cap);
510 datapath.StartRoutingNamespace(
511 kTestPID, "netns_foo", "arc_ns0", "veth0", Ipv4Addr(100, 115, 92, 128),
512 30, Ipv4Addr(100, 115, 92, 129), Ipv4Addr(100, 115, 92, 130), mac);
513 ioctl_reqs.clear();
514 ioctl_rtentry_args.clear();
515}
516
517TEST(DatapathTest, StopRoutingNamespace) {
518 MockProcessRunner runner;
519 MockFirewall firewall;
520
521 EXPECT_CALL(runner, iptables(StrEq("filter"),
522 ElementsAre("-D", "FORWARD", "-o", "arc_ns0",
523 "-j", "ACCEPT", "-w"),
524 true, nullptr));
525 EXPECT_CALL(runner,
526 iptables(StrEq("mangle"),
527 ElementsAre("-D", "PREROUTING", "-i", "arc_ns0", "-j",
528 "MARK", "--set-mark", "1/1", "-w"),
529 true, nullptr));
530 EXPECT_CALL(runner, ip_netns_delete(StrEq("netns_foo"), true));
531 EXPECT_CALL(runner, ip(StrEq("link"), StrEq("delete"), ElementsAre("arc_ns0"),
532 false));
533
534 Datapath datapath(&runner, &firewall);
535 datapath.StopRoutingNamespace("netns_foo", "arc_ns0",
536 Ipv4Addr(100, 115, 92, 128), 30,
537 Ipv4Addr(100, 115, 92, 129));
538}
539
Hugo Benichi8d622b52020-08-13 15:24:12 +0900540TEST(DatapathTest, StartRoutingDevice_Arc) {
541 MockProcessRunner runner;
542 MockFirewall firewall;
543 EXPECT_CALL(runner, iptables(StrEq("nat"),
544 ElementsAre("-A", "PREROUTING", "-i", "eth0",
545 "-m", "socket", "--nowildcard", "-j",
546 "ACCEPT", "-w"),
547 true, nullptr));
548 EXPECT_CALL(runner, iptables(StrEq("nat"),
549 ElementsAre("-A", "PREROUTING", "-i", "eth0",
550 "-p", "tcp", "-j", "DNAT",
551 "--to-destination", "1.2.3.4", "-w"),
552 true, nullptr));
553 EXPECT_CALL(runner, iptables(StrEq("nat"),
554 ElementsAre("-A", "PREROUTING", "-i", "eth0",
555 "-p", "udp", "-j", "DNAT",
556 "--to-destination", "1.2.3.4", "-w"),
557 true, nullptr));
558 EXPECT_CALL(runner, iptables(StrEq("filter"),
Hugo Benichic6ae67c2020-08-14 15:02:13 +0900559 ElementsAre("-A", "FORWARD", "-i", "eth0", "-o",
560 "arc_eth0", "-j", "ACCEPT", "-w"),
561 true, nullptr));
562 EXPECT_CALL(runner, iptables(StrEq("filter"),
563 ElementsAre("-A", "FORWARD", "-i", "arc_eth0",
564 "-o", "eth0", "-j", "ACCEPT", "-w"),
Hugo Benichi8d622b52020-08-13 15:24:12 +0900565 true, nullptr));
Hugo Benichi9be19b12020-08-14 15:33:40 +0900566 EXPECT_CALL(runner, iptables(StrEq("mangle"),
567 ElementsAre("-A", "PREROUTING", "-i", "arc_eth0",
568 "-j", "MARK", "--set-mark",
569 "0x00002000/0x00003f00", "-w"),
570 true, nullptr));
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900571 EXPECT_CALL(runner, iptables(StrEq("mangle"),
572 ElementsAre("-A", "PREROUTING", "-i", "arc_eth0",
573 "-j", "MARK", "--set-mark",
574 "0x03ea0000/0xffff0000", "-w"),
575 true, nullptr));
Hugo Benichi5c9c11c2020-09-15 17:25:26 +0900576 EXPECT_CALL(
577 runner,
578 ip6tables(StrEq("mangle"),
579 ElementsAre("-A", "PREROUTING", "-i", "arc_eth0", "-j", "MARK",
580 "--set-mark", "0x00002000/0x00003f00", "-w"),
581 true, nullptr));
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900582 EXPECT_CALL(
583 runner,
584 ip6tables(StrEq("mangle"),
585 ElementsAre("-A", "PREROUTING", "-i", "arc_eth0", "-j", "MARK",
586 "--set-mark", "0x03ea0000/0xffff0000", "-w"),
587 true, nullptr));
Hugo Benichi8d622b52020-08-13 15:24:12 +0900588
589 Datapath datapath(&runner, &firewall);
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900590 datapath.SetIfnameIndex("eth0", 2);
Hugo Benichi8d622b52020-08-13 15:24:12 +0900591 datapath.StartRoutingDevice("eth0", "arc_eth0", Ipv4Addr(1, 2, 3, 4),
592 TrafficSource::ARC);
593}
594
595TEST(DatapathTest, StartRoutingDevice_CrosVM) {
596 MockProcessRunner runner;
597 MockFirewall firewall;
598 EXPECT_CALL(runner, iptables(StrEq("filter"),
599 ElementsAre("-A", "FORWARD", "-o", "vmtap0",
600 "-j", "ACCEPT", "-w"),
601 true, nullptr));
Hugo Benichic6ae67c2020-08-14 15:02:13 +0900602 EXPECT_CALL(runner, iptables(StrEq("filter"),
603 ElementsAre("-A", "FORWARD", "-i", "vmtap0",
604 "-j", "ACCEPT", "-w"),
605 true, nullptr));
Hugo Benichi9be19b12020-08-14 15:33:40 +0900606 EXPECT_CALL(runner, iptables(StrEq("mangle"),
607 ElementsAre("-A", "PREROUTING", "-i", "vmtap0",
608 "-j", "MARK", "--set-mark",
609 "0x00002100/0x00003f00", "-w"),
610 true, nullptr));
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900611 EXPECT_CALL(runner, iptables(StrEq("mangle"),
612 ElementsAre("-A", "PREROUTING", "-i", "vmtap0",
613 "-j", "CONNMARK", "--restore-mark",
614 "--mask", "0xffff0000", "-w"),
615 true, nullptr));
Hugo Benichi5c9c11c2020-09-15 17:25:26 +0900616 EXPECT_CALL(runner, ip6tables(StrEq("mangle"),
617 ElementsAre("-A", "PREROUTING", "-i", "vmtap0",
618 "-j", "MARK", "--set-mark",
619 "0x00002100/0x00003f00", "-w"),
620 true, nullptr));
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900621 EXPECT_CALL(runner, ip6tables(StrEq("mangle"),
622 ElementsAre("-A", "PREROUTING", "-i", "vmtap0",
623 "-j", "CONNMARK", "--restore-mark",
624 "--mask", "0xffff0000", "-w"),
625 true, nullptr));
Hugo Benichi8d622b52020-08-13 15:24:12 +0900626
627 Datapath datapath(&runner, &firewall);
628 datapath.StartRoutingDevice("", "vmtap0", Ipv4Addr(1, 2, 3, 4),
629 TrafficSource::CROSVM);
630}
631
632TEST(DatapathTest, StopRoutingDevice_Arc) {
633 MockProcessRunner runner;
634 MockFirewall firewall;
635 EXPECT_CALL(runner, iptables(StrEq("nat"),
636 ElementsAre("-D", "PREROUTING", "-i", "eth0",
637 "-m", "socket", "--nowildcard", "-j",
638 "ACCEPT", "-w"),
639 true, nullptr));
640 EXPECT_CALL(runner, iptables(StrEq("nat"),
641 ElementsAre("-D", "PREROUTING", "-i", "eth0",
642 "-p", "tcp", "-j", "DNAT",
643 "--to-destination", "1.2.3.4", "-w"),
644 true, nullptr));
645 EXPECT_CALL(runner, iptables(StrEq("nat"),
646 ElementsAre("-D", "PREROUTING", "-i", "eth0",
647 "-p", "udp", "-j", "DNAT",
648 "--to-destination", "1.2.3.4", "-w"),
649 true, nullptr));
650 EXPECT_CALL(runner, iptables(StrEq("filter"),
Hugo Benichic6ae67c2020-08-14 15:02:13 +0900651 ElementsAre("-D", "FORWARD", "-i", "eth0", "-o",
652 "arc_eth0", "-j", "ACCEPT", "-w"),
653 true, nullptr));
654 EXPECT_CALL(runner, iptables(StrEq("filter"),
655 ElementsAre("-D", "FORWARD", "-i", "arc_eth0",
656 "-o", "eth0", "-j", "ACCEPT", "-w"),
Hugo Benichi8d622b52020-08-13 15:24:12 +0900657 true, nullptr));
Hugo Benichi9be19b12020-08-14 15:33:40 +0900658 EXPECT_CALL(runner, iptables(StrEq("mangle"),
659 ElementsAre("-D", "PREROUTING", "-i", "arc_eth0",
660 "-j", "MARK", "--set-mark",
661 "0x00002000/0x00003f00", "-w"),
662 true, nullptr));
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900663 EXPECT_CALL(runner, iptables(StrEq("mangle"),
664 ElementsAre("-D", "PREROUTING", "-i", "arc_eth0",
665 "-j", "MARK", "--set-mark",
666 "0x03ea0000/0xffff0000", "-w"),
667 true, nullptr));
Hugo Benichi5c9c11c2020-09-15 17:25:26 +0900668 EXPECT_CALL(
669 runner,
670 ip6tables(StrEq("mangle"),
671 ElementsAre("-D", "PREROUTING", "-i", "arc_eth0", "-j", "MARK",
672 "--set-mark", "0x00002000/0x00003f00", "-w"),
673 true, nullptr));
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900674 EXPECT_CALL(
675 runner,
676 ip6tables(StrEq("mangle"),
677 ElementsAre("-D", "PREROUTING", "-i", "arc_eth0", "-j", "MARK",
678 "--set-mark", "0x03ea0000/0xffff0000", "-w"),
679 true, nullptr));
Hugo Benichi8d622b52020-08-13 15:24:12 +0900680
681 Datapath datapath(&runner, &firewall);
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900682 datapath.SetIfnameIndex("eth0", 2);
Hugo Benichi8d622b52020-08-13 15:24:12 +0900683 datapath.StopRoutingDevice("eth0", "arc_eth0", Ipv4Addr(1, 2, 3, 4),
684 TrafficSource::ARC);
685}
686
687TEST(DatapathTest, StopRoutingDevice_CrosVM) {
688 MockProcessRunner runner;
689 MockFirewall firewall;
690 EXPECT_CALL(runner, iptables(StrEq("filter"),
691 ElementsAre("-D", "FORWARD", "-o", "vmtap0",
692 "-j", "ACCEPT", "-w"),
693 true, nullptr));
Hugo Benichic6ae67c2020-08-14 15:02:13 +0900694 EXPECT_CALL(runner, iptables(StrEq("filter"),
695 ElementsAre("-D", "FORWARD", "-i", "vmtap0",
696 "-j", "ACCEPT", "-w"),
697 true, nullptr));
Hugo Benichi9be19b12020-08-14 15:33:40 +0900698 EXPECT_CALL(runner, iptables(StrEq("mangle"),
699 ElementsAre("-D", "PREROUTING", "-i", "vmtap0",
700 "-j", "MARK", "--set-mark",
701 "0x00002100/0x00003f00", "-w"),
702 true, nullptr));
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900703 EXPECT_CALL(runner, iptables(StrEq("mangle"),
704 ElementsAre("-D", "PREROUTING", "-i", "vmtap0",
705 "-j", "CONNMARK", "--restore-mark",
706 "--mask", "0xffff0000", "-w"),
707 true, nullptr));
Hugo Benichi5c9c11c2020-09-15 17:25:26 +0900708 EXPECT_CALL(runner, ip6tables(StrEq("mangle"),
709 ElementsAre("-D", "PREROUTING", "-i", "vmtap0",
710 "-j", "MARK", "--set-mark",
711 "0x00002100/0x00003f00", "-w"),
712 true, nullptr));
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900713 EXPECT_CALL(runner, ip6tables(StrEq("mangle"),
714 ElementsAre("-D", "PREROUTING", "-i", "vmtap0",
715 "-j", "CONNMARK", "--restore-mark",
716 "--mask", "0xffff0000", "-w"),
717 true, nullptr));
Hugo Benichi8d622b52020-08-13 15:24:12 +0900718
719 Datapath datapath(&runner, &firewall);
720 datapath.StopRoutingDevice("", "vmtap0", Ipv4Addr(1, 2, 3, 4),
721 TrafficSource::CROSVM);
722}
723
Hugo Benichid82d8832020-08-14 10:05:03 +0900724TEST(DatapathTest, StartStopIpForwarding) {
725 struct {
726 IpFamily family;
727 std::string iif;
728 std::string oif;
729 std::vector<std::string> start_args;
730 std::vector<std::string> stop_args;
731 bool result;
732 } testcases[] = {
733 {IpFamily::IPv4, "", "", {}, {}, false},
734 {IpFamily::NONE, "foo", "bar", {}, {}, false},
735 {IpFamily::IPv4,
736 "foo",
737 "bar",
738 {"-A", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"},
739 {"-D", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"},
740 true},
741 {IpFamily::IPv4,
742 "",
743 "bar",
744 {"-A", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"},
745 {"-D", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"},
746 true},
747 {IpFamily::IPv4,
748 "foo",
749 "",
750 {"-A", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"},
751 {"-D", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"},
752 true},
753 {IpFamily::IPv6,
754 "foo",
755 "bar",
756 {"-A", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"},
757 {"-D", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"},
758 true},
759 {IpFamily::IPv6,
760 "",
761 "bar",
762 {"-A", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"},
763 {"-D", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"},
764 true},
765 {IpFamily::IPv6,
766 "foo",
767 "",
768 {"-A", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"},
769 {"-D", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"},
770 true},
771 {IpFamily::Dual,
772 "foo",
773 "bar",
774 {"-A", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"},
775 {"-D", "FORWARD", "-i", "foo", "-o", "bar", "-j", "ACCEPT", "-w"},
776 true},
777 {IpFamily::Dual,
778 "",
779 "bar",
780 {"-A", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"},
781 {"-D", "FORWARD", "-o", "bar", "-j", "ACCEPT", "-w"},
782 true},
783 {IpFamily::Dual,
784 "foo",
785 "",
786 {"-A", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"},
787 {"-D", "FORWARD", "-i", "foo", "-j", "ACCEPT", "-w"},
788 true},
789 };
790
791 for (const auto& tt : testcases) {
792 MockProcessRunner runner;
793 MockFirewall firewall;
794 if (tt.result) {
795 if (tt.family & IpFamily::IPv4) {
796 EXPECT_CALL(runner,
797 iptables(StrEq("filter"), tt.start_args, true, nullptr))
798 .WillOnce(Return(0));
799 EXPECT_CALL(runner,
800 iptables(StrEq("filter"), tt.stop_args, true, nullptr))
801 .WillOnce(Return(0));
802 }
803 if (tt.family & IpFamily::IPv6) {
804 EXPECT_CALL(runner,
805 ip6tables(StrEq("filter"), tt.start_args, true, nullptr))
806 .WillOnce(Return(0));
807 EXPECT_CALL(runner,
808 ip6tables(StrEq("filter"), tt.stop_args, true, nullptr))
809 .WillOnce(Return(0));
810 }
811 }
812 Datapath datapath(&runner, &firewall);
813
814 EXPECT_EQ(tt.result, datapath.StartIpForwarding(tt.family, tt.iif, tt.oif));
815 EXPECT_EQ(tt.result, datapath.StopIpForwarding(tt.family, tt.iif, tt.oif));
816 }
817}
818
Hugo Benichi76be34a2020-08-26 22:35:54 +0900819TEST(DatapathTest, StartStopConnectionPinning) {
820 MockProcessRunner runner;
821 MockFirewall firewall;
822 EXPECT_CALL(runner, iptables(StrEq("mangle"),
823 ElementsAre("-A", "POSTROUTING", "-o", "eth0",
824 "-j", "CONNMARK", "--set-mark",
825 "0x03eb0000/0xffff0000", "-w"),
826 true, nullptr));
827 EXPECT_CALL(runner, iptables(StrEq("mangle"),
828 ElementsAre("-D", "POSTROUTING", "-o", "eth0",
829 "-j", "CONNMARK", "--set-mark",
830 "0x03eb0000/0xffff0000", "-w"),
831 true, nullptr));
832 EXPECT_CALL(runner, ip6tables(StrEq("mangle"),
833 ElementsAre("-A", "POSTROUTING", "-o", "eth0",
834 "-j", "CONNMARK", "--set-mark",
835 "0x03eb0000/0xffff0000", "-w"),
836 true, nullptr));
837 EXPECT_CALL(runner, ip6tables(StrEq("mangle"),
838 ElementsAre("-D", "POSTROUTING", "-o", "eth0",
839 "-j", "CONNMARK", "--set-mark",
840 "0x03eb0000/0xffff0000", "-w"),
841 true, nullptr));
842 Datapath datapath(&runner, &firewall);
843 datapath.SetIfnameIndex("eth0", 3);
844 datapath.StartConnectionPinning("eth0");
845 datapath.StopConnectionPinning("eth0");
846}
847
Garrick Evansf0ab7132019-06-18 14:50:42 +0900848TEST(DatapathTest, AddInboundIPv4DNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900849 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900850 MockFirewall firewall;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900851 EXPECT_CALL(runner, iptables(StrEq("nat"),
852 ElementsAre("-A", "PREROUTING", "-i", "eth0",
853 "-m", "socket", "--nowildcard", "-j",
854 "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900855 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900856 EXPECT_CALL(runner, iptables(StrEq("nat"),
857 ElementsAre("-A", "PREROUTING", "-i", "eth0",
858 "-p", "tcp", "-j", "DNAT",
859 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900860 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900861 EXPECT_CALL(runner, iptables(StrEq("nat"),
862 ElementsAre("-A", "PREROUTING", "-i", "eth0",
863 "-p", "udp", "-j", "DNAT",
864 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900865 true, nullptr));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900866 Datapath datapath(&runner, &firewall);
Garrick Evansf0ab7132019-06-18 14:50:42 +0900867 datapath.AddInboundIPv4DNAT("eth0", "1.2.3.4");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900868}
869
870TEST(DatapathTest, RemoveInboundIPv4DNAT) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900871 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900872 MockFirewall firewall;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900873 EXPECT_CALL(runner, iptables(StrEq("nat"),
874 ElementsAre("-D", "PREROUTING", "-i", "eth0",
875 "-m", "socket", "--nowildcard", "-j",
876 "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900877 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900878 EXPECT_CALL(runner, iptables(StrEq("nat"),
879 ElementsAre("-D", "PREROUTING", "-i", "eth0",
880 "-p", "tcp", "-j", "DNAT",
881 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900882 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900883 EXPECT_CALL(runner, iptables(StrEq("nat"),
884 ElementsAre("-D", "PREROUTING", "-i", "eth0",
885 "-p", "udp", "-j", "DNAT",
886 "--to-destination", "1.2.3.4", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900887 true, nullptr));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900888 Datapath datapath(&runner, &firewall);
Garrick Evansf0ab7132019-06-18 14:50:42 +0900889 datapath.RemoveInboundIPv4DNAT("eth0", "1.2.3.4");
Garrick Evansf0ab7132019-06-18 14:50:42 +0900890}
891
Garrick Evans664a82f2019-12-17 12:18:05 +0900892TEST(DatapathTest, MaskInterfaceFlags) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900893 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900894 MockFirewall firewall;
895 Datapath datapath(&runner, &firewall, ioctl_req_cap);
Hugo Benichi7c342672020-09-08 09:18:14 +0900896
Garrick Evans664a82f2019-12-17 12:18:05 +0900897 bool result = datapath.MaskInterfaceFlags("foo0", IFF_DEBUG);
Taoyu Li90c13912019-11-26 17:56:54 +0900898 EXPECT_TRUE(result);
Hugo Benichie8758b52020-04-03 14:49:01 +0900899 std::vector<ioctl_req_t> expected = {SIOCGIFFLAGS, SIOCSIFFLAGS};
Taoyu Li90c13912019-11-26 17:56:54 +0900900 EXPECT_EQ(ioctl_reqs, expected);
901 ioctl_reqs.clear();
Hugo Benichi7c342672020-09-08 09:18:14 +0900902 ioctl_rtentry_args.clear();
Taoyu Li90c13912019-11-26 17:56:54 +0900903}
904
905TEST(DatapathTest, AddIPv6Forwarding) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900906 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900907 MockFirewall firewall;
Taoyu Lica49c832019-12-06 17:56:43 +0900908 // Return 1 on iptables -C to simulate rule not existing case
Garrick Evans8e8e3472020-01-23 14:03:50 +0900909 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
910 ElementsAre("-C", "FORWARD", "-i", "eth0", "-o",
911 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900912 false, nullptr))
Garrick Evans8e8e3472020-01-23 14:03:50 +0900913 .WillOnce(Return(1));
914 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
915 ElementsAre("-A", "FORWARD", "-i", "eth0", "-o",
916 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900917 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900918 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
919 ElementsAre("-C", "FORWARD", "-i", "arc_eth0",
920 "-o", "eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900921 false, nullptr))
Garrick Evans8e8e3472020-01-23 14:03:50 +0900922 .WillOnce(Return(1));
923 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
924 ElementsAre("-A", "FORWARD", "-i", "arc_eth0",
925 "-o", "eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900926 true, nullptr));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900927 Datapath datapath(&runner, &firewall);
Taoyu Li90c13912019-11-26 17:56:54 +0900928 datapath.AddIPv6Forwarding("eth0", "arc_eth0");
Taoyu Li90c13912019-11-26 17:56:54 +0900929}
930
Taoyu Lica49c832019-12-06 17:56:43 +0900931TEST(DatapathTest, AddIPv6ForwardingRuleExists) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900932 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900933 MockFirewall firewall;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900934 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
935 ElementsAre("-C", "FORWARD", "-i", "eth0", "-o",
936 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900937 false, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900938 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
939 ElementsAre("-C", "FORWARD", "-i", "arc_eth0",
940 "-o", "eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900941 false, nullptr));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900942 Datapath datapath(&runner, &firewall);
Taoyu Lica49c832019-12-06 17:56:43 +0900943 datapath.AddIPv6Forwarding("eth0", "arc_eth0");
Taoyu Lica49c832019-12-06 17:56:43 +0900944}
945
Taoyu Li90c13912019-11-26 17:56:54 +0900946TEST(DatapathTest, RemoveIPv6Forwarding) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900947 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900948 MockFirewall firewall;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900949 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
950 ElementsAre("-D", "FORWARD", "-i", "eth0", "-o",
951 "arc_eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900952 true, nullptr));
Garrick Evans8e8e3472020-01-23 14:03:50 +0900953 EXPECT_CALL(runner, ip6tables(StrEq("filter"),
954 ElementsAre("-D", "FORWARD", "-i", "arc_eth0",
955 "-o", "eth0", "-j", "ACCEPT", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900956 true, nullptr));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900957 Datapath datapath(&runner, &firewall);
Taoyu Li90c13912019-11-26 17:56:54 +0900958 datapath.RemoveIPv6Forwarding("eth0", "arc_eth0");
Taoyu Li90c13912019-11-26 17:56:54 +0900959}
960
Taoyu Lieb6cc8f2019-12-09 15:53:04 +0900961TEST(DatapathTest, AddIPv6HostRoute) {
Garrick Evans8e8e3472020-01-23 14:03:50 +0900962 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900963 MockFirewall firewall;
Garrick Evans8e8e3472020-01-23 14:03:50 +0900964 EXPECT_CALL(runner,
965 ip6(StrEq("route"), StrEq("replace"),
966 ElementsAre("2001:da8:e00::1234/128", "dev", "eth0"), true));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900967 Datapath datapath(&runner, &firewall);
Taoyu Lieb6cc8f2019-12-09 15:53:04 +0900968 datapath.AddIPv6HostRoute("eth0", "2001:da8:e00::1234", 128);
Taoyu Lieb6cc8f2019-12-09 15:53:04 +0900969}
970
Hugo Benichie8758b52020-04-03 14:49:01 +0900971TEST(DatapathTest, AddIPv4Route) {
972 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900973 MockFirewall firewall;
974 Datapath datapath(&runner, &firewall, (ioctl_t)ioctl_rtentry_cap);
Hugo Benichie8758b52020-04-03 14:49:01 +0900975
976 datapath.AddIPv4Route(Ipv4Addr(192, 168, 1, 1), Ipv4Addr(100, 115, 93, 0),
977 Ipv4Addr(255, 255, 255, 0));
978 datapath.DeleteIPv4Route(Ipv4Addr(192, 168, 1, 1), Ipv4Addr(100, 115, 93, 0),
979 Ipv4Addr(255, 255, 255, 0));
980 datapath.AddIPv4Route("eth0", Ipv4Addr(100, 115, 92, 8),
981 Ipv4Addr(255, 255, 255, 252));
982 datapath.DeleteIPv4Route("eth0", Ipv4Addr(100, 115, 92, 8),
983 Ipv4Addr(255, 255, 255, 252));
984
985 std::vector<ioctl_req_t> expected_reqs = {SIOCADDRT, SIOCDELRT, SIOCADDRT,
986 SIOCDELRT};
987 EXPECT_EQ(expected_reqs, ioctl_reqs);
Hugo Benichie8758b52020-04-03 14:49:01 +0900988
989 std::string route1 =
990 "{rt_dst: {family: AF_INET, port: 0, addr: 100.115.93.0}, rt_genmask: "
991 "{family: AF_INET, port: 0, addr: 255.255.255.0}, rt_gateway: {family: "
992 "AF_INET, port: 0, addr: 192.168.1.1}, rt_dev: null, rt_flags: RTF_UP | "
993 "RTF_GATEWAY}";
994 std::string route2 =
995 "{rt_dst: {family: AF_INET, port: 0, addr: 100.115.92.8}, rt_genmask: "
996 "{family: AF_INET, port: 0, addr: 255.255.255.252}, rt_gateway: {unset}, "
997 "rt_dev: eth0, rt_flags: RTF_UP | RTF_GATEWAY}";
998 std::vector<std::string> captured_routes;
999 for (const auto& route : ioctl_rtentry_args) {
1000 std::ostringstream stream;
1001 stream << route.second;
1002 captured_routes.emplace_back(stream.str());
1003 }
Hugo Benichie8758b52020-04-03 14:49:01 +09001004 EXPECT_EQ(route1, captured_routes[0]);
1005 EXPECT_EQ(route1, captured_routes[1]);
1006 EXPECT_EQ(route2, captured_routes[2]);
1007 EXPECT_EQ(route2, captured_routes[3]);
Hugo Benichi7c342672020-09-08 09:18:14 +09001008 ioctl_reqs.clear();
1009 ioctl_rtentry_args.clear();
Hugo Benichie8758b52020-04-03 14:49:01 +09001010}
1011
Garrick Evansd291af62020-05-25 10:39:06 +09001012TEST(DatapathTest, AddSNATMarkRules) {
1013 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +09001014 MockFirewall firewall;
Taoyu Li79871c92020-07-02 16:09:39 +09001015 EXPECT_CALL(
1016 runner,
1017 iptables(StrEq("filter"),
Hugo Benichi6c445322020-08-12 16:46:19 +09001018 ElementsAre("-A", "FORWARD", "-m", "mark", "--mark", "1/1", "-m",
Taoyu Li79871c92020-07-02 16:09:39 +09001019 "state", "--state", "INVALID", "-j", "DROP", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +09001020 true, nullptr));
Hugo Benichi6c445322020-08-12 16:46:19 +09001021 EXPECT_CALL(runner,
1022 iptables(StrEq("filter"),
1023 ElementsAre("-A", "FORWARD", "-m", "mark", "--mark",
1024 "1/1", "-j", "ACCEPT", "-w"),
1025 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +09001026 EXPECT_CALL(runner,
1027 iptables(StrEq("nat"),
1028 ElementsAre("-A", "POSTROUTING", "-m", "mark", "--mark",
Hugo Benichi6c445322020-08-12 16:46:19 +09001029 "1/1", "-j", "MASQUERADE", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +09001030 true, nullptr));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +09001031 Datapath datapath(&runner, &firewall);
Garrick Evansd291af62020-05-25 10:39:06 +09001032 datapath.AddSNATMarkRules();
1033}
1034
1035TEST(DatapathTest, RemoveSNATMarkRules) {
1036 MockProcessRunner runner;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +09001037 MockFirewall firewall;
Taoyu Li79871c92020-07-02 16:09:39 +09001038 EXPECT_CALL(
1039 runner,
1040 iptables(StrEq("filter"),
Hugo Benichi6c445322020-08-12 16:46:19 +09001041 ElementsAre("-D", "FORWARD", "-m", "mark", "--mark", "1/1", "-m",
Taoyu Li79871c92020-07-02 16:09:39 +09001042 "state", "--state", "INVALID", "-j", "DROP", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +09001043 true, nullptr));
Hugo Benichi6c445322020-08-12 16:46:19 +09001044 EXPECT_CALL(runner,
1045 iptables(StrEq("filter"),
1046 ElementsAre("-D", "FORWARD", "-m", "mark", "--mark",
1047 "1/1", "-j", "ACCEPT", "-w"),
1048 true, nullptr));
Garrick Evansd291af62020-05-25 10:39:06 +09001049 EXPECT_CALL(runner,
1050 iptables(StrEq("nat"),
1051 ElementsAre("-D", "POSTROUTING", "-m", "mark", "--mark",
Hugo Benichi6c445322020-08-12 16:46:19 +09001052 "1/1", "-j", "MASQUERADE", "-w"),
Jie Jiangcf5ce9c2020-07-14 17:22:03 +09001053 true, nullptr));
Jason Jeremy Imana7273a32020-08-04 11:25:31 +09001054 Datapath datapath(&runner, &firewall);
Garrick Evansd291af62020-05-25 10:39:06 +09001055 datapath.RemoveSNATMarkRules();
1056}
1057
Garrick Evans2f581a02020-05-11 10:43:35 +09001058TEST(DatapathTest, ArcVethHostName) {
1059 EXPECT_EQ("vetheth0", ArcVethHostName("eth0"));
1060 EXPECT_EQ("vethrmnet0", ArcVethHostName("rmnet0"));
1061 EXPECT_EQ("vethrmnet_data0", ArcVethHostName("rmnet_data0"));
1062 EXPECT_EQ("vethifnamsiz_i0", ArcVethHostName("ifnamsiz_ifnam0"));
1063 auto ifname = ArcVethHostName("exceeds_ifnamesiz_checkanyway");
1064 EXPECT_EQ("vethexceeds_ify", ifname);
1065 EXPECT_LT(ifname.length(), IFNAMSIZ);
1066}
1067
Garrick Evans8a067562020-05-11 12:47:30 +09001068TEST(DatapathTest, ArcBridgeName) {
1069 EXPECT_EQ("arc_eth0", ArcBridgeName("eth0"));
1070 EXPECT_EQ("arc_rmnet0", ArcBridgeName("rmnet0"));
1071 EXPECT_EQ("arc_rmnet_data0", ArcBridgeName("rmnet_data0"));
1072 EXPECT_EQ("arc_ifnamsiz_i0", ArcBridgeName("ifnamsiz_ifnam0"));
1073 auto ifname = ArcBridgeName("exceeds_ifnamesiz_checkanyway");
1074 EXPECT_EQ("arc_exceeds_ify", ifname);
1075 EXPECT_LT(ifname.length(), IFNAMSIZ);
1076}
1077
Garrick Evans3388a032020-03-24 11:25:55 +09001078} // namespace patchpanel