blob: 9800b6e3e4e0180127f135436516f599fdd01349 [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"
Devi Sandeep Endluri V V893c1222016-04-27 22:31:19 +053058#include "QtiConnectivityAdapter.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070059
JP Abgralldb7da582011-09-18 12:57:32 -070060/* Alphabetical */
SynergyDev7776cea2014-03-16 15:48:51 -070061#define ALERT_IPT_TEMPLATE "%s %s -m quota2 ! --quota %" PRId64" --name %s"
Jeff Sharkey8e188ed2012-07-12 18:32:03 -070062const char* BandwidthController::LOCAL_INPUT = "bw_INPUT";
63const char* BandwidthController::LOCAL_FORWARD = "bw_FORWARD";
64const char* BandwidthController::LOCAL_OUTPUT = "bw_OUTPUT";
65const char* BandwidthController::LOCAL_RAW_PREROUTING = "bw_raw_PREROUTING";
66const char* BandwidthController::LOCAL_MANGLE_POSTROUTING = "bw_mangle_POSTROUTING";
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090067
Lorenzo Colitti86a47982016-03-18 17:52:25 +090068auto BandwidthController::execFunction = android_fork_execvp;
69auto BandwidthController::popenFunction = popen;
Lorenzo Colitti13debb82016-03-27 17:46:30 +090070auto BandwidthController::iptablesRestoreFunction = execIptablesRestore;
Lorenzo Colitti86a47982016-03-18 17:52:25 +090071
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090072namespace {
73
74const char ALERT_GLOBAL_NAME[] = "globalAlert";
75const int MAX_CMD_ARGS = 32;
76const int MAX_CMD_LEN = 1024;
77const int MAX_IFACENAME_LEN = 64;
78const int MAX_IPT_OUTPUT_LINE_LEN = 256;
JP Abgralldb7da582011-09-18 12:57:32 -070079
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070080/**
81 * Some comments about the rules:
82 * * Ordering
83 * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
JP Abgrall29e8de22012-05-03 12:52:15 -070084 * E.g. "-I bw_INPUT -i rmnet0 --jump costly"
JP Abgrall7e51cde2013-07-03 13:33:05 -070085 * - quota'd rules in the costly chain should be before bw_penalty_box lookups.
JP Abgrall29e8de22012-05-03 12:52:15 -070086 * - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070087 *
88 * * global quota vs per interface quota
89 * - global quota for all costly interfaces uses a single costly chain:
90 * . initial rules
JP Abgrall7e51cde2013-07-03 13:33:05 -070091 * iptables -N bw_costly_shared
92 * iptables -I bw_INPUT -i iface0 --jump bw_costly_shared
93 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_shared
94 * iptables -I bw_costly_shared -m quota \! --quota 500000 \
JP Abgrallbfa74662011-06-29 19:23:04 -070095 * --jump REJECT --reject-with icmp-net-prohibited
JP Abgrall7e51cde2013-07-03 13:33:05 -070096 * iptables -A bw_costly_shared --jump bw_penalty_box
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090097 * iptables -A bw_penalty_box --jump bw_happy_box
Lorenzo Colitti464eabe2016-03-25 13:38:19 +090098 * iptables -A bw_happy_box --jump bw_data_saver
JP Abgrall8a932722011-07-13 19:17:35 -070099 *
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700100 * . adding a new iface to this, E.g.:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700101 * iptables -I bw_INPUT -i iface1 --jump bw_costly_shared
102 * iptables -I bw_OUTPUT -o iface1 --jump bw_costly_shared
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700103 *
104 * - quota per interface. This is achieve by having "costly" chains per quota.
105 * E.g. adding a new costly interface iface0 with its own quota:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700106 * iptables -N bw_costly_iface0
107 * iptables -I bw_INPUT -i iface0 --jump bw_costly_iface0
108 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_iface0
109 * iptables -A bw_costly_iface0 -m quota \! --quota 500000 \
JP Abgralle4788732013-07-02 20:28:45 -0700110 * --jump REJECT --reject-with icmp-port-unreachable
JP Abgrall7e51cde2013-07-03 13:33:05 -0700111 * iptables -A bw_costly_iface0 --jump bw_penalty_box
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700112 *
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900113 * * Penalty box, happy box and data saver.
114 * - bw_penalty box is a blacklist of apps that are rejected.
115 * - bw_happy_box is a whitelist of apps. It always includes all system apps
116 * - bw_data_saver implements data usage restrictions.
117 * - Via the UI the user can add and remove apps from the whitelist and
118 * blacklist, and turn on/off data saver.
119 * - The blacklist takes precedence over the whitelist and the whitelist
120 * takes precedence over data saver.
121 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700122 * * bw_penalty_box handling:
123 * - only one bw_penalty_box for all interfaces
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900124 * E.g Adding an app:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700125 * iptables -I bw_penalty_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700126 * --jump REJECT --reject-with icmp-port-unreachable
127 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700128 * * bw_happy_box handling:
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900129 * - The bw_happy_box comes after the penalty box.
JP Abgralle4788732013-07-02 20:28:45 -0700130 * E.g Adding a happy app,
JP Abgrall7e51cde2013-07-03 13:33:05 -0700131 * iptables -I bw_happy_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700132 * --jump RETURN
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900133 *
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900134 * * bw_data_saver handling:
135 * - The bw_data_saver comes after the happy box.
136 * Enable data saver:
137 * iptables -R 1 bw_data_saver --jump REJECT --reject-with icmp-port-unreachable
138 * Disable data saver:
139 * iptables -R 1 bw_data_saver --jump RETURN
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700140 */
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900141
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900142const std::string COMMIT_AND_CLOSE = "COMMIT\n\x04";
143const std::string DATA_SAVER_ENABLE_COMMAND = "-R bw_data_saver 1";
144const std::string HAPPY_BOX_WHITELIST_COMMAND = android::base::StringPrintf(
145 "-I bw_happy_box -m owner --uid-owner %d-%d --jump RETURN", 0, MAX_SYSTEM_UID);
146
147static const std::vector<std::string> IPT_FLUSH_COMMANDS = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700148 /*
149 * Cleanup rules.
JP Abgrall7e51cde2013-07-03 13:33:05 -0700150 * Should normally include bw_costly_<iface>, but we rely on the way they are setup
JP Abgrall0031cea2012-04-17 16:38:23 -0700151 * to allow coexistance.
JP Abgrall39f8f242011-06-29 19:21:58 -0700152 */
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900153 "*filter",
154 ":bw_INPUT -",
155 ":bw_OUTPUT -",
156 ":bw_FORWARD -",
157 ":bw_happy_box -",
158 ":bw_penalty_box -",
159 ":bw_data_saver -",
160 ":bw_costly_shared -",
161 "COMMIT",
162 "*raw",
163 ":bw_raw_PREROUTING -",
164 "COMMIT",
165 "*mangle",
166 ":bw_mangle_POSTROUTING -",
167 COMMIT_AND_CLOSE
JP Abgrall0031cea2012-04-17 16:38:23 -0700168};
169
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900170static const std::vector<std::string> IPT_BASIC_ACCOUNTING_COMMANDS = {
171 "*filter",
JP Abgrall0031cea2012-04-17 16:38:23 -0700172 "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0031cea2012-04-17 16:38:23 -0700173 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900174 "-A bw_costly_shared --jump bw_penalty_box",
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900175 "-A bw_penalty_box --jump bw_happy_box",
176 "-A bw_happy_box --jump bw_data_saver",
177 "-A bw_data_saver -j RETURN",
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900178 HAPPY_BOX_WHITELIST_COMMAND,
179 "COMMIT",
180
181 "*raw",
182 "-A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
183 "COMMIT",
184
185 "*mangle",
186 "-A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
187 COMMIT_AND_CLOSE
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900188};
189
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900190
191} // namespace
192
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700193BandwidthController::BandwidthController(void) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700194}
195
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700196int BandwidthController::runIpxtablesCmd(const char *cmd, IptJumpOp jumpHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700197 IptFailureLog failureHandling) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700198 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700199
Steve Block3fb42e02011-10-20 11:55:56 +0100200 ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700201 res |= runIptablesCmd(cmd, jumpHandling, IptIpV4, failureHandling);
202 res |= runIptablesCmd(cmd, jumpHandling, IptIpV6, failureHandling);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700203 return res;
204}
205
JP Abgrall26e0d492011-06-24 19:21:51 -0700206int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
207
208 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
209 strncpy(buffer, src, buffSize);
210 return buffer[buffSize - 1];
211}
212
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700213int BandwidthController::runIptablesCmd(const char *cmd, IptJumpOp jumpHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700214 IptIpVer iptVer, IptFailureLog failureHandling) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700215 char buffer[MAX_CMD_LEN];
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700216 const char *argv[MAX_CMD_ARGS];
JP Abgrall26e0d492011-06-24 19:21:51 -0700217 int argc = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700218 char *next = buffer;
219 char *tmp;
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700220 int res;
Rom Lemarchand14150212013-01-24 10:01:04 -0800221 int status = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700222
JP Abgrall0dad7c22011-06-24 11:58:14 -0700223 std::string fullCmd = cmd;
JP Abgrall26e0d492011-06-24 19:21:51 -0700224
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700225 switch (jumpHandling) {
226 case IptJumpReject:
JP Abgrall340d5cc2013-06-28 17:06:00 -0700227 /*
228 * Must be carefull what one rejects with, as uper layer protocols will just
229 * keep on hammering the device until the number of retries are done.
230 * For port-unreachable (default), TCP should consider as an abort (RFC1122).
231 */
232 fullCmd += " --jump REJECT";
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700233 break;
234 case IptJumpReturn:
235 fullCmd += " --jump RETURN";
236 break;
237 case IptJumpNoAdd:
238 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700239 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700240
Devi Sandeep Endluri V V9afc4f92016-10-13 13:15:17 +0530241 std::string iptOpts = " -w";
242 iptOpts += " -W ";
243 iptOpts += IPTABLES_RETRY_INTERVAL;
244 iptOpts += " ";
245 fullCmd.insert(0, iptOpts);
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700246 fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700247
Rom Lemarchand14150212013-01-24 10:01:04 -0800248 if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
249 ALOGE("iptables command too long");
250 return -1;
251 }
252
253 argc = 0;
254 while ((tmp = strsep(&next, " "))) {
255 argv[argc++] = tmp;
256 if (argc >= MAX_CMD_ARGS) {
257 ALOGE("iptables argument overflow");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700258 return -1;
259 }
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700260 }
Rom Lemarchand14150212013-01-24 10:01:04 -0800261
262 argv[argc] = NULL;
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900263 res = execFunction(argc, (char **)argv, &status, false,
Rom Lemarchand14150212013-01-24 10:01:04 -0800264 failureHandling == IptFailShow);
JP Abgrallc8dc63b2013-02-13 16:30:00 -0800265 res = res || !WIFEXITED(status) || WEXITSTATUS(status);
266 if (res && failureHandling == IptFailShow) {
267 ALOGE("runIptablesCmd(): res=%d status=%d failed %s", res, status,
268 fullCmd.c_str());
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700269 }
270 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700271}
272
JP Abgrall0e540ec2013-08-26 15:13:10 -0700273void BandwidthController::flushCleanTables(bool doClean) {
274 /* Flush and remove the bw_costly_<iface> tables */
275 flushExistingCostlyTables(doClean);
JP Abgrall0031cea2012-04-17 16:38:23 -0700276
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900277 std::string commands = android::base::Join(IPT_FLUSH_COMMANDS, '\n');
278 iptablesRestoreFunction(V4V6, commands);
JP Abgrall0e540ec2013-08-26 15:13:10 -0700279}
JP Abgrall0031cea2012-04-17 16:38:23 -0700280
JP Abgrall0e540ec2013-08-26 15:13:10 -0700281int BandwidthController::setupIptablesHooks(void) {
JP Abgrall0e540ec2013-08-26 15:13:10 -0700282 /* flush+clean is allowed to fail */
283 flushCleanTables(true);
JP Abgrall0031cea2012-04-17 16:38:23 -0700284 return 0;
JP Abgrall0031cea2012-04-17 16:38:23 -0700285}
286
287int BandwidthController::enableBandwidthControl(bool force) {
JP Abgrall0031cea2012-04-17 16:38:23 -0700288 char value[PROPERTY_VALUE_MAX];
289
290 if (!force) {
291 property_get("persist.bandwidth.enable", value, "1");
292 if (!strcmp(value, "0"))
293 return 0;
294 }
JP Abgrall8a932722011-07-13 19:17:35 -0700295
JP Abgralldb7da582011-09-18 12:57:32 -0700296 /* Let's pretend we started from scratch ... */
JP Abgrall8a932722011-07-13 19:17:35 -0700297 sharedQuotaIfaces.clear();
298 quotaIfaces.clear();
JP Abgralldb7da582011-09-18 12:57:32 -0700299 globalAlertBytes = 0;
JP Abgrallc6c67342011-10-07 16:28:54 -0700300 globalAlertTetherCount = 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700301 sharedQuotaBytes = sharedAlertBytes = 0;
302
farenld228c542016-09-01 12:30:35 +0800303 restrictAppUidsOnData.clear();
304 restrictAppUidsOnWlan.clear();
305
JP Abgrall0e540ec2013-08-26 15:13:10 -0700306 flushCleanTables(false);
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900307 std::string commands = android::base::Join(IPT_BASIC_ACCOUNTING_COMMANDS, '\n');
308 return iptablesRestoreFunction(V4V6, commands);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700309}
310
311int BandwidthController::disableBandwidthControl(void) {
JP Abgrall0e540ec2013-08-26 15:13:10 -0700312
313 flushCleanTables(false);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700314 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700315}
316
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900317int BandwidthController::enableDataSaver(bool enable) {
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900318 return runIpxtablesCmd(DATA_SAVER_ENABLE_COMMAND.c_str(),
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900319 enable ? IptJumpReject : IptJumpReturn, IptFailShow);
320}
321
JP Abgrall8a932722011-07-13 19:17:35 -0700322int BandwidthController::runCommands(int numCommands, const char *commands[],
323 RunCmdErrHandling cmdErrHandling) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700324 int res = 0;
JP Abgrallad729ac2012-04-24 23:27:44 -0700325 IptFailureLog failureLogging = IptFailShow;
326 if (cmdErrHandling == RunCmdFailureOk) {
327 failureLogging = IptFailHide;
328 }
Steve Block3fb42e02011-10-20 11:55:56 +0100329 ALOGV("runCommands(): %d commands", numCommands);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700330 for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700331 res = runIpxtablesCmd(commands[cmdNum], IptJumpNoAdd, failureLogging);
JP Abgrall0031cea2012-04-17 16:38:23 -0700332 if (res && cmdErrHandling != RunCmdFailureOk)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700333 return res;
334 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700335 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700336}
337
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700338std::string BandwidthController::makeIptablesSpecialAppCmd(IptOp op, int uid, const char *chain) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700339 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700340 char *buff;
341 const char *opFlag;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700342
343 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700344 case IptOpInsert:
345 opFlag = "-I";
346 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800347 case IptOpAppend:
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700348 ALOGE("Append op not supported for %s uids", chain);
349 res = "";
350 return res;
JP Abgrall109899b2013-02-12 19:20:13 -0800351 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700352 case IptOpReplace:
353 opFlag = "-R";
354 break;
355 default:
356 case IptOpDelete:
357 opFlag = "-D";
358 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700359 }
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700360 asprintf(&buff, "%s %s -m owner --uid-owner %d", opFlag, chain, uid);
JP Abgrall8a932722011-07-13 19:17:35 -0700361 res = buff;
362 free(buff);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700363 return res;
364}
365
366int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700367 return manipulateNaughtyApps(numUids, appUids, SpecialAppOpAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700368}
369
370int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700371 return manipulateNaughtyApps(numUids, appUids, SpecialAppOpRemove);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700372}
373
JP Abgralle4788732013-07-02 20:28:45 -0700374int BandwidthController::addNiceApps(int numUids, char *appUids[]) {
375 return manipulateNiceApps(numUids, appUids, SpecialAppOpAdd);
376}
377
378int BandwidthController::removeNiceApps(int numUids, char *appUids[]) {
379 return manipulateNiceApps(numUids, appUids, SpecialAppOpRemove);
380}
381
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700382int BandwidthController::manipulateNaughtyApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
Lorenzo Colittib1f05572016-03-18 11:55:56 +0900383 return manipulateSpecialApps(numUids, appStrUids, "bw_penalty_box", IptJumpReject, appOp);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700384}
385
JP Abgralle4788732013-07-02 20:28:45 -0700386int BandwidthController::manipulateNiceApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
Lorenzo Colittib1f05572016-03-18 11:55:56 +0900387 return manipulateSpecialApps(numUids, appStrUids, "bw_happy_box", IptJumpReturn, appOp);
JP Abgralle4788732013-07-02 20:28:45 -0700388}
389
farenld228c542016-09-01 12:30:35 +0800390int BandwidthController::manipulateRestrictAppsOnData(int numUids, char *appUids[],
391 RestrictAppOp appOp) {
392 int ret = manipulateRestrictApps(numUids, appUids, "INPUT -i rmnet_data0",
393 restrictAppUidsOnData, appOp);
394 if (ret != 0) {
395 return ret;
396 } else {
397 return manipulateRestrictApps(numUids, appUids, "OUTPUT -o rmnet_data0",
398 restrictAppUidsOnData, appOp);
399 }
400}
401
402int BandwidthController::manipulateRestrictAppsOnWlan(int numUids, char *appUids[],
403 RestrictAppOp appOp) {
404 int ret = manipulateRestrictApps(numUids, appUids,"INPUT -i wlan0",
405 restrictAppUidsOnWlan, appOp);
406 if (ret != 0) {
407 return ret;
408 } else {
409 return manipulateRestrictApps(numUids, appUids,"OUTPUT -o wlan0",
410 restrictAppUidsOnWlan, appOp);
411 }
412}
413int BandwidthController::addRestrictAppsOnData(int numUids, char *appUids[]) {
414 return manipulateRestrictAppsOnData(numUids, appUids, RestrictAppOpAdd);
415}
416
417int BandwidthController::removeRestrictAppsOnData(int numUids, char *appUids[]) {
418 return manipulateRestrictAppsOnData(numUids, appUids, RestrictAppOpRemove);
419}
420
421int BandwidthController::addRestrictAppsOnWlan(int numUids, char *appUids[]) {
422 return manipulateRestrictAppsOnWlan(numUids, appUids, RestrictAppOpAdd);
423}
424
425int BandwidthController::removeRestrictAppsOnWlan(int numUids, char *appUids[]) {
426 return manipulateRestrictAppsOnWlan(numUids, appUids, RestrictAppOpRemove);
427}
428
429
430int BandwidthController::manipulateRestrictApps(int numUids, char *appStrUids[],
431 const char *chain,
432 std::list<int /*appUid*/> &restrictAppUids,
433 RestrictAppOp appOp) {
434 int uidNum;
435 const char *failLogTemplate;
436 IptOp op;
437 int appUids[numUids];
438 std::string iptCmd;
439 std::list<int /*uid*/>::iterator it;
440 bool isOutputChain = !strncmp(chain, "OUTPUT", strlen("OUTPUT"));
441 switch (appOp) {
442 case RestrictAppOpAdd:
443 op = IptOpInsert;
444 failLogTemplate = "Failed to add app uid %s(%d) to %s.";
445 break;
446 case RestrictAppOpRemove:
447 op = IptOpDelete;
448 failLogTemplate = "Failed to delete app uid %s(%d) from %s box.";
449 break;
450 default:
451 ALOGE("Unexpected app Op %d", appOp);
452 return -1;
453 }
454 for (uidNum = 0; uidNum < numUids; uidNum++) {
455 char *end;
456 appUids[uidNum] = strtoul(appStrUids[uidNum], &end, 0);
457 if (*end || !*appStrUids[uidNum]) {
458 ALOGE(failLogTemplate, appStrUids[uidNum], appUids[uidNum], chain);
459 goto fail_parse;
460 }
461 }
462
463 for (uidNum = 0; uidNum < numUids; uidNum++) {
464 int uid = appUids[uidNum];
465 for (it = restrictAppUids.begin(); it != restrictAppUids.end(); it++) {
466 if (*it == uid)
467 break;
468 }
469 bool found = (it != restrictAppUids.end());
470
471 if (appOp == RestrictAppOpRemove) {
472 if (!found) {
473 ALOGE("No such appUid %d to remove", uid);
474 return -1;
475 }
476 restrictAppUids.erase(it);
477 } else {
478 if (found && !isOutputChain) {
479 ALOGE("appUid %d exists already", uid);
480 return -1;
481 }
482 restrictAppUids.push_front(uid);
483 }
484
485 iptCmd = makeIptablesSpecialAppCmd(op, uid, chain);
486 if (runIpxtablesCmd(iptCmd.c_str(), IptJumpReject)) {
487 ALOGE(failLogTemplate, appStrUids[uidNum], uid, chain);
488 goto fail_with_uidNum;
489 }
490 }
491 return 0;
492
493fail_with_uidNum:
494 /* Try to remove the uid that failed in any case*/
495 iptCmd = makeIptablesSpecialAppCmd(IptOpDelete, appUids[uidNum], chain);
496 runIpxtablesCmd(iptCmd.c_str(), IptJumpReject);
497fail_parse:
498 return -1;
499}
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700500
501int BandwidthController::manipulateSpecialApps(int numUids, char *appStrUids[],
502 const char *chain,
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700503 IptJumpOp jumpHandling, SpecialAppOp appOp) {
504
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700505 int uidNum;
JP Abgrall26e0d492011-06-24 19:21:51 -0700506 const char *failLogTemplate;
507 IptOp op;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700508 int appUids[numUids];
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700509 std::string iptCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700510
JP Abgrall26e0d492011-06-24 19:21:51 -0700511 switch (appOp) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700512 case SpecialAppOpAdd:
JP Abgrall8a932722011-07-13 19:17:35 -0700513 op = IptOpInsert;
JP Abgrallaf476f72013-07-03 12:23:55 -0700514 failLogTemplate = "Failed to add app uid %s(%d) to %s.";
JP Abgrall8a932722011-07-13 19:17:35 -0700515 break;
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700516 case SpecialAppOpRemove:
JP Abgrall8a932722011-07-13 19:17:35 -0700517 op = IptOpDelete;
JP Abgrallaf476f72013-07-03 12:23:55 -0700518 failLogTemplate = "Failed to delete app uid %s(%d) from %s box.";
JP Abgrall8a932722011-07-13 19:17:35 -0700519 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700520 default:
521 ALOGE("Unexpected app Op %d", appOp);
522 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700523 }
524
525 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallaf476f72013-07-03 12:23:55 -0700526 char *end;
527 appUids[uidNum] = strtoul(appStrUids[uidNum], &end, 0);
528 if (*end || !*appStrUids[uidNum]) {
529 ALOGE(failLogTemplate, appStrUids[uidNum], appUids[uidNum], chain);
JP Abgrall26e0d492011-06-24 19:21:51 -0700530 goto fail_parse;
531 }
532 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700533
534 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700535 int uid = appUids[uidNum];
JP Abgrallb1d24092012-04-27 01:02:31 -0700536
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700537 iptCmd = makeIptablesSpecialAppCmd(op, uid, chain);
538 if (runIpxtablesCmd(iptCmd.c_str(), jumpHandling)) {
JP Abgrallaf476f72013-07-03 12:23:55 -0700539 ALOGE(failLogTemplate, appStrUids[uidNum], uid, chain);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700540 goto fail_with_uidNum;
541 }
542 }
543 return 0;
544
JP Abgrall26e0d492011-06-24 19:21:51 -0700545fail_with_uidNum:
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700546 /* Try to remove the uid that failed in any case*/
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700547 iptCmd = makeIptablesSpecialAppCmd(IptOpDelete, appUids[uidNum], chain);
548 runIpxtablesCmd(iptCmd.c_str(), jumpHandling);
JP Abgrall26e0d492011-06-24 19:21:51 -0700549fail_parse:
550 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700551}
552
JP Abgrall26e0d492011-06-24 19:21:51 -0700553std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700554 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700555 char *buff;
556 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700557
SynergyDev7776cea2014-03-16 15:48:51 -0700558 ALOGV("makeIptablesQuotaCmd(%d, %" PRId64")", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700559
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700560 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700561 case IptOpInsert:
562 opFlag = "-I";
563 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800564 case IptOpAppend:
565 opFlag = "-A";
566 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700567 case IptOpReplace:
568 opFlag = "-R";
569 break;
570 default:
571 case IptOpDelete:
572 opFlag = "-D";
573 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700574 }
JP Abgrall8a932722011-07-13 19:17:35 -0700575
JP Abgrallbfa74662011-06-29 19:23:04 -0700576 // The requried IP version specific --jump REJECT ... will be added later.
SynergyDev7776cea2014-03-16 15:48:51 -0700577 asprintf(&buff, "%s bw_costly_%s -m quota2 ! --quota %" PRId64" --name %s", opFlag, costName, quota,
JP Abgrall8a932722011-07-13 19:17:35 -0700578 costName);
579 res = buff;
580 free(buff);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700581 return res;
582}
583
JP Abgrall26e0d492011-06-24 19:21:51 -0700584int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700585 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700586 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700587 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700588 std::string costString;
589 const char *costCString;
590
JP Abgrall0dad7c22011-06-24 11:58:14 -0700591 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700592 switch (quotaType) {
593 case QuotaUnique:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700594 costString = "bw_costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700595 costString += ifn;
596 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700597 /*
JP Abgrall7e51cde2013-07-03 13:33:05 -0700598 * Flush the bw_costly_<iface> is allowed to fail in case it didn't exist.
JP Abgrall0031cea2012-04-17 16:38:23 -0700599 * Creating a new one is allowed to fail in case it existed.
600 * This helps with netd restarts.
601 */
602 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700603 res1 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700604 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700605 res2 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700606 res = (res1 && res2) || (!res1 && !res2);
607
JP Abgrall7e51cde2013-07-03 13:33:05 -0700608 snprintf(cmd, sizeof(cmd), "-A %s -j bw_penalty_box", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700609 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700610 break;
611 case QuotaShared:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700612 costCString = "bw_costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700613 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700614 default:
615 ALOGE("Unexpected quotatype %d", quotaType);
616 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700617 }
618
JP Abgrall8a932722011-07-13 19:17:35 -0700619 if (globalAlertBytes) {
620 /* The alert rule comes 1st */
621 ruleInsertPos = 2;
622 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700623
624 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700625 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700626
627 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700628 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700629
630 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700631 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700632
633 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700634 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
Erik Kline58a94482015-10-02 17:52:37 +0900635
636 snprintf(cmd, sizeof(cmd), "-D bw_FORWARD -o %s --jump %s", ifn, costCString);
637 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
638 snprintf(cmd, sizeof(cmd), "-A bw_FORWARD -o %s --jump %s", ifn, costCString);
639 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
640
JP Abgrall0dad7c22011-06-24 11:58:14 -0700641 return res;
642}
643
JP Abgrall26e0d492011-06-24 19:21:51 -0700644int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700645 char cmd[MAX_CMD_LEN];
646 int res = 0;
647 std::string costString;
648 const char *costCString;
649
JP Abgrall26e0d492011-06-24 19:21:51 -0700650 switch (quotaType) {
651 case QuotaUnique:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700652 costString = "bw_costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700653 costString += ifn;
654 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700655 break;
656 case QuotaShared:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700657 costCString = "bw_costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700658 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700659 default:
660 ALOGE("Unexpected quotatype %d", quotaType);
661 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700662 }
663
JP Abgrall0031cea2012-04-17 16:38:23 -0700664 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700665 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
Erik Kline58a94482015-10-02 17:52:37 +0900666 for (const auto tableName : {LOCAL_OUTPUT, LOCAL_FORWARD}) {
667 snprintf(cmd, sizeof(cmd), "-D %s -o %s --jump %s", tableName, ifn, costCString);
668 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
669 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700670
JP Abgrall7e51cde2013-07-03 13:33:05 -0700671 /* The "-N bw_costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700672 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700673 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700674 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700675 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700676 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700677 }
678 return res;
679}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700680
JP Abgrall0dad7c22011-06-24 11:58:14 -0700681int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700682 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700683 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700684 std::string quotaCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700685 std::string ifaceName;
686 ;
JP Abgrallbfa74662011-06-29 19:23:04 -0700687 const char *costName = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700688 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700689
JP Abgrall8a932722011-07-13 19:17:35 -0700690 if (!maxBytes) {
691 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000692 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700693 return -1;
694 }
JP Abgrall69261cb2014-06-19 18:35:24 -0700695 if (!isIfaceName(iface))
696 return -1;
JP Abgrall26e0d492011-06-24 19:21:51 -0700697 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000698 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700699 return -1;
700 }
701 ifaceName = ifn;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700702
703 if (maxBytes == -1) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700704 return removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700705 }
706
707 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700708 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
709 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700710 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700711 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700712
JP Abgrall0dad7c22011-06-24 11:58:14 -0700713 if (it == sharedQuotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700714 res |= prepCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700715 if (sharedQuotaIfaces.empty()) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700716 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700717 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700718 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000719 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700720 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700721 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700722 sharedQuotaBytes = maxBytes;
723 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700724 sharedQuotaIfaces.push_front(ifaceName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700725
726 }
727
728 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700729 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700730 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000731 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700732 goto fail;
733 }
734 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700735 }
736 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700737
738 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700739 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700740 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
741 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700742 * For now callers needs to choose if they want to "ndc bandwidth enable"
743 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700744 */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700745 removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700746 return -1;
747}
748
JP Abgrall8a932722011-07-13 19:17:35 -0700749/* It will also cleanup any shared alerts */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700750int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700751 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700752 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700753 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700754 std::list<std::string>::iterator it;
JP Abgrallbfa74662011-06-29 19:23:04 -0700755 const char *costName = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700756
JP Abgrall69261cb2014-06-19 18:35:24 -0700757 if (!isIfaceName(iface))
758 return -1;
JP Abgrall8a932722011-07-13 19:17:35 -0700759 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000760 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700761 return -1;
762 }
JP Abgrall8a932722011-07-13 19:17:35 -0700763 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700764
JP Abgrall0dad7c22011-06-24 11:58:14 -0700765 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
766 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700767 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700768 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700769 if (it == sharedQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000770 ALOGE("No such iface %s to delete", ifn);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700771 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700772 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700773
JP Abgrall26e0d492011-06-24 19:21:51 -0700774 res |= cleanupCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700775 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700776
JP Abgrall0dad7c22011-06-24 11:58:14 -0700777 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700778 std::string quotaCmd;
JP Abgrallbfa74662011-06-29 19:23:04 -0700779 quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700780 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall8a932722011-07-13 19:17:35 -0700781 sharedQuotaBytes = 0;
782 if (sharedAlertBytes) {
783 removeSharedAlert();
784 sharedAlertBytes = 0;
785 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700786 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700787 return res;
788}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700789
790int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
791 char ifn[MAX_IFACENAME_LEN];
792 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700793 std::string ifaceName;
794 const char *costName;
795 std::list<QuotaInfo>::iterator it;
796 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700797
JP Abgrall69261cb2014-06-19 18:35:24 -0700798 if (!isIfaceName(iface))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700799 return -1;
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700800
JP Abgrall8a932722011-07-13 19:17:35 -0700801 if (!maxBytes) {
802 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000803 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700804 return -1;
805 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700806 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700807 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700808 }
809
JP Abgrall8a932722011-07-13 19:17:35 -0700810 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000811 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700812 return -1;
813 }
814 ifaceName = ifn;
815 costName = iface;
816
JP Abgrall0dad7c22011-06-24 11:58:14 -0700817 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700818 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700819 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700820 break;
821 }
822
823 if (it == quotaIfaces.end()) {
JP Abgralle4788732013-07-02 20:28:45 -0700824 /* Preparing the iface adds a penalty/happy box check */
JP Abgrall26e0d492011-06-24 19:21:51 -0700825 res |= prepCostlyIface(ifn, QuotaUnique);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700826 /*
JP Abgralle4788732013-07-02 20:28:45 -0700827 * The rejecting quota limit should go after the penalty/happy box checks
JP Abgrallbaeccc42013-06-25 09:44:10 -0700828 * or else a naughty app could just eat up the quota.
829 * So we append here.
830 */
JP Abgrall109899b2013-02-12 19:20:13 -0800831 quotaCmd = makeIptablesQuotaCmd(IptOpAppend, costName, maxBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700832 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700833 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000834 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700835 goto fail;
836 }
837
JP Abgrall8a932722011-07-13 19:17:35 -0700838 quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700839
840 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700841 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700842 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000843 ALOGE("Failed update quota for %s", iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700844 goto fail;
845 }
JP Abgrall8a932722011-07-13 19:17:35 -0700846 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700847 }
848 return 0;
849
850 fail:
851 /*
852 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
853 * rules in the kernel to see which ones need cleaning up.
854 * For now callers needs to choose if they want to "ndc bandwidth enable"
855 * which resets everything.
856 */
857 removeInterfaceSharedQuota(ifn);
858 return -1;
859}
860
JP Abgrall8a932722011-07-13 19:17:35 -0700861int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
862 return getInterfaceQuota("shared", bytes);
863}
864
865int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
866 FILE *fp;
867 char *fname;
868 int scanRes;
869
JP Abgrall69261cb2014-06-19 18:35:24 -0700870 if (!isIfaceName(costName))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700871 return -1;
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700872
JP Abgrall8a932722011-07-13 19:17:35 -0700873 asprintf(&fname, "/proc/net/xt_quota/%s", costName);
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800874 fp = fopen(fname, "re");
JP Abgrall8a932722011-07-13 19:17:35 -0700875 free(fname);
876 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000877 ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700878 return -1;
879 }
Mark Salyzynca0b5e22014-03-26 14:15:03 -0700880 scanRes = fscanf(fp, "%" SCNd64, bytes);
SynergyDev7776cea2014-03-16 15:48:51 -0700881 ALOGV("Read quota res=%d bytes=%" PRId64, scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700882 fclose(fp);
883 return scanRes == 1 ? 0 : -1;
884}
885
JP Abgrall0dad7c22011-06-24 11:58:14 -0700886int BandwidthController::removeInterfaceQuota(const char *iface) {
887
888 char ifn[MAX_IFACENAME_LEN];
889 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700890 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700891 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700892
JP Abgrall69261cb2014-06-19 18:35:24 -0700893 if (!isIfaceName(iface))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700894 return -1;
JP Abgrall8a932722011-07-13 19:17:35 -0700895 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000896 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700897 return -1;
898 }
899 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700900
JP Abgrall0dad7c22011-06-24 11:58:14 -0700901 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700902 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700903 break;
904 }
905
906 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000907 ALOGE("No such iface %s to delete", ifn);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700908 return -1;
909 }
910
911 /* This also removes the quota command of CostlyIface chain. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700912 res |= cleanupCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700913
914 quotaIfaces.erase(it);
915
916 return res;
917}
JP Abgrall8a932722011-07-13 19:17:35 -0700918
919int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
920 FILE *fp;
921 char *fname;
922
JP Abgrall69261cb2014-06-19 18:35:24 -0700923 if (!isIfaceName(quotaName)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700924 ALOGE("updateQuota: Invalid quotaName \"%s\"", quotaName);
925 return -1;
926 }
927
JP Abgrall8a932722011-07-13 19:17:35 -0700928 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800929 fp = fopen(fname, "we");
JP Abgrall8a932722011-07-13 19:17:35 -0700930 free(fname);
931 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000932 ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700933 return -1;
934 }
SynergyDev7776cea2014-03-16 15:48:51 -0700935 fprintf(fp, "%" PRId64"\n", bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700936 fclose(fp);
937 return 0;
938}
939
940int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
941 int res = 0;
942 const char *opFlag;
943 char *alertQuotaCmd;
944
945 switch (op) {
946 case IptOpInsert:
947 opFlag = "-I";
948 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800949 case IptOpAppend:
950 opFlag = "-A";
951 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700952 case IptOpReplace:
953 opFlag = "-R";
954 break;
955 default:
956 case IptOpDelete:
957 opFlag = "-D";
958 break;
959 }
960
JP Abgrall92009c82013-02-06 18:01:24 -0800961 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800962 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700963 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700964 free(alertQuotaCmd);
JP Abgrall92009c82013-02-06 18:01:24 -0800965 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800966 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700967 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700968 free(alertQuotaCmd);
969 return res;
970}
971
JP Abgrallc6c67342011-10-07 16:28:54 -0700972int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
973 int res = 0;
974 const char *opFlag;
JP Abgrall8a932722011-07-13 19:17:35 -0700975 char *alertQuotaCmd;
JP Abgrallc6c67342011-10-07 16:28:54 -0700976
977 switch (op) {
978 case IptOpInsert:
979 opFlag = "-I";
980 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800981 case IptOpAppend:
982 opFlag = "-A";
983 break;
JP Abgrallc6c67342011-10-07 16:28:54 -0700984 case IptOpReplace:
985 opFlag = "-R";
986 break;
987 default:
988 case IptOpDelete:
989 opFlag = "-D";
990 break;
991 }
992
JP Abgrall92009c82013-02-06 18:01:24 -0800993 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800994 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700995 res = runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrallc6c67342011-10-07 16:28:54 -0700996 free(alertQuotaCmd);
997 return res;
998}
999
1000int BandwidthController::setGlobalAlert(int64_t bytes) {
1001 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -07001002 int res = 0;
1003
1004 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001005 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -07001006 return -1;
1007 }
1008 if (globalAlertBytes) {
1009 res = updateQuota(alertName, bytes);
1010 } else {
1011 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -07001012 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +01001013 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -07001014 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
1015 }
JP Abgrall8a932722011-07-13 19:17:35 -07001016 }
1017 globalAlertBytes = bytes;
1018 return res;
1019}
1020
JP Abgrallc6c67342011-10-07 16:28:54 -07001021int BandwidthController::setGlobalAlertInForwardChain(void) {
1022 const char *alertName = ALERT_GLOBAL_NAME;
1023 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -07001024
JP Abgrallc6c67342011-10-07 16:28:54 -07001025 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +01001026 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -07001027
1028 /*
1029 * If there is no globalAlert active we are done.
1030 * If there is an active globalAlert but this is not the 1st
1031 * tether, we are also done.
1032 */
1033 if (!globalAlertBytes || globalAlertTetherCount != 1) {
1034 return 0;
1035 }
1036
1037 /* We only add the rule if this was the 1st tether added. */
1038 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
1039 return res;
1040}
1041
1042int BandwidthController::removeGlobalAlert(void) {
1043
1044 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -07001045 int res = 0;
1046
1047 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001048 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -07001049 return -1;
1050 }
1051 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -07001052 if (globalAlertTetherCount) {
1053 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
1054 }
JP Abgrall8a932722011-07-13 19:17:35 -07001055 globalAlertBytes = 0;
1056 return res;
1057}
1058
JP Abgrallc6c67342011-10-07 16:28:54 -07001059int BandwidthController::removeGlobalAlertInForwardChain(void) {
1060 int res = 0;
1061 const char *alertName = ALERT_GLOBAL_NAME;
1062
1063 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +00001064 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -07001065 return -1;
1066 }
1067
1068 globalAlertTetherCount--;
1069 /*
1070 * If there is no globalAlert active we are done.
1071 * If there is an active globalAlert but there are more
1072 * tethers, we are also done.
1073 */
1074 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
1075 return 0;
1076 }
1077
1078 /* We only detete the rule if this was the last tether removed. */
1079 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
1080 return res;
1081}
1082
JP Abgrall8a932722011-07-13 19:17:35 -07001083int BandwidthController::setSharedAlert(int64_t bytes) {
1084 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001085 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -07001086 return -1;
1087 }
1088 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001089 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -07001090 return -1;
1091 }
1092 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
1093}
1094
1095int BandwidthController::removeSharedAlert(void) {
1096 return removeCostlyAlert("shared", &sharedAlertBytes);
1097}
1098
1099int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
1100 std::list<QuotaInfo>::iterator it;
1101
JP Abgrall69261cb2014-06-19 18:35:24 -07001102 if (!isIfaceName(iface)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -07001103 ALOGE("setInterfaceAlert: Invalid iface \"%s\"", iface);
1104 return -1;
1105 }
1106
JP Abgrall8a932722011-07-13 19:17:35 -07001107 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001108 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -07001109 return -1;
1110 }
1111 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1112 if (it->ifaceName == iface)
1113 break;
1114 }
1115
1116 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +00001117 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -07001118 return -1;
1119 }
1120
1121 return setCostlyAlert(iface, bytes, &it->alert);
1122}
1123
1124int BandwidthController::removeInterfaceAlert(const char *iface) {
1125 std::list<QuotaInfo>::iterator it;
1126
JP Abgrall69261cb2014-06-19 18:35:24 -07001127 if (!isIfaceName(iface)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -07001128 ALOGE("removeInterfaceAlert: Invalid iface \"%s\"", iface);
1129 return -1;
1130 }
1131
JP Abgrall8a932722011-07-13 19:17:35 -07001132 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1133 if (it->ifaceName == iface)
1134 break;
1135 }
1136
1137 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +00001138 ALOGE("No prior alert set for interface %s", iface);
JP Abgrall8a932722011-07-13 19:17:35 -07001139 return -1;
1140 }
1141
1142 return removeCostlyAlert(iface, &it->alert);
1143}
1144
1145int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
1146 char *alertQuotaCmd;
JP Abgrall109899b2013-02-12 19:20:13 -08001147 char *chainName;
JP Abgrall8a932722011-07-13 19:17:35 -07001148 int res = 0;
1149 char *alertName;
1150
JP Abgrall69261cb2014-06-19 18:35:24 -07001151 if (!isIfaceName(costName)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -07001152 ALOGE("setCostlyAlert: Invalid costName \"%s\"", costName);
1153 return -1;
1154 }
1155
JP Abgrall8a932722011-07-13 19:17:35 -07001156 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001157 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -07001158 return -1;
1159 }
1160 asprintf(&alertName, "%sAlert", costName);
1161 if (*alertBytes) {
1162 res = updateQuota(alertName, *alertBytes);
1163 } else {
JP Abgrall7e51cde2013-07-03 13:33:05 -07001164 asprintf(&chainName, "bw_costly_%s", costName);
JP Abgrall109899b2013-02-12 19:20:13 -08001165 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-A", chainName, bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -07001166 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -07001167 free(alertQuotaCmd);
JP Abgrall109899b2013-02-12 19:20:13 -08001168 free(chainName);
JP Abgrall8a932722011-07-13 19:17:35 -07001169 }
1170 *alertBytes = bytes;
1171 free(alertName);
1172 return res;
1173}
1174
1175int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
1176 char *alertQuotaCmd;
1177 char *chainName;
1178 char *alertName;
1179 int res = 0;
1180
JP Abgrall69261cb2014-06-19 18:35:24 -07001181 if (!isIfaceName(costName)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -07001182 ALOGE("removeCostlyAlert: Invalid costName \"%s\"", costName);
1183 return -1;
1184 }
1185
JP Abgrall8a932722011-07-13 19:17:35 -07001186 if (!*alertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001187 ALOGE("No prior alert set for %s alert", costName);
JP Abgrall8a932722011-07-13 19:17:35 -07001188 return -1;
1189 }
1190
Jesper Hanssona9d791f2012-04-27 13:54:27 +02001191 asprintf(&alertName, "%sAlert", costName);
JP Abgrall7e51cde2013-07-03 13:33:05 -07001192 asprintf(&chainName, "bw_costly_%s", costName);
JP Abgrall92009c82013-02-06 18:01:24 -08001193 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -07001194 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -07001195 free(alertQuotaCmd);
1196 free(chainName);
1197
1198 *alertBytes = 0;
1199 free(alertName);
1200 return res;
1201}
JP Abgralldb7da582011-09-18 12:57:32 -07001202
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001203void BandwidthController::addStats(TetherStatsList& statsList, const TetherStats& stats) {
1204 for (TetherStats& existing : statsList) {
1205 if (existing.addStatsIfMatch(stats)) {
1206 return;
1207 }
1208 }
1209 // No match. Insert a new interface pair.
1210 statsList.push_back(stats);
1211}
1212
JP Abgralldb7da582011-09-18 12:57:32 -07001213/*
1214 * Parse the ptks and bytes out of:
JP Abgrallbaeccc42013-06-25 09:44:10 -07001215 * Chain natctrl_tether_counters (4 references)
1216 * pkts bytes target prot opt in out source destination
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001217 * 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
1218 * 27 2002 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0
1219 * 1040 107471 RETURN all -- bt-pan rmnet0 0.0.0.0/0 0.0.0.0/0
1220 * 1450 1708806 RETURN all -- rmnet0 bt-pan 0.0.0.0/0 0.0.0.0/0
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001221 * or:
1222 * Chain natctrl_tether_counters (0 references)
1223 * pkts bytes target prot opt in out source destination
1224 * 0 0 RETURN all wlan0 rmnet_data0 ::/0 ::/0
1225 * 0 0 RETURN all rmnet_data0 wlan0 ::/0 ::/0
1226 *
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001227 * It results in an error if invoked and no tethering counter rules exist. The constraint
1228 * helps detect complete parsing failure.
JP Abgralldb7da582011-09-18 12:57:32 -07001229 */
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001230int BandwidthController::addForwardChainStats(const TetherStats& filter,
1231 TetherStatsList& statsList, FILE *fp,
1232 std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001233 int res;
1234 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1235 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
1236 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
1237 char rest[MAX_IPT_OUTPUT_LINE_LEN];
1238
JP Abgrallbaeccc42013-06-25 09:44:10 -07001239 TetherStats stats;
JP Abgralldb7da582011-09-18 12:57:32 -07001240 char *buffPtr;
1241 int64_t packets, bytes;
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001242 int statsFound = 0;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001243
1244 bool filterPair = filter.intIface[0] && filter.extIface[0];
1245
1246 char *filterMsg = filter.getStatsLine();
1247 ALOGV("filter: %s", filterMsg);
1248 free(filterMsg);
1249
1250 stats = filter;
JP Abgralldb7da582011-09-18 12:57:32 -07001251
1252 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1253 /* Clean up, so a failed parse can still print info */
1254 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001255 if (strstr(buffPtr, "0.0.0.0")) {
1256 // IPv4 has -- indicating what to do with fragments...
1257 // 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
1258 res = sscanf(buffPtr, "%" SCNd64" %" SCNd64" RETURN all -- %s %s 0.%s",
1259 &packets, &bytes, iface0, iface1, rest);
1260 } else {
1261 // ... but IPv6 does not.
1262 // 26 2373 RETURN all wlan0 rmnet0 ::/0 ::/0
1263 res = sscanf(buffPtr, "%" SCNd64" %" SCNd64" RETURN all %s %s ::/%s",
1264 &packets, &bytes, iface0, iface1, rest);
1265 }
SynergyDev7776cea2014-03-16 15:48:51 -07001266 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 -07001267 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -08001268 extraProcessingInfo += buffPtr;
1269
JP Abgralldb7da582011-09-18 12:57:32 -07001270 if (res != 5) {
1271 continue;
1272 }
JP Abgrallbaeccc42013-06-25 09:44:10 -07001273 /*
1274 * The following assumes that the 1st rule has in:extIface out:intIface,
1275 * which is what NatController sets up.
1276 * If not filtering, the 1st match rx, and sets up the pair for the tx side.
1277 */
1278 if (filter.intIface[0] && filter.extIface[0]) {
1279 if (filter.intIface == iface0 && filter.extIface == iface1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001280 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 -07001281 stats.rxPackets = packets;
1282 stats.rxBytes = bytes;
1283 } else if (filter.intIface == iface1 && filter.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001284 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 -07001285 stats.txPackets = packets;
1286 stats.txBytes = bytes;
1287 }
1288 } else if (filter.intIface[0] || filter.extIface[0]) {
1289 if (filter.intIface == iface0 || filter.extIface == iface1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001290 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 -07001291 stats.intIface = iface0;
1292 stats.extIface = iface1;
1293 stats.rxPackets = packets;
1294 stats.rxBytes = bytes;
1295 } else if (filter.intIface == iface1 || filter.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001296 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 -07001297 stats.intIface = iface1;
1298 stats.extIface = iface0;
1299 stats.txPackets = packets;
1300 stats.txBytes = bytes;
1301 }
1302 } else /* if (!filter.intFace[0] && !filter.extIface[0]) */ {
1303 if (!stats.intIface[0]) {
SynergyDev7776cea2014-03-16 15:48:51 -07001304 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 -07001305 stats.intIface = iface0;
1306 stats.extIface = iface1;
1307 stats.rxPackets = packets;
1308 stats.rxBytes = bytes;
1309 } else if (stats.intIface == iface1 && stats.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001310 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 -07001311 stats.txPackets = packets;
1312 stats.txBytes = bytes;
1313 }
1314 }
1315 if (stats.rxBytes != -1 && stats.txBytes != -1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001316 ALOGV("rx_bytes=%" PRId64" tx_bytes=%" PRId64" filterPair=%d", stats.rxBytes, stats.txBytes, filterPair);
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001317 addStats(statsList, stats);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001318 if (filterPair) {
JP Abgrallbaeccc42013-06-25 09:44:10 -07001319 return 0;
1320 } else {
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001321 statsFound++;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001322 stats = filter;
1323 }
JP Abgralldb7da582011-09-18 12:57:32 -07001324 }
1325 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001326
1327 /* It is always an error to find only one side of the stats. */
1328 /* It is an error to find nothing when not filtering. */
1329 if (((stats.rxBytes == -1) != (stats.txBytes == -1)) ||
1330 (!statsFound && !filterPair)) {
1331 return -1;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001332 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001333 return 0;
JP Abgralldb7da582011-09-18 12:57:32 -07001334}
1335
JP Abgrallbaeccc42013-06-25 09:44:10 -07001336char *BandwidthController::TetherStats::getStatsLine(void) const {
JP Abgralldb7da582011-09-18 12:57:32 -07001337 char *msg;
SynergyDev7776cea2014-03-16 15:48:51 -07001338 asprintf(&msg, "%s %s %" PRId64" %" PRId64" %" PRId64" %" PRId64, intIface.c_str(), extIface.c_str(),
JP Abgralldb7da582011-09-18 12:57:32 -07001339 rxBytes, rxPackets, txBytes, txPackets);
1340 return msg;
1341}
1342
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001343std::string getTetherStatsCommand(const char *binary) {
JP Abgralldb7da582011-09-18 12:57:32 -07001344 /*
1345 * Why not use some kind of lib to talk to iptables?
1346 * Because the only libs are libiptc and libip6tc in iptables, and they are
1347 * not easy to use. They require the known iptables match modules to be
1348 * preloaded/linked, and require apparently a lot of wrapper code to get
1349 * the wanted info.
1350 */
Devi Sandeep Endluri V V9afc4f92016-10-13 13:15:17 +05301351 return android::base::StringPrintf("%s -nvx -w -W %s -L %s", binary,
1352 IPTABLES_RETRY_INTERVAL,
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001353 NatController::LOCAL_TETHER_COUNTERS_CHAIN);
1354}
JP Abgralldb7da582011-09-18 12:57:32 -07001355
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001356int BandwidthController::getTetherStats(SocketClient *cli, TetherStats& filter,
1357 std::string &extraProcessingInfo) {
1358 int res = 0;
1359 std::string fullCmd;
1360 FILE *iptOutput;
1361
1362 TetherStatsList statsList;
1363
1364 for (const auto binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
1365 fullCmd = getTetherStatsCommand(binary);
1366 iptOutput = popenFunction(fullCmd.c_str(), "r");
1367 if (!iptOutput) {
1368 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
1369 extraProcessingInfo += "Failed to run iptables.";
1370 return -1;
1371 }
1372
1373 res = addForwardChainStats(filter, statsList, iptOutput, extraProcessingInfo);
1374 pclose(iptOutput);
1375 if (res != 0) {
1376 return res;
1377 }
1378 }
JP Abgralldb7da582011-09-18 12:57:32 -07001379
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001380 if (filter.intIface[0] && filter.extIface[0] && statsList.size() == 1) {
1381 cli->sendMsg(ResponseCode::TetheringStatsResult, statsList[0].getStatsLine(), false);
1382 } else {
1383 for (const auto& stats: statsList) {
1384 cli->sendMsg(ResponseCode::TetheringStatsListResult, stats.getStatsLine(), false);
1385 }
1386 if (res == 0) {
1387 cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
1388 }
1389 }
1390
JP Abgralldb7da582011-09-18 12:57:32 -07001391 return res;
1392}
JP Abgrall0e540ec2013-08-26 15:13:10 -07001393
1394void BandwidthController::flushExistingCostlyTables(bool doClean) {
JP Abgrall0e540ec2013-08-26 15:13:10 -07001395 std::string fullCmd;
1396 FILE *iptOutput;
JP Abgrall0e540ec2013-08-26 15:13:10 -07001397
1398 /* Only lookup ip4 table names as ip6 will have the same tables ... */
1399 fullCmd = IPTABLES_PATH;
Devi Sandeep Endluri V V9afc4f92016-10-13 13:15:17 +05301400 fullCmd += " -w";
1401 fullCmd += " -W ";
1402 fullCmd += IPTABLES_RETRY_INTERVAL;
1403 fullCmd += " -S";
Lorenzo Colitti86a47982016-03-18 17:52:25 +09001404 iptOutput = popenFunction(fullCmd.c_str(), "r");
JP Abgrall0e540ec2013-08-26 15:13:10 -07001405 if (!iptOutput) {
1406 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
1407 return;
1408 }
1409 /* ... then flush/clean both ip4 and ip6 iptables. */
1410 parseAndFlushCostlyTables(iptOutput, doClean);
1411 pclose(iptOutput);
1412}
1413
1414void BandwidthController::parseAndFlushCostlyTables(FILE *fp, bool doRemove) {
1415 int res;
1416 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1417 char costlyIfaceName[MAX_IPT_OUTPUT_LINE_LEN];
1418 char cmd[MAX_CMD_LEN];
1419 char *buffPtr;
1420
1421 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1422 costlyIfaceName[0] = '\0'; /* So that debugging output always works */
1423 res = sscanf(buffPtr, "-N bw_costly_%s", costlyIfaceName);
1424 ALOGV("parse res=%d costly=<%s> orig line=<%s>", res,
1425 costlyIfaceName, buffPtr);
1426 if (res != 1) {
1427 continue;
1428 }
1429 /* Exclusions: "shared" is not an ifacename */
1430 if (!strcmp(costlyIfaceName, "shared")) {
1431 continue;
1432 }
1433
1434 snprintf(cmd, sizeof(cmd), "-F bw_costly_%s", costlyIfaceName);
1435 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1436 if (doRemove) {
1437 snprintf(cmd, sizeof(cmd), "-X bw_costly_%s", costlyIfaceName);
1438 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1439 }
1440 }
1441}