blob: 9aace9dabad7e6496a582b7d2bc6656315f9b9d5 [file] [log] [blame]
JP Abgrall4a5f5ca2011-06-15 18:37:39 -07001/*
2 * Copyright (C) 2011 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
JP Abgralle4788732013-07-02 20:28:45 -070017// #define LOG_NDEBUG 0
JP Abgralldb7da582011-09-18 12:57:32 -070018
19/*
20 * The CommandListener, FrameworkListener don't allow for
21 * multiple calls in parallel to reach the BandwidthController.
22 * If they ever were to allow it, then netd/ would need some tweaking.
23 */
24
Lorenzo Colitti13debb82016-03-27 17:46:30 +090025#include <string>
26#include <vector>
27
JP Abgrall8a932722011-07-13 19:17:35 -070028#include <errno.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070029#include <fcntl.h>
JP Abgralldb7da582011-09-18 12:57:32 -070030#include <stdio.h>
JP Abgrall8a932722011-07-13 19:17:35 -070031#include <stdlib.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070032#include <string.h>
Nick Kralevich0b2b9022014-05-01 13:10:45 -070033#include <ctype.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070034
Matthew Leach2a54d962013-01-14 15:07:12 +000035#define __STDC_FORMAT_MACROS 1
36#include <inttypes.h>
37
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070038#include <sys/socket.h>
39#include <sys/stat.h>
40#include <sys/types.h>
41#include <sys/wait.h>
42
43#include <linux/netlink.h>
44#include <linux/rtnetlink.h>
45#include <linux/pkt_sched.h>
46
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090047#include "android-base/stringprintf.h"
Lorenzo Colitti13debb82016-03-27 17:46:30 +090048#include "android-base/strings.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070049#define LOG_TAG "BandwidthController"
50#include <cutils/log.h>
51#include <cutils/properties.h>
Rom Lemarchand14150212013-01-24 10:01:04 -080052#include <logwrap/logwrap.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070053
JP Abgrall0031cea2012-04-17 16:38:23 -070054#include "NetdConstants.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070055#include "BandwidthController.h"
JP Abgrallbaeccc42013-06-25 09:44:10 -070056#include "NatController.h" /* For LOCAL_TETHER_COUNTERS_CHAIN */
57#include "ResponseCode.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070058
JP Abgralldb7da582011-09-18 12:57:32 -070059/* Alphabetical */
Lorenzo Colitti3c272702017-04-26 15:48:13 +090060#define ALERT_IPT_TEMPLATE "%s %s -m quota2 ! --quota %" PRId64" --name %s\n"
Joel Scherpelzbcad6612017-05-30 10:55:11 +090061const char BandwidthController::LOCAL_INPUT[] = "bw_INPUT";
62const char BandwidthController::LOCAL_FORWARD[] = "bw_FORWARD";
63const char BandwidthController::LOCAL_OUTPUT[] = "bw_OUTPUT";
64const char BandwidthController::LOCAL_RAW_PREROUTING[] = "bw_raw_PREROUTING";
65const char BandwidthController::LOCAL_MANGLE_POSTROUTING[] = "bw_mangle_POSTROUTING";
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090066
Lorenzo Colitti86a47982016-03-18 17:52:25 +090067auto BandwidthController::execFunction = android_fork_execvp;
68auto BandwidthController::popenFunction = popen;
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +090069auto BandwidthController::iptablesRestoreFunction = execIptablesRestoreWithOutput;
Lorenzo Colitti86a47982016-03-18 17:52:25 +090070
Lorenzo Colitti3c272702017-04-26 15:48:13 +090071using android::base::StringAppendF;
72using android::base::StringPrintf;
73
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090074namespace {
75
76const char ALERT_GLOBAL_NAME[] = "globalAlert";
77const int MAX_CMD_ARGS = 32;
78const int MAX_CMD_LEN = 1024;
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090079const int MAX_IPT_OUTPUT_LINE_LEN = 256;
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +090080const std::string NEW_CHAIN_COMMAND = "-N ";
Lorenzo Colitti3c272702017-04-26 15:48:13 +090081const std::string GET_TETHER_STATS_COMMAND = StringPrintf(
Lorenzo Colittice6748a2017-02-02 01:34:33 +090082 "*filter\n"
83 "-nvx -L %s\n"
84 "COMMIT\n", NatController::LOCAL_TETHER_COUNTERS_CHAIN);
85
Joel Scherpelzbcad6612017-05-30 10:55:11 +090086const char NAUGHTY_CHAIN[] = "bw_penalty_box";
87const char NICE_CHAIN[] = "bw_happy_box";
JP Abgralldb7da582011-09-18 12:57:32 -070088
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070089/**
90 * Some comments about the rules:
91 * * Ordering
92 * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
JP Abgrall29e8de22012-05-03 12:52:15 -070093 * E.g. "-I bw_INPUT -i rmnet0 --jump costly"
JP Abgrall7e51cde2013-07-03 13:33:05 -070094 * - quota'd rules in the costly chain should be before bw_penalty_box lookups.
JP Abgrall29e8de22012-05-03 12:52:15 -070095 * - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070096 *
97 * * global quota vs per interface quota
98 * - global quota for all costly interfaces uses a single costly chain:
99 * . initial rules
JP Abgrall7e51cde2013-07-03 13:33:05 -0700100 * iptables -N bw_costly_shared
101 * iptables -I bw_INPUT -i iface0 --jump bw_costly_shared
102 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_shared
103 * iptables -I bw_costly_shared -m quota \! --quota 500000 \
JP Abgrallbfa74662011-06-29 19:23:04 -0700104 * --jump REJECT --reject-with icmp-net-prohibited
JP Abgrall7e51cde2013-07-03 13:33:05 -0700105 * iptables -A bw_costly_shared --jump bw_penalty_box
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900106 * iptables -A bw_penalty_box --jump bw_happy_box
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900107 * iptables -A bw_happy_box --jump bw_data_saver
JP Abgrall8a932722011-07-13 19:17:35 -0700108 *
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700109 * . adding a new iface to this, E.g.:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700110 * iptables -I bw_INPUT -i iface1 --jump bw_costly_shared
111 * iptables -I bw_OUTPUT -o iface1 --jump bw_costly_shared
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700112 *
113 * - quota per interface. This is achieve by having "costly" chains per quota.
114 * E.g. adding a new costly interface iface0 with its own quota:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700115 * iptables -N bw_costly_iface0
116 * iptables -I bw_INPUT -i iface0 --jump bw_costly_iface0
117 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_iface0
118 * iptables -A bw_costly_iface0 -m quota \! --quota 500000 \
JP Abgralle4788732013-07-02 20:28:45 -0700119 * --jump REJECT --reject-with icmp-port-unreachable
JP Abgrall7e51cde2013-07-03 13:33:05 -0700120 * iptables -A bw_costly_iface0 --jump bw_penalty_box
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700121 *
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900122 * * Penalty box, happy box and data saver.
123 * - bw_penalty box is a blacklist of apps that are rejected.
124 * - bw_happy_box is a whitelist of apps. It always includes all system apps
125 * - bw_data_saver implements data usage restrictions.
126 * - Via the UI the user can add and remove apps from the whitelist and
127 * blacklist, and turn on/off data saver.
128 * - The blacklist takes precedence over the whitelist and the whitelist
129 * takes precedence over data saver.
130 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700131 * * bw_penalty_box handling:
132 * - only one bw_penalty_box for all interfaces
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900133 * E.g Adding an app:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700134 * iptables -I bw_penalty_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700135 * --jump REJECT --reject-with icmp-port-unreachable
136 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700137 * * bw_happy_box handling:
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900138 * - The bw_happy_box comes after the penalty box.
JP Abgralle4788732013-07-02 20:28:45 -0700139 * E.g Adding a happy app,
JP Abgrall7e51cde2013-07-03 13:33:05 -0700140 * iptables -I bw_happy_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700141 * --jump RETURN
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900142 *
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900143 * * bw_data_saver handling:
144 * - The bw_data_saver comes after the happy box.
145 * Enable data saver:
146 * iptables -R 1 bw_data_saver --jump REJECT --reject-with icmp-port-unreachable
147 * Disable data saver:
148 * iptables -R 1 bw_data_saver --jump RETURN
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700149 */
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900150
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900151const std::string COMMIT_AND_CLOSE = "COMMIT\n";
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900152const std::string HAPPY_BOX_WHITELIST_COMMAND = StringPrintf(
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900153 "-I bw_happy_box -m owner --uid-owner %d-%d --jump RETURN", 0, MAX_SYSTEM_UID);
154
155static const std::vector<std::string> IPT_FLUSH_COMMANDS = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700156 /*
157 * Cleanup rules.
JP Abgrall7e51cde2013-07-03 13:33:05 -0700158 * Should normally include bw_costly_<iface>, but we rely on the way they are setup
JP Abgrall0031cea2012-04-17 16:38:23 -0700159 * to allow coexistance.
JP Abgrall39f8f242011-06-29 19:21:58 -0700160 */
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900161 "*filter",
162 ":bw_INPUT -",
163 ":bw_OUTPUT -",
164 ":bw_FORWARD -",
165 ":bw_happy_box -",
166 ":bw_penalty_box -",
167 ":bw_data_saver -",
168 ":bw_costly_shared -",
169 "COMMIT",
170 "*raw",
171 ":bw_raw_PREROUTING -",
172 "COMMIT",
173 "*mangle",
174 ":bw_mangle_POSTROUTING -",
175 COMMIT_AND_CLOSE
JP Abgrall0031cea2012-04-17 16:38:23 -0700176};
177
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900178static const std::vector<std::string> IPT_BASIC_ACCOUNTING_COMMANDS = {
179 "*filter",
JP Abgrall0031cea2012-04-17 16:38:23 -0700180 "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0031cea2012-04-17 16:38:23 -0700181 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900182 "-A bw_costly_shared --jump bw_penalty_box",
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900183 "-A bw_penalty_box --jump bw_happy_box",
184 "-A bw_happy_box --jump bw_data_saver",
185 "-A bw_data_saver -j RETURN",
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900186 HAPPY_BOX_WHITELIST_COMMAND,
187 "COMMIT",
188
189 "*raw",
190 "-A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
191 "COMMIT",
192
193 "*mangle",
194 "-A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
195 COMMIT_AND_CLOSE
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900196};
197
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900198std::vector<std::string> toStrVec(int num, char* strs[]) {
199 std::vector<std::string> tmp;
200 for (int i = 0; i < num; ++i) {
201 tmp.emplace_back(strs[i]);
202 }
203 return tmp;
204}
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900205
206} // namespace
207
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900208BandwidthController::BandwidthController() {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700209}
210
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900211int BandwidthController::runIpxtablesCmd(const std::string& cmd, IptJumpOp jumpHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700212 IptFailureLog failureHandling) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700213 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700214
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900215 ALOGV("runIpxtablesCmd(cmd=%s)", cmd.c_str());
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700216 res |= runIptablesCmd(cmd, jumpHandling, IptIpV4, failureHandling);
217 res |= runIptablesCmd(cmd, jumpHandling, IptIpV6, failureHandling);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700218 return res;
219}
220
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900221int BandwidthController::StrncpyAndCheck(char* buffer, const std::string& src, size_t buffSize) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700222 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900223 strncpy(buffer, src.c_str(), buffSize);
JP Abgrall26e0d492011-06-24 19:21:51 -0700224 return buffer[buffSize - 1];
225}
226
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900227int BandwidthController::runIptablesCmd(const std::string& cmd, IptJumpOp jumpHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700228 IptIpVer iptVer, IptFailureLog failureHandling) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700229 char buffer[MAX_CMD_LEN];
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700230 const char *argv[MAX_CMD_ARGS];
JP Abgrall26e0d492011-06-24 19:21:51 -0700231 int argc = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700232 char *next = buffer;
233 char *tmp;
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700234 int res;
Rom Lemarchand14150212013-01-24 10:01:04 -0800235 int status = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700236
JP Abgrall0dad7c22011-06-24 11:58:14 -0700237 std::string fullCmd = cmd;
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900238 fullCmd += jumpToString(jumpHandling);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700239
Paul Jensen94b2ab92015-08-04 10:35:05 -0400240 fullCmd.insert(0, " -w ");
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700241 fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700242
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900243 if (StrncpyAndCheck(buffer, fullCmd, sizeof(buffer))) {
Rom Lemarchand14150212013-01-24 10:01:04 -0800244 ALOGE("iptables command too long");
245 return -1;
246 }
247
248 argc = 0;
249 while ((tmp = strsep(&next, " "))) {
250 argv[argc++] = tmp;
251 if (argc >= MAX_CMD_ARGS) {
252 ALOGE("iptables argument overflow");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700253 return -1;
254 }
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700255 }
Rom Lemarchand14150212013-01-24 10:01:04 -0800256
257 argv[argc] = NULL;
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900258 res = execFunction(argc, (char **)argv, &status, false,
Rom Lemarchand14150212013-01-24 10:01:04 -0800259 failureHandling == IptFailShow);
JP Abgrallc8dc63b2013-02-13 16:30:00 -0800260 res = res || !WIFEXITED(status) || WEXITSTATUS(status);
261 if (res && failureHandling == IptFailShow) {
262 ALOGE("runIptablesCmd(): res=%d status=%d failed %s", res, status,
263 fullCmd.c_str());
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700264 }
265 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700266}
267
JP Abgrall0e540ec2013-08-26 15:13:10 -0700268void BandwidthController::flushCleanTables(bool doClean) {
269 /* Flush and remove the bw_costly_<iface> tables */
270 flushExistingCostlyTables(doClean);
JP Abgrall0031cea2012-04-17 16:38:23 -0700271
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900272 std::string commands = android::base::Join(IPT_FLUSH_COMMANDS, '\n');
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900273 iptablesRestoreFunction(V4V6, commands, nullptr);
JP Abgrall0e540ec2013-08-26 15:13:10 -0700274}
JP Abgrall0031cea2012-04-17 16:38:23 -0700275
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900276int BandwidthController::setupIptablesHooks() {
JP Abgrall0e540ec2013-08-26 15:13:10 -0700277 /* flush+clean is allowed to fail */
278 flushCleanTables(true);
JP Abgrall0031cea2012-04-17 16:38:23 -0700279 return 0;
JP Abgrall0031cea2012-04-17 16:38:23 -0700280}
281
282int BandwidthController::enableBandwidthControl(bool force) {
JP Abgrall0031cea2012-04-17 16:38:23 -0700283 char value[PROPERTY_VALUE_MAX];
284
285 if (!force) {
286 property_get("persist.bandwidth.enable", value, "1");
287 if (!strcmp(value, "0"))
288 return 0;
289 }
JP Abgrall8a932722011-07-13 19:17:35 -0700290
JP Abgralldb7da582011-09-18 12:57:32 -0700291 /* Let's pretend we started from scratch ... */
JP Abgrall8a932722011-07-13 19:17:35 -0700292 sharedQuotaIfaces.clear();
293 quotaIfaces.clear();
JP Abgralldb7da582011-09-18 12:57:32 -0700294 globalAlertBytes = 0;
JP Abgrallc6c67342011-10-07 16:28:54 -0700295 globalAlertTetherCount = 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700296 sharedQuotaBytes = sharedAlertBytes = 0;
297
JP Abgrall0e540ec2013-08-26 15:13:10 -0700298 flushCleanTables(false);
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900299 std::string commands = android::base::Join(IPT_BASIC_ACCOUNTING_COMMANDS, '\n');
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900300 return iptablesRestoreFunction(V4V6, commands, nullptr);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700301}
302
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900303int BandwidthController::disableBandwidthControl() {
JP Abgrall0e540ec2013-08-26 15:13:10 -0700304
305 flushCleanTables(false);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700306 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700307}
308
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900309int BandwidthController::enableDataSaver(bool enable) {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900310 std::string cmd = StringPrintf(
311 "*filter\n"
312 "-R bw_data_saver 1%s\n"
313 "COMMIT\n", jumpToString(enable ? IptJumpReject : IptJumpReturn));
314 return iptablesRestoreFunction(V4V6, cmd, nullptr);
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900315}
316
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700317int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900318 return manipulateSpecialApps(toStrVec(numUids, appUids), NAUGHTY_CHAIN,
319 IptJumpReject, IptOpInsert);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700320}
321
322int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900323 return manipulateSpecialApps(toStrVec(numUids, appUids), NAUGHTY_CHAIN,
324 IptJumpReject, IptOpDelete);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700325}
326
JP Abgralle4788732013-07-02 20:28:45 -0700327int BandwidthController::addNiceApps(int numUids, char *appUids[]) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900328 return manipulateSpecialApps(toStrVec(numUids, appUids), NICE_CHAIN,
329 IptJumpReturn, IptOpInsert);
JP Abgralle4788732013-07-02 20:28:45 -0700330}
331
332int BandwidthController::removeNiceApps(int numUids, char *appUids[]) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900333 return manipulateSpecialApps(toStrVec(numUids, appUids), NICE_CHAIN,
334 IptJumpReturn, IptOpDelete);
JP Abgralle4788732013-07-02 20:28:45 -0700335}
336
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900337int BandwidthController::manipulateSpecialApps(const std::vector<std::string>& appStrUids,
338 const std::string& chain, IptJumpOp jumpHandling,
339 IptOp op) {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900340 std::string cmd = "*filter\n";
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900341 for (const auto& appStrUid : appStrUids) {
342 StringAppendF(&cmd, "%s %s -m owner --uid-owner %s%s\n", opToString(op), chain.c_str(),
343 appStrUid.c_str(), jumpToString(jumpHandling));
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700344 }
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900345 StringAppendF(&cmd, "COMMIT\n");
346 return iptablesRestoreFunction(V4V6, cmd, nullptr);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700347}
348
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900349std::string BandwidthController::makeIptablesQuotaCmd(IptFullOp op, const std::string& costName,
350 int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700351 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700352 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700353
SynergyDev7776cea2014-03-16 15:48:51 -0700354 ALOGV("makeIptablesQuotaCmd(%d, %" PRId64")", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700355
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700356 switch (op) {
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900357 case IptFullOpInsert:
JP Abgrall8a932722011-07-13 19:17:35 -0700358 opFlag = "-I";
359 break;
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900360 case IptFullOpAppend:
JP Abgrall109899b2013-02-12 19:20:13 -0800361 opFlag = "-A";
362 break;
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900363 case IptFullOpDelete:
JP Abgrall8a932722011-07-13 19:17:35 -0700364 opFlag = "-D";
365 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700366 }
JP Abgrall8a932722011-07-13 19:17:35 -0700367
JP Abgrallbfa74662011-06-29 19:23:04 -0700368 // The requried IP version specific --jump REJECT ... will be added later.
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900369 StringAppendF(&res, "%s bw_costly_%s -m quota2 ! --quota %" PRId64 " --name %s", opFlag,
370 costName.c_str(), quota, costName.c_str());
JP Abgrall0dad7c22011-06-24 11:58:14 -0700371 return res;
372}
373
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900374int BandwidthController::prepCostlyIface(const std::string& ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700375 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700376 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700377 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700378 std::string costString;
379 const char *costCString;
380
JP Abgrall0dad7c22011-06-24 11:58:14 -0700381 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700382 switch (quotaType) {
383 case QuotaUnique:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700384 costString = "bw_costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700385 costString += ifn;
386 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700387 /*
JP Abgrall7e51cde2013-07-03 13:33:05 -0700388 * Flush the bw_costly_<iface> is allowed to fail in case it didn't exist.
JP Abgrall0031cea2012-04-17 16:38:23 -0700389 * Creating a new one is allowed to fail in case it existed.
390 * This helps with netd restarts.
391 */
392 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700393 res1 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700394 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700395 res2 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700396 res = (res1 && res2) || (!res1 && !res2);
397
JP Abgrall7e51cde2013-07-03 13:33:05 -0700398 snprintf(cmd, sizeof(cmd), "-A %s -j bw_penalty_box", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700399 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700400 break;
401 case QuotaShared:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700402 costCString = "bw_costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700403 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700404 }
405
JP Abgrall8a932722011-07-13 19:17:35 -0700406 if (globalAlertBytes) {
407 /* The alert rule comes 1st */
408 ruleInsertPos = 2;
409 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700410
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900411 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn.c_str(), costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700412 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700413
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900414 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn.c_str(),
415 costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700416 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700417
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900418 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn.c_str(), costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700419 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700420
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900421 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn.c_str(),
422 costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700423 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
Erik Kline58a94482015-10-02 17:52:37 +0900424
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900425 snprintf(cmd, sizeof(cmd), "-D bw_FORWARD -o %s --jump %s", ifn.c_str(), costCString);
Erik Kline58a94482015-10-02 17:52:37 +0900426 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900427 snprintf(cmd, sizeof(cmd), "-A bw_FORWARD -o %s --jump %s", ifn.c_str(), costCString);
Erik Kline58a94482015-10-02 17:52:37 +0900428 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
429
JP Abgrall0dad7c22011-06-24 11:58:14 -0700430 return res;
431}
432
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900433int BandwidthController::cleanupCostlyIface(const std::string& ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700434 char cmd[MAX_CMD_LEN];
435 int res = 0;
436 std::string costString;
437 const char *costCString;
438
JP Abgrall26e0d492011-06-24 19:21:51 -0700439 switch (quotaType) {
440 case QuotaUnique:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700441 costString = "bw_costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700442 costString += ifn;
443 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700444 break;
445 case QuotaShared:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700446 costCString = "bw_costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700447 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700448 }
449
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900450 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn.c_str(), costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700451 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
Erik Kline58a94482015-10-02 17:52:37 +0900452 for (const auto tableName : {LOCAL_OUTPUT, LOCAL_FORWARD}) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900453 snprintf(cmd, sizeof(cmd), "-D %s -o %s --jump %s", tableName, ifn.c_str(), costCString);
Erik Kline58a94482015-10-02 17:52:37 +0900454 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
455 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700456
JP Abgrall7e51cde2013-07-03 13:33:05 -0700457 /* The "-N bw_costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700458 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700459 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700460 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700461 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700462 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700463 }
464 return res;
465}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700466
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900467int BandwidthController::setInterfaceSharedQuota(const std::string& iface, int64_t maxBytes) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700468 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700469 std::string quotaCmd;
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900470 const char costName[] = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700471 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700472
JP Abgrall8a932722011-07-13 19:17:35 -0700473 if (!maxBytes) {
474 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000475 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700476 return -1;
477 }
JP Abgrall69261cb2014-06-19 18:35:24 -0700478 if (!isIfaceName(iface))
479 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700480
481 if (maxBytes == -1) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900482 return removeInterfaceSharedQuota(iface);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700483 }
484
485 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700486 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900487 if (*it == iface)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700488 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700489 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700490
JP Abgrall0dad7c22011-06-24 11:58:14 -0700491 if (it == sharedQuotaIfaces.end()) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900492 res |= prepCostlyIface(iface, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700493 if (sharedQuotaIfaces.empty()) {
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900494 quotaCmd = makeIptablesQuotaCmd(IptFullOpInsert, costName, maxBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700495 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700496 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000497 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700498 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700499 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700500 sharedQuotaBytes = maxBytes;
501 }
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900502 sharedQuotaIfaces.push_front(iface);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700503
504 }
505
506 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700507 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700508 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000509 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700510 goto fail;
511 }
512 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700513 }
514 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700515
516 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700517 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700518 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
519 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700520 * For now callers needs to choose if they want to "ndc bandwidth enable"
521 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700522 */
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900523 removeInterfaceSharedQuota(iface);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700524 return -1;
525}
526
JP Abgrall8a932722011-07-13 19:17:35 -0700527/* It will also cleanup any shared alerts */
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900528int BandwidthController::removeInterfaceSharedQuota(const std::string& iface) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700529 int res = 0;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700530 std::list<std::string>::iterator it;
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900531 const char costName[] = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700532
JP Abgrall69261cb2014-06-19 18:35:24 -0700533 if (!isIfaceName(iface))
534 return -1;
JP Abgrall26e0d492011-06-24 19:21:51 -0700535
JP Abgrall0dad7c22011-06-24 11:58:14 -0700536 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900537 if (*it == iface)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700538 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700539 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700540 if (it == sharedQuotaIfaces.end()) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900541 ALOGE("No such iface %s to delete", iface.c_str());
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700542 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700543 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700544
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900545 res |= cleanupCostlyIface(iface, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700546 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700547
JP Abgrall0dad7c22011-06-24 11:58:14 -0700548 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700549 std::string quotaCmd;
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900550 quotaCmd = makeIptablesQuotaCmd(IptFullOpDelete, costName, sharedQuotaBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700551 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall8a932722011-07-13 19:17:35 -0700552 sharedQuotaBytes = 0;
553 if (sharedAlertBytes) {
554 removeSharedAlert();
555 sharedAlertBytes = 0;
556 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700557 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700558 return res;
559}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700560
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900561int BandwidthController::setInterfaceQuota(const std::string& iface, int64_t maxBytes) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700562 int res = 0;
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900563 const auto& costName = iface;
JP Abgrall26e0d492011-06-24 19:21:51 -0700564 std::list<QuotaInfo>::iterator it;
565 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700566
JP Abgrall69261cb2014-06-19 18:35:24 -0700567 if (!isIfaceName(iface))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700568 return -1;
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700569
JP Abgrall8a932722011-07-13 19:17:35 -0700570 if (!maxBytes) {
571 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000572 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700573 return -1;
574 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700575 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700576 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700577 }
578
JP Abgrall0dad7c22011-06-24 11:58:14 -0700579 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700580 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900581 if (it->ifaceName == iface)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700582 break;
583 }
584
585 if (it == quotaIfaces.end()) {
JP Abgralle4788732013-07-02 20:28:45 -0700586 /* Preparing the iface adds a penalty/happy box check */
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900587 res |= prepCostlyIface(iface, QuotaUnique);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700588 /*
JP Abgralle4788732013-07-02 20:28:45 -0700589 * The rejecting quota limit should go after the penalty/happy box checks
JP Abgrallbaeccc42013-06-25 09:44:10 -0700590 * or else a naughty app could just eat up the quota.
591 * So we append here.
592 */
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900593 quotaCmd = makeIptablesQuotaCmd(IptFullOpAppend, costName, maxBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700594 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700595 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000596 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700597 goto fail;
598 }
599
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900600 quotaIfaces.push_front(QuotaInfo(iface, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700601
602 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700603 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700604 if (res) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900605 ALOGE("Failed update quota for %s", iface.c_str());
JP Abgrall0dad7c22011-06-24 11:58:14 -0700606 goto fail;
607 }
JP Abgrall8a932722011-07-13 19:17:35 -0700608 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700609 }
610 return 0;
611
612 fail:
613 /*
614 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
615 * rules in the kernel to see which ones need cleaning up.
616 * For now callers needs to choose if they want to "ndc bandwidth enable"
617 * which resets everything.
618 */
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900619 removeInterfaceSharedQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700620 return -1;
621}
622
JP Abgrall8a932722011-07-13 19:17:35 -0700623int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
624 return getInterfaceQuota("shared", bytes);
625}
626
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900627int BandwidthController::getInterfaceQuota(const std::string& iface, int64_t* bytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700628 FILE *fp;
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900629 const std::string fname = "/proc/net/xt_quota/" + iface;
JP Abgrall8a932722011-07-13 19:17:35 -0700630 int scanRes;
631
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900632 if (!isIfaceName(iface)) return -1;
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700633
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900634 fp = fopen(fname.c_str(), "re");
JP Abgrall8a932722011-07-13 19:17:35 -0700635 if (!fp) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900636 ALOGE("Reading quota %s failed (%s)", iface.c_str(), strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700637 return -1;
638 }
Mark Salyzynca0b5e22014-03-26 14:15:03 -0700639 scanRes = fscanf(fp, "%" SCNd64, bytes);
SynergyDev7776cea2014-03-16 15:48:51 -0700640 ALOGV("Read quota res=%d bytes=%" PRId64, scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700641 fclose(fp);
642 return scanRes == 1 ? 0 : -1;
643}
644
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900645int BandwidthController::removeInterfaceQuota(const std::string& iface) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700646 int res = 0;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700647 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700648
JP Abgrall69261cb2014-06-19 18:35:24 -0700649 if (!isIfaceName(iface))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700650 return -1;
JP Abgrall26e0d492011-06-24 19:21:51 -0700651
JP Abgrall0dad7c22011-06-24 11:58:14 -0700652 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900653 if (it->ifaceName == iface)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700654 break;
655 }
656
657 if (it == quotaIfaces.end()) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900658 ALOGE("No such iface %s to delete", iface.c_str());
JP Abgrall0dad7c22011-06-24 11:58:14 -0700659 return -1;
660 }
661
662 /* This also removes the quota command of CostlyIface chain. */
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900663 res |= cleanupCostlyIface(iface, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700664
665 quotaIfaces.erase(it);
666
667 return res;
668}
JP Abgrall8a932722011-07-13 19:17:35 -0700669
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900670int BandwidthController::updateQuota(const std::string& quotaName, int64_t bytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700671 FILE *fp;
672 char *fname;
673
JP Abgrall69261cb2014-06-19 18:35:24 -0700674 if (!isIfaceName(quotaName)) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900675 ALOGE("updateQuota: Invalid quotaName \"%s\"", quotaName.c_str());
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700676 return -1;
677 }
678
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900679 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName.c_str());
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800680 fp = fopen(fname, "we");
JP Abgrall8a932722011-07-13 19:17:35 -0700681 free(fname);
682 if (!fp) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900683 ALOGE("Updating quota %s failed (%s)", quotaName.c_str(), strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700684 return -1;
685 }
SynergyDev7776cea2014-03-16 15:48:51 -0700686 fprintf(fp, "%" PRId64"\n", bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700687 fclose(fp);
688 return 0;
689}
690
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900691int BandwidthController::runIptablesAlertCmd(IptOp op, const std::string& alertName,
692 int64_t bytes) {
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900693 const char *opFlag = opToString(op);
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900694 std::string alertQuotaCmd = "*filter\n";
JP Abgrall8a932722011-07-13 19:17:35 -0700695
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900696 // TODO: consider using an alternate template for the delete that does not include the --quota
697 // value. This code works because the --quota value is ignored by deletes
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900698 StringAppendF(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT", bytes,
699 alertName.c_str());
700 StringAppendF(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT", bytes,
701 alertName.c_str());
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900702 StringAppendF(&alertQuotaCmd, "COMMIT\n");
703
Lorenzo Colitti4773cb42017-04-27 14:03:25 +0900704 return iptablesRestoreFunction(V4V6, alertQuotaCmd, nullptr);
JP Abgrall8a932722011-07-13 19:17:35 -0700705}
706
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900707int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const std::string& alertName,
708 int64_t bytes) {
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900709 const char *opFlag = opToString(op);
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900710 std::string alertQuotaCmd = "*filter\n";
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900711 StringAppendF(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD", bytes,
712 alertName.c_str());
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900713 StringAppendF(&alertQuotaCmd, "COMMIT\n");
714
715 return iptablesRestoreFunction(V4V6, alertQuotaCmd, nullptr);
JP Abgrallc6c67342011-10-07 16:28:54 -0700716}
717
718int BandwidthController::setGlobalAlert(int64_t bytes) {
719 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700720 int res = 0;
721
722 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000723 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700724 return -1;
725 }
726 if (globalAlertBytes) {
727 res = updateQuota(alertName, bytes);
728 } else {
729 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700730 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +0100731 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700732 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
733 }
JP Abgrall8a932722011-07-13 19:17:35 -0700734 }
735 globalAlertBytes = bytes;
736 return res;
737}
738
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900739int BandwidthController::setGlobalAlertInForwardChain() {
JP Abgrallc6c67342011-10-07 16:28:54 -0700740 const char *alertName = ALERT_GLOBAL_NAME;
741 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700742
JP Abgrallc6c67342011-10-07 16:28:54 -0700743 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +0100744 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700745
746 /*
747 * If there is no globalAlert active we are done.
748 * If there is an active globalAlert but this is not the 1st
749 * tether, we are also done.
750 */
751 if (!globalAlertBytes || globalAlertTetherCount != 1) {
752 return 0;
753 }
754
755 /* We only add the rule if this was the 1st tether added. */
756 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
757 return res;
758}
759
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900760int BandwidthController::removeGlobalAlert() {
JP Abgrallc6c67342011-10-07 16:28:54 -0700761
762 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700763 int res = 0;
764
765 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000766 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700767 return -1;
768 }
769 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700770 if (globalAlertTetherCount) {
771 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
772 }
JP Abgrall8a932722011-07-13 19:17:35 -0700773 globalAlertBytes = 0;
774 return res;
775}
776
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900777int BandwidthController::removeGlobalAlertInForwardChain() {
JP Abgrallc6c67342011-10-07 16:28:54 -0700778 int res = 0;
779 const char *alertName = ALERT_GLOBAL_NAME;
780
781 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000782 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700783 return -1;
784 }
785
786 globalAlertTetherCount--;
787 /*
788 * If there is no globalAlert active we are done.
789 * If there is an active globalAlert but there are more
790 * tethers, we are also done.
791 */
792 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
793 return 0;
794 }
795
796 /* We only detete the rule if this was the last tether removed. */
797 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
798 return res;
799}
800
JP Abgrall8a932722011-07-13 19:17:35 -0700801int BandwidthController::setSharedAlert(int64_t bytes) {
802 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000803 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700804 return -1;
805 }
806 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000807 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700808 return -1;
809 }
810 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
811}
812
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900813int BandwidthController::removeSharedAlert() {
JP Abgrall8a932722011-07-13 19:17:35 -0700814 return removeCostlyAlert("shared", &sharedAlertBytes);
815}
816
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900817int BandwidthController::setInterfaceAlert(const std::string& iface, int64_t bytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700818 std::list<QuotaInfo>::iterator it;
819
JP Abgrall69261cb2014-06-19 18:35:24 -0700820 if (!isIfaceName(iface)) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900821 ALOGE("setInterfaceAlert: Invalid iface \"%s\"", iface.c_str());
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700822 return -1;
823 }
824
JP Abgrall8a932722011-07-13 19:17:35 -0700825 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000826 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700827 return -1;
828 }
829 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
830 if (it->ifaceName == iface)
831 break;
832 }
833
834 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000835 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700836 return -1;
837 }
838
839 return setCostlyAlert(iface, bytes, &it->alert);
840}
841
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900842int BandwidthController::removeInterfaceAlert(const std::string& iface) {
JP Abgrall8a932722011-07-13 19:17:35 -0700843 std::list<QuotaInfo>::iterator it;
844
JP Abgrall69261cb2014-06-19 18:35:24 -0700845 if (!isIfaceName(iface)) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900846 ALOGE("removeInterfaceAlert: Invalid iface \"%s\"", iface.c_str());
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700847 return -1;
848 }
849
JP Abgrall8a932722011-07-13 19:17:35 -0700850 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
851 if (it->ifaceName == iface)
852 break;
853 }
854
855 if (it == quotaIfaces.end()) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900856 ALOGE("No prior alert set for interface %s", iface.c_str());
JP Abgrall8a932722011-07-13 19:17:35 -0700857 return -1;
858 }
859
860 return removeCostlyAlert(iface, &it->alert);
861}
862
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900863int BandwidthController::setCostlyAlert(const std::string& costName, int64_t bytes,
864 int64_t* alertBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700865 char *alertQuotaCmd;
JP Abgrall109899b2013-02-12 19:20:13 -0800866 char *chainName;
JP Abgrall8a932722011-07-13 19:17:35 -0700867 int res = 0;
868 char *alertName;
869
JP Abgrall69261cb2014-06-19 18:35:24 -0700870 if (!isIfaceName(costName)) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900871 ALOGE("setCostlyAlert: Invalid costName \"%s\"", costName.c_str());
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700872 return -1;
873 }
874
JP Abgrall8a932722011-07-13 19:17:35 -0700875 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000876 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700877 return -1;
878 }
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900879 asprintf(&alertName, "%sAlert", costName.c_str());
JP Abgrall8a932722011-07-13 19:17:35 -0700880 if (*alertBytes) {
881 res = updateQuota(alertName, *alertBytes);
882 } else {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900883 asprintf(&chainName, "bw_costly_%s", costName.c_str());
JP Abgrall109899b2013-02-12 19:20:13 -0800884 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-A", chainName, bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700885 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700886 free(alertQuotaCmd);
JP Abgrall109899b2013-02-12 19:20:13 -0800887 free(chainName);
JP Abgrall8a932722011-07-13 19:17:35 -0700888 }
889 *alertBytes = bytes;
890 free(alertName);
891 return res;
892}
893
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900894int BandwidthController::removeCostlyAlert(const std::string& costName, int64_t* alertBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700895 char *alertQuotaCmd;
896 char *chainName;
897 char *alertName;
898 int res = 0;
899
JP Abgrall69261cb2014-06-19 18:35:24 -0700900 if (!isIfaceName(costName)) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900901 ALOGE("removeCostlyAlert: Invalid costName \"%s\"", costName.c_str());
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700902 return -1;
903 }
904
JP Abgrall8a932722011-07-13 19:17:35 -0700905 if (!*alertBytes) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900906 ALOGE("No prior alert set for %s alert", costName.c_str());
JP Abgrall8a932722011-07-13 19:17:35 -0700907 return -1;
908 }
909
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900910 asprintf(&alertName, "%sAlert", costName.c_str());
911 asprintf(&chainName, "bw_costly_%s", costName.c_str());
JP Abgrall92009c82013-02-06 18:01:24 -0800912 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700913 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700914 free(alertQuotaCmd);
915 free(chainName);
916
917 *alertBytes = 0;
918 free(alertName);
919 return res;
920}
JP Abgralldb7da582011-09-18 12:57:32 -0700921
Lorenzo Colitti7364b752016-07-08 18:24:53 +0900922void BandwidthController::addStats(TetherStatsList& statsList, const TetherStats& stats) {
923 for (TetherStats& existing : statsList) {
924 if (existing.addStatsIfMatch(stats)) {
925 return;
926 }
927 }
928 // No match. Insert a new interface pair.
929 statsList.push_back(stats);
930}
931
JP Abgralldb7da582011-09-18 12:57:32 -0700932/*
933 * Parse the ptks and bytes out of:
JP Abgrallbaeccc42013-06-25 09:44:10 -0700934 * Chain natctrl_tether_counters (4 references)
935 * pkts bytes target prot opt in out source destination
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700936 * 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
937 * 27 2002 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0
938 * 1040 107471 RETURN all -- bt-pan rmnet0 0.0.0.0/0 0.0.0.0/0
939 * 1450 1708806 RETURN all -- rmnet0 bt-pan 0.0.0.0/0 0.0.0.0/0
Lorenzo Colitti26c91322016-07-11 11:36:25 +0900940 * or:
941 * Chain natctrl_tether_counters (0 references)
942 * pkts bytes target prot opt in out source destination
943 * 0 0 RETURN all wlan0 rmnet_data0 ::/0 ::/0
944 * 0 0 RETURN all rmnet_data0 wlan0 ::/0 ::/0
945 *
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700946 * It results in an error if invoked and no tethering counter rules exist. The constraint
947 * helps detect complete parsing failure.
JP Abgralldb7da582011-09-18 12:57:32 -0700948 */
Lorenzo Colitti7364b752016-07-08 18:24:53 +0900949int BandwidthController::addForwardChainStats(const TetherStats& filter,
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900950 TetherStatsList& statsList,
951 const std::string& statsOutput,
Lorenzo Colitti7364b752016-07-08 18:24:53 +0900952 std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -0700953 int res;
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900954 std::string statsLine;
JP Abgralldb7da582011-09-18 12:57:32 -0700955 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
956 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
957 char rest[MAX_IPT_OUTPUT_LINE_LEN];
958
JP Abgrallbaeccc42013-06-25 09:44:10 -0700959 TetherStats stats;
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900960 const char *buffPtr;
JP Abgralldb7da582011-09-18 12:57:32 -0700961 int64_t packets, bytes;
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700962 int statsFound = 0;
JP Abgrallbaeccc42013-06-25 09:44:10 -0700963
964 bool filterPair = filter.intIface[0] && filter.extIface[0];
965
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900966 ALOGV("filter: %s", filter.getStatsLine().c_str());
JP Abgrallbaeccc42013-06-25 09:44:10 -0700967
968 stats = filter;
JP Abgralldb7da582011-09-18 12:57:32 -0700969
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900970 std::stringstream stream(statsOutput);
971 while (std::getline(stream, statsLine, '\n')) {
972 buffPtr = statsLine.c_str();
973
JP Abgralldb7da582011-09-18 12:57:32 -0700974 /* Clean up, so a failed parse can still print info */
975 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
Lorenzo Colitti26c91322016-07-11 11:36:25 +0900976 if (strstr(buffPtr, "0.0.0.0")) {
977 // IPv4 has -- indicating what to do with fragments...
978 // 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
979 res = sscanf(buffPtr, "%" SCNd64" %" SCNd64" RETURN all -- %s %s 0.%s",
980 &packets, &bytes, iface0, iface1, rest);
981 } else {
982 // ... but IPv6 does not.
983 // 26 2373 RETURN all wlan0 rmnet0 ::/0 ::/0
984 res = sscanf(buffPtr, "%" SCNd64" %" SCNd64" RETURN all %s %s ::/%s",
985 &packets, &bytes, iface0, iface1, rest);
986 }
SynergyDev7776cea2014-03-16 15:48:51 -0700987 ALOGV("parse res=%d iface0=<%s> iface1=<%s> pkts=%" PRId64" bytes=%" PRId64" rest=<%s> orig line=<%s>", res,
JP Abgralldb7da582011-09-18 12:57:32 -0700988 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -0800989 extraProcessingInfo += buffPtr;
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900990 extraProcessingInfo += "\n";
JP Abgralla2a64f02011-11-11 20:36:16 -0800991
JP Abgralldb7da582011-09-18 12:57:32 -0700992 if (res != 5) {
993 continue;
994 }
JP Abgrallbaeccc42013-06-25 09:44:10 -0700995 /*
996 * The following assumes that the 1st rule has in:extIface out:intIface,
997 * which is what NatController sets up.
998 * If not filtering, the 1st match rx, and sets up the pair for the tx side.
999 */
1000 if (filter.intIface[0] && filter.extIface[0]) {
1001 if (filter.intIface == iface0 && filter.extIface == iface1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001002 ALOGV("2Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001003 stats.rxPackets = packets;
1004 stats.rxBytes = bytes;
1005 } else if (filter.intIface == iface1 && filter.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001006 ALOGV("2Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001007 stats.txPackets = packets;
1008 stats.txBytes = bytes;
1009 }
1010 } else if (filter.intIface[0] || filter.extIface[0]) {
1011 if (filter.intIface == iface0 || filter.extIface == iface1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001012 ALOGV("1Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001013 stats.intIface = iface0;
1014 stats.extIface = iface1;
1015 stats.rxPackets = packets;
1016 stats.rxBytes = bytes;
1017 } else if (filter.intIface == iface1 || filter.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001018 ALOGV("1Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001019 stats.intIface = iface1;
1020 stats.extIface = iface0;
1021 stats.txPackets = packets;
1022 stats.txBytes = bytes;
1023 }
1024 } else /* if (!filter.intFace[0] && !filter.extIface[0]) */ {
1025 if (!stats.intIface[0]) {
SynergyDev7776cea2014-03-16 15:48:51 -07001026 ALOGV("0Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001027 stats.intIface = iface0;
1028 stats.extIface = iface1;
1029 stats.rxPackets = packets;
1030 stats.rxBytes = bytes;
1031 } else if (stats.intIface == iface1 && stats.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001032 ALOGV("0Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001033 stats.txPackets = packets;
1034 stats.txBytes = bytes;
1035 }
1036 }
1037 if (stats.rxBytes != -1 && stats.txBytes != -1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001038 ALOGV("rx_bytes=%" PRId64" tx_bytes=%" PRId64" filterPair=%d", stats.rxBytes, stats.txBytes, filterPair);
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001039 addStats(statsList, stats);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001040 if (filterPair) {
JP Abgrallbaeccc42013-06-25 09:44:10 -07001041 return 0;
1042 } else {
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001043 statsFound++;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001044 stats = filter;
1045 }
JP Abgralldb7da582011-09-18 12:57:32 -07001046 }
1047 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001048
1049 /* It is always an error to find only one side of the stats. */
1050 /* It is an error to find nothing when not filtering. */
1051 if (((stats.rxBytes == -1) != (stats.txBytes == -1)) ||
1052 (!statsFound && !filterPair)) {
1053 return -1;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001054 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001055 return 0;
JP Abgralldb7da582011-09-18 12:57:32 -07001056}
1057
Joel Scherpelzbcad6612017-05-30 10:55:11 +09001058std::string BandwidthController::TetherStats::getStatsLine() const {
1059 std::string msg;
1060 StringAppendF(&msg, "%s %s %" PRId64" %" PRId64" %" PRId64" %" PRId64, intIface.c_str(),
1061 extIface.c_str(), rxBytes, rxPackets, txBytes, txPackets);
JP Abgralldb7da582011-09-18 12:57:32 -07001062 return msg;
1063}
1064
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001065int BandwidthController::getTetherStats(SocketClient *cli, TetherStats& filter,
1066 std::string &extraProcessingInfo) {
1067 int res = 0;
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001068
1069 TetherStatsList statsList;
1070
Lorenzo Colittice6748a2017-02-02 01:34:33 +09001071 for (const IptablesTarget target : {V4, V6}) {
1072 std::string statsString;
1073 res = iptablesRestoreFunction(target, GET_TETHER_STATS_COMMAND, &statsString);
1074 if (res != 0) {
1075 ALOGE("Failed to run %s err=%d", GET_TETHER_STATS_COMMAND.c_str(), res);
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001076 return -1;
1077 }
1078
Lorenzo Colittice6748a2017-02-02 01:34:33 +09001079 res = addForwardChainStats(filter, statsList, statsString, extraProcessingInfo);
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001080 if (res != 0) {
1081 return res;
1082 }
1083 }
JP Abgralldb7da582011-09-18 12:57:32 -07001084
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001085 if (filter.intIface[0] && filter.extIface[0] && statsList.size() == 1) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +09001086 cli->sendMsg(ResponseCode::TetheringStatsResult,
1087 statsList[0].getStatsLine().c_str(), false);
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001088 } else {
1089 for (const auto& stats: statsList) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +09001090 cli->sendMsg(ResponseCode::TetheringStatsListResult,
1091 stats.getStatsLine().c_str(), false);
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001092 }
1093 if (res == 0) {
1094 cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
1095 }
1096 }
1097
JP Abgralldb7da582011-09-18 12:57:32 -07001098 return res;
1099}
JP Abgrall0e540ec2013-08-26 15:13:10 -07001100
1101void BandwidthController::flushExistingCostlyTables(bool doClean) {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +09001102 std::string fullCmd = "*filter\n-S\nCOMMIT\n";
1103 std::string ruleList;
JP Abgrall0e540ec2013-08-26 15:13:10 -07001104
1105 /* Only lookup ip4 table names as ip6 will have the same tables ... */
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +09001106 if (int ret = iptablesRestoreFunction(V4, fullCmd, &ruleList)) {
1107 ALOGE("Failed to list existing costly tables ret=%d", ret);
JP Abgrall0e540ec2013-08-26 15:13:10 -07001108 return;
1109 }
1110 /* ... then flush/clean both ip4 and ip6 iptables. */
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +09001111 parseAndFlushCostlyTables(ruleList, doClean);
JP Abgrall0e540ec2013-08-26 15:13:10 -07001112}
1113
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +09001114void BandwidthController::parseAndFlushCostlyTables(const std::string& ruleList, bool doRemove) {
1115 std::stringstream stream(ruleList);
1116 std::string rule;
1117 std::vector<std::string> clearCommands = { "*filter" };
1118 std::string chainName;
JP Abgrall0e540ec2013-08-26 15:13:10 -07001119
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +09001120 // Find and flush all rules starting with "-N bw_costly_<iface>" except "-N bw_costly_shared".
1121 while (std::getline(stream, rule, '\n')) {
1122 if (rule.find(NEW_CHAIN_COMMAND) != 0) continue;
1123 chainName = rule.substr(NEW_CHAIN_COMMAND.size());
1124 ALOGV("parse chainName=<%s> orig line=<%s>", chainName.c_str(), rule.c_str());
1125
1126 if (chainName.find("bw_costly_") != 0 || chainName == std::string("bw_costly_shared")) {
JP Abgrall0e540ec2013-08-26 15:13:10 -07001127 continue;
1128 }
1129
Lorenzo Colitti3c272702017-04-26 15:48:13 +09001130 clearCommands.push_back(StringPrintf(":%s -", chainName.c_str()));
JP Abgrall0e540ec2013-08-26 15:13:10 -07001131 if (doRemove) {
Lorenzo Colitti3c272702017-04-26 15:48:13 +09001132 clearCommands.push_back(StringPrintf("-X %s", chainName.c_str()));
JP Abgrall0e540ec2013-08-26 15:13:10 -07001133 }
1134 }
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +09001135
1136 if (clearCommands.size() == 1) {
1137 // No rules found.
1138 return;
1139 }
1140
1141 clearCommands.push_back("COMMIT\n");
1142 iptablesRestoreFunction(V4V6, android::base::Join(clearCommands, '\n'), nullptr);
JP Abgrall0e540ec2013-08-26 15:13:10 -07001143}
Lorenzo Colittid9db08c2017-04-28 11:06:40 +09001144
1145inline const char *BandwidthController::opToString(IptOp op) {
1146 switch (op) {
1147 case IptOpInsert:
1148 return "-I";
1149 case IptOpDelete:
1150 return "-D";
1151 }
1152}
1153
1154inline const char *BandwidthController::jumpToString(IptJumpOp jumpHandling) {
1155 /*
1156 * Must be careful what one rejects with, as upper layer protocols will just
1157 * keep on hammering the device until the number of retries are done.
1158 * For port-unreachable (default), TCP should consider as an abort (RFC1122).
1159 */
1160 switch (jumpHandling) {
1161 case IptJumpNoAdd:
1162 return "";
1163 case IptJumpReject:
1164 return " --jump REJECT";
1165 case IptJumpReturn:
1166 return " --jump RETURN";
1167 }
1168}