blob: 313620a2fefff73bded783a5d68c9cdb88eb4ccf [file] [log] [blame]
Jie Jiangcf749152020-07-09 22:20:58 +09001// Copyright 2020 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/counters_service.h"
6
Jie Jiang8fd0ace2020-09-01 14:51:57 +09007#include <net/if.h>
Hugo Benichi058a26a2020-11-26 10:10:39 +09008
9#include <memory>
Jie Jiangcf749152020-07-09 22:20:58 +090010#include <string>
11#include <vector>
12
13#include <chromeos/dbus/service_constants.h>
14#include <gmock/gmock.h>
15#include <gtest/gtest.h>
16
Hugo Benichicd27f4e2020-11-19 18:32:23 +090017#include "patchpanel/mock_firewall.h"
Jie Jiangcf749152020-07-09 22:20:58 +090018
19namespace patchpanel {
Jie Jiangcf749152020-07-09 22:20:58 +090020
Hugo Benichi058a26a2020-11-26 10:10:39 +090021using ::testing::_;
22using ::testing::AnyNumber;
Jie Jianged0b1cc2020-07-10 15:55:33 +090023using ::testing::ContainerEq;
Jie Jiangcf749152020-07-09 22:20:58 +090024using ::testing::Contains;
Jie Jianged0b1cc2020-07-10 15:55:33 +090025using ::testing::DoAll;
Jie Jiang8fd0ace2020-09-01 14:51:57 +090026using ::testing::Each;
Jie Jiangcf749152020-07-09 22:20:58 +090027using ::testing::ElementsAreArray;
Jie Jiang8fd0ace2020-09-01 14:51:57 +090028using ::testing::Lt;
Jie Jianged0b1cc2020-07-10 15:55:33 +090029using ::testing::Return;
30using ::testing::SetArgPointee;
Jie Jiang8fd0ace2020-09-01 14:51:57 +090031using ::testing::SizeIs;
Jie Jianged0b1cc2020-07-10 15:55:33 +090032
33using Counter = CountersService::Counter;
34using SourceDevice = CountersService::SourceDevice;
35
36// The following two functions should be put outside the anounymous namespace
37// otherwise they could not be found in the tests.
38std::ostream& operator<<(std::ostream& os, const Counter& counter) {
39 os << "rx_bytes:" << counter.rx_bytes << ", rx_packets:" << counter.rx_packets
40 << ", tx_bytes:" << counter.tx_bytes
41 << ", tx_packets:" << counter.tx_packets;
42 return os;
43}
44
45bool operator==(const CountersService::Counter lhs,
46 const CountersService::Counter rhs) {
47 return lhs.rx_bytes == rhs.rx_bytes && lhs.rx_packets == rhs.rx_packets &&
48 lhs.tx_bytes == rhs.tx_bytes && lhs.tx_packets == rhs.tx_packets;
49}
50
51namespace {
52// The following string is copied from the real output of iptables v1.6.2 by
53// `iptables -t mangle -L -x -v`. This output contains all the accounting
54// chains/rules for eth0 and wlan0.
55// TODO(jiejiang): presubmit checker is complaining about the line length for
56// this (and the other raw strings in this file). Find a way to make it happy.
57const char kIptablesOutput[] = R"(
58Chain PREROUTING (policy ACCEPT 22785 packets, 136093545 bytes)
59 pkts bytes target prot opt in out source destination
60 18 2196 MARK all -- arcbr0 any anywhere anywhere MARK set 0x1
61 0 0 MARK all -- vmtap+ any anywhere anywhere MARK set 0x1
62 6526 68051766 MARK all -- arc_eth0 any anywhere anywhere MARK set 0x1
63 9 1104 MARK all -- arc_wlan0 any anywhere anywhere MARK set 0x1
64
65Chain INPUT (policy ACCEPT 4421 packets, 2461233 bytes)
66 pkts bytes target prot opt in out source destination
Hugo Benichi33af8f72020-11-20 10:08:47 +090067 312491 1767147156 rx_eth0 all -- eth0 any anywhere anywhere
68 0 0 rx_wlan0 all -- wlan0 any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +090069
70Chain FORWARD (policy ACCEPT 18194 packets, 133612816 bytes)
71 pkts bytes target prot opt in out source destination
Hugo Benichi33af8f72020-11-20 10:08:47 +090072 6511 68041668 tx_eth0 all -- any eth0 anywhere anywhere
73 11683 65571148 rx_eth0 all -- eth0 any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +090074
75Chain OUTPUT (policy ACCEPT 4574 packets, 2900995 bytes)
76 pkts bytes target prot opt in out source destination
77
78Chain POSTROUTING (policy ACCEPT 22811 packets, 136518827 bytes)
79 pkts bytes target prot opt in out source destination
Hugo Benichi33af8f72020-11-20 10:08:47 +090080 202160 1807550291 tx_eth0 all -- any eth0 anywhere anywhere owner socket exists
81 2 96 tx_wlan0 all -- any wlan0 anywhere anywhere owner socket exists
Jie Jianged0b1cc2020-07-10 15:55:33 +090082
Hugo Benichi33af8f72020-11-20 10:08:47 +090083Chain tx_eth0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +090084 pkts bytes target prot opt in out source destination
Hugo Benichi92fa2032020-11-20 17:47:32 +090085 1366 244427 RETURN all -- any any anywhere anywhere mark match 0x100/0x3f00
86 0 0 RETURN all -- any any anywhere anywhere mark match 0x200/0x3f00
87 20 1670 RETURN all -- any any anywhere anywhere mark match 0x300/0x3f00
88 550 138402 RETURN all -- any any anywhere anywhere mark match 0x400/0x3f00
89 0 0 RETURN all -- any any anywhere anywhere mark match 0x500/0x3f00
90 5374 876172 RETURN all -- any any anywhere anywhere mark match 0x2000/0x3f00
91 39 2690 RETURN all -- any any anywhere anywhere mark match 0x2100/0x3f00
92 0 0 RETURN all -- any any anywhere anywhere mark match 0x2200/0x3f00
93 0 0 RETURN all -- any any anywhere anywhere mark match 0x2300/0x3f00
94 0 0 RETURN all -- any any anywhere anywhere mark match 0x2400/0x3f00
Jie Jianged0b1cc2020-07-10 15:55:33 +090095
Hugo Benichi33af8f72020-11-20 10:08:47 +090096Chain tx_wlan0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +090097 pkts bytes target prot opt in out source destination
Hugo Benichi92fa2032020-11-20 17:47:32 +090098 310 57004 RETURN all -- any any anywhere anywhere mark match 0x100/0x3f00
99 0 0 RETURN all -- any any anywhere anywhere mark match 0x200/0x3f00
100 0 0 RETURN all -- any any anywhere anywhere mark match 0x300/0x3f00
101 24 2801 RETURN all -- any any anywhere anywhere mark match 0x400/0x3f00
102 0 0 RETURN all -- any any anywhere anywhere mark match 0x500/0x3f00
103 0 0 RETURN all -- any any anywhere anywhere mark match 0x2000/0x3f00
104 0 0 RETURN all -- any any anywhere anywhere mark match 0x2100/0x3f00
105 0 0 RETURN all -- any any anywhere anywhere mark match 0x2200/0x3f00
106 0 0 RETURN all -- any any anywhere anywhere mark match 0x2300/0x3f00
107 0 0 RETURN all -- any any anywhere anywhere mark match 0x2400/0x3f00
Jie Jianged0b1cc2020-07-10 15:55:33 +0900108
Hugo Benichi33af8f72020-11-20 10:08:47 +0900109Chain rx_eth0 (2 references)
Hugo Benichi92fa2032020-11-20 17:47:32 +0900110 pkts bytes target prot opt in out source destination
111 73 11938 RETURN all -- any any anywhere anywhere mark match 0x100/0x3f00
112 0 0 RETURN all -- any any anywhere anywhere mark match 0x200/0x3f00
113 0 0 RETURN all -- any any anywhere anywhere mark match 0x300/0x3f00
114 5 694 RETURN all -- any any anywhere anywhere mark match 0x400/0x3f00
115 0 0 RETURN all -- any any anywhere anywhere mark match 0x500/0x3f00
116 0 0 RETURN all -- any any anywhere anywhere mark match 0x2000/0x3f00
117 0 0 RETURN all -- any any anywhere anywhere mark match 0x2100/0x3f00
118 0 0 RETURN all -- any any anywhere anywhere mark match 0x2200/0x3f00
119 0 0 RETURN all -- any any anywhere anywhere mark match 0x2300/0x3f00
120 0 0 RETURN all -- any any anywhere anywhere mark match 0x2400/0x3f00
Jie Jianged0b1cc2020-07-10 15:55:33 +0900121
Hugo Benichi33af8f72020-11-20 10:08:47 +0900122Chain rx_wlan0 (2 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900123 pkts bytes target prot opt in out source destination
Hugo Benichi92fa2032020-11-20 17:47:32 +0900124 153 28098 RETURN all -- any any anywhere anywhere mark match 0x100/0x3f00
125 0 0 RETURN all -- any any anywhere anywhere mark match 0x200/0x3f00
126 0 0 RETURN all -- any any anywhere anywhere mark match 0x300/0x3f00
127 6 840 RETURN all -- any any anywhere anywhere mark match 0x400/0x3f00
128 0 0 RETURN all -- any any anywhere anywhere mark match 0x500/0x3f00
129 0 0 RETURN all -- any any anywhere anywhere mark match 0x2000/0x3f00
130 0 0 RETURN all -- any any anywhere anywhere mark match 0x2100/0x3f00
131 0 0 RETURN all -- any any anywhere anywhere mark match 0x2200/0x3f00
132 0 0 RETURN all -- any any anywhere anywhere mark match 0x2300/0x3f00
133 0 0 RETURN all -- any any anywhere anywhere mark match 0x2400/0x3f00
Jie Jianged0b1cc2020-07-10 15:55:33 +0900134)";
135
Jie Jiangcf749152020-07-09 22:20:58 +0900136class MockProcessRunner : public MinijailedProcessRunner {
137 public:
138 MockProcessRunner() = default;
139 ~MockProcessRunner() = default;
140
141 MOCK_METHOD(int,
142 iptables,
143 (const std::string& table,
144 const std::vector<std::string>& argv,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900145 bool log_failures,
146 std::string* output),
Jie Jiangcf749152020-07-09 22:20:58 +0900147 (override));
148 MOCK_METHOD(int,
149 ip6tables,
150 (const std::string& table,
151 const std::vector<std::string>& argv,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900152 bool log_failures,
153 std::string* output),
Jie Jiangcf749152020-07-09 22:20:58 +0900154 (override));
155};
156
157class CountersServiceTest : public testing::Test {
158 protected:
159 void SetUp() override {
Hugo Benichicd27f4e2020-11-19 18:32:23 +0900160 datapath_ = std::make_unique<Datapath>(&runner_, &firewall_);
Hugo Benichi058a26a2020-11-26 10:10:39 +0900161 counters_svc_ =
162 std::make_unique<CountersService>(datapath_.get(), &runner_);
Jie Jiangcf749152020-07-09 22:20:58 +0900163 }
164
Jie Jianged0b1cc2020-07-10 15:55:33 +0900165 // Makes `iptables` returning a bad |output|. Expects an empty map from
166 // GetCounters().
167 void TestBadIptablesOutput(const std::string& output) {
168 EXPECT_CALL(runner_, iptables(_, _, _, _))
169 .WillRepeatedly(DoAll(SetArgPointee<3>(output), Return(0)));
170 EXPECT_CALL(runner_, ip6tables(_, _, _, _))
171 .WillRepeatedly(DoAll(SetArgPointee<3>(kIptablesOutput), Return(0)));
172
173 auto actual = counters_svc_->GetCounters({});
174 std::map<SourceDevice, Counter> expected;
175
176 EXPECT_THAT(actual, ContainerEq(expected));
177 }
178
179 // Makes `ip6tables` returning a bad |output|. Expects an empty map from
180 // GetCounters().
181 void TestBadIp6tablesOutput(const std::string& output) {
182 EXPECT_CALL(runner_, iptables(_, _, _, _))
183 .WillRepeatedly(DoAll(SetArgPointee<3>(kIptablesOutput), Return(0)));
184 EXPECT_CALL(runner_, ip6tables(_, _, _, _))
185 .WillRepeatedly(DoAll(SetArgPointee<3>(output), Return(0)));
186
187 auto actual = counters_svc_->GetCounters({});
188 std::map<SourceDevice, Counter> expected;
189
190 EXPECT_THAT(actual, ContainerEq(expected));
191 }
192
Jie Jiangcf749152020-07-09 22:20:58 +0900193 MockProcessRunner runner_;
Hugo Benichicd27f4e2020-11-19 18:32:23 +0900194 MockFirewall firewall_;
Hugo Benichicd27f4e2020-11-19 18:32:23 +0900195 std::unique_ptr<Datapath> datapath_;
Jie Jiangcf749152020-07-09 22:20:58 +0900196 std::unique_ptr<CountersService> counters_svc_;
197};
198
Hugo Benichi058a26a2020-11-26 10:10:39 +0900199TEST_F(CountersServiceTest, OnCreation_WithNoDevices) {
200 // The following commands are expected when eth0 comes up.
201 const std::vector<std::vector<std::string>> expected_calls{
202 {"-N", "rx_vpn", "-w"},
203 {"-N", "tx_vpn", "-w"},
204 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
205 "RETURN", "-w"},
206 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
207 "RETURN", "-w"},
208 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
209 "RETURN", "-w"},
210 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
211 "RETURN", "-w"},
212 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
213 "RETURN", "-w"},
214 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
215 "RETURN", "-w"},
216 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
217 "RETURN", "-w"},
218 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
219 "RETURN", "-w"},
220 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
221 "RETURN", "-w"},
222 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
223 "RETURN", "-w"},
224 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
225 "RETURN", "-w"},
226 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
227 "RETURN", "-w"},
228 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
229 "RETURN", "-w"},
230 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
231 "RETURN", "-w"},
232 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
233 "RETURN", "-w"},
234 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
235 "RETURN", "-w"},
236 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
237 "RETURN", "-w"},
238 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
239 "RETURN", "-w"},
240 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
241 "RETURN", "-w"},
242 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
243 "RETURN", "-w"},
244 };
245
246 for (const auto& rule : expected_calls) {
247 EXPECT_CALL(runner_, iptables("mangle", ElementsAreArray(rule), _, _));
248 EXPECT_CALL(runner_, ip6tables("mangle", ElementsAreArray(rule), _, _));
249 }
250
251 counters_svc_->Init({});
252}
253
254TEST_F(CountersServiceTest, OnCreation_WithDevices) {
255 // The following commands are expected when eth0 comes up.
256 const std::vector<std::vector<std::string>> expected_calls{
257 {"-N", "rx_vpn", "-w"},
258 {"-N", "tx_vpn", "-w"},
259 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
260 "RETURN", "-w"},
261 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
262 "RETURN", "-w"},
263 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
264 "RETURN", "-w"},
265 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
266 "RETURN", "-w"},
267 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
268 "RETURN", "-w"},
269 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
270 "RETURN", "-w"},
271 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
272 "RETURN", "-w"},
273 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
274 "RETURN", "-w"},
275 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
276 "RETURN", "-w"},
277 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
278 "RETURN", "-w"},
279 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
280 "RETURN", "-w"},
281 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
282 "RETURN", "-w"},
283 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
284 "RETURN", "-w"},
285 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
286 "RETURN", "-w"},
287 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
288 "RETURN", "-w"},
289 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
290 "RETURN", "-w"},
291 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
292 "RETURN", "-w"},
293 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
294 "RETURN", "-w"},
295 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
296 "RETURN", "-w"},
297 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
298 "RETURN", "-w"},
299 {"-N", "rx_wlan0", "-w"},
300 {"-N", "tx_wlan0", "-w"},
301 {"-A", "INPUT", "-i", "wlan0", "-j", "rx_wlan0", "-w"},
302 {"-A", "FORWARD", "-i", "wlan0", "-j", "rx_wlan0", "-w"},
303 {"-A", "POSTROUTING", "-o", "wlan0", "-j", "tx_wlan0", "-w"},
304 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
305 "RETURN", "-w"},
306 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
307 "RETURN", "-w"},
308 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
309 "RETURN", "-w"},
310 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
311 "RETURN", "-w"},
312 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
313 "RETURN", "-w"},
314 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
315 "RETURN", "-w"},
316 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
317 "RETURN", "-w"},
318 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
319 "RETURN", "-w"},
320 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
321 "RETURN", "-w"},
322 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
323 "RETURN", "-w"},
324 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
325 "RETURN", "-w"},
326 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
327 "RETURN", "-w"},
328 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
329 "RETURN", "-w"},
330 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
331 "RETURN", "-w"},
332 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
333 "RETURN", "-w"},
334 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
335 "RETURN", "-w"},
336 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
337 "RETURN", "-w"},
338 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
339 "RETURN", "-w"},
340 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
341 "RETURN", "-w"},
342 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
343 "RETURN", "-w"},
344 };
345
346 for (const auto& rule : expected_calls) {
347 EXPECT_CALL(runner_, iptables("mangle", ElementsAreArray(rule), _, _));
348 EXPECT_CALL(runner_, ip6tables("mangle", ElementsAreArray(rule), _, _));
349 }
350
351 counters_svc_->Init({"wlan0"});
352}
353
354TEST_F(CountersServiceTest, OnPhysicalDeviceAdded) {
Jie Jiangcf749152020-07-09 22:20:58 +0900355 // The following commands are expected when eth0 comes up.
356 const std::vector<std::vector<std::string>> expected_calls{
Hugo Benichi33af8f72020-11-20 10:08:47 +0900357 {"-N", "rx_eth0", "-w"},
Hugo Benichiaf2021b2020-11-20 14:07:16 +0900358 {"-N", "tx_eth0", "-w"},
Hugo Benichi33af8f72020-11-20 10:08:47 +0900359 {"-A", "INPUT", "-i", "eth0", "-j", "rx_eth0", "-w"},
360 {"-A", "FORWARD", "-i", "eth0", "-j", "rx_eth0", "-w"},
Hugo Benichi33af8f72020-11-20 10:08:47 +0900361 {"-A", "POSTROUTING", "-o", "eth0", "-j", "tx_eth0", "-w"},
Hugo Benichiaf2021b2020-11-20 14:07:16 +0900362 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
363 "RETURN", "-w"},
364 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
365 "RETURN", "-w"},
366 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
367 "RETURN", "-w"},
368 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
369 "RETURN", "-w"},
370 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
371 "RETURN", "-w"},
372 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
373 "RETURN", "-w"},
374 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
375 "RETURN", "-w"},
376 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
377 "RETURN", "-w"},
378 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
379 "RETURN", "-w"},
380 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
381 "RETURN", "-w"},
382 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
383 "RETURN", "-w"},
384 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
385 "RETURN", "-w"},
386 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
387 "RETURN", "-w"},
388 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
389 "RETURN", "-w"},
390 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
391 "RETURN", "-w"},
392 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
393 "RETURN", "-w"},
394 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
395 "RETURN", "-w"},
396 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
397 "RETURN", "-w"},
398 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
399 "RETURN", "-w"},
400 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
401 "RETURN", "-w"},
Jie Jiangcf749152020-07-09 22:20:58 +0900402 };
403
404 for (const auto& rule : expected_calls) {
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900405 EXPECT_CALL(runner_, iptables("mangle", ElementsAreArray(rule), _, _));
406 EXPECT_CALL(runner_, ip6tables("mangle", ElementsAreArray(rule), _, _));
Jie Jiangcf749152020-07-09 22:20:58 +0900407 }
408
Hugo Benichi058a26a2020-11-26 10:10:39 +0900409 counters_svc_->OnPhysicalDeviceAdded("eth0");
410}
411
412TEST_F(CountersServiceTest, OnVpnDeviceAdded) {
413 // The following commands are expected when eth0 comes up.
414 const std::vector<std::vector<std::string>> expected_calls{
415 {"-N", "rx_vpn", "-w"},
416 {"-N", "tx_vpn", "-w"},
417 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
418 "RETURN", "-w"},
419 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
420 "RETURN", "-w"},
421 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
422 "RETURN", "-w"},
423 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
424 "RETURN", "-w"},
425 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
426 "RETURN", "-w"},
427 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
428 "RETURN", "-w"},
429 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
430 "RETURN", "-w"},
431 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
432 "RETURN", "-w"},
433 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
434 "RETURN", "-w"},
435 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
436 "RETURN", "-w"},
437 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
438 "RETURN", "-w"},
439 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
440 "RETURN", "-w"},
441 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
442 "RETURN", "-w"},
443 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
444 "RETURN", "-w"},
445 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
446 "RETURN", "-w"},
447 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
448 "RETURN", "-w"},
449 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
450 "RETURN", "-w"},
451 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
452 "RETURN", "-w"},
453 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
454 "RETURN", "-w"},
455 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
456 "RETURN", "-w"},
457 {"-A", "FORWARD", "-i", "tun0", "-j", "rx_vpn", "-w"},
458 {"-A", "INPUT", "-i", "tun0", "-j", "rx_vpn", "-w"},
459 {"-A", "POSTROUTING", "-o", "tun0", "-j", "tx_vpn", "-w"},
460 };
461
462 for (const auto& rule : expected_calls) {
463 EXPECT_CALL(runner_, iptables("mangle", ElementsAreArray(rule), _, _));
464 EXPECT_CALL(runner_, ip6tables("mangle", ElementsAreArray(rule), _, _));
465 }
466
467 counters_svc_->Init({});
468 counters_svc_->OnVpnDeviceAdded("tun0");
Jie Jiangcf749152020-07-09 22:20:58 +0900469}
470
471TEST_F(CountersServiceTest, OnSameDeviceAppearAgain) {
Hugo Benichiddf00842020-11-20 10:24:08 +0900472 // Makes the chain creation commands return false (we already have these
473 // rules).
474 EXPECT_CALL(runner_, iptables(_, Contains("-N"), _, _))
475 .WillRepeatedly(Return(1));
476 EXPECT_CALL(runner_, ip6tables(_, Contains("-N"), _, _))
477 .WillRepeatedly(Return(1));
Jie Jiangcf749152020-07-09 22:20:58 +0900478
479 // Creating chains commands are expected but no more creating rules command
480 // (with "-I" or "-A") should come.
Hugo Benichiddf00842020-11-20 10:24:08 +0900481 EXPECT_CALL(runner_, iptables(_, Contains("-A"), _, _)).Times(0);
482 EXPECT_CALL(runner_, ip6tables(_, Contains("-A"), _, _)).Times(0);
483 EXPECT_CALL(runner_, iptables(_, Contains("-I"), _, _)).Times(0);
484 EXPECT_CALL(runner_, ip6tables(_, Contains("-I"), _, _)).Times(0);
Jie Jiangcf749152020-07-09 22:20:58 +0900485
Hugo Benichi058a26a2020-11-26 10:10:39 +0900486 counters_svc_->OnPhysicalDeviceAdded("eth0");
Jie Jiangcf749152020-07-09 22:20:58 +0900487}
488
Jie Jiang8fd0ace2020-09-01 14:51:57 +0900489TEST_F(CountersServiceTest, ChainNameLength) {
Jie Jiang8fd0ace2020-09-01 14:51:57 +0900490 // The name of a new chain must be shorter than 29 characters, otherwise
491 // iptables will reject the request. Uses Each() here for simplicity since no
492 // other params could be longer than 29 for now.
493 static constexpr int kMaxChainNameLength = 29;
494 EXPECT_CALL(runner_, iptables(_, Each(SizeIs(Lt(kMaxChainNameLength))), _, _))
495 .Times(AnyNumber());
496 EXPECT_CALL(runner_,
497 ip6tables(_, Each(SizeIs(Lt(kMaxChainNameLength))), _, _))
498 .Times(AnyNumber());
499
500 static const std::string kLongInterfaceName(IFNAMSIZ, 'a');
Hugo Benichi058a26a2020-11-26 10:10:39 +0900501 counters_svc_->OnPhysicalDeviceAdded(kLongInterfaceName);
Jie Jiang8fd0ace2020-09-01 14:51:57 +0900502}
503
Jie Jianged0b1cc2020-07-10 15:55:33 +0900504TEST_F(CountersServiceTest, QueryTrafficCounters) {
505 EXPECT_CALL(runner_, iptables(_, _, _, _))
506 .WillRepeatedly(DoAll(SetArgPointee<3>(kIptablesOutput), Return(0)));
507 EXPECT_CALL(runner_, ip6tables(_, _, _, _))
508 .WillRepeatedly(DoAll(SetArgPointee<3>(kIptablesOutput), Return(0)));
509
510 auto actual = counters_svc_->GetCounters({});
511
Hugo Benichi92fa2032020-11-20 17:47:32 +0900512 // The expected counters for eth0 and wlan0. All values are doubled because
513 // the same output will be returned for both iptables and ip6tables in the
514 // tests.
Jie Jianged0b1cc2020-07-10 15:55:33 +0900515 std::map<SourceDevice, Counter> expected{
Hugo Benichi92fa2032020-11-20 17:47:32 +0900516 {{TrafficCounter::CHROME, "eth0"},
517 {23876 /*rx_bytes*/, 146 /*rx_packets*/, 488854 /*tx_bytes*/,
518 2732 /*tx_packets*/}},
519 {{TrafficCounter::UPDATE_ENGINE, "eth0"},
520 {0 /*rx_bytes*/, 0 /*rx_packets*/, 3340 /*tx_bytes*/,
521 40 /*tx_packets*/}},
522 {{TrafficCounter::SYSTEM, "eth0"},
523 {1388 /*rx_bytes*/, 10 /*rx_packets*/, 276804 /*tx_bytes*/,
524 1100 /*tx_packets*/}},
525 {{TrafficCounter::ARC, "eth0"},
526 {0 /*rx_bytes*/, 0 /*rx_packets*/, 1752344 /*tx_bytes*/,
527 10748 /*tx_packets*/}},
528 {{TrafficCounter::CROSVM, "eth0"},
529 {0 /*rx_bytes*/, 0 /*rx_packets*/, 5380 /*tx_bytes*/,
530 78 /*tx_packets*/}},
531 {{TrafficCounter::CHROME, "wlan0"},
532 {56196 /*rx_bytes*/, 306 /*rx_packets*/, 114008 /*tx_bytes*/,
533 620 /*tx_packets*/}},
534 {{TrafficCounter::SYSTEM, "wlan0"},
535 {1680 /*rx_bytes*/, 12 /*rx_packets*/, 5602 /*tx_bytes*/,
536 48 /*tx_packets*/}}};
Jie Jianged0b1cc2020-07-10 15:55:33 +0900537
538 EXPECT_THAT(actual, ContainerEq(expected));
539}
540
541TEST_F(CountersServiceTest, QueryTrafficCountersWithFilter) {
542 EXPECT_CALL(runner_, iptables(_, _, _, _))
543 .WillRepeatedly(DoAll(SetArgPointee<3>(kIptablesOutput), Return(0)));
544 EXPECT_CALL(runner_, ip6tables(_, _, _, _))
545 .WillRepeatedly(DoAll(SetArgPointee<3>(kIptablesOutput), Return(0)));
546
547 // Only counters for eth0 should be returned. eth1 should be ignored.
548 auto actual = counters_svc_->GetCounters({"eth0", "eth1"});
549
Hugo Benichi92fa2032020-11-20 17:47:32 +0900550 // The expected counters for eth0. All values are doubled because
551 // the same output will be returned for both iptables and ip6tables in the
552 // tests.
Jie Jianged0b1cc2020-07-10 15:55:33 +0900553 std::map<SourceDevice, Counter> expected{
Hugo Benichi92fa2032020-11-20 17:47:32 +0900554 {{TrafficCounter::CHROME, "eth0"},
555 {23876 /*rx_bytes*/, 146 /*rx_packets*/, 488854 /*tx_bytes*/,
556 2732 /*tx_packets*/}},
557 {{TrafficCounter::UPDATE_ENGINE, "eth0"},
558 {0 /*rx_bytes*/, 0 /*rx_packets*/, 3340 /*tx_bytes*/,
559 40 /*tx_packets*/}},
560 {{TrafficCounter::SYSTEM, "eth0"},
561 {1388 /*rx_bytes*/, 10 /*rx_packets*/, 276804 /*tx_bytes*/,
562 1100 /*tx_packets*/}},
563 {{TrafficCounter::ARC, "eth0"},
564 {0 /*rx_bytes*/, 0 /*rx_packets*/, 1752344 /*tx_bytes*/,
565 10748 /*tx_packets*/}},
566 {{TrafficCounter::CROSVM, "eth0"},
567 {0 /*rx_bytes*/, 0 /*rx_packets*/, 5380 /*tx_bytes*/,
568 78 /*tx_packets*/}},
Jie Jianged0b1cc2020-07-10 15:55:33 +0900569 };
570
571 EXPECT_THAT(actual, ContainerEq(expected));
572}
573
574TEST_F(CountersServiceTest, QueryTrafficCountersWithEmptyIPv4Output) {
575 const std::string kEmptyOutput = "";
576 TestBadIptablesOutput(kEmptyOutput);
577}
578
579TEST_F(CountersServiceTest, QueryTrafficCountersWithEmptyIPv6Output) {
580 const std::string kEmptyOutput = "";
581 TestBadIp6tablesOutput(kEmptyOutput);
582}
583
584TEST_F(CountersServiceTest, QueryTrafficCountersWithOnlyChainName) {
585 const std::string kBadOutput = R"(
Hugo Benichi92fa2032020-11-20 17:47:32 +0900586Chain tx_eth0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900587 pkts bytes target prot opt in out source destination
Hugo Benichi92fa2032020-11-20 17:47:32 +0900588 6511 68041668 RETURN all -- any any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +0900589
Hugo Benichi92fa2032020-11-20 17:47:32 +0900590Chain tx_wlan0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900591)";
592 TestBadIptablesOutput(kBadOutput);
593}
594
595TEST_F(CountersServiceTest, QueryTrafficCountersWithOnlyChainNameAndHeader) {
596 const std::string kBadOutput = R"(
Hugo Benichi92fa2032020-11-20 17:47:32 +0900597Chain tx_eth0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900598 pkts bytes target prot opt in out source destination
Hugo Benichi92fa2032020-11-20 17:47:32 +0900599 6511 68041668 RETURN all -- any any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +0900600
601Chain tx_fwd_wlan0 (1 references)
602 pkts bytes target prot opt in out source destination
603)";
604 TestBadIptablesOutput(kBadOutput);
605}
606
607TEST_F(CountersServiceTest, QueryTrafficCountersWithNotFinishedCountersLine) {
608 const std::string kBadOutput = R"(
Hugo Benichi92fa2032020-11-20 17:47:32 +0900609Chain tx_eth0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900610 pkts bytes target prot opt in out source destination
Hugo Benichi92fa2032020-11-20 17:47:32 +0900611 6511 68041668 RETURN all -- any any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +0900612
Hugo Benichi92fa2032020-11-20 17:47:32 +0900613Chain tx_wlan0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900614 pkts bytes target prot opt in out source destination pkts bytes target prot opt in out source destination
615 0 )";
616 TestBadIptablesOutput(kBadOutput);
617}
618
Jie Jiangcf749152020-07-09 22:20:58 +0900619} // namespace
620} // namespace patchpanel