blob: b5b7e7f0c699c8ce0ea49aff9dc38c8d5aa2a229 [file] [log] [blame]
Lorenzo Colitti86a47982016-03-18 17:52:25 +09001/*
2 * Copyright 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * BandwidthControllerTest.cpp - unit tests for BandwidthController.cpp
17 */
18
19#include <string>
20#include <vector>
Lorenzo Colitti86a47982016-03-18 17:52:25 +090021
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +090022#include <inttypes.h>
Lorenzo Colittibbeaf9a2016-07-08 18:24:26 +090023#include <fcntl.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/socket.h>
27
Lorenzo Colitti86a47982016-03-18 17:52:25 +090028#include <gtest/gtest.h>
29
Lorenzo Colitti13debb82016-03-27 17:46:30 +090030#include <android-base/strings.h>
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +090031#include <android-base/stringprintf.h>
Lorenzo Colitti13debb82016-03-27 17:46:30 +090032
Joel Scherpelz01cc5492017-06-16 10:45:14 +090033#include <netdutils/MockSyscalls.h>
Lorenzo Colitti86a47982016-03-18 17:52:25 +090034#include "BandwidthController.h"
Benedict Wongb9baf262017-12-03 15:43:08 -080035#include "Fwmark.h"
Lorenzo Colitti0f150552016-03-28 02:30:27 +090036#include "IptablesBaseTest.h"
Chenbo Fenga121e202018-03-19 11:51:54 -070037#include "bpf/BpfUtils.h"
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +090038#include "tun_interface.h"
39
Joel Scherpelz01cc5492017-06-16 10:45:14 +090040using ::testing::ByMove;
41using ::testing::Invoke;
42using ::testing::Return;
43using ::testing::StrictMock;
44using ::testing::Test;
45using ::testing::_;
46
Lorenzo Colitti48f83002017-07-06 15:06:04 +090047using android::base::Join;
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +090048using android::base::StringPrintf;
Chenbo Feng95892f32018-06-07 14:52:02 -070049using android::bpf::XT_BPF_BLACKLIST_PROG_PATH;
Chenbo Fenga121e202018-03-19 11:51:54 -070050using android::bpf::XT_BPF_EGRESS_PROG_PATH;
51using android::bpf::XT_BPF_INGRESS_PROG_PATH;
Chenbo Feng95892f32018-06-07 14:52:02 -070052using android::bpf::XT_BPF_WHITELIST_PROG_PATH;
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +090053using android::net::TunInterface;
Joel Scherpelz01cc5492017-06-16 10:45:14 +090054using android::netdutils::status::ok;
55using android::netdutils::UniqueFile;
Lorenzo Colitti86a47982016-03-18 17:52:25 +090056
Chenbo Feng44c0f442018-07-10 16:54:30 -070057const std::string ACCOUNT_RULES_WITHOUT_BPF =
58 "*filter\n"
59 "-A bw_INPUT -p esp -j RETURN\n"
60 "-A bw_INPUT -m mark --mark 0x100000/0x100000 -j RETURN\n"
61 "-A bw_INPUT -m owner --socket-exists\n"
62 "-A bw_INPUT -j MARK --or-mark 0x100000\n"
63 "-A bw_OUTPUT -o ipsec+ -j RETURN\n"
64 "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN\n"
65 "-A bw_OUTPUT -m owner --socket-exists\n"
66 "-A bw_costly_shared --jump bw_penalty_box\n"
67 "\n"
68 "-A bw_penalty_box --jump bw_happy_box\n"
69 "-A bw_happy_box --jump bw_data_saver\n"
70 "-A bw_data_saver -j RETURN\n"
71 "-I bw_happy_box -m owner --uid-owner 0-9999 --jump RETURN\n"
72 "COMMIT\n"
73 "*raw\n"
74 "-A bw_raw_PREROUTING -i ipsec+ -j RETURN\n"
75 "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n"
76 "-A bw_raw_PREROUTING -m owner --socket-exists\n"
77 "COMMIT\n"
78 "*mangle\n"
79 "-A bw_mangle_POSTROUTING -o ipsec+ -j RETURN\n"
80 "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
81 "-A bw_mangle_POSTROUTING -m owner --socket-exists\n"
82 "-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x100000\n"
83 "\n"
84 "COMMIT\n";
85
86const std::string ACCOUNT_RULES_WITH_BPF =
87 "*filter\n"
88 "-A bw_INPUT -p esp -j RETURN\n"
89 "-A bw_INPUT -m mark --mark 0x100000/0x100000 -j RETURN\n"
90 "\n"
91 "-A bw_INPUT -j MARK --or-mark 0x100000\n"
92 "-A bw_OUTPUT -o ipsec+ -j RETURN\n"
93 "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN\n"
94 "\n"
95 "-A bw_costly_shared --jump bw_penalty_box\n" +
96 StringPrintf("-I bw_penalty_box -m bpf --object-pinned %s -j REJECT\n",
97 XT_BPF_BLACKLIST_PROG_PATH) +
98 "-A bw_penalty_box --jump bw_happy_box\n"
99 "-A bw_happy_box --jump bw_data_saver\n"
100 "-A bw_data_saver -j RETURN\n" +
101 StringPrintf("-I bw_happy_box -m bpf --object-pinned %s -j RETURN\n",
102 XT_BPF_WHITELIST_PROG_PATH) +
103 "COMMIT\n"
104 "*raw\n"
105 "-A bw_raw_PREROUTING -i ipsec+ -j RETURN\n"
106 "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n" +
107 StringPrintf("-A bw_raw_PREROUTING -m bpf --object-pinned %s\n", XT_BPF_INGRESS_PROG_PATH) +
108 "COMMIT\n"
109 "*mangle\n"
110 "-A bw_mangle_POSTROUTING -o ipsec+ -j RETURN\n"
111 "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
112 "\n"
113 "-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x100000\n" +
114 StringPrintf("-A bw_mangle_POSTROUTING -m bpf --object-pinned %s\n",
115 XT_BPF_EGRESS_PROG_PATH) +
116 "COMMIT\n";
117
Lorenzo Colitti0f150552016-03-28 02:30:27 +0900118class BandwidthControllerTest : public IptablesBaseTest {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900119protected:
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900120 BandwidthControllerTest() {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900121 BandwidthController::iptablesRestoreFunction = fakeExecIptablesRestoreWithOutput;
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900122 }
123 BandwidthController mBw;
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900124 TunInterface mTun;
125
126 void SetUp() {
127 ASSERT_EQ(0, mTun.init());
128 }
129
130 void TearDown() {
131 mTun.destroy();
132 }
Lorenzo Colittibbeaf9a2016-07-08 18:24:26 +0900133
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900134 void expectSetupCommands(const std::string& expectedClean, std::string expectedAccounting) {
135 std::string expectedList =
136 "*filter\n"
137 "-S\n"
138 "COMMIT\n";
139
140 std::string expectedFlush =
141 "*filter\n"
142 ":bw_INPUT -\n"
143 ":bw_OUTPUT -\n"
144 ":bw_FORWARD -\n"
145 ":bw_happy_box -\n"
146 ":bw_penalty_box -\n"
147 ":bw_data_saver -\n"
148 ":bw_costly_shared -\n"
149 "COMMIT\n"
150 "*raw\n"
151 ":bw_raw_PREROUTING -\n"
152 "COMMIT\n"
153 "*mangle\n"
154 ":bw_mangle_POSTROUTING -\n"
155 "COMMIT\n";
156
157 ExpectedIptablesCommands expected = {{ V4, expectedList }};
158 if (expectedClean.size()) {
159 expected.push_back({ V4V6, expectedClean });
160 }
161 expected.push_back({ V4V6, expectedFlush });
162 if (expectedAccounting.size()) {
163 expected.push_back({ V4V6, expectedAccounting });
164 }
165
166 expectIptablesRestoreCommands(expected);
167 }
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900168
169 using IptOp = BandwidthController::IptOp;
170
171 int runIptablesAlertCmd(IptOp a, const char *b, int64_t c) {
172 return mBw.runIptablesAlertCmd(a, b, c);
173 }
174
175 int runIptablesAlertFwdCmd(IptOp a, const char *b, int64_t c) {
176 return mBw.runIptablesAlertFwdCmd(a, b, c);
177 }
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900178
Bernie Innocenti7e25ec02018-07-02 19:32:17 +0900179 int setCostlyAlert(const std::string& a, int64_t b, int64_t* c) {
Lorenzo Colitti38078222017-07-06 17:27:23 +0900180 return mBw.setCostlyAlert(a, b, c);
181 }
182
Bernie Innocenti7e25ec02018-07-02 19:32:17 +0900183 int removeCostlyAlert(const std::string& a, int64_t* b) { return mBw.removeCostlyAlert(a, b); }
Lorenzo Colitti38078222017-07-06 17:27:23 +0900184
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900185 void expectUpdateQuota(uint64_t quota) {
186 uintptr_t dummy;
187 FILE* dummyFile = reinterpret_cast<FILE*>(&dummy);
188
189 EXPECT_CALL(mSyscalls, fopen(_, _)).WillOnce(Return(ByMove(UniqueFile(dummyFile))));
190 EXPECT_CALL(mSyscalls, vfprintf(dummyFile, _, _))
191 .WillOnce(Invoke([quota](FILE*, const std::string&, va_list ap) {
192 EXPECT_EQ(quota, va_arg(ap, uint64_t));
193 return 0;
194 }));
195 EXPECT_CALL(mSyscalls, fclose(dummyFile)).WillOnce(Return(ok));
196 }
197
Chenbo Feng44c0f442018-07-10 16:54:30 -0700198 void checkBandwithControl(bool useBpf) {
199 // Pretend no bw_costly_shared_<iface> rules already exist...
200 addIptablesRestoreOutput(
201 "-P OUTPUT ACCEPT\n"
202 "-N bw_costly_shared\n"
203 "-N unrelated\n");
204
205 // ... so none are flushed or deleted.
206 std::string expectedClean = "";
207
208 std::string expectedAccounting =
209 useBpf ? ACCOUNT_RULES_WITH_BPF : ACCOUNT_RULES_WITHOUT_BPF;
210 mBw.setBpfEnabled(useBpf);
Luke Huangf44a3c12018-09-07 12:10:12 +0800211 mBw.enableBandwidthControl();
Chenbo Feng44c0f442018-07-10 16:54:30 -0700212 expectSetupCommands(expectedClean, expectedAccounting);
213 }
214
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900215 StrictMock<android::netdutils::ScopedMockSyscalls> mSyscalls;
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900216};
217
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900218TEST_F(BandwidthControllerTest, TestSetupIptablesHooks) {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900219 // Pretend some bw_costly_shared_<iface> rules already exist...
220 addIptablesRestoreOutput(
221 "-P OUTPUT ACCEPT\n"
222 "-N bw_costly_rmnet_data0\n"
223 "-N bw_costly_shared\n"
224 "-N unrelated\n"
225 "-N bw_costly_rmnet_data7\n");
226
227 // ... and expect that they be flushed and deleted.
228 std::string expectedCleanCmds =
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900229 "*filter\n"
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900230 ":bw_costly_rmnet_data0 -\n"
231 "-X bw_costly_rmnet_data0\n"
232 ":bw_costly_rmnet_data7 -\n"
233 "-X bw_costly_rmnet_data7\n"
234 "COMMIT\n";
235
236 mBw.setupIptablesHooks();
237 expectSetupCommands(expectedCleanCmds, "");
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900238}
239
Benedict Wongb9baf262017-12-03 15:43:08 -0800240TEST_F(BandwidthControllerTest, TestCheckUidBillingMask) {
241 uint32_t uidBillingMask = Fwmark::getUidBillingMask();
242
243 // If mask is non-zero, and mask & mask-1 is equal to 0, then the mask is a power of two.
244 bool isPowerOfTwo = uidBillingMask && (uidBillingMask & (uidBillingMask - 1)) == 0;
245
246 // Must be exactly a power of two
247 EXPECT_TRUE(isPowerOfTwo);
248}
249
Chenbo Feng44c0f442018-07-10 16:54:30 -0700250TEST_F(BandwidthControllerTest, TestEnableBandwidthControlWithBpf) {
251 checkBandwithControl(true);
252}
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900253
Chenbo Feng44c0f442018-07-10 16:54:30 -0700254TEST_F(BandwidthControllerTest, TestEnableBandwidthControlWithoutBpf) {
255 checkBandwithControl(false);
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900256}
257
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900258TEST_F(BandwidthControllerTest, TestDisableBandwidthControl) {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900259 // Pretend some bw_costly_shared_<iface> rules already exist...
260 addIptablesRestoreOutput(
261 "-P OUTPUT ACCEPT\n"
262 "-N bw_costly_rmnet_data0\n"
263 "-N bw_costly_shared\n"
264 "-N unrelated\n"
265 "-N bw_costly_rmnet_data7\n");
266
267 // ... and expect that they be flushed.
268 std::string expectedCleanCmds =
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900269 "*filter\n"
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900270 ":bw_costly_rmnet_data0 -\n"
271 ":bw_costly_rmnet_data7 -\n"
272 "COMMIT\n";
273
274 mBw.disableBandwidthControl();
275 expectSetupCommands(expectedCleanCmds, "");
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900276}
277
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900278TEST_F(BandwidthControllerTest, TestEnableDataSaver) {
279 mBw.enableDataSaver(true);
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900280 std::string expected4 =
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900281 "*filter\n"
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900282 ":bw_data_saver -\n"
283 "-A bw_data_saver --jump REJECT\n"
284 "COMMIT\n";
285 std::string expected6 =
286 "*filter\n"
287 ":bw_data_saver -\n"
288 "-A bw_data_saver -p icmpv6 --icmpv6-type packet-too-big -j RETURN\n"
289 "-A bw_data_saver -p icmpv6 --icmpv6-type router-solicitation -j RETURN\n"
290 "-A bw_data_saver -p icmpv6 --icmpv6-type router-advertisement -j RETURN\n"
291 "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN\n"
292 "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN\n"
293 "-A bw_data_saver -p icmpv6 --icmpv6-type redirect -j RETURN\n"
294 "-A bw_data_saver --jump REJECT\n"
295 "COMMIT\n";
296 expectIptablesRestoreCommands({
297 {V4, expected4},
298 {V6, expected6},
299 });
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900300
301 mBw.enableDataSaver(false);
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900302 std::string expected = {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900303 "*filter\n"
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900304 ":bw_data_saver -\n"
305 "-A bw_data_saver --jump RETURN\n"
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900306 "COMMIT\n"
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900307 };
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900308 expectIptablesRestoreCommands({
309 {V4, expected},
310 {V6, expected},
311 });
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900312}
Lorenzo Colittibbeaf9a2016-07-08 18:24:26 +0900313
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900314const std::vector<std::string> makeInterfaceQuotaCommands(const std::string& iface, int ruleIndex,
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900315 int64_t quota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900316 const std::string chain = "bw_costly_" + iface;
317 const char* c_chain = chain.c_str();
318 const char* c_iface = iface.c_str();
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900319 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900320 "*filter",
321 StringPrintf(":%s -", c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900322 StringPrintf("-A %s -j bw_penalty_box", c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900323 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleIndex, c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900324 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleIndex, c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900325 StringPrintf("-A bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900326 StringPrintf("-A bw_FORWARD -o %s --jump %s", c_iface, c_chain),
327 StringPrintf("-A %s -m quota2 ! --quota %" PRIu64 " --name %s --jump REJECT", c_chain,
328 quota, c_iface),
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900329 "COMMIT\n",
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900330 };
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900331 return {Join(cmds, "\n")};
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900332}
333
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900334const std::vector<std::string> removeInterfaceQuotaCommands(const std::string& iface) {
335 const std::string chain = "bw_costly_" + iface;
336 const char* c_chain = chain.c_str();
337 const char* c_iface = iface.c_str();
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900338 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900339 "*filter",
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900340 StringPrintf("-D bw_INPUT -i %s --jump %s", c_iface, c_chain),
341 StringPrintf("-D bw_OUTPUT -o %s --jump %s", c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900342 StringPrintf("-D bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900343 StringPrintf("-D bw_FORWARD -o %s --jump %s", c_iface, c_chain),
344 StringPrintf("-F %s", c_chain),
345 StringPrintf("-X %s", c_chain),
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900346 "COMMIT\n",
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900347 };
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900348 return {Join(cmds, "\n")};
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900349}
350
351TEST_F(BandwidthControllerTest, TestSetInterfaceQuota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900352 constexpr uint64_t kOldQuota = 123456;
353 const std::string iface = mTun.name();
354 std::vector<std::string> expected = makeInterfaceQuotaCommands(iface, 1, kOldQuota);
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900355
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900356 EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kOldQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900357 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900358
359 constexpr uint64_t kNewQuota = kOldQuota + 1;
360 expected = {};
361 expectUpdateQuota(kNewQuota);
362 EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kNewQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900363 expectIptablesRestoreCommands(expected);
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900364
365 expected = removeInterfaceQuotaCommands(iface);
366 EXPECT_EQ(0, mBw.removeInterfaceQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900367 expectIptablesRestoreCommands(expected);
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900368}
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900369
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900370const std::vector<std::string> makeInterfaceSharedQuotaCommands(const std::string& iface,
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900371 int ruleIndex, int64_t quota,
372 bool insertQuota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900373 const std::string chain = "bw_costly_shared";
374 const char* c_chain = chain.c_str();
375 const char* c_iface = iface.c_str();
376 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900377 "*filter",
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900378 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleIndex, c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900379 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleIndex, c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900380 StringPrintf("-A bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900381 StringPrintf("-A bw_FORWARD -o %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900382 };
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900383 if (insertQuota) {
384 cmds.push_back(StringPrintf(
385 "-I %s -m quota2 ! --quota %" PRIu64 " --name shared --jump REJECT", c_chain, quota));
386 }
387 cmds.push_back("COMMIT\n");
388 return {Join(cmds, "\n")};
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900389}
390
391const std::vector<std::string> removeInterfaceSharedQuotaCommands(const std::string& iface,
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900392 int64_t quota, bool deleteQuota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900393 const std::string chain = "bw_costly_shared";
394 const char* c_chain = chain.c_str();
395 const char* c_iface = iface.c_str();
396 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900397 "*filter",
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900398 StringPrintf("-D bw_INPUT -i %s --jump %s", c_iface, c_chain),
399 StringPrintf("-D bw_OUTPUT -o %s --jump %s", c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900400 StringPrintf("-D bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900401 StringPrintf("-D bw_FORWARD -o %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900402 };
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900403 if (deleteQuota) {
404 cmds.push_back(StringPrintf(
405 "-D %s -m quota2 ! --quota %" PRIu64 " --name shared --jump REJECT", c_chain, quota));
406 }
407 cmds.push_back("COMMIT\n");
408 return {Join(cmds, "\n")};
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900409}
410
411TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaDuplicate) {
412 constexpr uint64_t kQuota = 123456;
413 const std::string iface = mTun.name();
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900414 std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, 123456, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900415 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900416 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900417
418 expected = {};
419 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900420 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900421
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900422 expected = removeInterfaceSharedQuotaCommands(iface, kQuota, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900423 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900424 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900425}
426
427TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaUpdate) {
428 constexpr uint64_t kOldQuota = 123456;
429 const std::string iface = mTun.name();
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900430 std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, kOldQuota, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900431 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kOldQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900432 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900433
434 constexpr uint64_t kNewQuota = kOldQuota + 1;
435 expected = {};
436 expectUpdateQuota(kNewQuota);
437 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kNewQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900438 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900439
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900440 expected = removeInterfaceSharedQuotaCommands(iface, kNewQuota, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900441 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900442 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900443}
444
445TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaTwoInterfaces) {
446 constexpr uint64_t kQuota = 123456;
447 const std::vector<std::string> ifaces{
448 {"a" + mTun.name()},
449 {"b" + mTun.name()},
450 };
451
452 for (const auto& iface : ifaces) {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900453 // Quota rule is only added when the total number of
454 // interfaces transitions from 0 -> 1.
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900455 bool first = (iface == ifaces[0]);
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900456 auto expected = makeInterfaceSharedQuotaCommands(iface, 1, kQuota, first);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900457 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900458 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900459 }
460
461 for (const auto& iface : ifaces) {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900462 // Quota rule is only removed when the total number of
463 // interfaces transitions from 1 -> 0.
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900464 bool last = (iface == ifaces[1]);
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900465 auto expected = removeInterfaceSharedQuotaCommands(iface, kQuota, last);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900466 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900467 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900468 }
469}
470
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900471TEST_F(BandwidthControllerTest, IptablesAlertCmd) {
472 std::vector<std::string> expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900473 "*filter\n"
474 "-I bw_INPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
475 "-I bw_OUTPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
476 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900477 };
478 EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900479 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900480
481 expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900482 "*filter\n"
483 "-D bw_INPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
484 "-D bw_OUTPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
485 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900486 };
487 EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900488 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900489}
490
491TEST_F(BandwidthControllerTest, IptablesAlertFwdCmd) {
492 std::vector<std::string> expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900493 "*filter\n"
494 "-I bw_FORWARD -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
495 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900496 };
497 EXPECT_EQ(0, runIptablesAlertFwdCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900498 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900499
500 expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900501 "*filter\n"
502 "-D bw_FORWARD -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
503 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900504 };
505 EXPECT_EQ(0, runIptablesAlertFwdCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900506 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900507}
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900508
Lorenzo Colitti38078222017-07-06 17:27:23 +0900509TEST_F(BandwidthControllerTest, CostlyAlert) {
510 const int64_t kQuota = 123456;
511 int64_t alertBytes = 0;
512
513 std::vector<std::string> expected = {
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900514 "*filter\n"
515 "-A bw_costly_shared -m quota2 ! --quota 123456 --name sharedAlert\n"
516 "COMMIT\n"
Lorenzo Colitti38078222017-07-06 17:27:23 +0900517 };
518 EXPECT_EQ(0, setCostlyAlert("shared", kQuota, &alertBytes));
519 EXPECT_EQ(kQuota, alertBytes);
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900520 expectIptablesRestoreCommands(expected);
Lorenzo Colitti38078222017-07-06 17:27:23 +0900521
522 expected = {};
523 expectUpdateQuota(kQuota);
524 EXPECT_EQ(0, setCostlyAlert("shared", kQuota + 1, &alertBytes));
525 EXPECT_EQ(kQuota + 1, alertBytes);
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900526 expectIptablesRestoreCommands(expected);
Lorenzo Colitti38078222017-07-06 17:27:23 +0900527
528 expected = {
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900529 "*filter\n"
Lorenzo Colitti38078222017-07-06 17:27:23 +0900530 "-D bw_costly_shared -m quota2 ! --quota 123457 --name sharedAlert\n"
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900531 "COMMIT\n"
Lorenzo Colitti38078222017-07-06 17:27:23 +0900532 };
533 EXPECT_EQ(0, removeCostlyAlert("shared", &alertBytes));
534 EXPECT_EQ(0, alertBytes);
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900535 expectIptablesRestoreCommands(expected);
Lorenzo Colitti38078222017-07-06 17:27:23 +0900536}
537
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900538TEST_F(BandwidthControllerTest, ManipulateSpecialApps) {
539 std::vector<const char *> appUids = { "1000", "1001", "10012" };
540
541 std::vector<std::string> expected = {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900542 "*filter\n"
543 "-I bw_happy_box -m owner --uid-owner 1000 --jump RETURN\n"
544 "-I bw_happy_box -m owner --uid-owner 1001 --jump RETURN\n"
545 "-I bw_happy_box -m owner --uid-owner 10012 --jump RETURN\n"
546 "COMMIT\n"
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900547 };
548 EXPECT_EQ(0, mBw.addNiceApps(appUids.size(), const_cast<char**>(&appUids[0])));
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900549 expectIptablesRestoreCommands(expected);
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900550
551 expected = {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900552 "*filter\n"
553 "-D bw_penalty_box -m owner --uid-owner 1000 --jump REJECT\n"
554 "-D bw_penalty_box -m owner --uid-owner 1001 --jump REJECT\n"
555 "-D bw_penalty_box -m owner --uid-owner 10012 --jump REJECT\n"
556 "COMMIT\n"
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900557 };
558 EXPECT_EQ(0, mBw.removeNaughtyApps(appUids.size(), const_cast<char**>(&appUids[0])));
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900559 expectIptablesRestoreCommands(expected);
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900560}