blob: 795d0f1a133043bfb50a04ea5c41197d4ad5555d [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
Hugo Benichiae5803d2020-12-08 10:49:48 +090095 4 123 all -- any any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +090096
Hugo Benichi33af8f72020-11-20 10:08:47 +090097Chain tx_wlan0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +090098 pkts bytes target prot opt in out source destination
Hugo Benichi92fa2032020-11-20 17:47:32 +090099 310 57004 RETURN all -- any any anywhere anywhere mark match 0x100/0x3f00
100 0 0 RETURN all -- any any anywhere anywhere mark match 0x200/0x3f00
101 0 0 RETURN all -- any any anywhere anywhere mark match 0x300/0x3f00
102 24 2801 RETURN all -- any any anywhere anywhere mark match 0x400/0x3f00
103 0 0 RETURN all -- any any anywhere anywhere mark match 0x500/0x3f00
104 0 0 RETURN all -- any any anywhere anywhere mark match 0x2000/0x3f00
105 0 0 RETURN all -- any any anywhere anywhere mark match 0x2100/0x3f00
106 0 0 RETURN all -- any any anywhere anywhere mark match 0x2200/0x3f00
107 0 0 RETURN all -- any any anywhere anywhere mark match 0x2300/0x3f00
108 0 0 RETURN all -- any any anywhere anywhere mark match 0x2400/0x3f00
Hugo Benichiae5803d2020-12-08 10:49:48 +0900109 0 0 all -- any any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +0900110
Hugo Benichi33af8f72020-11-20 10:08:47 +0900111Chain rx_eth0 (2 references)
Hugo Benichi92fa2032020-11-20 17:47:32 +0900112 pkts bytes target prot opt in out source destination
113 73 11938 RETURN all -- any any anywhere anywhere mark match 0x100/0x3f00
114 0 0 RETURN all -- any any anywhere anywhere mark match 0x200/0x3f00
115 0 0 RETURN all -- any any anywhere anywhere mark match 0x300/0x3f00
116 5 694 RETURN all -- any any anywhere anywhere mark match 0x400/0x3f00
117 0 0 RETURN all -- any any anywhere anywhere mark match 0x500/0x3f00
118 0 0 RETURN all -- any any anywhere anywhere mark match 0x2000/0x3f00
119 0 0 RETURN all -- any any anywhere anywhere mark match 0x2100/0x3f00
120 0 0 RETURN all -- any any anywhere anywhere mark match 0x2200/0x3f00
121 0 0 RETURN all -- any any anywhere anywhere mark match 0x2300/0x3f00
122 0 0 RETURN all -- any any anywhere anywhere mark match 0x2400/0x3f00
Hugo Benichiae5803d2020-12-08 10:49:48 +0900123 6 345 all -- any any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +0900124
Hugo Benichi33af8f72020-11-20 10:08:47 +0900125Chain rx_wlan0 (2 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900126 pkts bytes target prot opt in out source destination
Hugo Benichi92fa2032020-11-20 17:47:32 +0900127 153 28098 RETURN all -- any any anywhere anywhere mark match 0x100/0x3f00
128 0 0 RETURN all -- any any anywhere anywhere mark match 0x200/0x3f00
129 0 0 RETURN all -- any any anywhere anywhere mark match 0x300/0x3f00
130 6 840 RETURN all -- any any anywhere anywhere mark match 0x400/0x3f00
131 0 0 RETURN all -- any any anywhere anywhere mark match 0x500/0x3f00
132 0 0 RETURN all -- any any anywhere anywhere mark match 0x2000/0x3f00
133 0 0 RETURN all -- any any anywhere anywhere mark match 0x2100/0x3f00
134 0 0 RETURN all -- any any anywhere anywhere mark match 0x2200/0x3f00
135 0 0 RETURN all -- any any anywhere anywhere mark match 0x2300/0x3f00
136 0 0 RETURN all -- any any anywhere anywhere mark match 0x2400/0x3f00
Hugo Benichiae5803d2020-12-08 10:49:48 +0900137 0 0 all -- any any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +0900138)";
139
Jie Jiangcf749152020-07-09 22:20:58 +0900140class MockProcessRunner : public MinijailedProcessRunner {
141 public:
142 MockProcessRunner() = default;
143 ~MockProcessRunner() = default;
144
145 MOCK_METHOD(int,
146 iptables,
147 (const std::string& table,
148 const std::vector<std::string>& argv,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900149 bool log_failures,
150 std::string* output),
Jie Jiangcf749152020-07-09 22:20:58 +0900151 (override));
152 MOCK_METHOD(int,
153 ip6tables,
154 (const std::string& table,
155 const std::vector<std::string>& argv,
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900156 bool log_failures,
157 std::string* output),
Jie Jiangcf749152020-07-09 22:20:58 +0900158 (override));
159};
160
161class CountersServiceTest : public testing::Test {
162 protected:
163 void SetUp() override {
Hugo Benichicd27f4e2020-11-19 18:32:23 +0900164 datapath_ = std::make_unique<Datapath>(&runner_, &firewall_);
Hugo Benichi058a26a2020-11-26 10:10:39 +0900165 counters_svc_ =
166 std::make_unique<CountersService>(datapath_.get(), &runner_);
Jie Jiangcf749152020-07-09 22:20:58 +0900167 }
168
Hugo Benichiae5803d2020-12-08 10:49:48 +0900169 // Makes `iptables` and `ip6tables` returning |ipv4_output| and
170 // |ipv6_output|, respectively. Expects an empty map from GetCounters().
171 void TestBadIptablesOutput(const std::string& ipv4_output,
172 const std::string& ipv6_output) {
Jie Jianged0b1cc2020-07-10 15:55:33 +0900173 EXPECT_CALL(runner_, iptables(_, _, _, _))
Hugo Benichiae5803d2020-12-08 10:49:48 +0900174 .WillRepeatedly(DoAll(SetArgPointee<3>(ipv4_output), Return(0)));
Jie Jianged0b1cc2020-07-10 15:55:33 +0900175 EXPECT_CALL(runner_, ip6tables(_, _, _, _))
Hugo Benichiae5803d2020-12-08 10:49:48 +0900176 .WillRepeatedly(DoAll(SetArgPointee<3>(ipv6_output), Return(0)));
Jie Jianged0b1cc2020-07-10 15:55:33 +0900177
178 auto actual = counters_svc_->GetCounters({});
179 std::map<SourceDevice, Counter> expected;
180
181 EXPECT_THAT(actual, ContainerEq(expected));
182 }
183
Jie Jiangcf749152020-07-09 22:20:58 +0900184 MockProcessRunner runner_;
Hugo Benichicd27f4e2020-11-19 18:32:23 +0900185 MockFirewall firewall_;
Hugo Benichicd27f4e2020-11-19 18:32:23 +0900186 std::unique_ptr<Datapath> datapath_;
Jie Jiangcf749152020-07-09 22:20:58 +0900187 std::unique_ptr<CountersService> counters_svc_;
188};
189
Hugo Benichi058a26a2020-11-26 10:10:39 +0900190TEST_F(CountersServiceTest, OnCreation_WithNoDevices) {
191 // The following commands are expected when eth0 comes up.
192 const std::vector<std::vector<std::string>> expected_calls{
193 {"-N", "rx_vpn", "-w"},
194 {"-N", "tx_vpn", "-w"},
195 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
196 "RETURN", "-w"},
197 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
198 "RETURN", "-w"},
199 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
200 "RETURN", "-w"},
201 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
202 "RETURN", "-w"},
203 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
204 "RETURN", "-w"},
205 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
206 "RETURN", "-w"},
207 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
208 "RETURN", "-w"},
209 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
210 "RETURN", "-w"},
211 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
212 "RETURN", "-w"},
213 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
214 "RETURN", "-w"},
215 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
216 "RETURN", "-w"},
217 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
218 "RETURN", "-w"},
219 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
220 "RETURN", "-w"},
221 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
222 "RETURN", "-w"},
223 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
224 "RETURN", "-w"},
225 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
226 "RETURN", "-w"},
227 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
228 "RETURN", "-w"},
229 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
230 "RETURN", "-w"},
231 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
232 "RETURN", "-w"},
233 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
234 "RETURN", "-w"},
Hugo Benichiae5803d2020-12-08 10:49:48 +0900235 {"-A", "tx_vpn", "-w"},
236 {"-A", "rx_vpn", "-w"},
Hugo Benichi058a26a2020-11-26 10:10:39 +0900237 };
238
239 for (const auto& rule : expected_calls) {
240 EXPECT_CALL(runner_, iptables("mangle", ElementsAreArray(rule), _, _));
241 EXPECT_CALL(runner_, ip6tables("mangle", ElementsAreArray(rule), _, _));
242 }
243
244 counters_svc_->Init({});
245}
246
247TEST_F(CountersServiceTest, OnCreation_WithDevices) {
248 // The following commands are expected when eth0 comes up.
249 const std::vector<std::vector<std::string>> expected_calls{
250 {"-N", "rx_vpn", "-w"},
251 {"-N", "tx_vpn", "-w"},
252 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
253 "RETURN", "-w"},
254 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
255 "RETURN", "-w"},
256 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
257 "RETURN", "-w"},
258 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
259 "RETURN", "-w"},
260 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
261 "RETURN", "-w"},
262 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
263 "RETURN", "-w"},
264 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
265 "RETURN", "-w"},
266 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
267 "RETURN", "-w"},
268 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
269 "RETURN", "-w"},
270 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
271 "RETURN", "-w"},
272 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
273 "RETURN", "-w"},
274 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
275 "RETURN", "-w"},
276 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
277 "RETURN", "-w"},
278 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
279 "RETURN", "-w"},
280 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
281 "RETURN", "-w"},
282 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
283 "RETURN", "-w"},
284 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
285 "RETURN", "-w"},
286 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
287 "RETURN", "-w"},
288 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
289 "RETURN", "-w"},
290 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
291 "RETURN", "-w"},
Hugo Benichiae5803d2020-12-08 10:49:48 +0900292 {"-A", "tx_vpn", "-w"},
293 {"-A", "rx_vpn", "-w"},
Hugo Benichi058a26a2020-11-26 10:10:39 +0900294 {"-N", "rx_wlan0", "-w"},
295 {"-N", "tx_wlan0", "-w"},
296 {"-A", "INPUT", "-i", "wlan0", "-j", "rx_wlan0", "-w"},
297 {"-A", "FORWARD", "-i", "wlan0", "-j", "rx_wlan0", "-w"},
298 {"-A", "POSTROUTING", "-o", "wlan0", "-j", "tx_wlan0", "-w"},
299 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
300 "RETURN", "-w"},
301 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
302 "RETURN", "-w"},
303 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
304 "RETURN", "-w"},
305 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
306 "RETURN", "-w"},
307 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
308 "RETURN", "-w"},
309 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
310 "RETURN", "-w"},
311 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
312 "RETURN", "-w"},
313 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
314 "RETURN", "-w"},
315 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
316 "RETURN", "-w"},
317 {"-A", "tx_wlan0", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
318 "RETURN", "-w"},
319 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
320 "RETURN", "-w"},
321 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
322 "RETURN", "-w"},
323 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
324 "RETURN", "-w"},
325 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
326 "RETURN", "-w"},
327 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
328 "RETURN", "-w"},
329 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
330 "RETURN", "-w"},
331 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
332 "RETURN", "-w"},
333 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
334 "RETURN", "-w"},
335 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
336 "RETURN", "-w"},
337 {"-A", "rx_wlan0", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
338 "RETURN", "-w"},
Hugo Benichiae5803d2020-12-08 10:49:48 +0900339 {"-A", "tx_wlan0", "-w"},
340 {"-A", "rx_wlan0", "-w"},
Hugo Benichi058a26a2020-11-26 10:10:39 +0900341 };
342
343 for (const auto& rule : expected_calls) {
344 EXPECT_CALL(runner_, iptables("mangle", ElementsAreArray(rule), _, _));
345 EXPECT_CALL(runner_, ip6tables("mangle", ElementsAreArray(rule), _, _));
346 }
347
348 counters_svc_->Init({"wlan0"});
349}
350
351TEST_F(CountersServiceTest, OnPhysicalDeviceAdded) {
Jie Jiangcf749152020-07-09 22:20:58 +0900352 // The following commands are expected when eth0 comes up.
353 const std::vector<std::vector<std::string>> expected_calls{
Hugo Benichi33af8f72020-11-20 10:08:47 +0900354 {"-N", "rx_eth0", "-w"},
Hugo Benichiaf2021b2020-11-20 14:07:16 +0900355 {"-N", "tx_eth0", "-w"},
Hugo Benichi33af8f72020-11-20 10:08:47 +0900356 {"-A", "INPUT", "-i", "eth0", "-j", "rx_eth0", "-w"},
357 {"-A", "FORWARD", "-i", "eth0", "-j", "rx_eth0", "-w"},
Hugo Benichi33af8f72020-11-20 10:08:47 +0900358 {"-A", "POSTROUTING", "-o", "eth0", "-j", "tx_eth0", "-w"},
Hugo Benichiaf2021b2020-11-20 14:07:16 +0900359 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
360 "RETURN", "-w"},
361 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
362 "RETURN", "-w"},
363 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
364 "RETURN", "-w"},
365 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
366 "RETURN", "-w"},
367 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
368 "RETURN", "-w"},
369 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
370 "RETURN", "-w"},
371 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
372 "RETURN", "-w"},
373 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
374 "RETURN", "-w"},
375 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
376 "RETURN", "-w"},
377 {"-A", "tx_eth0", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
378 "RETURN", "-w"},
379 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
380 "RETURN", "-w"},
381 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
382 "RETURN", "-w"},
383 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
384 "RETURN", "-w"},
385 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
386 "RETURN", "-w"},
387 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
388 "RETURN", "-w"},
389 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
390 "RETURN", "-w"},
391 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
392 "RETURN", "-w"},
393 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
394 "RETURN", "-w"},
395 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
396 "RETURN", "-w"},
397 {"-A", "rx_eth0", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
398 "RETURN", "-w"},
Hugo Benichiae5803d2020-12-08 10:49:48 +0900399 {"-A", "tx_eth0", "-w"},
400 {"-A", "rx_eth0", "-w"},
Jie Jiangcf749152020-07-09 22:20:58 +0900401 };
402
403 for (const auto& rule : expected_calls) {
Jie Jiangcf5ce9c2020-07-14 17:22:03 +0900404 EXPECT_CALL(runner_, iptables("mangle", ElementsAreArray(rule), _, _));
405 EXPECT_CALL(runner_, ip6tables("mangle", ElementsAreArray(rule), _, _));
Jie Jiangcf749152020-07-09 22:20:58 +0900406 }
407
Hugo Benichi058a26a2020-11-26 10:10:39 +0900408 counters_svc_->OnPhysicalDeviceAdded("eth0");
409}
410
411TEST_F(CountersServiceTest, OnVpnDeviceAdded) {
412 // The following commands are expected when eth0 comes up.
413 const std::vector<std::vector<std::string>> expected_calls{
414 {"-N", "rx_vpn", "-w"},
415 {"-N", "tx_vpn", "-w"},
416 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
417 "RETURN", "-w"},
418 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
419 "RETURN", "-w"},
420 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
421 "RETURN", "-w"},
422 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
423 "RETURN", "-w"},
424 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
425 "RETURN", "-w"},
426 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
427 "RETURN", "-w"},
428 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
429 "RETURN", "-w"},
430 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
431 "RETURN", "-w"},
432 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
433 "RETURN", "-w"},
434 {"-A", "tx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
435 "RETURN", "-w"},
436 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000100/0x00003f00", "-j",
437 "RETURN", "-w"},
438 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000200/0x00003f00", "-j",
439 "RETURN", "-w"},
440 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000300/0x00003f00", "-j",
441 "RETURN", "-w"},
442 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000400/0x00003f00", "-j",
443 "RETURN", "-w"},
444 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00000500/0x00003f00", "-j",
445 "RETURN", "-w"},
446 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002000/0x00003f00", "-j",
447 "RETURN", "-w"},
448 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002100/0x00003f00", "-j",
449 "RETURN", "-w"},
450 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002200/0x00003f00", "-j",
451 "RETURN", "-w"},
452 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002300/0x00003f00", "-j",
453 "RETURN", "-w"},
454 {"-A", "rx_vpn", "-m", "mark", "--mark", "0x00002400/0x00003f00", "-j",
455 "RETURN", "-w"},
Hugo Benichiae5803d2020-12-08 10:49:48 +0900456 {"-A", "tx_vpn", "-w"},
457 {"-A", "rx_vpn", "-w"},
Hugo Benichi058a26a2020-11-26 10:10:39 +0900458 {"-A", "FORWARD", "-i", "tun0", "-j", "rx_vpn", "-w"},
459 {"-A", "INPUT", "-i", "tun0", "-j", "rx_vpn", "-w"},
460 {"-A", "POSTROUTING", "-o", "tun0", "-j", "tx_vpn", "-w"},
461 };
462
463 for (const auto& rule : expected_calls) {
464 EXPECT_CALL(runner_, iptables("mangle", ElementsAreArray(rule), _, _));
465 EXPECT_CALL(runner_, ip6tables("mangle", ElementsAreArray(rule), _, _));
466 }
467
468 counters_svc_->Init({});
469 counters_svc_->OnVpnDeviceAdded("tun0");
Jie Jiangcf749152020-07-09 22:20:58 +0900470}
471
Hugo Benichi2f8a1ea2020-12-14 14:19:21 +0900472TEST_F(CountersServiceTest, OnVpnDeviceRemoved) {
473 const std::vector<std::vector<std::string>> expected_calls{
474 {"-D", "FORWARD", "-i", "ppp0", "-j", "rx_vpn", "-w"},
475 {"-D", "INPUT", "-i", "ppp0", "-j", "rx_vpn", "-w"},
476 {"-D", "POSTROUTING", "-o", "ppp0", "-j", "tx_vpn", "-w"},
477 };
478
479 for (const auto& rule : expected_calls) {
480 EXPECT_CALL(runner_, iptables("mangle", ElementsAreArray(rule), _, _));
481 EXPECT_CALL(runner_, ip6tables("mangle", ElementsAreArray(rule), _, _));
482 }
483
484 counters_svc_->OnVpnDeviceRemoved("ppp0");
485}
486
Jie Jiangcf749152020-07-09 22:20:58 +0900487TEST_F(CountersServiceTest, OnSameDeviceAppearAgain) {
Hugo Benichiddf00842020-11-20 10:24:08 +0900488 // Makes the chain creation commands return false (we already have these
489 // rules).
490 EXPECT_CALL(runner_, iptables(_, Contains("-N"), _, _))
491 .WillRepeatedly(Return(1));
492 EXPECT_CALL(runner_, ip6tables(_, Contains("-N"), _, _))
493 .WillRepeatedly(Return(1));
Jie Jiangcf749152020-07-09 22:20:58 +0900494
495 // Creating chains commands are expected but no more creating rules command
496 // (with "-I" or "-A") should come.
Hugo Benichiddf00842020-11-20 10:24:08 +0900497 EXPECT_CALL(runner_, iptables(_, Contains("-A"), _, _)).Times(0);
498 EXPECT_CALL(runner_, ip6tables(_, Contains("-A"), _, _)).Times(0);
499 EXPECT_CALL(runner_, iptables(_, Contains("-I"), _, _)).Times(0);
500 EXPECT_CALL(runner_, ip6tables(_, Contains("-I"), _, _)).Times(0);
Jie Jiangcf749152020-07-09 22:20:58 +0900501
Hugo Benichi058a26a2020-11-26 10:10:39 +0900502 counters_svc_->OnPhysicalDeviceAdded("eth0");
Jie Jiangcf749152020-07-09 22:20:58 +0900503}
504
Jie Jiang8fd0ace2020-09-01 14:51:57 +0900505TEST_F(CountersServiceTest, ChainNameLength) {
Jie Jiang8fd0ace2020-09-01 14:51:57 +0900506 // The name of a new chain must be shorter than 29 characters, otherwise
507 // iptables will reject the request. Uses Each() here for simplicity since no
508 // other params could be longer than 29 for now.
509 static constexpr int kMaxChainNameLength = 29;
510 EXPECT_CALL(runner_, iptables(_, Each(SizeIs(Lt(kMaxChainNameLength))), _, _))
511 .Times(AnyNumber());
512 EXPECT_CALL(runner_,
513 ip6tables(_, Each(SizeIs(Lt(kMaxChainNameLength))), _, _))
514 .Times(AnyNumber());
515
516 static const std::string kLongInterfaceName(IFNAMSIZ, 'a');
Hugo Benichi058a26a2020-11-26 10:10:39 +0900517 counters_svc_->OnPhysicalDeviceAdded(kLongInterfaceName);
Jie Jiang8fd0ace2020-09-01 14:51:57 +0900518}
519
Jie Jianged0b1cc2020-07-10 15:55:33 +0900520TEST_F(CountersServiceTest, QueryTrafficCounters) {
521 EXPECT_CALL(runner_, iptables(_, _, _, _))
522 .WillRepeatedly(DoAll(SetArgPointee<3>(kIptablesOutput), Return(0)));
523 EXPECT_CALL(runner_, ip6tables(_, _, _, _))
524 .WillRepeatedly(DoAll(SetArgPointee<3>(kIptablesOutput), Return(0)));
525
526 auto actual = counters_svc_->GetCounters({});
527
Hugo Benichi92fa2032020-11-20 17:47:32 +0900528 // The expected counters for eth0 and wlan0. All values are doubled because
529 // the same output will be returned for both iptables and ip6tables in the
530 // tests.
Jie Jianged0b1cc2020-07-10 15:55:33 +0900531 std::map<SourceDevice, Counter> expected{
Hugo Benichi92fa2032020-11-20 17:47:32 +0900532 {{TrafficCounter::CHROME, "eth0"},
533 {23876 /*rx_bytes*/, 146 /*rx_packets*/, 488854 /*tx_bytes*/,
534 2732 /*tx_packets*/}},
535 {{TrafficCounter::UPDATE_ENGINE, "eth0"},
536 {0 /*rx_bytes*/, 0 /*rx_packets*/, 3340 /*tx_bytes*/,
537 40 /*tx_packets*/}},
538 {{TrafficCounter::SYSTEM, "eth0"},
539 {1388 /*rx_bytes*/, 10 /*rx_packets*/, 276804 /*tx_bytes*/,
540 1100 /*tx_packets*/}},
541 {{TrafficCounter::ARC, "eth0"},
542 {0 /*rx_bytes*/, 0 /*rx_packets*/, 1752344 /*tx_bytes*/,
543 10748 /*tx_packets*/}},
544 {{TrafficCounter::CROSVM, "eth0"},
545 {0 /*rx_bytes*/, 0 /*rx_packets*/, 5380 /*tx_bytes*/,
546 78 /*tx_packets*/}},
Hugo Benichiae5803d2020-12-08 10:49:48 +0900547 {{TrafficCounter::UNKNOWN, "eth0"},
548 {690 /*rx_bytes*/, 12 /*rx_packets*/, 246 /*tx_bytes*/,
549 8 /*tx_packets*/}},
Hugo Benichi92fa2032020-11-20 17:47:32 +0900550 {{TrafficCounter::CHROME, "wlan0"},
551 {56196 /*rx_bytes*/, 306 /*rx_packets*/, 114008 /*tx_bytes*/,
552 620 /*tx_packets*/}},
553 {{TrafficCounter::SYSTEM, "wlan0"},
554 {1680 /*rx_bytes*/, 12 /*rx_packets*/, 5602 /*tx_bytes*/,
Hugo Benichiae5803d2020-12-08 10:49:48 +0900555 48 /*tx_packets*/}},
556 };
Jie Jianged0b1cc2020-07-10 15:55:33 +0900557
558 EXPECT_THAT(actual, ContainerEq(expected));
559}
560
561TEST_F(CountersServiceTest, QueryTrafficCountersWithFilter) {
562 EXPECT_CALL(runner_, iptables(_, _, _, _))
563 .WillRepeatedly(DoAll(SetArgPointee<3>(kIptablesOutput), Return(0)));
564 EXPECT_CALL(runner_, ip6tables(_, _, _, _))
565 .WillRepeatedly(DoAll(SetArgPointee<3>(kIptablesOutput), Return(0)));
566
567 // Only counters for eth0 should be returned. eth1 should be ignored.
568 auto actual = counters_svc_->GetCounters({"eth0", "eth1"});
569
Hugo Benichi92fa2032020-11-20 17:47:32 +0900570 // The expected counters for eth0. All values are doubled because
571 // the same output will be returned for both iptables and ip6tables in the
572 // tests.
Jie Jianged0b1cc2020-07-10 15:55:33 +0900573 std::map<SourceDevice, Counter> expected{
Hugo Benichi92fa2032020-11-20 17:47:32 +0900574 {{TrafficCounter::CHROME, "eth0"},
575 {23876 /*rx_bytes*/, 146 /*rx_packets*/, 488854 /*tx_bytes*/,
576 2732 /*tx_packets*/}},
577 {{TrafficCounter::UPDATE_ENGINE, "eth0"},
578 {0 /*rx_bytes*/, 0 /*rx_packets*/, 3340 /*tx_bytes*/,
579 40 /*tx_packets*/}},
580 {{TrafficCounter::SYSTEM, "eth0"},
581 {1388 /*rx_bytes*/, 10 /*rx_packets*/, 276804 /*tx_bytes*/,
582 1100 /*tx_packets*/}},
583 {{TrafficCounter::ARC, "eth0"},
584 {0 /*rx_bytes*/, 0 /*rx_packets*/, 1752344 /*tx_bytes*/,
585 10748 /*tx_packets*/}},
586 {{TrafficCounter::CROSVM, "eth0"},
587 {0 /*rx_bytes*/, 0 /*rx_packets*/, 5380 /*tx_bytes*/,
588 78 /*tx_packets*/}},
Hugo Benichiae5803d2020-12-08 10:49:48 +0900589 {{TrafficCounter::UNKNOWN, "eth0"},
590 {690 /*rx_bytes*/, 12 /*rx_packets*/, 246 /*tx_bytes*/,
591 8 /*tx_packets*/}},
592 };
593
594 EXPECT_THAT(actual, ContainerEq(expected));
595}
596
597TEST_F(CountersServiceTest, QueryTraffic_UnknownTrafficOnly) {
598 const std::string unkwown_traffic_only = R"(
599Chain tx_eth0 (1 references)
600 pkts bytes target prot opt in out source destination
601 6511 68041668 all -- any any anywhere anywhere
602)";
603
604 EXPECT_CALL(runner_, iptables(_, _, _, _))
605 .WillRepeatedly(DoAll(SetArgPointee<3>(unkwown_traffic_only), Return(0)));
606 EXPECT_CALL(runner_, ip6tables(_, _, _, _))
607 .WillRepeatedly(DoAll(SetArgPointee<3>(unkwown_traffic_only), Return(0)));
608
609 auto actual = counters_svc_->GetCounters({});
610
611 std::map<SourceDevice, Counter> expected{
612 {{TrafficCounter::UNKNOWN, "eth0"},
613 {0 /*rx_bytes*/, 0 /*rx_packets*/, 136083336 /*tx_bytes*/,
614 13022 /*tx_packets*/}},
Jie Jianged0b1cc2020-07-10 15:55:33 +0900615 };
616
617 EXPECT_THAT(actual, ContainerEq(expected));
618}
619
620TEST_F(CountersServiceTest, QueryTrafficCountersWithEmptyIPv4Output) {
Hugo Benichiae5803d2020-12-08 10:49:48 +0900621 TestBadIptablesOutput("", kIptablesOutput);
Jie Jianged0b1cc2020-07-10 15:55:33 +0900622}
623
624TEST_F(CountersServiceTest, QueryTrafficCountersWithEmptyIPv6Output) {
Hugo Benichiae5803d2020-12-08 10:49:48 +0900625 TestBadIptablesOutput(kIptablesOutput, "");
Jie Jianged0b1cc2020-07-10 15:55:33 +0900626}
627
628TEST_F(CountersServiceTest, QueryTrafficCountersWithOnlyChainName) {
629 const std::string kBadOutput = R"(
Hugo Benichi92fa2032020-11-20 17:47:32 +0900630Chain tx_eth0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900631 pkts bytes target prot opt in out source destination
Hugo Benichi92fa2032020-11-20 17:47:32 +0900632 6511 68041668 RETURN all -- any any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +0900633
Hugo Benichi92fa2032020-11-20 17:47:32 +0900634Chain tx_wlan0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900635)";
Hugo Benichiae5803d2020-12-08 10:49:48 +0900636 TestBadIptablesOutput(kBadOutput, kIptablesOutput);
Jie Jianged0b1cc2020-07-10 15:55:33 +0900637}
638
639TEST_F(CountersServiceTest, QueryTrafficCountersWithOnlyChainNameAndHeader) {
640 const std::string kBadOutput = R"(
Hugo Benichi92fa2032020-11-20 17:47:32 +0900641Chain tx_eth0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900642 pkts bytes target prot opt in out source destination
Hugo Benichi92fa2032020-11-20 17:47:32 +0900643 6511 68041668 RETURN all -- any any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +0900644
Hugo Benichiae5803d2020-12-08 10:49:48 +0900645Chain tx_wlan0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900646 pkts bytes target prot opt in out source destination
647)";
Hugo Benichiae5803d2020-12-08 10:49:48 +0900648 TestBadIptablesOutput(kBadOutput, kIptablesOutput);
Jie Jianged0b1cc2020-07-10 15:55:33 +0900649}
650
651TEST_F(CountersServiceTest, QueryTrafficCountersWithNotFinishedCountersLine) {
652 const std::string kBadOutput = R"(
Hugo Benichi92fa2032020-11-20 17:47:32 +0900653Chain tx_eth0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900654 pkts bytes target prot opt in out source destination
Hugo Benichi92fa2032020-11-20 17:47:32 +0900655 6511 68041668 RETURN all -- any any anywhere anywhere
Jie Jianged0b1cc2020-07-10 15:55:33 +0900656
Hugo Benichi92fa2032020-11-20 17:47:32 +0900657Chain tx_wlan0 (1 references)
Jie Jianged0b1cc2020-07-10 15:55:33 +0900658 pkts bytes target prot opt in out source destination pkts bytes target prot opt in out source destination
659 0 )";
Hugo Benichiae5803d2020-12-08 10:49:48 +0900660 TestBadIptablesOutput(kBadOutput, kIptablesOutput);
Jie Jianged0b1cc2020-07-10 15:55:33 +0900661}
662
Jie Jiangcf749152020-07-09 22:20:58 +0900663} // namespace
664} // namespace patchpanel