blob: a1e48c3a3ca80e495cce4526ea26653d616c9793 [file] [log] [blame]
Jason Jeremy Iman54c046f2020-06-23 23:12:00 +09001// Copyright 2017 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
5#include "patchpanel/firewall.h"
6
7#include <string>
8#include <vector>
9
10#include <gtest/gtest.h>
11
12#include "patchpanel/mock_firewall.h"
13
14namespace patchpanel {
15
16using testing::_;
17using testing::Return;
18
19class FirewallTest : public testing::Test {
20 public:
21 FirewallTest() = default;
22 ~FirewallTest() override = default;
23
24 protected:
25 void SetMockExpectations(MockFirewall* firewall, bool success) {
26 // Empty criterion matches all commands.
27 firewall->SetRunInMinijailFailCriterion(std::vector<std::string>(), true,
28 success);
29 }
30
31 void SetMockExpectationsPerExecutable(MockFirewall* firewall,
32 bool ip4_success,
33 bool ip6_success) {
34 if (!ip4_success)
35 firewall->SetRunInMinijailFailCriterion(
36 std::vector<std::string>({kIpTablesPath}), true /* repeat */,
37 false /* omit_failure */);
38 if (!ip6_success)
39 firewall->SetRunInMinijailFailCriterion(
40 std::vector<std::string>({kIp6TablesPath}), true, false);
41 }
42
43 private:
44 DISALLOW_COPY_AND_ASSIGN(FirewallTest);
45};
46
47TEST_F(FirewallTest, Port0Fails) {
48 MockFirewall mock_firewall;
49 // Don't fail on anything.
50 int id = mock_firewall.SetRunInMinijailFailCriterion(
51 std::vector<std::string>(), true, true);
52
53 // Try to punch hole for TCP port 0, port 0 is not a valid port.
54 EXPECT_FALSE(
55 mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 0, "iface"));
56 // Try to punch hole for UDP port 0, port 0 is not a valid port.
57 EXPECT_FALSE(
58 mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 0, "iface"));
59
60 // Try to plug hole for TCP port 0, port 0 is not a valid port.
61 EXPECT_FALSE(
62 mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::TCP, 0, "iface"));
63 // Try to plug hole for UDP port 0, port 0 is not a valid port.
64 EXPECT_FALSE(
65 mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::UDP, 0, "iface"));
66
67 // We should not be adding/removing any rules for port 0.
68 EXPECT_EQ(mock_firewall.GetRunInMinijailCriterionMatchCount(id), 0);
69}
70
71TEST_F(FirewallTest, ValidInterfaceName) {
72 MockFirewall mock_firewall;
73 SetMockExpectations(&mock_firewall, true /* success */);
74
75 EXPECT_TRUE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80,
76 "shortname"));
77 EXPECT_TRUE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53,
78 "shortname"));
79 EXPECT_TRUE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80,
80 "middle-dash"));
81 EXPECT_TRUE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53,
82 "middle-dash"));
83 EXPECT_TRUE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80,
84 "middle.dot"));
85 EXPECT_TRUE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53,
86 "middle.dot"));
87}
88
89TEST_F(FirewallTest, InvalidInterfaceName) {
90 MockFirewall mock_firewall;
91 int id = mock_firewall.SetRunInMinijailFailCriterion(
92 std::vector<std::string>(), true, true);
93
94 EXPECT_FALSE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80,
95 "reallylonginterfacename"));
96 EXPECT_FALSE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80,
97 "with spaces"));
98 EXPECT_FALSE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80,
99 "with$ymbols"));
100 EXPECT_FALSE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80,
101 "-startdash"));
102 EXPECT_FALSE(
103 mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80, "enddash-"));
104 EXPECT_FALSE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80,
105 ".startdot"));
106 EXPECT_FALSE(
107 mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80, "enddot."));
108
109 EXPECT_FALSE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53,
110 "reallylonginterfacename"));
111 EXPECT_FALSE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53,
112 "with spaces"));
113 EXPECT_FALSE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53,
114 "with$ymbols"));
115 EXPECT_FALSE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53,
116 "-startdash"));
117 EXPECT_FALSE(
118 mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53, "enddash-"));
119 EXPECT_FALSE(mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53,
120 ".startdot"));
121 EXPECT_FALSE(
122 mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53, "enddot."));
123
124 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::TCP, 80,
125 "reallylonginterfacename"));
126 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::TCP, 80,
127 "with spaces"));
128 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::TCP, 80,
129 "with$ymbols"));
130 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::TCP, 80,
131 "-startdash"));
132 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::TCP, 80,
133 "enddash-"));
134 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::TCP, 80,
135 ".startdot"));
136 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::TCP, 80,
137 "enddot."));
138
139 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::UDP, 53,
140 "reallylonginterfacename"));
141 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::UDP, 53,
142 "with spaces"));
143 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::UDP, 53,
144 "with$ymbols"));
145 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::UDP, 53,
146 "-startdash"));
147 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::UDP, 53,
148 "enddash-"));
149 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::UDP, 53,
150 ".startdot"));
151 EXPECT_FALSE(mock_firewall.DeleteAcceptRules(ModifyPortRuleRequest::UDP, 53,
152 "enddot."));
153
154 // We should not be adding/removing any rules for invalid interface names.
155 EXPECT_EQ(mock_firewall.GetRunInMinijailCriterionMatchCount(id), 0);
156}
157
158TEST_F(FirewallTest, AddAcceptRules_Fails) {
159 MockFirewall mock_firewall;
160 SetMockExpectations(&mock_firewall, false /* success */);
161
162 // Punch hole for TCP port 80, should fail.
163 ASSERT_FALSE(
164 mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80, "iface"));
165 // Punch hole for UDP port 53, should fail.
166 ASSERT_FALSE(
167 mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53, "iface"));
168}
169
170TEST_F(FirewallTest, AddAcceptRules_Ipv6Fails) {
171 MockFirewall mock_firewall;
172 SetMockExpectationsPerExecutable(&mock_firewall, true /* ip4_success */,
173 false /* ip6_success */);
174
175 // Punch hole for TCP port 80, should fail because 'ip6tables' fails.
176 ASSERT_FALSE(
177 mock_firewall.AddAcceptRules(ModifyPortRuleRequest::TCP, 80, "iface"));
178 // Punch hole for UDP port 53, should fail because 'ip6tables' fails.
179 ASSERT_FALSE(
180 mock_firewall.AddAcceptRules(ModifyPortRuleRequest::UDP, 53, "iface"));
181}
182
183TEST_F(FirewallTest, Port0LockdownFails) {
184 MockFirewall mock_firewall;
185 // Don't fail on anything.
186 int id = mock_firewall.SetRunInMinijailFailCriterion(
187 std::vector<std::string>(), true, true);
188
189 // Try to lock down TCP port 0, port 0 is not a valid port.
190 EXPECT_FALSE(
191 mock_firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 0));
192 // Try to lock down UDP port 0, port 0 is not a valid port.
193 EXPECT_FALSE(
194 mock_firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::UDP, 0));
195
196 // We should not be adding/removing any rules for port 0.
197 EXPECT_EQ(mock_firewall.GetRunInMinijailCriterionMatchCount(id), 0);
198}
199
200TEST_F(FirewallTest, AddLoopbackLockdownRules_Success) {
201 MockFirewall mock_firewall;
202 SetMockExpectations(&mock_firewall, true /* success */);
203 ASSERT_TRUE(
204 mock_firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 80));
205 ASSERT_TRUE(
206 mock_firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::UDP, 53));
207 ASSERT_TRUE(
208 mock_firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 1234));
209 ASSERT_TRUE(
210 mock_firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 8080));
211}
212
213TEST_F(FirewallTest, AddLoopbackLockdownRules_Fails) {
214 MockFirewall mock_firewall;
215 SetMockExpectations(&mock_firewall, false /* success */);
216
217 // Lock down TCP port 80, should fail.
218 ASSERT_FALSE(
219 mock_firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 80));
220 // Lock down UDP port 53, should fail.
221 ASSERT_FALSE(
222 mock_firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::UDP, 53));
223}
224
225TEST_F(FirewallTest, AddLoopbackLockdownRules_Ipv6Fails) {
226 MockFirewall mock_firewall;
227 SetMockExpectationsPerExecutable(&mock_firewall, true /* ip4_success */,
228 false /* ip6_success */);
229
230 // Lock down TCP port 80, should fail because 'ip6tables' fails.
231 ASSERT_FALSE(
232 mock_firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::TCP, 80));
233 // Lock down UDP port 53, should fail because 'ip6tables' fails.
234 ASSERT_FALSE(
235 mock_firewall.AddLoopbackLockdownRules(ModifyPortRuleRequest::UDP, 53));
236}
237
238TEST_F(FirewallTest, AddIpv4ForwardRules_InvalidArguments) {
239 MockFirewall mock_firewall;
240 // Don't fail on anything.
241 mock_firewall.SetRunInMinijailFailCriterion({}, true, true);
242
243 // Invalid input interface. No iptables commands are issued.
244 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(
245 ModifyPortRuleRequest::TCP, "", 80, "-startdash", "100.115.92.5", 8080));
246 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(
247 ModifyPortRuleRequest::UDP, "", 80, "enddash-", "100.115.92.5", 8080));
248 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
249 ModifyPortRuleRequest::TCP, "", 80, ".startdot", "100.115.92.5", 8080));
250 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
251 ModifyPortRuleRequest::UDP, "", 80, "enddot.", "100.115.92.5", 8080));
252 ASSERT_TRUE(mock_firewall.GetAllCommands().empty());
253 mock_firewall.ResetStoredCommands();
254
255 // Empty interface. No iptables commands are issused.
256 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(ModifyPortRuleRequest::TCP, "",
257 80, "", "100.115.92.5", 8080));
258 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(ModifyPortRuleRequest::UDP, "",
259 80, "", "100.115.92.5", 8080));
260 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
261 ModifyPortRuleRequest::TCP, "", 80, "", "100.115.92.5", 8080));
262 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
263 ModifyPortRuleRequest::UDP, "", 80, "", "100.115.92.5", 8080));
264 ASSERT_TRUE(mock_firewall.GetAllCommands().empty());
265 mock_firewall.ResetStoredCommands();
266
267 // Invalid input dst address. No iptables commands are issused.
268 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(ModifyPortRuleRequest::TCP,
269 "256.256.256.256", 80, "iface",
270 "100.115.92.5", 8080));
271 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(ModifyPortRuleRequest::UDP,
272 "qodpjqwpod", 80, "iface",
273 "100.115.92.5", 8080));
274 // Trying to delete an IPv4 forward rule with an invalid input address will
275 // still trigger an explicit iptables -D command for the associated FORWARD
276 // ACCEPT rule. Two such commands are expected.
277 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
278 ModifyPortRuleRequest::TCP, "1.1", 80, "iface", "100.115.92.5", 8080));
279 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(ModifyPortRuleRequest::UDP,
280 "2001:db8::1", 80, "iface",
281 "100.115.92.5", 8080));
282 {
283 std::vector<std::string> expected_commands = {
284 "/sbin/iptables -t filter -D FORWARD -i iface -p tcp -d 100.115.92.5 "
285 "--dport 8080 -j ACCEPT -w",
286 "/sbin/iptables -t filter -D FORWARD -i iface -p udp -d 100.115.92.5 "
287 "--dport 8080 -j ACCEPT -w",
288 };
289 std::vector<std::string> issued_commands = mock_firewall.GetAllCommands();
290 EXPECT_EQ(expected_commands.size(), issued_commands.size());
291 for (int i = 0; i < expected_commands.size(); i++) {
292 ASSERT_EQ(expected_commands[i], issued_commands[i]);
293 }
294 }
295 mock_firewall.ResetStoredCommands();
296
297 // Invalid input dst port.
298 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(
299 ModifyPortRuleRequest::TCP, "", 0, "iface", "100.115.92.5", 8080));
300 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(
301 ModifyPortRuleRequest::TCP, "", 0, "iface", "100.115.92.5", 8080));
302 // Trying to delete an IPv4 forward rule with an invalid input port will
303 // still trigger an explicit iptables -D command for the associated FORWARD
304 // ACCEPT rule. Two such commands are expected.
305 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
306 ModifyPortRuleRequest::TCP, "", 0, "iface", "100.115.92.5", 8080));
307 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
308 ModifyPortRuleRequest::UDP, "", 0, "iface", "100.115.92.5", 8080));
309 {
310 std::vector<std::string> expected_commands = {
311 "/sbin/iptables -t filter -D FORWARD -i iface -p tcp -d 100.115.92.5 "
312 "--dport 8080 -j ACCEPT -w",
313 "/sbin/iptables -t filter -D FORWARD -i iface -p udp -d 100.115.92.5 "
314 "--dport 8080 -j ACCEPT -w",
315 };
316 std::vector<std::string> issued_commands = mock_firewall.GetAllCommands();
317 EXPECT_EQ(expected_commands.size(), issued_commands.size());
318 for (int i = 0; i < expected_commands.size(); i++) {
319 ASSERT_EQ(expected_commands[i], issued_commands[i]);
320 }
321 }
322 mock_firewall.ResetStoredCommands();
323
324 // Invalid output dst address. No iptables commands are issused.
325 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(ModifyPortRuleRequest::TCP, "",
326 80, "iface", "", 8080));
327 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(
328 ModifyPortRuleRequest::UDP, "", 80, "iface", "qodpjqwpod", 8080));
329 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
330 ModifyPortRuleRequest::TCP, "", 80, "iface", "1.1", 8080));
331 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
332 ModifyPortRuleRequest::UDP, "", 80, "iface", "2001:db8::1", 8080));
333 ASSERT_TRUE(mock_firewall.GetAllCommands().empty());
334 mock_firewall.ResetStoredCommands();
335
336 // Invalid output dst port. No iptables commands are issused.
337 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(
338 ModifyPortRuleRequest::TCP, "", 80, "iface", "100.115.92.5", 0));
339 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(
340 ModifyPortRuleRequest::UDP, "", 80, "iface", "100.115.92.5", 0));
341 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
342 ModifyPortRuleRequest::TCP, "", 80, "iface", "100.115.92.5", 0));
343 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
344 ModifyPortRuleRequest::UDP, "", 80, "iface", "100.115.92.5", 0));
345 ASSERT_TRUE(mock_firewall.GetAllCommands().empty());
346 mock_firewall.ResetStoredCommands();
347}
348
349TEST_F(FirewallTest, AddIpv4ForwardRules_IptablesFails) {
350 MockFirewall mock_firewall;
351 mock_firewall.SetRunInMinijailFailCriterion({}, true, false);
352
353 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(
354 ModifyPortRuleRequest::TCP, "", 80, "iface", "100.115.92.6", 8080));
355 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(
356 ModifyPortRuleRequest::UDP, "", 80, "iface", "100.115.92.6", 8080));
357 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
358 ModifyPortRuleRequest::TCP, "", 80, "iface", "100.115.92.6", 8080));
359 ASSERT_FALSE(mock_firewall.DeleteIpv4ForwardRule(
360 ModifyPortRuleRequest::UDP, "", 80, "iface", "100.115.92.6", 8080));
361
362 // AddIpv4ForwardRule: Firewall should return at the first failure and issue
363 // only a single command.
364 // DeleteIpv4ForwardRule: Firewall should try to delete both the DNAT rule
365 // and the FORWARD rule regardless of iptables failures.
366 std::vector<std::string> expected_commands = {
367 // Failed first AddIpv4ForwardRule call
368 "/sbin/iptables -t nat -I PREROUTING -i iface -p tcp --dport 80 -j DNAT "
369 "--to-destination 100.115.92.6:8080 -w",
370 // Failed second AddIpv4ForwardRule call
371 "/sbin/iptables -t nat -I PREROUTING -i iface -p udp --dport 80 -j DNAT "
372 "--to-destination 100.115.92.6:8080 -w",
373 // Failed first DeleteIpv4ForwardRule call
374 "/sbin/iptables -t nat -D PREROUTING -i iface -p tcp --dport 80 -j DNAT "
375 "--to-destination 100.115.92.6:8080 -w",
376 "/sbin/iptables -t filter -D FORWARD -i iface -p tcp -d 100.115.92.6 "
377 "--dport 8080 -j ACCEPT -w",
378 // Failed second DeleteIpv4ForwardRule call
379 "/sbin/iptables -t nat -D PREROUTING -i iface -p udp --dport 80 -j DNAT "
380 "--to-destination 100.115.92.6:8080 -w",
381 "/sbin/iptables -t filter -D FORWARD -i iface -p udp -d 100.115.92.6 "
382 "--dport 8080 -j ACCEPT -w",
383 };
384 std::vector<std::string> issued_commands = mock_firewall.GetAllCommands();
385 EXPECT_EQ(expected_commands.size(), issued_commands.size());
386 for (int i = 0; i < expected_commands.size(); i++) {
387 ASSERT_EQ(expected_commands[i], issued_commands[i]);
388 }
389}
390
391TEST_F(FirewallTest, AddIpv4ForwardRules_ValidRules) {
392 MockFirewall mock_firewall;
393 mock_firewall.SetRunInMinijailFailCriterion({}, true, true);
394
395 ASSERT_TRUE(mock_firewall.AddIpv4ForwardRule(
396 ModifyPortRuleRequest::TCP, "", 80, "wlan0", "100.115.92.2", 8080));
397 ASSERT_TRUE(mock_firewall.AddIpv4ForwardRule(ModifyPortRuleRequest::TCP,
398 "100.115.92.2", 5555, "vmtap0",
399 "127.0.0.1", 5550));
400 ASSERT_TRUE(mock_firewall.AddIpv4ForwardRule(
401 ModifyPortRuleRequest::UDP, "", 5353, "eth0", "192.168.1.1", 5353));
402 ASSERT_TRUE(mock_firewall.DeleteIpv4ForwardRule(
403 ModifyPortRuleRequest::TCP, "", 5000, "mlan0", "10.0.0.24", 5001));
404 ASSERT_TRUE(mock_firewall.DeleteIpv4ForwardRule(ModifyPortRuleRequest::TCP,
405 "100.115.92.2", 5555,
406 "vmtap0", "127.0.0.1", 5550));
407 ASSERT_TRUE(mock_firewall.DeleteIpv4ForwardRule(
408 ModifyPortRuleRequest::UDP, "", 443, "eth1", "1.2.3.4", 443));
409
410 std::vector<std::string> expected_commands = {
411 "/sbin/iptables -t nat -I PREROUTING -i wlan0 -p tcp --dport 80 -j DNAT "
412 "--to-destination 100.115.92.2:8080 -w",
413 "/sbin/iptables -t filter -A FORWARD -i wlan0 -p tcp -d 100.115.92.2 "
414 "--dport 8080 -j ACCEPT -w",
415 "/sbin/iptables -t nat -I PREROUTING -i vmtap0 -p tcp -d 100.115.92.2 "
416 "--dport 5555 -j DNAT --to-destination 127.0.0.1:5550 -w",
417 "/sbin/iptables -t filter -A FORWARD -i vmtap0 -p tcp -d 127.0.0.1 "
418 "--dport 5550 -j ACCEPT -w",
419 "/sbin/iptables -t nat -I PREROUTING -i eth0 -p udp --dport 5353 -j DNAT "
420 "--to-destination 192.168.1.1:5353 -w",
421 "/sbin/iptables -t filter -A FORWARD -i eth0 -p udp -d 192.168.1.1 "
422 "--dport 5353 -j ACCEPT -w",
423 "/sbin/iptables -t nat -D PREROUTING -i mlan0 -p tcp --dport 5000 -j "
424 "DNAT --to-destination 10.0.0.24:5001 -w",
425 "/sbin/iptables -t filter -D FORWARD -i mlan0 -p tcp -d 10.0.0.24 "
426 "--dport 5001 -j ACCEPT -w",
427 "/sbin/iptables -t nat -D PREROUTING -i vmtap0 -p tcp -d 100.115.92.2 "
428 "--dport 5555 -j DNAT --to-destination 127.0.0.1:5550 -w",
429 "/sbin/iptables -t filter -D FORWARD -i vmtap0 -p tcp -d 127.0.0.1 "
430 "--dport 5550 -j ACCEPT -w",
431 "/sbin/iptables -t nat -D PREROUTING -i eth1 -p udp --dport 443 -j DNAT "
432 "--to-destination 1.2.3.4:443 -w",
433 "/sbin/iptables -t filter -D FORWARD -i eth1 -p udp -d 1.2.3.4 "
434 "--dport 443 -j ACCEPT -w",
435 };
436 std::vector<std::string> issued_commands = mock_firewall.GetAllCommands();
437 EXPECT_EQ(expected_commands.size(), issued_commands.size());
438 for (int i = 0; i < expected_commands.size(); i++) {
439 ASSERT_EQ(expected_commands[i], issued_commands[i]);
440 }
441}
442
443TEST_F(FirewallTest, AddIpv4ForwardRules_PartialFailure) {
444 MockFirewall mock_firewall;
445 mock_firewall.SetRunInMinijailFailCriterion({"FORWARD"}, true, false);
446
447 ASSERT_FALSE(mock_firewall.AddIpv4ForwardRule(
448 ModifyPortRuleRequest::TCP, "", 80, "wlan0", "100.115.92.2", 8080));
449
450 // When the second issued FORWARD command fails, expect a delete command to
451 // cleanup the PREROUTING command that succeeded.
452 std::vector<std::string> expected_commands = {
453 "/sbin/iptables -t nat -I PREROUTING -i wlan0 -p tcp --dport 80 -j DNAT "
454 "--to-destination 100.115.92.2:8080 -w",
455 "/sbin/iptables -t filter -A FORWARD -i wlan0 -p tcp -d 100.115.92.2 "
456 "--dport 8080 -j ACCEPT -w",
457 "/sbin/iptables -t nat -D PREROUTING -i wlan0 -p tcp --dport 80 -j DNAT "
458 "--to-destination 100.115.92.2:8080 -w",
459 };
460 std::vector<std::string> issued_commands = mock_firewall.GetAllCommands();
461 ASSERT_EQ(expected_commands.size(), issued_commands.size());
462 for (int i = 0; i < expected_commands.size(); i++) {
463 ASSERT_EQ(expected_commands[i], issued_commands[i]);
464 }
465}
466
467TEST_F(FirewallTest, DeleteIpv4ForwardRules_PartialFailure) {
468 MockFirewall mock_firewall1;
469 MockFirewall mock_firewall2;
470
471 mock_firewall1.SetRunInMinijailFailCriterion({"FORWARD"}, false, false);
472 mock_firewall2.SetRunInMinijailFailCriterion({"PREROUTING"}, false, false);
473
474 ASSERT_FALSE(mock_firewall1.DeleteIpv4ForwardRule(
475 ModifyPortRuleRequest::TCP, "", 80, "wlan0", "100.115.92.2", 8080));
476 ASSERT_FALSE(mock_firewall2.DeleteIpv4ForwardRule(
477 ModifyPortRuleRequest::TCP, "", 80, "wlan0", "100.115.92.2", 8080));
478
479 // Cleanup commands for both FORWARD and PREROUTING rules are both issued
480 // regardless of any iptables failures.
481 std::vector<std::string> expected_commands = {
482 "/sbin/iptables -t nat -D PREROUTING -i wlan0 -p tcp --dport 80 -j DNAT "
483 "--to-destination 100.115.92.2:8080 -w",
484 "/sbin/iptables -t filter -D FORWARD -i wlan0 -p tcp -d 100.115.92.2 "
485 "--dport 8080 -j ACCEPT -w",
486 };
487 std::vector<std::string> issued_commands1 = mock_firewall1.GetAllCommands();
488 std::vector<std::string> issued_commands2 = mock_firewall2.GetAllCommands();
489 ASSERT_EQ(expected_commands.size(), issued_commands1.size());
490 ASSERT_EQ(expected_commands.size(), issued_commands2.size());
491 for (int i = 0; i < expected_commands.size(); i++) {
492 ASSERT_EQ(expected_commands[i], issued_commands1[i]);
493 ASSERT_EQ(expected_commands[i], issued_commands2[i]);
494 }
495}
496} // namespace patchpanel