blob: 09dc4833b50f9a3b629943c29e0ed36fe4ecbfc2 [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 */
SynergyDev7776cea2014-03-16 15:48:51 -070060#define ALERT_IPT_TEMPLATE "%s %s -m quota2 ! --quota %" PRId64" --name %s"
Jeff Sharkey8e188ed2012-07-12 18:32:03 -070061const 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 Colitti13debb82016-03-27 17:46:30 +090069auto BandwidthController::iptablesRestoreFunction = execIptablesRestore;
Lorenzo Colitti86a47982016-03-18 17:52:25 +090070
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090071namespace {
72
73const char ALERT_GLOBAL_NAME[] = "globalAlert";
74const int MAX_CMD_ARGS = 32;
75const int MAX_CMD_LEN = 1024;
76const int MAX_IFACENAME_LEN = 64;
77const int MAX_IPT_OUTPUT_LINE_LEN = 256;
JP Abgralldb7da582011-09-18 12:57:32 -070078
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070079/**
80 * Some comments about the rules:
81 * * Ordering
82 * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
JP Abgrall29e8de22012-05-03 12:52:15 -070083 * E.g. "-I bw_INPUT -i rmnet0 --jump costly"
JP Abgrall7e51cde2013-07-03 13:33:05 -070084 * - quota'd rules in the costly chain should be before bw_penalty_box lookups.
JP Abgrall29e8de22012-05-03 12:52:15 -070085 * - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070086 *
87 * * global quota vs per interface quota
88 * - global quota for all costly interfaces uses a single costly chain:
89 * . initial rules
JP Abgrall7e51cde2013-07-03 13:33:05 -070090 * iptables -N bw_costly_shared
91 * iptables -I bw_INPUT -i iface0 --jump bw_costly_shared
92 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_shared
93 * iptables -I bw_costly_shared -m quota \! --quota 500000 \
JP Abgrallbfa74662011-06-29 19:23:04 -070094 * --jump REJECT --reject-with icmp-net-prohibited
JP Abgrall7e51cde2013-07-03 13:33:05 -070095 * iptables -A bw_costly_shared --jump bw_penalty_box
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090096 * iptables -A bw_penalty_box --jump bw_happy_box
Lorenzo Colitti464eabe2016-03-25 13:38:19 +090097 * iptables -A bw_happy_box --jump bw_data_saver
JP Abgrall8a932722011-07-13 19:17:35 -070098 *
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070099 * . adding a new iface to this, E.g.:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700100 * iptables -I bw_INPUT -i iface1 --jump bw_costly_shared
101 * iptables -I bw_OUTPUT -o iface1 --jump bw_costly_shared
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700102 *
103 * - quota per interface. This is achieve by having "costly" chains per quota.
104 * E.g. adding a new costly interface iface0 with its own quota:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700105 * iptables -N bw_costly_iface0
106 * iptables -I bw_INPUT -i iface0 --jump bw_costly_iface0
107 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_iface0
108 * iptables -A bw_costly_iface0 -m quota \! --quota 500000 \
JP Abgralle4788732013-07-02 20:28:45 -0700109 * --jump REJECT --reject-with icmp-port-unreachable
JP Abgrall7e51cde2013-07-03 13:33:05 -0700110 * iptables -A bw_costly_iface0 --jump bw_penalty_box
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700111 *
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900112 * * Penalty box, happy box and data saver.
113 * - bw_penalty box is a blacklist of apps that are rejected.
114 * - bw_happy_box is a whitelist of apps. It always includes all system apps
115 * - bw_data_saver implements data usage restrictions.
116 * - Via the UI the user can add and remove apps from the whitelist and
117 * blacklist, and turn on/off data saver.
118 * - The blacklist takes precedence over the whitelist and the whitelist
119 * takes precedence over data saver.
120 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700121 * * bw_penalty_box handling:
122 * - only one bw_penalty_box for all interfaces
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900123 * E.g Adding an app:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700124 * iptables -I bw_penalty_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700125 * --jump REJECT --reject-with icmp-port-unreachable
126 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700127 * * bw_happy_box handling:
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900128 * - The bw_happy_box comes after the penalty box.
JP Abgralle4788732013-07-02 20:28:45 -0700129 * E.g Adding a happy app,
JP Abgrall7e51cde2013-07-03 13:33:05 -0700130 * iptables -I bw_happy_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700131 * --jump RETURN
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900132 *
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900133 * * bw_data_saver handling:
134 * - The bw_data_saver comes after the happy box.
135 * Enable data saver:
136 * iptables -R 1 bw_data_saver --jump REJECT --reject-with icmp-port-unreachable
137 * Disable data saver:
138 * iptables -R 1 bw_data_saver --jump RETURN
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700139 */
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900140
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900141const std::string COMMIT_AND_CLOSE = "COMMIT\n\x04";
142const std::string DATA_SAVER_ENABLE_COMMAND = "-R bw_data_saver 1";
143const std::string HAPPY_BOX_WHITELIST_COMMAND = android::base::StringPrintf(
144 "-I bw_happy_box -m owner --uid-owner %d-%d --jump RETURN", 0, MAX_SYSTEM_UID);
145
146static const std::vector<std::string> IPT_FLUSH_COMMANDS = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700147 /*
148 * Cleanup rules.
JP Abgrall7e51cde2013-07-03 13:33:05 -0700149 * Should normally include bw_costly_<iface>, but we rely on the way they are setup
JP Abgrall0031cea2012-04-17 16:38:23 -0700150 * to allow coexistance.
JP Abgrall39f8f242011-06-29 19:21:58 -0700151 */
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900152 "*filter",
153 ":bw_INPUT -",
154 ":bw_OUTPUT -",
155 ":bw_FORWARD -",
156 ":bw_happy_box -",
157 ":bw_penalty_box -",
158 ":bw_data_saver -",
159 ":bw_costly_shared -",
160 "COMMIT",
161 "*raw",
162 ":bw_raw_PREROUTING -",
163 "COMMIT",
164 "*mangle",
165 ":bw_mangle_POSTROUTING -",
166 COMMIT_AND_CLOSE
JP Abgrall0031cea2012-04-17 16:38:23 -0700167};
168
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900169static const std::vector<std::string> IPT_BASIC_ACCOUNTING_COMMANDS = {
170 "*filter",
JP Abgrall0031cea2012-04-17 16:38:23 -0700171 "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0031cea2012-04-17 16:38:23 -0700172 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900173 "-A bw_costly_shared --jump bw_penalty_box",
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900174 "-A bw_penalty_box --jump bw_happy_box",
175 "-A bw_happy_box --jump bw_data_saver",
176 "-A bw_data_saver -j RETURN",
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900177 HAPPY_BOX_WHITELIST_COMMAND,
178 "COMMIT",
179
180 "*raw",
181 "-A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
182 "COMMIT",
183
184 "*mangle",
185 "-A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
186 COMMIT_AND_CLOSE
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900187};
188
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900189
190} // namespace
191
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700192BandwidthController::BandwidthController(void) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700193}
194
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700195int BandwidthController::runIpxtablesCmd(const char *cmd, IptJumpOp jumpHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700196 IptFailureLog failureHandling) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700197 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700198
Steve Block3fb42e02011-10-20 11:55:56 +0100199 ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700200 res |= runIptablesCmd(cmd, jumpHandling, IptIpV4, failureHandling);
201 res |= runIptablesCmd(cmd, jumpHandling, IptIpV6, failureHandling);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700202 return res;
203}
204
JP Abgrall26e0d492011-06-24 19:21:51 -0700205int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
206
207 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
208 strncpy(buffer, src, buffSize);
209 return buffer[buffSize - 1];
210}
211
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700212int BandwidthController::runIptablesCmd(const char *cmd, IptJumpOp jumpHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700213 IptIpVer iptVer, IptFailureLog failureHandling) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700214 char buffer[MAX_CMD_LEN];
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700215 const char *argv[MAX_CMD_ARGS];
JP Abgrall26e0d492011-06-24 19:21:51 -0700216 int argc = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700217 char *next = buffer;
218 char *tmp;
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700219 int res;
Rom Lemarchand14150212013-01-24 10:01:04 -0800220 int status = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700221
JP Abgrall0dad7c22011-06-24 11:58:14 -0700222 std::string fullCmd = cmd;
JP Abgrall26e0d492011-06-24 19:21:51 -0700223
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700224 switch (jumpHandling) {
225 case IptJumpReject:
JP Abgrall340d5cc2013-06-28 17:06:00 -0700226 /*
227 * Must be carefull what one rejects with, as uper layer protocols will just
228 * keep on hammering the device until the number of retries are done.
229 * For port-unreachable (default), TCP should consider as an abort (RFC1122).
230 */
231 fullCmd += " --jump REJECT";
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700232 break;
233 case IptJumpReturn:
234 fullCmd += " --jump RETURN";
235 break;
236 case IptJumpNoAdd:
237 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700238 }
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
Rom Lemarchand14150212013-01-24 10:01:04 -0800243 if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
244 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');
273 iptablesRestoreFunction(V4V6, commands);
JP Abgrall0e540ec2013-08-26 15:13:10 -0700274}
JP Abgrall0031cea2012-04-17 16:38:23 -0700275
JP Abgrall0e540ec2013-08-26 15:13:10 -0700276int BandwidthController::setupIptablesHooks(void) {
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');
300 return iptablesRestoreFunction(V4V6, commands);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700301}
302
303int BandwidthController::disableBandwidthControl(void) {
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 Colitti13debb82016-03-27 17:46:30 +0900310 return runIpxtablesCmd(DATA_SAVER_ENABLE_COMMAND.c_str(),
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900311 enable ? IptJumpReject : IptJumpReturn, IptFailShow);
312}
313
JP Abgrall8a932722011-07-13 19:17:35 -0700314int BandwidthController::runCommands(int numCommands, const char *commands[],
315 RunCmdErrHandling cmdErrHandling) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700316 int res = 0;
JP Abgrallad729ac2012-04-24 23:27:44 -0700317 IptFailureLog failureLogging = IptFailShow;
318 if (cmdErrHandling == RunCmdFailureOk) {
319 failureLogging = IptFailHide;
320 }
Steve Block3fb42e02011-10-20 11:55:56 +0100321 ALOGV("runCommands(): %d commands", numCommands);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700322 for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700323 res = runIpxtablesCmd(commands[cmdNum], IptJumpNoAdd, failureLogging);
JP Abgrall0031cea2012-04-17 16:38:23 -0700324 if (res && cmdErrHandling != RunCmdFailureOk)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700325 return res;
326 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700327 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700328}
329
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700330std::string BandwidthController::makeIptablesSpecialAppCmd(IptOp op, int uid, const char *chain) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700331 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700332 char *buff;
333 const char *opFlag;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700334
335 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700336 case IptOpInsert:
337 opFlag = "-I";
338 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800339 case IptOpAppend:
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700340 ALOGE("Append op not supported for %s uids", chain);
341 res = "";
342 return res;
JP Abgrall109899b2013-02-12 19:20:13 -0800343 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700344 case IptOpReplace:
345 opFlag = "-R";
346 break;
347 default:
348 case IptOpDelete:
349 opFlag = "-D";
350 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700351 }
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700352 asprintf(&buff, "%s %s -m owner --uid-owner %d", opFlag, chain, uid);
JP Abgrall8a932722011-07-13 19:17:35 -0700353 res = buff;
354 free(buff);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700355 return res;
356}
357
358int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700359 return manipulateNaughtyApps(numUids, appUids, SpecialAppOpAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700360}
361
362int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700363 return manipulateNaughtyApps(numUids, appUids, SpecialAppOpRemove);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700364}
365
JP Abgralle4788732013-07-02 20:28:45 -0700366int BandwidthController::addNiceApps(int numUids, char *appUids[]) {
367 return manipulateNiceApps(numUids, appUids, SpecialAppOpAdd);
368}
369
370int BandwidthController::removeNiceApps(int numUids, char *appUids[]) {
371 return manipulateNiceApps(numUids, appUids, SpecialAppOpRemove);
372}
373
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700374int BandwidthController::manipulateNaughtyApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
Lorenzo Colittib1f05572016-03-18 11:55:56 +0900375 return manipulateSpecialApps(numUids, appStrUids, "bw_penalty_box", IptJumpReject, appOp);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700376}
377
JP Abgralle4788732013-07-02 20:28:45 -0700378int BandwidthController::manipulateNiceApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
Lorenzo Colittib1f05572016-03-18 11:55:56 +0900379 return manipulateSpecialApps(numUids, appStrUids, "bw_happy_box", IptJumpReturn, appOp);
JP Abgralle4788732013-07-02 20:28:45 -0700380}
381
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700382
383int BandwidthController::manipulateSpecialApps(int numUids, char *appStrUids[],
384 const char *chain,
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700385 IptJumpOp jumpHandling, SpecialAppOp appOp) {
386
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700387 int uidNum;
JP Abgrall26e0d492011-06-24 19:21:51 -0700388 const char *failLogTemplate;
389 IptOp op;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700390 int appUids[numUids];
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700391 std::string iptCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700392
JP Abgrall26e0d492011-06-24 19:21:51 -0700393 switch (appOp) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700394 case SpecialAppOpAdd:
JP Abgrall8a932722011-07-13 19:17:35 -0700395 op = IptOpInsert;
JP Abgrallaf476f72013-07-03 12:23:55 -0700396 failLogTemplate = "Failed to add app uid %s(%d) to %s.";
JP Abgrall8a932722011-07-13 19:17:35 -0700397 break;
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700398 case SpecialAppOpRemove:
JP Abgrall8a932722011-07-13 19:17:35 -0700399 op = IptOpDelete;
JP Abgrallaf476f72013-07-03 12:23:55 -0700400 failLogTemplate = "Failed to delete app uid %s(%d) from %s box.";
JP Abgrall8a932722011-07-13 19:17:35 -0700401 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700402 default:
403 ALOGE("Unexpected app Op %d", appOp);
404 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700405 }
406
407 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallaf476f72013-07-03 12:23:55 -0700408 char *end;
409 appUids[uidNum] = strtoul(appStrUids[uidNum], &end, 0);
410 if (*end || !*appStrUids[uidNum]) {
411 ALOGE(failLogTemplate, appStrUids[uidNum], appUids[uidNum], chain);
JP Abgrall26e0d492011-06-24 19:21:51 -0700412 goto fail_parse;
413 }
414 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700415
416 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700417 int uid = appUids[uidNum];
JP Abgrallb1d24092012-04-27 01:02:31 -0700418
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700419 iptCmd = makeIptablesSpecialAppCmd(op, uid, chain);
420 if (runIpxtablesCmd(iptCmd.c_str(), jumpHandling)) {
JP Abgrallaf476f72013-07-03 12:23:55 -0700421 ALOGE(failLogTemplate, appStrUids[uidNum], uid, chain);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700422 goto fail_with_uidNum;
423 }
424 }
425 return 0;
426
JP Abgrall26e0d492011-06-24 19:21:51 -0700427fail_with_uidNum:
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700428 /* Try to remove the uid that failed in any case*/
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700429 iptCmd = makeIptablesSpecialAppCmd(IptOpDelete, appUids[uidNum], chain);
430 runIpxtablesCmd(iptCmd.c_str(), jumpHandling);
JP Abgrall26e0d492011-06-24 19:21:51 -0700431fail_parse:
432 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700433}
434
JP Abgrall26e0d492011-06-24 19:21:51 -0700435std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700436 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700437 char *buff;
438 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700439
SynergyDev7776cea2014-03-16 15:48:51 -0700440 ALOGV("makeIptablesQuotaCmd(%d, %" PRId64")", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700441
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700442 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700443 case IptOpInsert:
444 opFlag = "-I";
445 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800446 case IptOpAppend:
447 opFlag = "-A";
448 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700449 case IptOpReplace:
450 opFlag = "-R";
451 break;
452 default:
453 case IptOpDelete:
454 opFlag = "-D";
455 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700456 }
JP Abgrall8a932722011-07-13 19:17:35 -0700457
JP Abgrallbfa74662011-06-29 19:23:04 -0700458 // The requried IP version specific --jump REJECT ... will be added later.
SynergyDev7776cea2014-03-16 15:48:51 -0700459 asprintf(&buff, "%s bw_costly_%s -m quota2 ! --quota %" PRId64" --name %s", opFlag, costName, quota,
JP Abgrall8a932722011-07-13 19:17:35 -0700460 costName);
461 res = buff;
462 free(buff);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700463 return res;
464}
465
JP Abgrall26e0d492011-06-24 19:21:51 -0700466int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700467 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700468 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700469 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700470 std::string costString;
471 const char *costCString;
472
JP Abgrall0dad7c22011-06-24 11:58:14 -0700473 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700474 switch (quotaType) {
475 case QuotaUnique:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700476 costString = "bw_costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700477 costString += ifn;
478 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700479 /*
JP Abgrall7e51cde2013-07-03 13:33:05 -0700480 * Flush the bw_costly_<iface> is allowed to fail in case it didn't exist.
JP Abgrall0031cea2012-04-17 16:38:23 -0700481 * Creating a new one is allowed to fail in case it existed.
482 * This helps with netd restarts.
483 */
484 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700485 res1 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700486 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700487 res2 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700488 res = (res1 && res2) || (!res1 && !res2);
489
JP Abgrall7e51cde2013-07-03 13:33:05 -0700490 snprintf(cmd, sizeof(cmd), "-A %s -j bw_penalty_box", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700491 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700492 break;
493 case QuotaShared:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700494 costCString = "bw_costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700495 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700496 default:
497 ALOGE("Unexpected quotatype %d", quotaType);
498 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700499 }
500
JP Abgrall8a932722011-07-13 19:17:35 -0700501 if (globalAlertBytes) {
502 /* The alert rule comes 1st */
503 ruleInsertPos = 2;
504 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700505
506 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700507 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700508
509 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700510 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700511
512 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700513 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700514
515 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700516 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
Erik Kline58a94482015-10-02 17:52:37 +0900517
518 snprintf(cmd, sizeof(cmd), "-D bw_FORWARD -o %s --jump %s", ifn, costCString);
519 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
520 snprintf(cmd, sizeof(cmd), "-A bw_FORWARD -o %s --jump %s", ifn, costCString);
521 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
522
JP Abgrall0dad7c22011-06-24 11:58:14 -0700523 return res;
524}
525
JP Abgrall26e0d492011-06-24 19:21:51 -0700526int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700527 char cmd[MAX_CMD_LEN];
528 int res = 0;
529 std::string costString;
530 const char *costCString;
531
JP Abgrall26e0d492011-06-24 19:21:51 -0700532 switch (quotaType) {
533 case QuotaUnique:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700534 costString = "bw_costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700535 costString += ifn;
536 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700537 break;
538 case QuotaShared:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700539 costCString = "bw_costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700540 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700541 default:
542 ALOGE("Unexpected quotatype %d", quotaType);
543 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700544 }
545
JP Abgrall0031cea2012-04-17 16:38:23 -0700546 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700547 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
Erik Kline58a94482015-10-02 17:52:37 +0900548 for (const auto tableName : {LOCAL_OUTPUT, LOCAL_FORWARD}) {
549 snprintf(cmd, sizeof(cmd), "-D %s -o %s --jump %s", tableName, ifn, costCString);
550 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
551 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700552
JP Abgrall7e51cde2013-07-03 13:33:05 -0700553 /* The "-N bw_costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700554 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700555 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700556 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700557 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700558 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700559 }
560 return res;
561}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700562
JP Abgrall0dad7c22011-06-24 11:58:14 -0700563int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700564 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700565 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700566 std::string quotaCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700567 std::string ifaceName;
568 ;
JP Abgrallbfa74662011-06-29 19:23:04 -0700569 const char *costName = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700570 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700571
JP Abgrall8a932722011-07-13 19:17:35 -0700572 if (!maxBytes) {
573 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000574 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700575 return -1;
576 }
JP Abgrall69261cb2014-06-19 18:35:24 -0700577 if (!isIfaceName(iface))
578 return -1;
JP Abgrall26e0d492011-06-24 19:21:51 -0700579 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000580 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700581 return -1;
582 }
583 ifaceName = ifn;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700584
585 if (maxBytes == -1) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700586 return removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700587 }
588
589 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700590 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
591 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700592 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700593 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700594
JP Abgrall0dad7c22011-06-24 11:58:14 -0700595 if (it == sharedQuotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700596 res |= prepCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700597 if (sharedQuotaIfaces.empty()) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700598 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700599 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700600 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000601 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700602 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700603 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700604 sharedQuotaBytes = maxBytes;
605 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700606 sharedQuotaIfaces.push_front(ifaceName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700607
608 }
609
610 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700611 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700612 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000613 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700614 goto fail;
615 }
616 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700617 }
618 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700619
620 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700621 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700622 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
623 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700624 * For now callers needs to choose if they want to "ndc bandwidth enable"
625 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700626 */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700627 removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700628 return -1;
629}
630
JP Abgrall8a932722011-07-13 19:17:35 -0700631/* It will also cleanup any shared alerts */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700632int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700633 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700634 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700635 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700636 std::list<std::string>::iterator it;
JP Abgrallbfa74662011-06-29 19:23:04 -0700637 const char *costName = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700638
JP Abgrall69261cb2014-06-19 18:35:24 -0700639 if (!isIfaceName(iface))
640 return -1;
JP Abgrall8a932722011-07-13 19:17:35 -0700641 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000642 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700643 return -1;
644 }
JP Abgrall8a932722011-07-13 19:17:35 -0700645 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700646
JP Abgrall0dad7c22011-06-24 11:58:14 -0700647 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
648 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700649 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700650 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700651 if (it == sharedQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000652 ALOGE("No such iface %s to delete", ifn);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700653 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700654 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700655
JP Abgrall26e0d492011-06-24 19:21:51 -0700656 res |= cleanupCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700657 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700658
JP Abgrall0dad7c22011-06-24 11:58:14 -0700659 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700660 std::string quotaCmd;
JP Abgrallbfa74662011-06-29 19:23:04 -0700661 quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700662 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall8a932722011-07-13 19:17:35 -0700663 sharedQuotaBytes = 0;
664 if (sharedAlertBytes) {
665 removeSharedAlert();
666 sharedAlertBytes = 0;
667 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700668 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700669 return res;
670}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700671
672int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
673 char ifn[MAX_IFACENAME_LEN];
674 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700675 std::string ifaceName;
676 const char *costName;
677 std::list<QuotaInfo>::iterator it;
678 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700679
JP Abgrall69261cb2014-06-19 18:35:24 -0700680 if (!isIfaceName(iface))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700681 return -1;
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700682
JP Abgrall8a932722011-07-13 19:17:35 -0700683 if (!maxBytes) {
684 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000685 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700686 return -1;
687 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700688 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700689 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700690 }
691
JP Abgrall8a932722011-07-13 19:17:35 -0700692 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000693 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700694 return -1;
695 }
696 ifaceName = ifn;
697 costName = iface;
698
JP Abgrall0dad7c22011-06-24 11:58:14 -0700699 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700700 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700701 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700702 break;
703 }
704
705 if (it == quotaIfaces.end()) {
JP Abgralle4788732013-07-02 20:28:45 -0700706 /* Preparing the iface adds a penalty/happy box check */
JP Abgrall26e0d492011-06-24 19:21:51 -0700707 res |= prepCostlyIface(ifn, QuotaUnique);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700708 /*
JP Abgralle4788732013-07-02 20:28:45 -0700709 * The rejecting quota limit should go after the penalty/happy box checks
JP Abgrallbaeccc42013-06-25 09:44:10 -0700710 * or else a naughty app could just eat up the quota.
711 * So we append here.
712 */
JP Abgrall109899b2013-02-12 19:20:13 -0800713 quotaCmd = makeIptablesQuotaCmd(IptOpAppend, costName, maxBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700714 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700715 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000716 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700717 goto fail;
718 }
719
JP Abgrall8a932722011-07-13 19:17:35 -0700720 quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700721
722 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700723 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700724 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000725 ALOGE("Failed update quota for %s", iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700726 goto fail;
727 }
JP Abgrall8a932722011-07-13 19:17:35 -0700728 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700729 }
730 return 0;
731
732 fail:
733 /*
734 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
735 * rules in the kernel to see which ones need cleaning up.
736 * For now callers needs to choose if they want to "ndc bandwidth enable"
737 * which resets everything.
738 */
739 removeInterfaceSharedQuota(ifn);
740 return -1;
741}
742
JP Abgrall8a932722011-07-13 19:17:35 -0700743int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
744 return getInterfaceQuota("shared", bytes);
745}
746
747int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
748 FILE *fp;
749 char *fname;
750 int scanRes;
751
JP Abgrall69261cb2014-06-19 18:35:24 -0700752 if (!isIfaceName(costName))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700753 return -1;
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700754
JP Abgrall8a932722011-07-13 19:17:35 -0700755 asprintf(&fname, "/proc/net/xt_quota/%s", costName);
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800756 fp = fopen(fname, "re");
JP Abgrall8a932722011-07-13 19:17:35 -0700757 free(fname);
758 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000759 ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700760 return -1;
761 }
Mark Salyzynca0b5e22014-03-26 14:15:03 -0700762 scanRes = fscanf(fp, "%" SCNd64, bytes);
SynergyDev7776cea2014-03-16 15:48:51 -0700763 ALOGV("Read quota res=%d bytes=%" PRId64, scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700764 fclose(fp);
765 return scanRes == 1 ? 0 : -1;
766}
767
JP Abgrall0dad7c22011-06-24 11:58:14 -0700768int BandwidthController::removeInterfaceQuota(const char *iface) {
769
770 char ifn[MAX_IFACENAME_LEN];
771 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700772 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700773 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700774
JP Abgrall69261cb2014-06-19 18:35:24 -0700775 if (!isIfaceName(iface))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700776 return -1;
JP Abgrall8a932722011-07-13 19:17:35 -0700777 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000778 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700779 return -1;
780 }
781 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700782
JP Abgrall0dad7c22011-06-24 11:58:14 -0700783 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700784 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700785 break;
786 }
787
788 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000789 ALOGE("No such iface %s to delete", ifn);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700790 return -1;
791 }
792
793 /* This also removes the quota command of CostlyIface chain. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700794 res |= cleanupCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700795
796 quotaIfaces.erase(it);
797
798 return res;
799}
JP Abgrall8a932722011-07-13 19:17:35 -0700800
801int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
802 FILE *fp;
803 char *fname;
804
JP Abgrall69261cb2014-06-19 18:35:24 -0700805 if (!isIfaceName(quotaName)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700806 ALOGE("updateQuota: Invalid quotaName \"%s\"", quotaName);
807 return -1;
808 }
809
JP Abgrall8a932722011-07-13 19:17:35 -0700810 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800811 fp = fopen(fname, "we");
JP Abgrall8a932722011-07-13 19:17:35 -0700812 free(fname);
813 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000814 ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700815 return -1;
816 }
SynergyDev7776cea2014-03-16 15:48:51 -0700817 fprintf(fp, "%" PRId64"\n", bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700818 fclose(fp);
819 return 0;
820}
821
822int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
823 int res = 0;
824 const char *opFlag;
825 char *alertQuotaCmd;
826
827 switch (op) {
828 case IptOpInsert:
829 opFlag = "-I";
830 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800831 case IptOpAppend:
832 opFlag = "-A";
833 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700834 case IptOpReplace:
835 opFlag = "-R";
836 break;
837 default:
838 case IptOpDelete:
839 opFlag = "-D";
840 break;
841 }
842
JP Abgrall92009c82013-02-06 18:01:24 -0800843 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800844 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700845 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700846 free(alertQuotaCmd);
JP Abgrall92009c82013-02-06 18:01:24 -0800847 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800848 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700849 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700850 free(alertQuotaCmd);
851 return res;
852}
853
JP Abgrallc6c67342011-10-07 16:28:54 -0700854int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
855 int res = 0;
856 const char *opFlag;
JP Abgrall8a932722011-07-13 19:17:35 -0700857 char *alertQuotaCmd;
JP Abgrallc6c67342011-10-07 16:28:54 -0700858
859 switch (op) {
860 case IptOpInsert:
861 opFlag = "-I";
862 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800863 case IptOpAppend:
864 opFlag = "-A";
865 break;
JP Abgrallc6c67342011-10-07 16:28:54 -0700866 case IptOpReplace:
867 opFlag = "-R";
868 break;
869 default:
870 case IptOpDelete:
871 opFlag = "-D";
872 break;
873 }
874
JP Abgrall92009c82013-02-06 18:01:24 -0800875 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800876 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700877 res = runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrallc6c67342011-10-07 16:28:54 -0700878 free(alertQuotaCmd);
879 return res;
880}
881
882int BandwidthController::setGlobalAlert(int64_t bytes) {
883 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700884 int res = 0;
885
886 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000887 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700888 return -1;
889 }
890 if (globalAlertBytes) {
891 res = updateQuota(alertName, bytes);
892 } else {
893 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700894 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +0100895 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700896 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
897 }
JP Abgrall8a932722011-07-13 19:17:35 -0700898 }
899 globalAlertBytes = bytes;
900 return res;
901}
902
JP Abgrallc6c67342011-10-07 16:28:54 -0700903int BandwidthController::setGlobalAlertInForwardChain(void) {
904 const char *alertName = ALERT_GLOBAL_NAME;
905 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700906
JP Abgrallc6c67342011-10-07 16:28:54 -0700907 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +0100908 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700909
910 /*
911 * If there is no globalAlert active we are done.
912 * If there is an active globalAlert but this is not the 1st
913 * tether, we are also done.
914 */
915 if (!globalAlertBytes || globalAlertTetherCount != 1) {
916 return 0;
917 }
918
919 /* We only add the rule if this was the 1st tether added. */
920 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
921 return res;
922}
923
924int BandwidthController::removeGlobalAlert(void) {
925
926 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700927 int res = 0;
928
929 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000930 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700931 return -1;
932 }
933 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700934 if (globalAlertTetherCount) {
935 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
936 }
JP Abgrall8a932722011-07-13 19:17:35 -0700937 globalAlertBytes = 0;
938 return res;
939}
940
JP Abgrallc6c67342011-10-07 16:28:54 -0700941int BandwidthController::removeGlobalAlertInForwardChain(void) {
942 int res = 0;
943 const char *alertName = ALERT_GLOBAL_NAME;
944
945 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000946 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700947 return -1;
948 }
949
950 globalAlertTetherCount--;
951 /*
952 * If there is no globalAlert active we are done.
953 * If there is an active globalAlert but there are more
954 * tethers, we are also done.
955 */
956 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
957 return 0;
958 }
959
960 /* We only detete the rule if this was the last tether removed. */
961 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
962 return res;
963}
964
JP Abgrall8a932722011-07-13 19:17:35 -0700965int BandwidthController::setSharedAlert(int64_t bytes) {
966 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000967 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700968 return -1;
969 }
970 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000971 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700972 return -1;
973 }
974 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
975}
976
977int BandwidthController::removeSharedAlert(void) {
978 return removeCostlyAlert("shared", &sharedAlertBytes);
979}
980
981int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
982 std::list<QuotaInfo>::iterator it;
983
JP Abgrall69261cb2014-06-19 18:35:24 -0700984 if (!isIfaceName(iface)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700985 ALOGE("setInterfaceAlert: Invalid iface \"%s\"", iface);
986 return -1;
987 }
988
JP Abgrall8a932722011-07-13 19:17:35 -0700989 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000990 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700991 return -1;
992 }
993 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
994 if (it->ifaceName == iface)
995 break;
996 }
997
998 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000999 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -07001000 return -1;
1001 }
1002
1003 return setCostlyAlert(iface, bytes, &it->alert);
1004}
1005
1006int BandwidthController::removeInterfaceAlert(const char *iface) {
1007 std::list<QuotaInfo>::iterator it;
1008
JP Abgrall69261cb2014-06-19 18:35:24 -07001009 if (!isIfaceName(iface)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -07001010 ALOGE("removeInterfaceAlert: Invalid iface \"%s\"", iface);
1011 return -1;
1012 }
1013
JP Abgrall8a932722011-07-13 19:17:35 -07001014 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1015 if (it->ifaceName == iface)
1016 break;
1017 }
1018
1019 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +00001020 ALOGE("No prior alert set for interface %s", iface);
JP Abgrall8a932722011-07-13 19:17:35 -07001021 return -1;
1022 }
1023
1024 return removeCostlyAlert(iface, &it->alert);
1025}
1026
1027int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
1028 char *alertQuotaCmd;
JP Abgrall109899b2013-02-12 19:20:13 -08001029 char *chainName;
JP Abgrall8a932722011-07-13 19:17:35 -07001030 int res = 0;
1031 char *alertName;
1032
JP Abgrall69261cb2014-06-19 18:35:24 -07001033 if (!isIfaceName(costName)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -07001034 ALOGE("setCostlyAlert: Invalid costName \"%s\"", costName);
1035 return -1;
1036 }
1037
JP Abgrall8a932722011-07-13 19:17:35 -07001038 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001039 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -07001040 return -1;
1041 }
1042 asprintf(&alertName, "%sAlert", costName);
1043 if (*alertBytes) {
1044 res = updateQuota(alertName, *alertBytes);
1045 } else {
JP Abgrall7e51cde2013-07-03 13:33:05 -07001046 asprintf(&chainName, "bw_costly_%s", costName);
JP Abgrall109899b2013-02-12 19:20:13 -08001047 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-A", chainName, bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -07001048 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -07001049 free(alertQuotaCmd);
JP Abgrall109899b2013-02-12 19:20:13 -08001050 free(chainName);
JP Abgrall8a932722011-07-13 19:17:35 -07001051 }
1052 *alertBytes = bytes;
1053 free(alertName);
1054 return res;
1055}
1056
1057int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
1058 char *alertQuotaCmd;
1059 char *chainName;
1060 char *alertName;
1061 int res = 0;
1062
JP Abgrall69261cb2014-06-19 18:35:24 -07001063 if (!isIfaceName(costName)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -07001064 ALOGE("removeCostlyAlert: Invalid costName \"%s\"", costName);
1065 return -1;
1066 }
1067
JP Abgrall8a932722011-07-13 19:17:35 -07001068 if (!*alertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001069 ALOGE("No prior alert set for %s alert", costName);
JP Abgrall8a932722011-07-13 19:17:35 -07001070 return -1;
1071 }
1072
Jesper Hanssona9d791f2012-04-27 13:54:27 +02001073 asprintf(&alertName, "%sAlert", costName);
JP Abgrall7e51cde2013-07-03 13:33:05 -07001074 asprintf(&chainName, "bw_costly_%s", costName);
JP Abgrall92009c82013-02-06 18:01:24 -08001075 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -07001076 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -07001077 free(alertQuotaCmd);
1078 free(chainName);
1079
1080 *alertBytes = 0;
1081 free(alertName);
1082 return res;
1083}
JP Abgralldb7da582011-09-18 12:57:32 -07001084
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001085void BandwidthController::addStats(TetherStatsList& statsList, const TetherStats& stats) {
1086 for (TetherStats& existing : statsList) {
1087 if (existing.addStatsIfMatch(stats)) {
1088 return;
1089 }
1090 }
1091 // No match. Insert a new interface pair.
1092 statsList.push_back(stats);
1093}
1094
JP Abgralldb7da582011-09-18 12:57:32 -07001095/*
1096 * Parse the ptks and bytes out of:
JP Abgrallbaeccc42013-06-25 09:44:10 -07001097 * Chain natctrl_tether_counters (4 references)
1098 * pkts bytes target prot opt in out source destination
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001099 * 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
1100 * 27 2002 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0
1101 * 1040 107471 RETURN all -- bt-pan rmnet0 0.0.0.0/0 0.0.0.0/0
1102 * 1450 1708806 RETURN all -- rmnet0 bt-pan 0.0.0.0/0 0.0.0.0/0
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001103 * or:
1104 * Chain natctrl_tether_counters (0 references)
1105 * pkts bytes target prot opt in out source destination
1106 * 0 0 RETURN all wlan0 rmnet_data0 ::/0 ::/0
1107 * 0 0 RETURN all rmnet_data0 wlan0 ::/0 ::/0
1108 *
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001109 * It results in an error if invoked and no tethering counter rules exist. The constraint
1110 * helps detect complete parsing failure.
JP Abgralldb7da582011-09-18 12:57:32 -07001111 */
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001112int BandwidthController::addForwardChainStats(const TetherStats& filter,
1113 TetherStatsList& statsList, FILE *fp,
1114 std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001115 int res;
1116 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1117 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
1118 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
1119 char rest[MAX_IPT_OUTPUT_LINE_LEN];
1120
JP Abgrallbaeccc42013-06-25 09:44:10 -07001121 TetherStats stats;
JP Abgralldb7da582011-09-18 12:57:32 -07001122 char *buffPtr;
1123 int64_t packets, bytes;
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001124 int statsFound = 0;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001125
1126 bool filterPair = filter.intIface[0] && filter.extIface[0];
1127
1128 char *filterMsg = filter.getStatsLine();
1129 ALOGV("filter: %s", filterMsg);
1130 free(filterMsg);
1131
1132 stats = filter;
JP Abgralldb7da582011-09-18 12:57:32 -07001133
1134 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1135 /* Clean up, so a failed parse can still print info */
1136 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001137 if (strstr(buffPtr, "0.0.0.0")) {
1138 // IPv4 has -- indicating what to do with fragments...
1139 // 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
1140 res = sscanf(buffPtr, "%" SCNd64" %" SCNd64" RETURN all -- %s %s 0.%s",
1141 &packets, &bytes, iface0, iface1, rest);
1142 } else {
1143 // ... but IPv6 does not.
1144 // 26 2373 RETURN all wlan0 rmnet0 ::/0 ::/0
1145 res = sscanf(buffPtr, "%" SCNd64" %" SCNd64" RETURN all %s %s ::/%s",
1146 &packets, &bytes, iface0, iface1, rest);
1147 }
SynergyDev7776cea2014-03-16 15:48:51 -07001148 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 -07001149 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -08001150 extraProcessingInfo += buffPtr;
1151
JP Abgralldb7da582011-09-18 12:57:32 -07001152 if (res != 5) {
1153 continue;
1154 }
JP Abgrallbaeccc42013-06-25 09:44:10 -07001155 /*
1156 * The following assumes that the 1st rule has in:extIface out:intIface,
1157 * which is what NatController sets up.
1158 * If not filtering, the 1st match rx, and sets up the pair for the tx side.
1159 */
1160 if (filter.intIface[0] && filter.extIface[0]) {
1161 if (filter.intIface == iface0 && filter.extIface == iface1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001162 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 -07001163 stats.rxPackets = packets;
1164 stats.rxBytes = bytes;
1165 } else if (filter.intIface == iface1 && filter.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001166 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 -07001167 stats.txPackets = packets;
1168 stats.txBytes = bytes;
1169 }
1170 } else if (filter.intIface[0] || filter.extIface[0]) {
1171 if (filter.intIface == iface0 || filter.extIface == iface1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001172 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 -07001173 stats.intIface = iface0;
1174 stats.extIface = iface1;
1175 stats.rxPackets = packets;
1176 stats.rxBytes = bytes;
1177 } else if (filter.intIface == iface1 || filter.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001178 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 -07001179 stats.intIface = iface1;
1180 stats.extIface = iface0;
1181 stats.txPackets = packets;
1182 stats.txBytes = bytes;
1183 }
1184 } else /* if (!filter.intFace[0] && !filter.extIface[0]) */ {
1185 if (!stats.intIface[0]) {
SynergyDev7776cea2014-03-16 15:48:51 -07001186 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 -07001187 stats.intIface = iface0;
1188 stats.extIface = iface1;
1189 stats.rxPackets = packets;
1190 stats.rxBytes = bytes;
1191 } else if (stats.intIface == iface1 && stats.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001192 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 -07001193 stats.txPackets = packets;
1194 stats.txBytes = bytes;
1195 }
1196 }
1197 if (stats.rxBytes != -1 && stats.txBytes != -1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001198 ALOGV("rx_bytes=%" PRId64" tx_bytes=%" PRId64" filterPair=%d", stats.rxBytes, stats.txBytes, filterPair);
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001199 addStats(statsList, stats);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001200 if (filterPair) {
JP Abgrallbaeccc42013-06-25 09:44:10 -07001201 return 0;
1202 } else {
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001203 statsFound++;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001204 stats = filter;
1205 }
JP Abgralldb7da582011-09-18 12:57:32 -07001206 }
1207 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001208
1209 /* It is always an error to find only one side of the stats. */
1210 /* It is an error to find nothing when not filtering. */
1211 if (((stats.rxBytes == -1) != (stats.txBytes == -1)) ||
1212 (!statsFound && !filterPair)) {
1213 return -1;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001214 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001215 return 0;
JP Abgralldb7da582011-09-18 12:57:32 -07001216}
1217
JP Abgrallbaeccc42013-06-25 09:44:10 -07001218char *BandwidthController::TetherStats::getStatsLine(void) const {
JP Abgralldb7da582011-09-18 12:57:32 -07001219 char *msg;
SynergyDev7776cea2014-03-16 15:48:51 -07001220 asprintf(&msg, "%s %s %" PRId64" %" PRId64" %" PRId64" %" PRId64, intIface.c_str(), extIface.c_str(),
JP Abgralldb7da582011-09-18 12:57:32 -07001221 rxBytes, rxPackets, txBytes, txPackets);
1222 return msg;
1223}
1224
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001225std::string getTetherStatsCommand(const char *binary) {
JP Abgralldb7da582011-09-18 12:57:32 -07001226 /*
1227 * Why not use some kind of lib to talk to iptables?
1228 * Because the only libs are libiptc and libip6tc in iptables, and they are
1229 * not easy to use. They require the known iptables match modules to be
1230 * preloaded/linked, and require apparently a lot of wrapper code to get
1231 * the wanted info.
1232 */
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001233 return android::base::StringPrintf("%s -nvx -w -L %s", binary,
1234 NatController::LOCAL_TETHER_COUNTERS_CHAIN);
1235}
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001236
Lorenzo Colitti26c91322016-07-11 11:36:25 +09001237int BandwidthController::getTetherStats(SocketClient *cli, TetherStats& filter,
1238 std::string &extraProcessingInfo) {
1239 int res = 0;
1240 std::string fullCmd;
1241 FILE *iptOutput;
1242
1243 TetherStatsList statsList;
1244
1245 for (const auto binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
1246 fullCmd = getTetherStatsCommand(binary);
1247 iptOutput = popenFunction(fullCmd.c_str(), "r");
1248 if (!iptOutput) {
1249 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
1250 extraProcessingInfo += "Failed to run iptables.";
1251 return -1;
1252 }
1253
1254 res = addForwardChainStats(filter, statsList, iptOutput, extraProcessingInfo);
1255 pclose(iptOutput);
1256 if (res != 0) {
1257 return res;
1258 }
1259 }
JP Abgralldb7da582011-09-18 12:57:32 -07001260
Lorenzo Colitti7364b752016-07-08 18:24:53 +09001261 if (filter.intIface[0] && filter.extIface[0] && statsList.size() == 1) {
1262 cli->sendMsg(ResponseCode::TetheringStatsResult, statsList[0].getStatsLine(), false);
1263 } else {
1264 for (const auto& stats: statsList) {
1265 cli->sendMsg(ResponseCode::TetheringStatsListResult, stats.getStatsLine(), false);
1266 }
1267 if (res == 0) {
1268 cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
1269 }
1270 }
1271
JP Abgralldb7da582011-09-18 12:57:32 -07001272 return res;
1273}
JP Abgrall0e540ec2013-08-26 15:13:10 -07001274
1275void BandwidthController::flushExistingCostlyTables(bool doClean) {
JP Abgrall0e540ec2013-08-26 15:13:10 -07001276 std::string fullCmd;
1277 FILE *iptOutput;
JP Abgrall0e540ec2013-08-26 15:13:10 -07001278
1279 /* Only lookup ip4 table names as ip6 will have the same tables ... */
1280 fullCmd = IPTABLES_PATH;
Yusuke Sato99b40502015-08-19 13:47:30 -07001281 fullCmd += " -w -S";
Lorenzo Colitti86a47982016-03-18 17:52:25 +09001282 iptOutput = popenFunction(fullCmd.c_str(), "r");
JP Abgrall0e540ec2013-08-26 15:13:10 -07001283 if (!iptOutput) {
1284 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
1285 return;
1286 }
1287 /* ... then flush/clean both ip4 and ip6 iptables. */
1288 parseAndFlushCostlyTables(iptOutput, doClean);
1289 pclose(iptOutput);
1290}
1291
1292void BandwidthController::parseAndFlushCostlyTables(FILE *fp, bool doRemove) {
1293 int res;
1294 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1295 char costlyIfaceName[MAX_IPT_OUTPUT_LINE_LEN];
1296 char cmd[MAX_CMD_LEN];
1297 char *buffPtr;
1298
1299 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1300 costlyIfaceName[0] = '\0'; /* So that debugging output always works */
1301 res = sscanf(buffPtr, "-N bw_costly_%s", costlyIfaceName);
1302 ALOGV("parse res=%d costly=<%s> orig line=<%s>", res,
1303 costlyIfaceName, buffPtr);
1304 if (res != 1) {
1305 continue;
1306 }
1307 /* Exclusions: "shared" is not an ifacename */
1308 if (!strcmp(costlyIfaceName, "shared")) {
1309 continue;
1310 }
1311
1312 snprintf(cmd, sizeof(cmd), "-F bw_costly_%s", costlyIfaceName);
1313 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1314 if (doRemove) {
1315 snprintf(cmd, sizeof(cmd), "-X bw_costly_%s", costlyIfaceName);
1316 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1317 }
1318 }
1319}