blob: 95af14860922f3ac3b807e2c732698617964f9ab [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
Lorenzo Colitti38078222017-07-06 17:27:23 +0900118 int setCostlyAlert(const std::string a, int64_t b, int64_t *c) {
119 return mBw.setCostlyAlert(a, b, c);
120 }
121
122 int removeCostlyAlert(const std::string a, int64_t *b) {
123 return mBw.removeCostlyAlert(a, b);
124 }
125
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900126 void expectUpdateQuota(uint64_t quota) {
127 uintptr_t dummy;
128 FILE* dummyFile = reinterpret_cast<FILE*>(&dummy);
129
130 EXPECT_CALL(mSyscalls, fopen(_, _)).WillOnce(Return(ByMove(UniqueFile(dummyFile))));
131 EXPECT_CALL(mSyscalls, vfprintf(dummyFile, _, _))
132 .WillOnce(Invoke([quota](FILE*, const std::string&, va_list ap) {
133 EXPECT_EQ(quota, va_arg(ap, uint64_t));
134 return 0;
135 }));
136 EXPECT_CALL(mSyscalls, fclose(dummyFile)).WillOnce(Return(ok));
137 }
138
139 StrictMock<android::netdutils::ScopedMockSyscalls> mSyscalls;
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900140};
141
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900142TEST_F(BandwidthControllerTest, TestSetupIptablesHooks) {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900143 // Pretend some bw_costly_shared_<iface> rules already exist...
144 addIptablesRestoreOutput(
145 "-P OUTPUT ACCEPT\n"
146 "-N bw_costly_rmnet_data0\n"
147 "-N bw_costly_shared\n"
148 "-N unrelated\n"
149 "-N bw_costly_rmnet_data7\n");
150
151 // ... and expect that they be flushed and deleted.
152 std::string expectedCleanCmds =
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900153 "*filter\n"
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900154 ":bw_costly_rmnet_data0 -\n"
155 "-X bw_costly_rmnet_data0\n"
156 ":bw_costly_rmnet_data7 -\n"
157 "-X bw_costly_rmnet_data7\n"
158 "COMMIT\n";
159
160 mBw.setupIptablesHooks();
161 expectSetupCommands(expectedCleanCmds, "");
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900162}
163
Benedict Wongb9baf262017-12-03 15:43:08 -0800164TEST_F(BandwidthControllerTest, TestCheckUidBillingMask) {
165 uint32_t uidBillingMask = Fwmark::getUidBillingMask();
166
167 // If mask is non-zero, and mask & mask-1 is equal to 0, then the mask is a power of two.
168 bool isPowerOfTwo = uidBillingMask && (uidBillingMask & (uidBillingMask - 1)) == 0;
169
170 // Must be exactly a power of two
171 EXPECT_TRUE(isPowerOfTwo);
172}
173
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900174TEST_F(BandwidthControllerTest, TestEnableBandwidthControl) {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900175 // Pretend no bw_costly_shared_<iface> rules already exist...
176 addIptablesRestoreOutput(
177 "-P OUTPUT ACCEPT\n"
178 "-N bw_costly_shared\n"
179 "-N unrelated\n");
180
181 // ... so none are flushed or deleted.
182 std::string expectedClean = "";
183
Benedict Wongb9baf262017-12-03 15:43:08 -0800184 uint32_t uidBillingMask = Fwmark::getUidBillingMask();
Chenbo Feng95892f32018-06-07 14:52:02 -0700185 bool useBpf = BandwidthController::getBpfStatus();
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900186 std::string expectedAccounting =
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900187 "*filter\n"
Benedict Wongb9baf262017-12-03 15:43:08 -0800188 "-A bw_INPUT -p esp -j RETURN\n" +
189 StringPrintf("-A bw_INPUT -m mark --mark 0x%x/0x%x -j RETURN\n",
190 uidBillingMask, uidBillingMask) +
191 "-A bw_INPUT -m owner --socket-exists\n" +
192 StringPrintf("-A bw_INPUT -j MARK --or-mark 0x%x\n", uidBillingMask) +
193 "-A bw_OUTPUT -o " IPSEC_IFACE_PREFIX "+ -j RETURN\n"
194 "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN\n"
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900195 "-A bw_OUTPUT -m owner --socket-exists\n"
Chenbo Feng95892f32018-06-07 14:52:02 -0700196 "-A bw_costly_shared --jump bw_penalty_box\n";
197 if (useBpf) {
198 expectedAccounting +=
199 StringPrintf("-I bw_penalty_box -m bpf --object-pinned %s -j REJECT\n",
200 XT_BPF_BLACKLIST_PROG_PATH) +
201 "-A bw_penalty_box --jump bw_happy_box\n" +
202 "-A bw_happy_box --jump bw_data_saver\n"
203 "-A bw_data_saver -j RETURN\n" +
204 StringPrintf("-I bw_happy_box -m bpf --object-pinned %s -j RETURN\n",
205 XT_BPF_WHITELIST_PROG_PATH);
206 } else {
207 expectedAccounting +=
208 "\n-A bw_penalty_box --jump bw_happy_box\n"
209 "-A bw_happy_box --jump bw_data_saver\n"
210 "-A bw_data_saver -j RETURN\n"
211 "-I bw_happy_box -m owner --uid-owner 0-9999 --jump RETURN\n";
212 }
213 expectedAccounting +=
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900214 "COMMIT\n"
215 "*raw\n"
Benedict Wongb9baf262017-12-03 15:43:08 -0800216 "-A bw_raw_PREROUTING -i " IPSEC_IFACE_PREFIX "+ -j RETURN\n"
217 "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n"
Chenbo Fenga121e202018-03-19 11:51:54 -0700218 "-A bw_raw_PREROUTING -m owner --socket-exists\n";
219 if (useBpf) {
220 expectedAccounting += StringPrintf("-A bw_raw_PREROUTING -m bpf --object-pinned %s\n",
221 XT_BPF_INGRESS_PROG_PATH);
222 } else {
223 expectedAccounting += "\n";
224 }
225 expectedAccounting +=
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900226 "COMMIT\n"
227 "*mangle\n"
Benedict Wongb9baf262017-12-03 15:43:08 -0800228 "-A bw_mangle_POSTROUTING -o " IPSEC_IFACE_PREFIX "+ -j RETURN\n"
229 "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
230 "-A bw_mangle_POSTROUTING -m owner --socket-exists\n" +
Chenbo Fenga121e202018-03-19 11:51:54 -0700231 StringPrintf("-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x%x\n", uidBillingMask);
232 if (useBpf) {
233 expectedAccounting += StringPrintf("-A bw_mangle_POSTROUTING -m bpf --object-pinned %s\n",
234 XT_BPF_EGRESS_PROG_PATH);
235 } else {
236 expectedAccounting += "\n";
237 }
238 expectedAccounting += "COMMIT\n";
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900239 mBw.enableBandwidthControl(false);
240 expectSetupCommands(expectedClean, expectedAccounting);
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900241}
242
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900243TEST_F(BandwidthControllerTest, TestDisableBandwidthControl) {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900244 // Pretend some bw_costly_shared_<iface> rules already exist...
245 addIptablesRestoreOutput(
246 "-P OUTPUT ACCEPT\n"
247 "-N bw_costly_rmnet_data0\n"
248 "-N bw_costly_shared\n"
249 "-N unrelated\n"
250 "-N bw_costly_rmnet_data7\n");
251
252 // ... and expect that they be flushed.
253 std::string expectedCleanCmds =
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900254 "*filter\n"
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900255 ":bw_costly_rmnet_data0 -\n"
256 ":bw_costly_rmnet_data7 -\n"
257 "COMMIT\n";
258
259 mBw.disableBandwidthControl();
260 expectSetupCommands(expectedCleanCmds, "");
Lorenzo Colittia0dc8a52016-03-26 22:42:07 +0900261}
262
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900263TEST_F(BandwidthControllerTest, TestEnableDataSaver) {
264 mBw.enableDataSaver(true);
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900265 std::string expected4 =
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900266 "*filter\n"
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900267 ":bw_data_saver -\n"
268 "-A bw_data_saver --jump REJECT\n"
269 "COMMIT\n";
270 std::string expected6 =
271 "*filter\n"
272 ":bw_data_saver -\n"
273 "-A bw_data_saver -p icmpv6 --icmpv6-type packet-too-big -j RETURN\n"
274 "-A bw_data_saver -p icmpv6 --icmpv6-type router-solicitation -j RETURN\n"
275 "-A bw_data_saver -p icmpv6 --icmpv6-type router-advertisement -j RETURN\n"
276 "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN\n"
277 "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN\n"
278 "-A bw_data_saver -p icmpv6 --icmpv6-type redirect -j RETURN\n"
279 "-A bw_data_saver --jump REJECT\n"
280 "COMMIT\n";
281 expectIptablesRestoreCommands({
282 {V4, expected4},
283 {V6, expected6},
284 });
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900285
286 mBw.enableDataSaver(false);
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900287 std::string expected = {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900288 "*filter\n"
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900289 ":bw_data_saver -\n"
290 "-A bw_data_saver --jump RETURN\n"
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900291 "COMMIT\n"
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900292 };
Lorenzo Colittiaff28792017-09-26 17:46:18 +0900293 expectIptablesRestoreCommands({
294 {V4, expected},
295 {V6, expected},
296 });
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900297}
Lorenzo Colittibbeaf9a2016-07-08 18:24:26 +0900298
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900299const std::vector<std::string> makeInterfaceQuotaCommands(const std::string& iface, int ruleIndex,
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900300 int64_t quota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900301 const std::string chain = "bw_costly_" + iface;
302 const char* c_chain = chain.c_str();
303 const char* c_iface = iface.c_str();
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900304 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900305 "*filter",
306 StringPrintf(":%s -", c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900307 StringPrintf("-A %s -j bw_penalty_box", c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900308 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleIndex, c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900309 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleIndex, c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900310 StringPrintf("-A bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900311 StringPrintf("-A bw_FORWARD -o %s --jump %s", c_iface, c_chain),
312 StringPrintf("-A %s -m quota2 ! --quota %" PRIu64 " --name %s --jump REJECT", c_chain,
313 quota, c_iface),
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900314 "COMMIT\n",
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900315 };
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900316 return {Join(cmds, "\n")};
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900317}
318
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900319const std::vector<std::string> removeInterfaceQuotaCommands(const std::string& iface) {
320 const std::string chain = "bw_costly_" + iface;
321 const char* c_chain = chain.c_str();
322 const char* c_iface = iface.c_str();
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900323 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900324 "*filter",
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900325 StringPrintf("-D bw_INPUT -i %s --jump %s", c_iface, c_chain),
326 StringPrintf("-D bw_OUTPUT -o %s --jump %s", c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900327 StringPrintf("-D bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900328 StringPrintf("-D bw_FORWARD -o %s --jump %s", c_iface, c_chain),
329 StringPrintf("-F %s", c_chain),
330 StringPrintf("-X %s", c_chain),
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900331 "COMMIT\n",
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900332 };
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900333 return {Join(cmds, "\n")};
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900334}
335
336TEST_F(BandwidthControllerTest, TestSetInterfaceQuota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900337 constexpr uint64_t kOldQuota = 123456;
338 const std::string iface = mTun.name();
339 std::vector<std::string> expected = makeInterfaceQuotaCommands(iface, 1, kOldQuota);
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900340
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900341 EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kOldQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900342 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900343
344 constexpr uint64_t kNewQuota = kOldQuota + 1;
345 expected = {};
346 expectUpdateQuota(kNewQuota);
347 EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kNewQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900348 expectIptablesRestoreCommands(expected);
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900349
350 expected = removeInterfaceQuotaCommands(iface);
351 EXPECT_EQ(0, mBw.removeInterfaceQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900352 expectIptablesRestoreCommands(expected);
Lorenzo Colittidf42ddd2017-02-28 01:20:13 +0900353}
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900354
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900355const std::vector<std::string> makeInterfaceSharedQuotaCommands(const std::string& iface,
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900356 int ruleIndex, int64_t quota,
357 bool insertQuota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900358 const std::string chain = "bw_costly_shared";
359 const char* c_chain = chain.c_str();
360 const char* c_iface = iface.c_str();
361 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900362 "*filter",
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900363 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleIndex, c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900364 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleIndex, c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900365 StringPrintf("-A bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900366 StringPrintf("-A bw_FORWARD -o %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900367 };
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900368 if (insertQuota) {
369 cmds.push_back(StringPrintf(
370 "-I %s -m quota2 ! --quota %" PRIu64 " --name shared --jump REJECT", c_chain, quota));
371 }
372 cmds.push_back("COMMIT\n");
373 return {Join(cmds, "\n")};
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900374}
375
376const std::vector<std::string> removeInterfaceSharedQuotaCommands(const std::string& iface,
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900377 int64_t quota, bool deleteQuota) {
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900378 const std::string chain = "bw_costly_shared";
379 const char* c_chain = chain.c_str();
380 const char* c_iface = iface.c_str();
381 std::vector<std::string> cmds = {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900382 "*filter",
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900383 StringPrintf("-D bw_INPUT -i %s --jump %s", c_iface, c_chain),
384 StringPrintf("-D bw_OUTPUT -o %s --jump %s", c_iface, c_chain),
Erik Kline51eb3242017-09-20 18:30:47 +0900385 StringPrintf("-D bw_FORWARD -i %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900386 StringPrintf("-D bw_FORWARD -o %s --jump %s", c_iface, c_chain),
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900387 };
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900388 if (deleteQuota) {
389 cmds.push_back(StringPrintf(
390 "-D %s -m quota2 ! --quota %" PRIu64 " --name shared --jump REJECT", c_chain, quota));
391 }
392 cmds.push_back("COMMIT\n");
393 return {Join(cmds, "\n")};
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900394}
395
396TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaDuplicate) {
397 constexpr uint64_t kQuota = 123456;
398 const std::string iface = mTun.name();
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900399 std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, 123456, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900400 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900401 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900402
403 expected = {};
404 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900405 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900406
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900407 expected = removeInterfaceSharedQuotaCommands(iface, kQuota, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900408 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900409 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900410}
411
412TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaUpdate) {
413 constexpr uint64_t kOldQuota = 123456;
414 const std::string iface = mTun.name();
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900415 std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, kOldQuota, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900416 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kOldQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900417 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900418
419 constexpr uint64_t kNewQuota = kOldQuota + 1;
420 expected = {};
421 expectUpdateQuota(kNewQuota);
422 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kNewQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900423 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900424
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900425 expected = removeInterfaceSharedQuotaCommands(iface, kNewQuota, true);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900426 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900427 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900428}
429
430TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaTwoInterfaces) {
431 constexpr uint64_t kQuota = 123456;
432 const std::vector<std::string> ifaces{
433 {"a" + mTun.name()},
434 {"b" + mTun.name()},
435 };
436
437 for (const auto& iface : ifaces) {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900438 // Quota rule is only added when the total number of
439 // interfaces transitions from 0 -> 1.
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900440 bool first = (iface == ifaces[0]);
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900441 auto expected = makeInterfaceSharedQuotaCommands(iface, 1, kQuota, first);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900442 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900443 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900444 }
445
446 for (const auto& iface : ifaces) {
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900447 // Quota rule is only removed when the total number of
448 // interfaces transitions from 1 -> 0.
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900449 bool last = (iface == ifaces[1]);
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900450 auto expected = removeInterfaceSharedQuotaCommands(iface, kQuota, last);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900451 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
Lorenzo Colitti48f83002017-07-06 15:06:04 +0900452 expectIptablesRestoreCommands(expected);
Joel Scherpelz01cc5492017-06-16 10:45:14 +0900453 }
454}
455
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900456TEST_F(BandwidthControllerTest, IptablesAlertCmd) {
457 std::vector<std::string> expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900458 "*filter\n"
459 "-I bw_INPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
460 "-I bw_OUTPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
461 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900462 };
463 EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900464 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900465
466 expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900467 "*filter\n"
468 "-D bw_INPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
469 "-D bw_OUTPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
470 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900471 };
472 EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900473 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900474}
475
476TEST_F(BandwidthControllerTest, IptablesAlertFwdCmd) {
477 std::vector<std::string> expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900478 "*filter\n"
479 "-I bw_FORWARD -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
480 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900481 };
482 EXPECT_EQ(0, runIptablesAlertFwdCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900483 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900484
485 expected = {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900486 "*filter\n"
487 "-D bw_FORWARD -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
488 "COMMIT\n"
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900489 };
490 EXPECT_EQ(0, runIptablesAlertFwdCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900491 expectIptablesRestoreCommands(expected);
Lorenzo Colittie8b56e42017-04-26 15:16:03 +0900492}
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900493
Lorenzo Colitti38078222017-07-06 17:27:23 +0900494TEST_F(BandwidthControllerTest, CostlyAlert) {
495 const int64_t kQuota = 123456;
496 int64_t alertBytes = 0;
497
498 std::vector<std::string> expected = {
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900499 "*filter\n"
500 "-A bw_costly_shared -m quota2 ! --quota 123456 --name sharedAlert\n"
501 "COMMIT\n"
Lorenzo Colitti38078222017-07-06 17:27:23 +0900502 };
503 EXPECT_EQ(0, setCostlyAlert("shared", kQuota, &alertBytes));
504 EXPECT_EQ(kQuota, alertBytes);
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900505 expectIptablesRestoreCommands(expected);
Lorenzo Colitti38078222017-07-06 17:27:23 +0900506
507 expected = {};
508 expectUpdateQuota(kQuota);
509 EXPECT_EQ(0, setCostlyAlert("shared", kQuota + 1, &alertBytes));
510 EXPECT_EQ(kQuota + 1, alertBytes);
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900511 expectIptablesRestoreCommands(expected);
Lorenzo Colitti38078222017-07-06 17:27:23 +0900512
513 expected = {
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900514 "*filter\n"
Lorenzo Colitti38078222017-07-06 17:27:23 +0900515 "-D bw_costly_shared -m quota2 ! --quota 123457 --name sharedAlert\n"
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900516 "COMMIT\n"
Lorenzo Colitti38078222017-07-06 17:27:23 +0900517 };
518 EXPECT_EQ(0, removeCostlyAlert("shared", &alertBytes));
519 EXPECT_EQ(0, alertBytes);
Lorenzo Colittie85ffe12017-07-06 17:25:37 +0900520 expectIptablesRestoreCommands(expected);
Lorenzo Colitti38078222017-07-06 17:27:23 +0900521}
522
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900523TEST_F(BandwidthControllerTest, ManipulateSpecialApps) {
Chenbo Feng95892f32018-06-07 14:52:02 -0700524 if (BandwidthController::getBpfStatus()) return;
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900525 std::vector<const char *> appUids = { "1000", "1001", "10012" };
526
527 std::vector<std::string> expected = {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900528 "*filter\n"
529 "-I bw_happy_box -m owner --uid-owner 1000 --jump RETURN\n"
530 "-I bw_happy_box -m owner --uid-owner 1001 --jump RETURN\n"
531 "-I bw_happy_box -m owner --uid-owner 10012 --jump RETURN\n"
532 "COMMIT\n"
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900533 };
534 EXPECT_EQ(0, mBw.addNiceApps(appUids.size(), const_cast<char**>(&appUids[0])));
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900535 expectIptablesRestoreCommands(expected);
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900536
537 expected = {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900538 "*filter\n"
539 "-D bw_penalty_box -m owner --uid-owner 1000 --jump REJECT\n"
540 "-D bw_penalty_box -m owner --uid-owner 1001 --jump REJECT\n"
541 "-D bw_penalty_box -m owner --uid-owner 10012 --jump REJECT\n"
542 "COMMIT\n"
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900543 };
544 EXPECT_EQ(0, mBw.removeNaughtyApps(appUids.size(), const_cast<char**>(&appUids[0])));
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900545 expectIptablesRestoreCommands(expected);
Lorenzo Colittif4dfa682017-04-28 11:09:07 +0900546}