xref: /aosp_15_r20/system/netd/server/BandwidthControllerTest.cpp (revision 8542734a0dd1db395a4d42aae09c37f3c3c3e7a1)
1*8542734aSAndroid Build Coastguard Worker /*
2*8542734aSAndroid Build Coastguard Worker  * Copyright 2016 The Android Open Source Project
3*8542734aSAndroid Build Coastguard Worker  *
4*8542734aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*8542734aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*8542734aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*8542734aSAndroid Build Coastguard Worker  *
8*8542734aSAndroid Build Coastguard Worker  * http://www.apache.org/licenses/LICENSE-2.0
9*8542734aSAndroid Build Coastguard Worker  *
10*8542734aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*8542734aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*8542734aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8542734aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*8542734aSAndroid Build Coastguard Worker  * limitations under the License.
15*8542734aSAndroid Build Coastguard Worker  *
16*8542734aSAndroid Build Coastguard Worker  * BandwidthControllerTest.cpp - unit tests for BandwidthController.cpp
17*8542734aSAndroid Build Coastguard Worker  */
18*8542734aSAndroid Build Coastguard Worker 
19*8542734aSAndroid Build Coastguard Worker #include <string>
20*8542734aSAndroid Build Coastguard Worker #include <vector>
21*8542734aSAndroid Build Coastguard Worker 
22*8542734aSAndroid Build Coastguard Worker #include <inttypes.h>
23*8542734aSAndroid Build Coastguard Worker #include <fcntl.h>
24*8542734aSAndroid Build Coastguard Worker #include <unistd.h>
25*8542734aSAndroid Build Coastguard Worker #include <sys/types.h>
26*8542734aSAndroid Build Coastguard Worker #include <sys/socket.h>
27*8542734aSAndroid Build Coastguard Worker 
28*8542734aSAndroid Build Coastguard Worker #include <gtest/gtest.h>
29*8542734aSAndroid Build Coastguard Worker 
30*8542734aSAndroid Build Coastguard Worker #include <android-base/strings.h>
31*8542734aSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
32*8542734aSAndroid Build Coastguard Worker 
33*8542734aSAndroid Build Coastguard Worker #include <netdutils/MockSyscalls.h>
34*8542734aSAndroid Build Coastguard Worker #include "BandwidthController.h"
35*8542734aSAndroid Build Coastguard Worker #include "Fwmark.h"
36*8542734aSAndroid Build Coastguard Worker #include "IptablesBaseTest.h"
37*8542734aSAndroid Build Coastguard Worker #include "mainline/XtBpfProgLocations.h"
38*8542734aSAndroid Build Coastguard Worker #include "tun_interface.h"
39*8542734aSAndroid Build Coastguard Worker 
40*8542734aSAndroid Build Coastguard Worker using ::testing::_;
41*8542734aSAndroid Build Coastguard Worker using ::testing::ByMove;
42*8542734aSAndroid Build Coastguard Worker using ::testing::Invoke;
43*8542734aSAndroid Build Coastguard Worker using ::testing::Return;
44*8542734aSAndroid Build Coastguard Worker using ::testing::StrictMock;
45*8542734aSAndroid Build Coastguard Worker 
46*8542734aSAndroid Build Coastguard Worker using android::base::Join;
47*8542734aSAndroid Build Coastguard Worker using android::base::StringPrintf;
48*8542734aSAndroid Build Coastguard Worker using android::net::TunInterface;
49*8542734aSAndroid Build Coastguard Worker using android::netdutils::UniqueFile;
50*8542734aSAndroid Build Coastguard Worker using android::netdutils::status::ok;
51*8542734aSAndroid Build Coastguard Worker 
52*8542734aSAndroid Build Coastguard Worker class BandwidthControllerTest : public IptablesBaseTest {
53*8542734aSAndroid Build Coastguard Worker protected:
BandwidthControllerTest()54*8542734aSAndroid Build Coastguard Worker     BandwidthControllerTest() {
55*8542734aSAndroid Build Coastguard Worker         BandwidthController::iptablesRestoreFunction = fakeExecIptablesRestoreWithOutput;
56*8542734aSAndroid Build Coastguard Worker     }
57*8542734aSAndroid Build Coastguard Worker     BandwidthController mBw;
58*8542734aSAndroid Build Coastguard Worker     TunInterface mTun;
59*8542734aSAndroid Build Coastguard Worker 
SetUp()60*8542734aSAndroid Build Coastguard Worker     void SetUp() {
61*8542734aSAndroid Build Coastguard Worker         ASSERT_EQ(0, mTun.init());
62*8542734aSAndroid Build Coastguard Worker     }
63*8542734aSAndroid Build Coastguard Worker 
TearDown()64*8542734aSAndroid Build Coastguard Worker     void TearDown() {
65*8542734aSAndroid Build Coastguard Worker         mTun.destroy();
66*8542734aSAndroid Build Coastguard Worker     }
67*8542734aSAndroid Build Coastguard Worker 
expectSetupCommands(const std::string & expectedClean,const std::string & expectedAccounting)68*8542734aSAndroid Build Coastguard Worker     void expectSetupCommands(const std::string& expectedClean,
69*8542734aSAndroid Build Coastguard Worker                              const std::string& expectedAccounting) {
70*8542734aSAndroid Build Coastguard Worker         std::string expectedList =
71*8542734aSAndroid Build Coastguard Worker             "*filter\n"
72*8542734aSAndroid Build Coastguard Worker             "-S\n"
73*8542734aSAndroid Build Coastguard Worker             "COMMIT\n";
74*8542734aSAndroid Build Coastguard Worker 
75*8542734aSAndroid Build Coastguard Worker         std::string expectedFlush =
76*8542734aSAndroid Build Coastguard Worker                 "*filter\n"
77*8542734aSAndroid Build Coastguard Worker                 ":bw_INPUT -\n"
78*8542734aSAndroid Build Coastguard Worker                 ":bw_OUTPUT -\n"
79*8542734aSAndroid Build Coastguard Worker                 ":bw_FORWARD -\n"
80*8542734aSAndroid Build Coastguard Worker                 ":bw_happy_box -\n"
81*8542734aSAndroid Build Coastguard Worker                 ":bw_penalty_box -\n"
82*8542734aSAndroid Build Coastguard Worker                 ":bw_data_saver -\n"
83*8542734aSAndroid Build Coastguard Worker                 ":bw_costly_shared -\n"
84*8542734aSAndroid Build Coastguard Worker                 ":bw_global_alert -\n"
85*8542734aSAndroid Build Coastguard Worker                 "COMMIT\n"
86*8542734aSAndroid Build Coastguard Worker                 "*raw\n"
87*8542734aSAndroid Build Coastguard Worker                 ":bw_raw_PREROUTING -\n"
88*8542734aSAndroid Build Coastguard Worker                 "COMMIT\n"
89*8542734aSAndroid Build Coastguard Worker                 "*mangle\n"
90*8542734aSAndroid Build Coastguard Worker                 ":bw_mangle_POSTROUTING -\n"
91*8542734aSAndroid Build Coastguard Worker                 "COMMIT\n";
92*8542734aSAndroid Build Coastguard Worker 
93*8542734aSAndroid Build Coastguard Worker         ExpectedIptablesCommands expected = {{ V4, expectedList }};
94*8542734aSAndroid Build Coastguard Worker         if (expectedClean.size()) {
95*8542734aSAndroid Build Coastguard Worker             expected.push_back({ V4V6, expectedClean });
96*8542734aSAndroid Build Coastguard Worker         }
97*8542734aSAndroid Build Coastguard Worker         expected.push_back({ V4V6, expectedFlush });
98*8542734aSAndroid Build Coastguard Worker         if (expectedAccounting.size()) {
99*8542734aSAndroid Build Coastguard Worker             expected.push_back({ V4V6, expectedAccounting });
100*8542734aSAndroid Build Coastguard Worker         }
101*8542734aSAndroid Build Coastguard Worker 
102*8542734aSAndroid Build Coastguard Worker         expectIptablesRestoreCommands(expected);
103*8542734aSAndroid Build Coastguard Worker     }
104*8542734aSAndroid Build Coastguard Worker 
105*8542734aSAndroid Build Coastguard Worker     using IptOp = BandwidthController::IptOp;
106*8542734aSAndroid Build Coastguard Worker 
runIptablesAlertCmd(IptOp a,const char * b,int64_t c)107*8542734aSAndroid Build Coastguard Worker     int runIptablesAlertCmd(IptOp a, const char* b, int64_t c) {
108*8542734aSAndroid Build Coastguard Worker         return mBw.runIptablesAlertCmd(a, b, c);
109*8542734aSAndroid Build Coastguard Worker     }
110*8542734aSAndroid Build Coastguard Worker 
setCostlyAlert(const std::string & a,int64_t b,int64_t * c)111*8542734aSAndroid Build Coastguard Worker     int setCostlyAlert(const std::string& a, int64_t b, int64_t* c) {
112*8542734aSAndroid Build Coastguard Worker         return mBw.setCostlyAlert(a, b, c);
113*8542734aSAndroid Build Coastguard Worker     }
114*8542734aSAndroid Build Coastguard Worker 
removeCostlyAlert(const std::string & a,int64_t * b)115*8542734aSAndroid Build Coastguard Worker     int removeCostlyAlert(const std::string& a, int64_t* b) { return mBw.removeCostlyAlert(a, b); }
116*8542734aSAndroid Build Coastguard Worker 
expectUpdateQuota(uint64_t quota)117*8542734aSAndroid Build Coastguard Worker     void expectUpdateQuota(uint64_t quota) {
118*8542734aSAndroid Build Coastguard Worker         uintptr_t dummy;
119*8542734aSAndroid Build Coastguard Worker         FILE* dummyFile = reinterpret_cast<FILE*>(&dummy);
120*8542734aSAndroid Build Coastguard Worker 
121*8542734aSAndroid Build Coastguard Worker         EXPECT_CALL(mSyscalls, fopen(_, _)).WillOnce(Return(ByMove(UniqueFile(dummyFile))));
122*8542734aSAndroid Build Coastguard Worker         EXPECT_CALL(mSyscalls, vfprintf(dummyFile, _, _))
123*8542734aSAndroid Build Coastguard Worker             .WillOnce(Invoke([quota](FILE*, const std::string&, va_list ap) {
124*8542734aSAndroid Build Coastguard Worker                 EXPECT_EQ(quota, va_arg(ap, uint64_t));
125*8542734aSAndroid Build Coastguard Worker                 return 0;
126*8542734aSAndroid Build Coastguard Worker             }));
127*8542734aSAndroid Build Coastguard Worker         EXPECT_CALL(mSyscalls, fclose(dummyFile)).WillOnce(Return(ok));
128*8542734aSAndroid Build Coastguard Worker     }
129*8542734aSAndroid Build Coastguard Worker 
130*8542734aSAndroid Build Coastguard Worker     StrictMock<android::netdutils::ScopedMockSyscalls> mSyscalls;
131*8542734aSAndroid Build Coastguard Worker };
132*8542734aSAndroid Build Coastguard Worker 
TEST_F(BandwidthControllerTest,TestSetupIptablesHooks)133*8542734aSAndroid Build Coastguard Worker TEST_F(BandwidthControllerTest, TestSetupIptablesHooks) {
134*8542734aSAndroid Build Coastguard Worker     // Pretend some bw_costly_shared_<iface> rules already exist...
135*8542734aSAndroid Build Coastguard Worker     addIptablesRestoreOutput(
136*8542734aSAndroid Build Coastguard Worker         "-P OUTPUT ACCEPT\n"
137*8542734aSAndroid Build Coastguard Worker         "-N bw_costly_rmnet_data0\n"
138*8542734aSAndroid Build Coastguard Worker         "-N bw_costly_shared\n"
139*8542734aSAndroid Build Coastguard Worker         "-N unrelated\n"
140*8542734aSAndroid Build Coastguard Worker         "-N bw_costly_rmnet_data7\n");
141*8542734aSAndroid Build Coastguard Worker 
142*8542734aSAndroid Build Coastguard Worker     // ... and expect that they be flushed and deleted.
143*8542734aSAndroid Build Coastguard Worker     std::string expectedCleanCmds =
144*8542734aSAndroid Build Coastguard Worker         "*filter\n"
145*8542734aSAndroid Build Coastguard Worker         ":bw_costly_rmnet_data0 -\n"
146*8542734aSAndroid Build Coastguard Worker         "-X bw_costly_rmnet_data0\n"
147*8542734aSAndroid Build Coastguard Worker         ":bw_costly_rmnet_data7 -\n"
148*8542734aSAndroid Build Coastguard Worker         "-X bw_costly_rmnet_data7\n"
149*8542734aSAndroid Build Coastguard Worker         "COMMIT\n";
150*8542734aSAndroid Build Coastguard Worker 
151*8542734aSAndroid Build Coastguard Worker     mBw.setupIptablesHooks();
152*8542734aSAndroid Build Coastguard Worker     expectSetupCommands(expectedCleanCmds, "");
153*8542734aSAndroid Build Coastguard Worker }
154*8542734aSAndroid Build Coastguard Worker 
TEST_F(BandwidthControllerTest,TestCheckUidBillingMask)155*8542734aSAndroid Build Coastguard Worker TEST_F(BandwidthControllerTest, TestCheckUidBillingMask) {
156*8542734aSAndroid Build Coastguard Worker     uint32_t uidBillingMask = Fwmark::getUidBillingMask();
157*8542734aSAndroid Build Coastguard Worker 
158*8542734aSAndroid Build Coastguard Worker     // If mask is non-zero, and mask & mask-1 is equal to 0, then the mask is a power of two.
159*8542734aSAndroid Build Coastguard Worker     bool isPowerOfTwo = uidBillingMask && (uidBillingMask & (uidBillingMask - 1)) == 0;
160*8542734aSAndroid Build Coastguard Worker 
161*8542734aSAndroid Build Coastguard Worker     // Must be exactly a power of two
162*8542734aSAndroid Build Coastguard Worker     EXPECT_TRUE(isPowerOfTwo);
163*8542734aSAndroid Build Coastguard Worker }
164*8542734aSAndroid Build Coastguard Worker 
TEST_F(BandwidthControllerTest,TestEnableBandwidthControl)165*8542734aSAndroid Build Coastguard Worker TEST_F(BandwidthControllerTest, TestEnableBandwidthControl) {
166*8542734aSAndroid Build Coastguard Worker     // Pretend no bw_costly_shared_<iface> rules already exist...
167*8542734aSAndroid Build Coastguard Worker     addIptablesRestoreOutput(
168*8542734aSAndroid Build Coastguard Worker             "-P OUTPUT ACCEPT\n"
169*8542734aSAndroid Build Coastguard Worker             "-N bw_costly_shared\n"
170*8542734aSAndroid Build Coastguard Worker             "-N unrelated\n");
171*8542734aSAndroid Build Coastguard Worker 
172*8542734aSAndroid Build Coastguard Worker     // ... so none are flushed or deleted.
173*8542734aSAndroid Build Coastguard Worker     // clang-format off
174*8542734aSAndroid Build Coastguard Worker     static const std::string expectedClean = "";
175*8542734aSAndroid Build Coastguard Worker     static const std::string expectedAccounting =
176*8542734aSAndroid Build Coastguard Worker             "*filter\n"
177*8542734aSAndroid Build Coastguard Worker             "-A bw_INPUT -j bw_global_alert\n"
178*8542734aSAndroid Build Coastguard Worker             "-A bw_INPUT -p esp -j RETURN\n"
179*8542734aSAndroid Build Coastguard Worker             "-A bw_INPUT -m mark --mark 0x100000/0x100000 -j RETURN\n"
180*8542734aSAndroid Build Coastguard Worker             "-A bw_INPUT -j MARK --or-mark 0x100000\n"
181*8542734aSAndroid Build Coastguard Worker             "-A bw_OUTPUT -j bw_global_alert\n"
182*8542734aSAndroid Build Coastguard Worker             "-A bw_costly_shared -j bw_penalty_box\n"
183*8542734aSAndroid Build Coastguard Worker             "-I bw_penalty_box -m bpf --object-pinned " XT_BPF_DENYLIST_PROG_PATH " -j REJECT\n"
184*8542734aSAndroid Build Coastguard Worker             "-A bw_penalty_box -j bw_happy_box\n"
185*8542734aSAndroid Build Coastguard Worker             "-A bw_happy_box -j bw_data_saver\n"
186*8542734aSAndroid Build Coastguard Worker             "-A bw_data_saver -j RETURN\n"
187*8542734aSAndroid Build Coastguard Worker             "-I bw_happy_box -m bpf --object-pinned " XT_BPF_ALLOWLIST_PROG_PATH " -j RETURN\n"
188*8542734aSAndroid Build Coastguard Worker             "COMMIT\n"
189*8542734aSAndroid Build Coastguard Worker             "*raw\n"
190*8542734aSAndroid Build Coastguard Worker             "-A bw_raw_PREROUTING -m mark --mark 0xdeadc1a7 -j DROP\n"
191*8542734aSAndroid Build Coastguard Worker             "-A bw_raw_PREROUTING -i ipsec+ -j RETURN\n"
192*8542734aSAndroid Build Coastguard Worker             "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n"
193*8542734aSAndroid Build Coastguard Worker             "-A bw_raw_PREROUTING -m bpf --object-pinned " XT_BPF_INGRESS_PROG_PATH "\n"
194*8542734aSAndroid Build Coastguard Worker             "COMMIT\n"
195*8542734aSAndroid Build Coastguard Worker             "*mangle\n"
196*8542734aSAndroid Build Coastguard Worker             "-A bw_mangle_POSTROUTING -o ipsec+ -j RETURN\n"
197*8542734aSAndroid Build Coastguard Worker             "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
198*8542734aSAndroid Build Coastguard Worker             "-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x100000\n"
199*8542734aSAndroid Build Coastguard Worker             "-A bw_mangle_POSTROUTING -m bpf --object-pinned " XT_BPF_EGRESS_PROG_PATH "\n"
200*8542734aSAndroid Build Coastguard Worker             "COMMIT\n";
201*8542734aSAndroid Build Coastguard Worker     // clang-format on
202*8542734aSAndroid Build Coastguard Worker 
203*8542734aSAndroid Build Coastguard Worker     mBw.enableBandwidthControl();
204*8542734aSAndroid Build Coastguard Worker     expectSetupCommands(expectedClean, expectedAccounting);
205*8542734aSAndroid Build Coastguard Worker }
206*8542734aSAndroid Build Coastguard Worker 
TEST_F(BandwidthControllerTest,TestEnableDataSaver)207*8542734aSAndroid Build Coastguard Worker TEST_F(BandwidthControllerTest, TestEnableDataSaver) {
208*8542734aSAndroid Build Coastguard Worker     mBw.enableDataSaver(true);
209*8542734aSAndroid Build Coastguard Worker     std::string expected4 =
210*8542734aSAndroid Build Coastguard Worker             "*filter\n"
211*8542734aSAndroid Build Coastguard Worker             ":bw_data_saver -\n"
212*8542734aSAndroid Build Coastguard Worker             "-A bw_data_saver -j REJECT\n"
213*8542734aSAndroid Build Coastguard Worker             "COMMIT\n";
214*8542734aSAndroid Build Coastguard Worker     std::string expected6 =
215*8542734aSAndroid Build Coastguard Worker             "*filter\n"
216*8542734aSAndroid Build Coastguard Worker             ":bw_data_saver -\n"
217*8542734aSAndroid Build Coastguard Worker             "-A bw_data_saver -p icmpv6 --icmpv6-type packet-too-big -j RETURN\n"
218*8542734aSAndroid Build Coastguard Worker             "-A bw_data_saver -p icmpv6 --icmpv6-type router-solicitation -j RETURN\n"
219*8542734aSAndroid Build Coastguard Worker             "-A bw_data_saver -p icmpv6 --icmpv6-type router-advertisement -j RETURN\n"
220*8542734aSAndroid Build Coastguard Worker             "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN\n"
221*8542734aSAndroid Build Coastguard Worker             "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN\n"
222*8542734aSAndroid Build Coastguard Worker             "-A bw_data_saver -p icmpv6 --icmpv6-type redirect -j RETURN\n"
223*8542734aSAndroid Build Coastguard Worker             "-A bw_data_saver -j REJECT\n"
224*8542734aSAndroid Build Coastguard Worker             "COMMIT\n";
225*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands({
226*8542734aSAndroid Build Coastguard Worker         {V4, expected4},
227*8542734aSAndroid Build Coastguard Worker         {V6, expected6},
228*8542734aSAndroid Build Coastguard Worker     });
229*8542734aSAndroid Build Coastguard Worker 
230*8542734aSAndroid Build Coastguard Worker     mBw.enableDataSaver(false);
231*8542734aSAndroid Build Coastguard Worker     std::string expected = {
232*8542734aSAndroid Build Coastguard Worker             "*filter\n"
233*8542734aSAndroid Build Coastguard Worker             ":bw_data_saver -\n"
234*8542734aSAndroid Build Coastguard Worker             "-A bw_data_saver -j RETURN\n"
235*8542734aSAndroid Build Coastguard Worker             "COMMIT\n"};
236*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands({
237*8542734aSAndroid Build Coastguard Worker         {V4, expected},
238*8542734aSAndroid Build Coastguard Worker         {V6, expected},
239*8542734aSAndroid Build Coastguard Worker     });
240*8542734aSAndroid Build Coastguard Worker }
241*8542734aSAndroid Build Coastguard Worker 
makeInterfaceQuotaCommands(const std::string & iface,int ruleIndex,int64_t quota)242*8542734aSAndroid Build Coastguard Worker const std::vector<std::string> makeInterfaceQuotaCommands(const std::string& iface, int ruleIndex,
243*8542734aSAndroid Build Coastguard Worker                                                           int64_t quota) {
244*8542734aSAndroid Build Coastguard Worker     const std::string chain = "bw_costly_" + iface;
245*8542734aSAndroid Build Coastguard Worker     const char* c_chain = chain.c_str();
246*8542734aSAndroid Build Coastguard Worker     const char* c_iface = iface.c_str();
247*8542734aSAndroid Build Coastguard Worker     std::vector<std::string> cmds = {
248*8542734aSAndroid Build Coastguard Worker             "*filter",
249*8542734aSAndroid Build Coastguard Worker             StringPrintf(":%s -", c_chain),
250*8542734aSAndroid Build Coastguard Worker             StringPrintf("-A %s -j bw_penalty_box", c_chain),
251*8542734aSAndroid Build Coastguard Worker             StringPrintf("-I bw_INPUT %d -i %s -j %s", ruleIndex, c_iface, c_chain),
252*8542734aSAndroid Build Coastguard Worker             StringPrintf("-I bw_OUTPUT %d -o %s -j %s", ruleIndex, c_iface, c_chain),
253*8542734aSAndroid Build Coastguard Worker             StringPrintf("-A bw_FORWARD -i %s -j %s", c_iface, c_chain),
254*8542734aSAndroid Build Coastguard Worker             StringPrintf("-A bw_FORWARD -o %s -j %s", c_iface, c_chain),
255*8542734aSAndroid Build Coastguard Worker             StringPrintf("-A %s -m quota2 ! --quota %" PRIu64 " --name %s -j REJECT", c_chain,
256*8542734aSAndroid Build Coastguard Worker                          quota, c_iface),
257*8542734aSAndroid Build Coastguard Worker             "COMMIT\n",
258*8542734aSAndroid Build Coastguard Worker     };
259*8542734aSAndroid Build Coastguard Worker     return {Join(cmds, "\n")};
260*8542734aSAndroid Build Coastguard Worker }
261*8542734aSAndroid Build Coastguard Worker 
removeInterfaceQuotaCommands(const std::string & iface)262*8542734aSAndroid Build Coastguard Worker const std::vector<std::string> removeInterfaceQuotaCommands(const std::string& iface) {
263*8542734aSAndroid Build Coastguard Worker     const std::string chain = "bw_costly_" + iface;
264*8542734aSAndroid Build Coastguard Worker     const char* c_chain = chain.c_str();
265*8542734aSAndroid Build Coastguard Worker     const char* c_iface = iface.c_str();
266*8542734aSAndroid Build Coastguard Worker     std::vector<std::string> cmds = {
267*8542734aSAndroid Build Coastguard Worker             "*filter",
268*8542734aSAndroid Build Coastguard Worker             StringPrintf("-D bw_INPUT -i %s -j %s", c_iface, c_chain),
269*8542734aSAndroid Build Coastguard Worker             StringPrintf("-D bw_OUTPUT -o %s -j %s", c_iface, c_chain),
270*8542734aSAndroid Build Coastguard Worker             StringPrintf("-D bw_FORWARD -i %s -j %s", c_iface, c_chain),
271*8542734aSAndroid Build Coastguard Worker             StringPrintf("-D bw_FORWARD -o %s -j %s", c_iface, c_chain),
272*8542734aSAndroid Build Coastguard Worker             StringPrintf("-F %s", c_chain),
273*8542734aSAndroid Build Coastguard Worker             StringPrintf("-X %s", c_chain),
274*8542734aSAndroid Build Coastguard Worker             "COMMIT\n",
275*8542734aSAndroid Build Coastguard Worker     };
276*8542734aSAndroid Build Coastguard Worker     return {Join(cmds, "\n")};
277*8542734aSAndroid Build Coastguard Worker }
278*8542734aSAndroid Build Coastguard Worker 
TEST_F(BandwidthControllerTest,TestSetInterfaceQuota)279*8542734aSAndroid Build Coastguard Worker TEST_F(BandwidthControllerTest, TestSetInterfaceQuota) {
280*8542734aSAndroid Build Coastguard Worker     constexpr uint64_t kOldQuota = 123456;
281*8542734aSAndroid Build Coastguard Worker     const std::string iface = mTun.name();
282*8542734aSAndroid Build Coastguard Worker     std::vector<std::string> expected = makeInterfaceQuotaCommands(iface, 1, kOldQuota);
283*8542734aSAndroid Build Coastguard Worker 
284*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kOldQuota));
285*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
286*8542734aSAndroid Build Coastguard Worker 
287*8542734aSAndroid Build Coastguard Worker     constexpr uint64_t kNewQuota = kOldQuota + 1;
288*8542734aSAndroid Build Coastguard Worker     expected = {};
289*8542734aSAndroid Build Coastguard Worker     expectUpdateQuota(kNewQuota);
290*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kNewQuota));
291*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
292*8542734aSAndroid Build Coastguard Worker 
293*8542734aSAndroid Build Coastguard Worker     expected = removeInterfaceQuotaCommands(iface);
294*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, mBw.removeInterfaceQuota(iface));
295*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
296*8542734aSAndroid Build Coastguard Worker }
297*8542734aSAndroid Build Coastguard Worker 
makeInterfaceSharedQuotaCommands(const std::string & iface,int ruleIndex,int64_t quota,bool insertQuota)298*8542734aSAndroid Build Coastguard Worker const std::vector<std::string> makeInterfaceSharedQuotaCommands(const std::string& iface,
299*8542734aSAndroid Build Coastguard Worker                                                                 int ruleIndex, int64_t quota,
300*8542734aSAndroid Build Coastguard Worker                                                                 bool insertQuota) {
301*8542734aSAndroid Build Coastguard Worker     const std::string chain = "bw_costly_shared";
302*8542734aSAndroid Build Coastguard Worker     const char* c_chain = chain.c_str();
303*8542734aSAndroid Build Coastguard Worker     const char* c_iface = iface.c_str();
304*8542734aSAndroid Build Coastguard Worker     std::vector<std::string> cmds = {
305*8542734aSAndroid Build Coastguard Worker             "*filter",
306*8542734aSAndroid Build Coastguard Worker             StringPrintf("-I bw_INPUT %d -i %s -j %s", ruleIndex, c_iface, c_chain),
307*8542734aSAndroid Build Coastguard Worker             StringPrintf("-I bw_OUTPUT %d -o %s -j %s", ruleIndex, c_iface, c_chain),
308*8542734aSAndroid Build Coastguard Worker             StringPrintf("-A bw_FORWARD -i %s -j %s", c_iface, c_chain),
309*8542734aSAndroid Build Coastguard Worker             StringPrintf("-A bw_FORWARD -o %s -j %s", c_iface, c_chain),
310*8542734aSAndroid Build Coastguard Worker     };
311*8542734aSAndroid Build Coastguard Worker     if (insertQuota) {
312*8542734aSAndroid Build Coastguard Worker         cmds.push_back(StringPrintf("-I %s -m quota2 ! --quota %" PRIu64 " --name shared -j REJECT",
313*8542734aSAndroid Build Coastguard Worker                                     c_chain, quota));
314*8542734aSAndroid Build Coastguard Worker     }
315*8542734aSAndroid Build Coastguard Worker     cmds.push_back("COMMIT\n");
316*8542734aSAndroid Build Coastguard Worker     return {Join(cmds, "\n")};
317*8542734aSAndroid Build Coastguard Worker }
318*8542734aSAndroid Build Coastguard Worker 
removeInterfaceSharedQuotaCommands(const std::string & iface,int64_t quota,bool deleteQuota)319*8542734aSAndroid Build Coastguard Worker const std::vector<std::string> removeInterfaceSharedQuotaCommands(const std::string& iface,
320*8542734aSAndroid Build Coastguard Worker                                                                   int64_t quota, bool deleteQuota) {
321*8542734aSAndroid Build Coastguard Worker     const std::string chain = "bw_costly_shared";
322*8542734aSAndroid Build Coastguard Worker     const char* c_chain = chain.c_str();
323*8542734aSAndroid Build Coastguard Worker     const char* c_iface = iface.c_str();
324*8542734aSAndroid Build Coastguard Worker     std::vector<std::string> cmds = {
325*8542734aSAndroid Build Coastguard Worker             "*filter",
326*8542734aSAndroid Build Coastguard Worker             StringPrintf("-D bw_INPUT -i %s -j %s", c_iface, c_chain),
327*8542734aSAndroid Build Coastguard Worker             StringPrintf("-D bw_OUTPUT -o %s -j %s", c_iface, c_chain),
328*8542734aSAndroid Build Coastguard Worker             StringPrintf("-D bw_FORWARD -i %s -j %s", c_iface, c_chain),
329*8542734aSAndroid Build Coastguard Worker             StringPrintf("-D bw_FORWARD -o %s -j %s", c_iface, c_chain),
330*8542734aSAndroid Build Coastguard Worker     };
331*8542734aSAndroid Build Coastguard Worker     if (deleteQuota) {
332*8542734aSAndroid Build Coastguard Worker         cmds.push_back(StringPrintf("-D %s -m quota2 ! --quota %" PRIu64 " --name shared -j REJECT",
333*8542734aSAndroid Build Coastguard Worker                                     c_chain, quota));
334*8542734aSAndroid Build Coastguard Worker     }
335*8542734aSAndroid Build Coastguard Worker     cmds.push_back("COMMIT\n");
336*8542734aSAndroid Build Coastguard Worker     return {Join(cmds, "\n")};
337*8542734aSAndroid Build Coastguard Worker }
338*8542734aSAndroid Build Coastguard Worker 
TEST_F(BandwidthControllerTest,TestSetInterfaceSharedQuotaDuplicate)339*8542734aSAndroid Build Coastguard Worker TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaDuplicate) {
340*8542734aSAndroid Build Coastguard Worker     constexpr uint64_t kQuota = 123456;
341*8542734aSAndroid Build Coastguard Worker     const std::string iface = mTun.name();
342*8542734aSAndroid Build Coastguard Worker     std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, 123456, true);
343*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
344*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
345*8542734aSAndroid Build Coastguard Worker 
346*8542734aSAndroid Build Coastguard Worker     expected = {};
347*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
348*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
349*8542734aSAndroid Build Coastguard Worker 
350*8542734aSAndroid Build Coastguard Worker     expected = removeInterfaceSharedQuotaCommands(iface, kQuota, true);
351*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
352*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
353*8542734aSAndroid Build Coastguard Worker }
354*8542734aSAndroid Build Coastguard Worker 
TEST_F(BandwidthControllerTest,TestSetInterfaceSharedQuotaUpdate)355*8542734aSAndroid Build Coastguard Worker TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaUpdate) {
356*8542734aSAndroid Build Coastguard Worker     constexpr uint64_t kOldQuota = 123456;
357*8542734aSAndroid Build Coastguard Worker     const std::string iface = mTun.name();
358*8542734aSAndroid Build Coastguard Worker     std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, kOldQuota, true);
359*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kOldQuota));
360*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
361*8542734aSAndroid Build Coastguard Worker 
362*8542734aSAndroid Build Coastguard Worker     constexpr uint64_t kNewQuota = kOldQuota + 1;
363*8542734aSAndroid Build Coastguard Worker     expected = {};
364*8542734aSAndroid Build Coastguard Worker     expectUpdateQuota(kNewQuota);
365*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kNewQuota));
366*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
367*8542734aSAndroid Build Coastguard Worker 
368*8542734aSAndroid Build Coastguard Worker     expected = removeInterfaceSharedQuotaCommands(iface, kNewQuota, true);
369*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
370*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
371*8542734aSAndroid Build Coastguard Worker }
372*8542734aSAndroid Build Coastguard Worker 
TEST_F(BandwidthControllerTest,TestSetInterfaceSharedQuotaTwoInterfaces)373*8542734aSAndroid Build Coastguard Worker TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaTwoInterfaces) {
374*8542734aSAndroid Build Coastguard Worker     constexpr uint64_t kQuota = 123456;
375*8542734aSAndroid Build Coastguard Worker     const std::vector<std::string> ifaces{
376*8542734aSAndroid Build Coastguard Worker         {"a" + mTun.name()},
377*8542734aSAndroid Build Coastguard Worker         {"b" + mTun.name()},
378*8542734aSAndroid Build Coastguard Worker     };
379*8542734aSAndroid Build Coastguard Worker 
380*8542734aSAndroid Build Coastguard Worker     for (const auto& iface : ifaces) {
381*8542734aSAndroid Build Coastguard Worker         // Quota rule is only added when the total number of
382*8542734aSAndroid Build Coastguard Worker         // interfaces transitions from 0 -> 1.
383*8542734aSAndroid Build Coastguard Worker         bool first = (iface == ifaces[0]);
384*8542734aSAndroid Build Coastguard Worker         auto expected = makeInterfaceSharedQuotaCommands(iface, 1, kQuota, first);
385*8542734aSAndroid Build Coastguard Worker         EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
386*8542734aSAndroid Build Coastguard Worker         expectIptablesRestoreCommands(expected);
387*8542734aSAndroid Build Coastguard Worker     }
388*8542734aSAndroid Build Coastguard Worker 
389*8542734aSAndroid Build Coastguard Worker     for (const auto& iface : ifaces) {
390*8542734aSAndroid Build Coastguard Worker         // Quota rule is only removed when the total number of
391*8542734aSAndroid Build Coastguard Worker         // interfaces transitions from 1 -> 0.
392*8542734aSAndroid Build Coastguard Worker         bool last = (iface == ifaces[1]);
393*8542734aSAndroid Build Coastguard Worker         auto expected = removeInterfaceSharedQuotaCommands(iface, kQuota, last);
394*8542734aSAndroid Build Coastguard Worker         EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
395*8542734aSAndroid Build Coastguard Worker         expectIptablesRestoreCommands(expected);
396*8542734aSAndroid Build Coastguard Worker     }
397*8542734aSAndroid Build Coastguard Worker }
398*8542734aSAndroid Build Coastguard Worker 
TEST_F(BandwidthControllerTest,IptablesAlertCmd)399*8542734aSAndroid Build Coastguard Worker TEST_F(BandwidthControllerTest, IptablesAlertCmd) {
400*8542734aSAndroid Build Coastguard Worker     std::vector<std::string> expected = {
401*8542734aSAndroid Build Coastguard Worker             "*filter\n"
402*8542734aSAndroid Build Coastguard Worker             "-I bw_global_alert -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
403*8542734aSAndroid Build Coastguard Worker             "COMMIT\n"};
404*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
405*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
406*8542734aSAndroid Build Coastguard Worker 
407*8542734aSAndroid Build Coastguard Worker     expected = {
408*8542734aSAndroid Build Coastguard Worker             "*filter\n"
409*8542734aSAndroid Build Coastguard Worker             "-D bw_global_alert -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
410*8542734aSAndroid Build Coastguard Worker             "COMMIT\n"};
411*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
412*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
413*8542734aSAndroid Build Coastguard Worker }
414*8542734aSAndroid Build Coastguard Worker 
TEST_F(BandwidthControllerTest,CostlyAlert)415*8542734aSAndroid Build Coastguard Worker TEST_F(BandwidthControllerTest, CostlyAlert) {
416*8542734aSAndroid Build Coastguard Worker     const int64_t kQuota = 123456;
417*8542734aSAndroid Build Coastguard Worker     int64_t alertBytes = 0;
418*8542734aSAndroid Build Coastguard Worker 
419*8542734aSAndroid Build Coastguard Worker     std::vector<std::string> expected = {
420*8542734aSAndroid Build Coastguard Worker         "*filter\n"
421*8542734aSAndroid Build Coastguard Worker         "-A bw_costly_shared -m quota2 ! --quota 123456 --name sharedAlert\n"
422*8542734aSAndroid Build Coastguard Worker         "COMMIT\n"
423*8542734aSAndroid Build Coastguard Worker     };
424*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, setCostlyAlert("shared", kQuota, &alertBytes));
425*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(kQuota, alertBytes);
426*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
427*8542734aSAndroid Build Coastguard Worker 
428*8542734aSAndroid Build Coastguard Worker     expected = {};
429*8542734aSAndroid Build Coastguard Worker     expectUpdateQuota(kQuota);
430*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, setCostlyAlert("shared", kQuota + 1, &alertBytes));
431*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(kQuota + 1, alertBytes);
432*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
433*8542734aSAndroid Build Coastguard Worker 
434*8542734aSAndroid Build Coastguard Worker     expected = {
435*8542734aSAndroid Build Coastguard Worker         "*filter\n"
436*8542734aSAndroid Build Coastguard Worker         "-D bw_costly_shared -m quota2 ! --quota 123457 --name sharedAlert\n"
437*8542734aSAndroid Build Coastguard Worker         "COMMIT\n"
438*8542734aSAndroid Build Coastguard Worker     };
439*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, removeCostlyAlert("shared", &alertBytes));
440*8542734aSAndroid Build Coastguard Worker     EXPECT_EQ(0, alertBytes);
441*8542734aSAndroid Build Coastguard Worker     expectIptablesRestoreCommands(expected);
442*8542734aSAndroid Build Coastguard Worker }
443*8542734aSAndroid Build Coastguard Worker 
444