blob: 7a3a057367650db72fb4b9c08eec6f72cd687a1d [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
Lorenzo Colitti0f150552016-03-28 02:30:27 +090057class BandwidthControllerTest : public IptablesBaseTest {
Joel Scherpelz01cc5492017-06-16 10:45:14 +090058protected:
Lorenzo Colitti86a47982016-03-18 17:52:25 +090059 BandwidthControllerTest() {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +090060 BandwidthController::iptablesRestoreFunction = fakeExecIptablesRestoreWithOutput;
Lorenzo Colitti86a47982016-03-18 17:52:25 +090061 }
62 BandwidthController mBw;
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +090063 TunInterface mTun;
64
65 void SetUp() {
66 ASSERT_EQ(0, mTun.init());
67 }
68
69 void TearDown() {
70 mTun.destroy();
71 }
Lorenzo Colittibbeaf9a2016-07-08 18:24:26 +090072
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +090073 void expectSetupCommands(const std::string& expectedClean, std::string expectedAccounting) {
74 std::string expectedList =
75 "*filter\n"
76 "-S\n"
77 "COMMIT\n";
78
79 std::string expectedFlush =
80 "*filter\n"
81 ":bw_INPUT -\n"
82 ":bw_OUTPUT -\n"
83 ":bw_FORWARD -\n"
84 ":bw_happy_box -\n"
85 ":bw_penalty_box -\n"
86 ":bw_data_saver -\n"
87 ":bw_costly_shared -\n"
88 "COMMIT\n"
89 "*raw\n"
90 ":bw_raw_PREROUTING -\n"
91 "COMMIT\n"
92 "*mangle\n"
93 ":bw_mangle_POSTROUTING -\n"
94 "COMMIT\n";
95
96 ExpectedIptablesCommands expected = {{ V4, expectedList }};
97 if (expectedClean.size()) {
98 expected.push_back({ V4V6, expectedClean });
99 }
100 expected.push_back({ V4V6, expectedFlush });
101 if (expectedAccounting.size()) {
102 expected.push_back({ V4V6, expectedAccounting });
103 }
104
105 expectIptablesRestoreCommands(expected);
106 }
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900107
108 using IptOp = BandwidthController::IptOp;
109
110 int runIptablesAlertCmd(IptOp a, const char *b, int64_t c) {
111 return mBw.runIptablesAlertCmd(a, b, c);
112 }
113
114 int runIptablesAlertFwdCmd(IptOp a, const char *b, int64_t c) {
115 return mBw.runIptablesAlertFwdCmd(a, b, c);
116 }
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900117
Bernie Innocenti7e25ec02018-07-02 19:32:17 +0900118 int setCostlyAlert(const std::string& a, int64_t b, int64_t* c) {
Lorenzo Colitti38078222017-07-06 17:27:23 +0900119 return mBw.setCostlyAlert(a, b, c);
120 }
121
Bernie Innocenti7e25ec02018-07-02 19:32:17 +0900122 int removeCostlyAlert(const std::string& a, int64_t* b) { return mBw.removeCostlyAlert(a, b); }
Lorenzo Colitti38078222017-07-06 17:27:23 +0900123
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900124 void expectUpdateQuota(uint64_t quota) {
125 uintptr_t dummy;
126 FILE* dummyFile = reinterpret_cast<FILE*>(&dummy);
127
128 EXPECT_CALL(mSyscalls, fopen(_, _)).WillOnce(Return(ByMove(UniqueFile(dummyFile))));
129 EXPECT_CALL(mSyscalls, vfprintf(dummyFile, _, _))
130 .WillOnce(Invoke([quota](FILE*, const std::string&, va_list ap) {
131 EXPECT_EQ(quota, va_arg(ap, uint64_t));
132 return 0;
133 }));
134 EXPECT_CALL(mSyscalls, fclose(dummyFile)).WillOnce(Return(ok));
135 }
136
137 StrictMock<android::netdutils::ScopedMockSyscalls> mSyscalls;
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900138};
139
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900140TEST_F(BandwidthControllerTest, TestSetupIptablesHooks) {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900141 // Pretend some bw_costly_shared_<iface> rules already exist...
142 addIptablesRestoreOutput(
143 "-P OUTPUT ACCEPT\n"
144 "-N bw_costly_rmnet_data0\n"
145 "-N bw_costly_shared\n"
146 "-N unrelated\n"
147 "-N bw_costly_rmnet_data7\n");
148
149 // ... and expect that they be flushed and deleted.
150 std::string expectedCleanCmds =
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900151 "*filter\n"
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900152 ":bw_costly_rmnet_data0 -\n"
153 "-X bw_costly_rmnet_data0\n"
154 ":bw_costly_rmnet_data7 -\n"
155 "-X bw_costly_rmnet_data7\n"
156 "COMMIT\n";
157
158 mBw.setupIptablesHooks();
159 expectSetupCommands(expectedCleanCmds, "");
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900160}
161
Benedict Wongb9baf262017-12-03 15:43:08 -0800162TEST_F(BandwidthControllerTest, TestCheckUidBillingMask) {
163 uint32_t uidBillingMask = Fwmark::getUidBillingMask();
164
165 // If mask is non-zero, and mask & mask-1 is equal to 0, then the mask is a power of two.
166 bool isPowerOfTwo = uidBillingMask && (uidBillingMask & (uidBillingMask - 1)) == 0;
167
168 // Must be exactly a power of two
169 EXPECT_TRUE(isPowerOfTwo);
170}
171
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900172TEST_F(BandwidthControllerTest, TestEnableBandwidthControl) {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900173 // Pretend no bw_costly_shared_<iface> rules already exist...
174 addIptablesRestoreOutput(
175 "-P OUTPUT ACCEPT\n"
176 "-N bw_costly_shared\n"
177 "-N unrelated\n");
178
179 // ... so none are flushed or deleted.
180 std::string expectedClean = "";
181
Benedict Wongb9baf262017-12-03 15:43:08 -0800182 uint32_t uidBillingMask = Fwmark::getUidBillingMask();
Chenbo Feng95892f32018-06-07 14:52:02 -0700183 bool useBpf = BandwidthController::getBpfStatus();
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900184 std::string expectedAccounting =
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900185 "*filter\n"
Benedict Wongb9baf262017-12-03 15:43:08 -0800186 "-A bw_INPUT -p esp -j RETURN\n" +
187 StringPrintf("-A bw_INPUT -m mark --mark 0x%x/0x%x -j RETURN\n",
188 uidBillingMask, uidBillingMask) +
189 "-A bw_INPUT -m owner --socket-exists\n" +
190 StringPrintf("-A bw_INPUT -j MARK --or-mark 0x%x\n", uidBillingMask) +
191 "-A bw_OUTPUT -o " IPSEC_IFACE_PREFIX "+ -j RETURN\n"
192 "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN\n"
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900193 "-A bw_OUTPUT -m owner --socket-exists\n"
Chenbo Feng95892f32018-06-07 14:52:02 -0700194 "-A bw_costly_shared --jump bw_penalty_box\n";
195 if (useBpf) {
196 expectedAccounting +=
197 StringPrintf("-I bw_penalty_box -m bpf --object-pinned %s -j REJECT\n",
198 XT_BPF_BLACKLIST_PROG_PATH) +
199 "-A bw_penalty_box --jump bw_happy_box\n" +
200 "-A bw_happy_box --jump bw_data_saver\n"
201 "-A bw_data_saver -j RETURN\n" +
202 StringPrintf("-I bw_happy_box -m bpf --object-pinned %s -j RETURN\n",
203 XT_BPF_WHITELIST_PROG_PATH);
204 } else {
205 expectedAccounting +=
206 "\n-A bw_penalty_box --jump bw_happy_box\n"
207 "-A bw_happy_box --jump bw_data_saver\n"
208 "-A bw_data_saver -j RETURN\n"
209 "-I bw_happy_box -m owner --uid-owner 0-9999 --jump RETURN\n";
210 }
211 expectedAccounting +=
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900212 "COMMIT\n"
213 "*raw\n"
Benedict Wongb9baf262017-12-03 15:43:08 -0800214 "-A bw_raw_PREROUTING -i " IPSEC_IFACE_PREFIX "+ -j RETURN\n"
215 "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n"
Chenbo Fenga121e202018-03-19 11:51:54 -0700216 "-A bw_raw_PREROUTING -m owner --socket-exists\n";
217 if (useBpf) {
218 expectedAccounting += StringPrintf("-A bw_raw_PREROUTING -m bpf --object-pinned %s\n",
219 XT_BPF_INGRESS_PROG_PATH);
220 } else {
221 expectedAccounting += "\n";
222 }
223 expectedAccounting +=
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900224 "COMMIT\n"
225 "*mangle\n"
Benedict Wongb9baf262017-12-03 15:43:08 -0800226 "-A bw_mangle_POSTROUTING -o " IPSEC_IFACE_PREFIX "+ -j RETURN\n"
227 "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
228 "-A bw_mangle_POSTROUTING -m owner --socket-exists\n" +
Chenbo Fenga121e202018-03-19 11:51:54 -0700229 StringPrintf("-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x%x\n", uidBillingMask);
230 if (useBpf) {
231 expectedAccounting += StringPrintf("-A bw_mangle_POSTROUTING -m bpf --object-pinned %s\n",
232 XT_BPF_EGRESS_PROG_PATH);
233 } else {
234 expectedAccounting += "\n";
235 }
236 expectedAccounting += "COMMIT\n";
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900237 mBw.enableBandwidthControl(false);
238 expectSetupCommands(expectedClean, expectedAccounting);
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900239}
240
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900241TEST_F(BandwidthControllerTest, TestDisableBandwidthControl) {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900242 // Pretend some bw_costly_shared_<iface> rules already exist...
243 addIptablesRestoreOutput(
244 "-P OUTPUT ACCEPT\n"
245 "-N bw_costly_rmnet_data0\n"
246 "-N bw_costly_shared\n"
247 "-N unrelated\n"
248 "-N bw_costly_rmnet_data7\n");
249
250 // ... and expect that they be flushed.
251 std::string expectedCleanCmds =
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900252 "*filter\n"
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900253 ":bw_costly_rmnet_data0 -\n"
254 ":bw_costly_rmnet_data7 -\n"
255 "COMMIT\n";
256
257 mBw.disableBandwidthControl();
258 expectSetupCommands(expectedCleanCmds, "");
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900259}
260
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900261TEST_F(BandwidthControllerTest, TestEnableDataSaver) {
262 mBw.enableDataSaver(true);
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900263 std::string expected4 =
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900264 "*filter\n"
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900265 ":bw_data_saver -\n"
266 "-A bw_data_saver --jump REJECT\n"
267 "COMMIT\n";
268 std::string expected6 =
269 "*filter\n"
270 ":bw_data_saver -\n"
271 "-A bw_data_saver -p icmpv6 --icmpv6-type packet-too-big -j RETURN\n"
272 "-A bw_data_saver -p icmpv6 --icmpv6-type router-solicitation -j RETURN\n"
273 "-A bw_data_saver -p icmpv6 --icmpv6-type router-advertisement -j RETURN\n"
274 "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN\n"
275 "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN\n"
276 "-A bw_data_saver -p icmpv6 --icmpv6-type redirect -j RETURN\n"
277 "-A bw_data_saver --jump REJECT\n"
278 "COMMIT\n";
279 expectIptablesRestoreCommands({
280 {V4, expected4},
281 {V6, expected6},
282 });
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900283
284 mBw.enableDataSaver(false);
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900285 std::string expected = {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900286 "*filter\n"
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900287 ":bw_data_saver -\n"
288 "-A bw_data_saver --jump RETURN\n"
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900289 "COMMIT\n"
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900290 };
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900291 expectIptablesRestoreCommands({
292 {V4, expected},
293 {V6, expected},
294 });
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900295}
Lorenzo Colittibbeaf9a2016-07-08 18:24:26 +0900296
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900297const std::vector<std::string> makeInterfaceQuotaCommands(const std::string& iface, int ruleIndex,
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900298 int64_t quota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900299 const std::string chain = "bw_costly_" + iface;
300 const char* c_chain = chain.c_str();
301 const char* c_iface = iface.c_str();
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900302 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900303 "*filter",
304 StringPrintf(":%s -", c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900305 StringPrintf("-A %s -j bw_penalty_box", c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900306 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleIndex, c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900307 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleIndex, c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900308 StringPrintf("-A bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900309 StringPrintf("-A bw_FORWARD -o %s --jump %s", c_iface, c_chain),
310 StringPrintf("-A %s -m quota2 ! --quota %" PRIu64 " --name %s --jump REJECT", c_chain,
311 quota, c_iface),
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900312 "COMMIT\n",
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900313 };
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900314 return {Join(cmds, "\n")};
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900315}
316
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900317const std::vector<std::string> removeInterfaceQuotaCommands(const std::string& iface) {
318 const std::string chain = "bw_costly_" + iface;
319 const char* c_chain = chain.c_str();
320 const char* c_iface = iface.c_str();
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900321 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900322 "*filter",
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900323 StringPrintf("-D bw_INPUT -i %s --jump %s", c_iface, c_chain),
324 StringPrintf("-D bw_OUTPUT -o %s --jump %s", c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900325 StringPrintf("-D bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900326 StringPrintf("-D bw_FORWARD -o %s --jump %s", c_iface, c_chain),
327 StringPrintf("-F %s", c_chain),
328 StringPrintf("-X %s", c_chain),
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
334TEST_F(BandwidthControllerTest, TestSetInterfaceQuota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900335 constexpr uint64_t kOldQuota = 123456;
336 const std::string iface = mTun.name();
337 std::vector<std::string> expected = makeInterfaceQuotaCommands(iface, 1, kOldQuota);
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900338
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900339 EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kOldQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900340 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900341
342 constexpr uint64_t kNewQuota = kOldQuota + 1;
343 expected = {};
344 expectUpdateQuota(kNewQuota);
345 EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kNewQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900346 expectIptablesRestoreCommands(expected);
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900347
348 expected = removeInterfaceQuotaCommands(iface);
349 EXPECT_EQ(0, mBw.removeInterfaceQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900350 expectIptablesRestoreCommands(expected);
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900351}
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900352
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900353const std::vector<std::string> makeInterfaceSharedQuotaCommands(const std::string& iface,
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900354 int ruleIndex, int64_t quota,
355 bool insertQuota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900356 const std::string chain = "bw_costly_shared";
357 const char* c_chain = chain.c_str();
358 const char* c_iface = iface.c_str();
359 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900360 "*filter",
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900361 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleIndex, c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900362 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleIndex, c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900363 StringPrintf("-A bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900364 StringPrintf("-A bw_FORWARD -o %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900365 };
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900366 if (insertQuota) {
367 cmds.push_back(StringPrintf(
368 "-I %s -m quota2 ! --quota %" PRIu64 " --name shared --jump REJECT", c_chain, quota));
369 }
370 cmds.push_back("COMMIT\n");
371 return {Join(cmds, "\n")};
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900372}
373
374const std::vector<std::string> removeInterfaceSharedQuotaCommands(const std::string& iface,
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900375 int64_t quota, bool deleteQuota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900376 const std::string chain = "bw_costly_shared";
377 const char* c_chain = chain.c_str();
378 const char* c_iface = iface.c_str();
379 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900380 "*filter",
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900381 StringPrintf("-D bw_INPUT -i %s --jump %s", c_iface, c_chain),
382 StringPrintf("-D bw_OUTPUT -o %s --jump %s", c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900383 StringPrintf("-D bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900384 StringPrintf("-D bw_FORWARD -o %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900385 };
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900386 if (deleteQuota) {
387 cmds.push_back(StringPrintf(
388 "-D %s -m quota2 ! --quota %" PRIu64 " --name shared --jump REJECT", c_chain, quota));
389 }
390 cmds.push_back("COMMIT\n");
391 return {Join(cmds, "\n")};
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900392}
393
394TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaDuplicate) {
395 constexpr uint64_t kQuota = 123456;
396 const std::string iface = mTun.name();
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900397 std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, 123456, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900398 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900399 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900400
401 expected = {};
402 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900403 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900404
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900405 expected = removeInterfaceSharedQuotaCommands(iface, kQuota, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900406 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900407 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900408}
409
410TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaUpdate) {
411 constexpr uint64_t kOldQuota = 123456;
412 const std::string iface = mTun.name();
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900413 std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, kOldQuota, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900414 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kOldQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900415 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900416
417 constexpr uint64_t kNewQuota = kOldQuota + 1;
418 expected = {};
419 expectUpdateQuota(kNewQuota);
420 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kNewQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900421 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900422
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900423 expected = removeInterfaceSharedQuotaCommands(iface, kNewQuota, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900424 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900425 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900426}
427
428TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaTwoInterfaces) {
429 constexpr uint64_t kQuota = 123456;
430 const std::vector<std::string> ifaces{
431 {"a" + mTun.name()},
432 {"b" + mTun.name()},
433 };
434
435 for (const auto& iface : ifaces) {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900436 // Quota rule is only added when the total number of
437 // interfaces transitions from 0 -> 1.
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900438 bool first = (iface == ifaces[0]);
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900439 auto expected = makeInterfaceSharedQuotaCommands(iface, 1, kQuota, first);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900440 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900441 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900442 }
443
444 for (const auto& iface : ifaces) {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900445 // Quota rule is only removed when the total number of
446 // interfaces transitions from 1 -> 0.
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900447 bool last = (iface == ifaces[1]);
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900448 auto expected = removeInterfaceSharedQuotaCommands(iface, kQuota, last);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900449 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900450 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900451 }
452}
453
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900454TEST_F(BandwidthControllerTest, IptablesAlertCmd) {
455 std::vector<std::string> expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900456 "*filter\n"
457 "-I bw_INPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
458 "-I bw_OUTPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
459 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900460 };
461 EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900462 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900463
464 expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900465 "*filter\n"
466 "-D bw_INPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
467 "-D bw_OUTPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
468 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900469 };
470 EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900471 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900472}
473
474TEST_F(BandwidthControllerTest, IptablesAlertFwdCmd) {
475 std::vector<std::string> expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900476 "*filter\n"
477 "-I bw_FORWARD -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
478 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900479 };
480 EXPECT_EQ(0, runIptablesAlertFwdCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900481 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900482
483 expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900484 "*filter\n"
485 "-D bw_FORWARD -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
486 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900487 };
488 EXPECT_EQ(0, runIptablesAlertFwdCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900489 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900490}
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900491
Lorenzo Colitti38078222017-07-06 17:27:23 +0900492TEST_F(BandwidthControllerTest, CostlyAlert) {
493 const int64_t kQuota = 123456;
494 int64_t alertBytes = 0;
495
496 std::vector<std::string> expected = {
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900497 "*filter\n"
498 "-A bw_costly_shared -m quota2 ! --quota 123456 --name sharedAlert\n"
499 "COMMIT\n"
Lorenzo Colitti38078222017-07-06 17:27:23 +0900500 };
501 EXPECT_EQ(0, setCostlyAlert("shared", kQuota, &alertBytes));
502 EXPECT_EQ(kQuota, alertBytes);
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900503 expectIptablesRestoreCommands(expected);
Lorenzo Colitti38078222017-07-06 17:27:23 +0900504
505 expected = {};
506 expectUpdateQuota(kQuota);
507 EXPECT_EQ(0, setCostlyAlert("shared", kQuota + 1, &alertBytes));
508 EXPECT_EQ(kQuota + 1, alertBytes);
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900509 expectIptablesRestoreCommands(expected);
Lorenzo Colitti38078222017-07-06 17:27:23 +0900510
511 expected = {
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900512 "*filter\n"
Lorenzo Colitti38078222017-07-06 17:27:23 +0900513 "-D bw_costly_shared -m quota2 ! --quota 123457 --name sharedAlert\n"
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900514 "COMMIT\n"
Lorenzo Colitti38078222017-07-06 17:27:23 +0900515 };
516 EXPECT_EQ(0, removeCostlyAlert("shared", &alertBytes));
517 EXPECT_EQ(0, alertBytes);
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900518 expectIptablesRestoreCommands(expected);
Lorenzo Colitti38078222017-07-06 17:27:23 +0900519}
520
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900521TEST_F(BandwidthControllerTest, ManipulateSpecialApps) {
Chenbo Feng95892f32018-06-07 14:52:02 -0700522 if (BandwidthController::getBpfStatus()) return;
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900523 std::vector<const char *> appUids = { "1000", "1001", "10012" };
524
525 std::vector<std::string> expected = {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900526 "*filter\n"
527 "-I bw_happy_box -m owner --uid-owner 1000 --jump RETURN\n"
528 "-I bw_happy_box -m owner --uid-owner 1001 --jump RETURN\n"
529 "-I bw_happy_box -m owner --uid-owner 10012 --jump RETURN\n"
530 "COMMIT\n"
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900531 };
532 EXPECT_EQ(0, mBw.addNiceApps(appUids.size(), const_cast<char**>(&appUids[0])));
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900533 expectIptablesRestoreCommands(expected);
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900534
535 expected = {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900536 "*filter\n"
537 "-D bw_penalty_box -m owner --uid-owner 1000 --jump REJECT\n"
538 "-D bw_penalty_box -m owner --uid-owner 1001 --jump REJECT\n"
539 "-D bw_penalty_box -m owner --uid-owner 10012 --jump REJECT\n"
540 "COMMIT\n"
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900541 };
542 EXPECT_EQ(0, mBw.removeNaughtyApps(appUids.size(), const_cast<char**>(&appUids[0])));
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900543 expectIptablesRestoreCommands(expected);
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900544}