blob: 2f129ab83b661dae110aa43cd3e842980879d397 [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
JP Abgrall8a932722011-07-13 19:17:35 -070025#include <errno.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070026#include <fcntl.h>
JP Abgralldb7da582011-09-18 12:57:32 -070027#include <stdio.h>
JP Abgrall8a932722011-07-13 19:17:35 -070028#include <stdlib.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070029#include <string.h>
Nick Kralevich0b2b9022014-05-01 13:10:45 -070030#include <ctype.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070031
Matthew Leach2a54d962013-01-14 15:07:12 +000032#define __STDC_FORMAT_MACROS 1
33#include <inttypes.h>
34
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070035#include <sys/socket.h>
36#include <sys/stat.h>
37#include <sys/types.h>
38#include <sys/wait.h>
39
40#include <linux/netlink.h>
41#include <linux/rtnetlink.h>
42#include <linux/pkt_sched.h>
43
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090044#include "android-base/stringprintf.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070045#define LOG_TAG "BandwidthController"
46#include <cutils/log.h>
47#include <cutils/properties.h>
Rom Lemarchand14150212013-01-24 10:01:04 -080048#include <logwrap/logwrap.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070049
JP Abgrall0031cea2012-04-17 16:38:23 -070050#include "NetdConstants.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070051#include "BandwidthController.h"
JP Abgrallbaeccc42013-06-25 09:44:10 -070052#include "NatController.h" /* For LOCAL_TETHER_COUNTERS_CHAIN */
53#include "ResponseCode.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070054
JP Abgralldb7da582011-09-18 12:57:32 -070055/* Alphabetical */
SynergyDev7776cea2014-03-16 15:48:51 -070056#define ALERT_IPT_TEMPLATE "%s %s -m quota2 ! --quota %" PRId64" --name %s"
Jeff Sharkey8e188ed2012-07-12 18:32:03 -070057const char* BandwidthController::LOCAL_INPUT = "bw_INPUT";
58const char* BandwidthController::LOCAL_FORWARD = "bw_FORWARD";
59const char* BandwidthController::LOCAL_OUTPUT = "bw_OUTPUT";
60const char* BandwidthController::LOCAL_RAW_PREROUTING = "bw_raw_PREROUTING";
61const char* BandwidthController::LOCAL_MANGLE_POSTROUTING = "bw_mangle_POSTROUTING";
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090062
Lorenzo Colitti86a47982016-03-18 17:52:25 +090063auto BandwidthController::execFunction = android_fork_execvp;
64auto BandwidthController::popenFunction = popen;
65
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090066namespace {
67
68const char ALERT_GLOBAL_NAME[] = "globalAlert";
69const int MAX_CMD_ARGS = 32;
70const int MAX_CMD_LEN = 1024;
71const int MAX_IFACENAME_LEN = 64;
72const int MAX_IPT_OUTPUT_LINE_LEN = 256;
JP Abgralldb7da582011-09-18 12:57:32 -070073
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070074/**
75 * Some comments about the rules:
76 * * Ordering
77 * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
JP Abgrall29e8de22012-05-03 12:52:15 -070078 * E.g. "-I bw_INPUT -i rmnet0 --jump costly"
JP Abgrall7e51cde2013-07-03 13:33:05 -070079 * - quota'd rules in the costly chain should be before bw_penalty_box lookups.
80 * - bw_happy_box rejects everything by default.
JP Abgrall29e8de22012-05-03 12:52:15 -070081 * - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070082 *
83 * * global quota vs per interface quota
84 * - global quota for all costly interfaces uses a single costly chain:
85 * . initial rules
JP Abgrall7e51cde2013-07-03 13:33:05 -070086 * iptables -N bw_costly_shared
87 * iptables -I bw_INPUT -i iface0 --jump bw_costly_shared
88 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_shared
89 * iptables -I bw_costly_shared -m quota \! --quota 500000 \
JP Abgrallbfa74662011-06-29 19:23:04 -070090 * --jump REJECT --reject-with icmp-net-prohibited
JP Abgrall7e51cde2013-07-03 13:33:05 -070091 * iptables -A bw_costly_shared --jump bw_penalty_box
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090092 * iptables -A bw_penalty_box --jump bw_happy_box
JP Abgrall8a932722011-07-13 19:17:35 -070093 *
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070094 * . adding a new iface to this, E.g.:
JP Abgrall7e51cde2013-07-03 13:33:05 -070095 * iptables -I bw_INPUT -i iface1 --jump bw_costly_shared
96 * iptables -I bw_OUTPUT -o iface1 --jump bw_costly_shared
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070097 *
98 * - quota per interface. This is achieve by having "costly" chains per quota.
99 * E.g. adding a new costly interface iface0 with its own quota:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700100 * iptables -N bw_costly_iface0
101 * iptables -I bw_INPUT -i iface0 --jump bw_costly_iface0
102 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_iface0
103 * iptables -A bw_costly_iface0 -m quota \! --quota 500000 \
JP Abgralle4788732013-07-02 20:28:45 -0700104 * --jump REJECT --reject-with icmp-port-unreachable
JP Abgrall7e51cde2013-07-03 13:33:05 -0700105 * iptables -A bw_costly_iface0 --jump bw_penalty_box
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700106 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700107 * * bw_penalty_box handling:
108 * - only one bw_penalty_box for all interfaces
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900109 * E.g Adding an app:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700110 * iptables -I bw_penalty_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700111 * --jump REJECT --reject-with icmp-port-unreachable
112 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700113 * * bw_happy_box handling:
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900114 * - The bw_happy_box comes after the penalty box.
JP Abgralle4788732013-07-02 20:28:45 -0700115 * E.g Adding a happy app,
JP Abgrall7e51cde2013-07-03 13:33:05 -0700116 * iptables -I bw_happy_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700117 * --jump RETURN
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900118 *
119 * * Turning data saver on and off:
120 * - Adds or removes a REJECT at the end of the bw_costly_shared chain
121 * iptables -A bw_costly_shared --jump REJECT --reject-with icmp-port-unreachable
122 * iptables -D bw_costly_shared --jump REJECT --reject-with icmp-port-unreachable
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700123 */
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900124
125const char *IPT_FLUSH_COMMANDS[] = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700126 /*
127 * Cleanup rules.
JP Abgrall7e51cde2013-07-03 13:33:05 -0700128 * Should normally include bw_costly_<iface>, but we rely on the way they are setup
JP Abgrall0031cea2012-04-17 16:38:23 -0700129 * to allow coexistance.
JP Abgrall39f8f242011-06-29 19:21:58 -0700130 */
JP Abgrall0031cea2012-04-17 16:38:23 -0700131 "-F bw_INPUT",
132 "-F bw_OUTPUT",
133 "-F bw_FORWARD",
JP Abgrall7e51cde2013-07-03 13:33:05 -0700134 "-F bw_happy_box",
135 "-F bw_penalty_box",
136 "-F bw_costly_shared",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700137
138 "-t raw -F bw_raw_PREROUTING",
139 "-t mangle -F bw_mangle_POSTROUTING",
JP Abgrall0031cea2012-04-17 16:38:23 -0700140};
141
142/* The cleanup commands assume flushing has been done. */
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900143const char *IPT_CLEANUP_COMMANDS[] = {
JP Abgrall7e51cde2013-07-03 13:33:05 -0700144 "-X bw_happy_box",
145 "-X bw_penalty_box",
146 "-X bw_costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700147};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700148
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900149const char *IPT_SETUP_COMMANDS[] = {
JP Abgrall7e51cde2013-07-03 13:33:05 -0700150 "-N bw_happy_box",
151 "-N bw_penalty_box",
152 "-N bw_costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700153};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700154
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900155const char *IPT_BASIC_ACCOUNTING_COMMANDS[] = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700156 "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700157
JP Abgrall0031cea2012-04-17 16:38:23 -0700158 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700159
JP Abgrall92009c82013-02-06 18:01:24 -0800160 "-t raw -A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
161 "-t mangle -A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700162};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700163
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900164const char *COSTLY_SHARED_COMMANDS[] = {
165 "-A bw_costly_shared --jump bw_penalty_box",
166 "-A bw_costly_shared --jump bw_happy_box",
167 "-A bw_costly_shared --jump RETURN",
168};
169
170const std::string kDataSaverEnableCommand = android::base::StringPrintf(
171 "-R bw_costly_shared %zu", ARRAY_SIZE(COSTLY_SHARED_COMMANDS));
172
173} // namespace
174
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700175BandwidthController::BandwidthController(void) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700176}
177
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700178int BandwidthController::runIpxtablesCmd(const char *cmd, IptJumpOp jumpHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700179 IptFailureLog failureHandling) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700180 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700181
Steve Block3fb42e02011-10-20 11:55:56 +0100182 ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700183 res |= runIptablesCmd(cmd, jumpHandling, IptIpV4, failureHandling);
184 res |= runIptablesCmd(cmd, jumpHandling, IptIpV6, failureHandling);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700185 return res;
186}
187
JP Abgrall26e0d492011-06-24 19:21:51 -0700188int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
189
190 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
191 strncpy(buffer, src, buffSize);
192 return buffer[buffSize - 1];
193}
194
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700195int BandwidthController::runIptablesCmd(const char *cmd, IptJumpOp jumpHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700196 IptIpVer iptVer, IptFailureLog failureHandling) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700197 char buffer[MAX_CMD_LEN];
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700198 const char *argv[MAX_CMD_ARGS];
JP Abgrall26e0d492011-06-24 19:21:51 -0700199 int argc = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700200 char *next = buffer;
201 char *tmp;
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700202 int res;
Rom Lemarchand14150212013-01-24 10:01:04 -0800203 int status = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700204
JP Abgrall0dad7c22011-06-24 11:58:14 -0700205 std::string fullCmd = cmd;
JP Abgrall26e0d492011-06-24 19:21:51 -0700206
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700207 switch (jumpHandling) {
208 case IptJumpReject:
JP Abgrall340d5cc2013-06-28 17:06:00 -0700209 /*
210 * Must be carefull what one rejects with, as uper layer protocols will just
211 * keep on hammering the device until the number of retries are done.
212 * For port-unreachable (default), TCP should consider as an abort (RFC1122).
213 */
214 fullCmd += " --jump REJECT";
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700215 break;
216 case IptJumpReturn:
217 fullCmd += " --jump RETURN";
218 break;
219 case IptJumpNoAdd:
220 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700221 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700222
Paul Jensen94b2ab92015-08-04 10:35:05 -0400223 fullCmd.insert(0, " -w ");
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700224 fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700225
Rom Lemarchand14150212013-01-24 10:01:04 -0800226 if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
227 ALOGE("iptables command too long");
228 return -1;
229 }
230
231 argc = 0;
232 while ((tmp = strsep(&next, " "))) {
233 argv[argc++] = tmp;
234 if (argc >= MAX_CMD_ARGS) {
235 ALOGE("iptables argument overflow");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700236 return -1;
237 }
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700238 }
Rom Lemarchand14150212013-01-24 10:01:04 -0800239
240 argv[argc] = NULL;
Lorenzo Colitti86a47982016-03-18 17:52:25 +0900241 res = execFunction(argc, (char **)argv, &status, false,
Rom Lemarchand14150212013-01-24 10:01:04 -0800242 failureHandling == IptFailShow);
JP Abgrallc8dc63b2013-02-13 16:30:00 -0800243 res = res || !WIFEXITED(status) || WEXITSTATUS(status);
244 if (res && failureHandling == IptFailShow) {
245 ALOGE("runIptablesCmd(): res=%d status=%d failed %s", res, status,
246 fullCmd.c_str());
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700247 }
248 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700249}
250
JP Abgrall0e540ec2013-08-26 15:13:10 -0700251void BandwidthController::flushCleanTables(bool doClean) {
252 /* Flush and remove the bw_costly_<iface> tables */
253 flushExistingCostlyTables(doClean);
JP Abgrall0031cea2012-04-17 16:38:23 -0700254
255 /* Some of the initialCommands are allowed to fail */
256 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
257 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
258
JP Abgrall0e540ec2013-08-26 15:13:10 -0700259 if (doClean) {
260 runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
261 IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
262 }
263}
JP Abgrall0031cea2012-04-17 16:38:23 -0700264
JP Abgrall0e540ec2013-08-26 15:13:10 -0700265int BandwidthController::setupIptablesHooks(void) {
266
267 /* flush+clean is allowed to fail */
268 flushCleanTables(true);
JP Abgrall0031cea2012-04-17 16:38:23 -0700269 runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
270 IPT_SETUP_COMMANDS, RunCmdFailureBad);
271
272 return 0;
JP Abgrall0031cea2012-04-17 16:38:23 -0700273}
274
275int BandwidthController::enableBandwidthControl(bool force) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700276 int res;
JP Abgrall0031cea2012-04-17 16:38:23 -0700277 char value[PROPERTY_VALUE_MAX];
278
279 if (!force) {
280 property_get("persist.bandwidth.enable", value, "1");
281 if (!strcmp(value, "0"))
282 return 0;
283 }
JP Abgrall8a932722011-07-13 19:17:35 -0700284
JP Abgralldb7da582011-09-18 12:57:32 -0700285 /* Let's pretend we started from scratch ... */
JP Abgrall8a932722011-07-13 19:17:35 -0700286 sharedQuotaIfaces.clear();
287 quotaIfaces.clear();
JP Abgralldb7da582011-09-18 12:57:32 -0700288 globalAlertBytes = 0;
JP Abgrallc6c67342011-10-07 16:28:54 -0700289 globalAlertTetherCount = 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700290 sharedQuotaBytes = sharedAlertBytes = 0;
291
JP Abgrall0e540ec2013-08-26 15:13:10 -0700292 flushCleanTables(false);
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900293 res = runCommands(ARRAY_SIZE(IPT_BASIC_ACCOUNTING_COMMANDS),
JP Abgralldb7da582011-09-18 12:57:32 -0700294 IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
JP Abgrall8a932722011-07-13 19:17:35 -0700295
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900296 res |= runCommands(ARRAY_SIZE(COSTLY_SHARED_COMMANDS),
297 COSTLY_SHARED_COMMANDS, RunCmdFailureBad);
298
299 char cmd[MAX_CMD_LEN];
300 snprintf(cmd, sizeof(cmd),
301 "-A bw_happy_box -m owner --uid-owner %d-%d", 0, MAX_SYSTEM_UID);
302 runIpxtablesCmd(cmd, IptJumpReturn);
303
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700304 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700305
306}
307
308int BandwidthController::disableBandwidthControl(void) {
JP Abgrall0e540ec2013-08-26 15:13:10 -0700309
310 flushCleanTables(false);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700311 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700312}
313
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900314int BandwidthController::enableDataSaver(bool enable) {
315 return runIpxtablesCmd(kDataSaverEnableCommand.c_str(),
316 enable ? IptJumpReject : IptJumpReturn, IptFailShow);
317}
318
JP Abgrall8a932722011-07-13 19:17:35 -0700319int BandwidthController::runCommands(int numCommands, const char *commands[],
320 RunCmdErrHandling cmdErrHandling) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700321 int res = 0;
JP Abgrallad729ac2012-04-24 23:27:44 -0700322 IptFailureLog failureLogging = IptFailShow;
323 if (cmdErrHandling == RunCmdFailureOk) {
324 failureLogging = IptFailHide;
325 }
Steve Block3fb42e02011-10-20 11:55:56 +0100326 ALOGV("runCommands(): %d commands", numCommands);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700327 for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700328 res = runIpxtablesCmd(commands[cmdNum], IptJumpNoAdd, failureLogging);
JP Abgrall0031cea2012-04-17 16:38:23 -0700329 if (res && cmdErrHandling != RunCmdFailureOk)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700330 return res;
331 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700332 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700333}
334
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700335std::string BandwidthController::makeIptablesSpecialAppCmd(IptOp op, int uid, const char *chain) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700336 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700337 char *buff;
338 const char *opFlag;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700339
340 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700341 case IptOpInsert:
342 opFlag = "-I";
343 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800344 case IptOpAppend:
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700345 ALOGE("Append op not supported for %s uids", chain);
346 res = "";
347 return res;
JP Abgrall109899b2013-02-12 19:20:13 -0800348 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700349 case IptOpReplace:
350 opFlag = "-R";
351 break;
352 default:
353 case IptOpDelete:
354 opFlag = "-D";
355 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700356 }
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700357 asprintf(&buff, "%s %s -m owner --uid-owner %d", opFlag, chain, uid);
JP Abgrall8a932722011-07-13 19:17:35 -0700358 res = buff;
359 free(buff);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700360 return res;
361}
362
363int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700364 return manipulateNaughtyApps(numUids, appUids, SpecialAppOpAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700365}
366
367int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700368 return manipulateNaughtyApps(numUids, appUids, SpecialAppOpRemove);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700369}
370
JP Abgralle4788732013-07-02 20:28:45 -0700371int BandwidthController::addNiceApps(int numUids, char *appUids[]) {
372 return manipulateNiceApps(numUids, appUids, SpecialAppOpAdd);
373}
374
375int BandwidthController::removeNiceApps(int numUids, char *appUids[]) {
376 return manipulateNiceApps(numUids, appUids, SpecialAppOpRemove);
377}
378
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700379int BandwidthController::manipulateNaughtyApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
Lorenzo Colittib1f05572016-03-18 11:55:56 +0900380 return manipulateSpecialApps(numUids, appStrUids, "bw_penalty_box", IptJumpReject, appOp);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700381}
382
JP Abgralle4788732013-07-02 20:28:45 -0700383int BandwidthController::manipulateNiceApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
Lorenzo Colittib1f05572016-03-18 11:55:56 +0900384 return manipulateSpecialApps(numUids, appStrUids, "bw_happy_box", IptJumpReturn, appOp);
JP Abgralle4788732013-07-02 20:28:45 -0700385}
386
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700387
388int BandwidthController::manipulateSpecialApps(int numUids, char *appStrUids[],
389 const char *chain,
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700390 IptJumpOp jumpHandling, SpecialAppOp appOp) {
391
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700392 int uidNum;
JP Abgrall26e0d492011-06-24 19:21:51 -0700393 const char *failLogTemplate;
394 IptOp op;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700395 int appUids[numUids];
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700396 std::string iptCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700397
JP Abgrall26e0d492011-06-24 19:21:51 -0700398 switch (appOp) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700399 case SpecialAppOpAdd:
JP Abgrall8a932722011-07-13 19:17:35 -0700400 op = IptOpInsert;
JP Abgrallaf476f72013-07-03 12:23:55 -0700401 failLogTemplate = "Failed to add app uid %s(%d) to %s.";
JP Abgrall8a932722011-07-13 19:17:35 -0700402 break;
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700403 case SpecialAppOpRemove:
JP Abgrall8a932722011-07-13 19:17:35 -0700404 op = IptOpDelete;
JP Abgrallaf476f72013-07-03 12:23:55 -0700405 failLogTemplate = "Failed to delete app uid %s(%d) from %s box.";
JP Abgrall8a932722011-07-13 19:17:35 -0700406 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700407 default:
408 ALOGE("Unexpected app Op %d", appOp);
409 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700410 }
411
412 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallaf476f72013-07-03 12:23:55 -0700413 char *end;
414 appUids[uidNum] = strtoul(appStrUids[uidNum], &end, 0);
415 if (*end || !*appStrUids[uidNum]) {
416 ALOGE(failLogTemplate, appStrUids[uidNum], appUids[uidNum], chain);
JP Abgrall26e0d492011-06-24 19:21:51 -0700417 goto fail_parse;
418 }
419 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700420
421 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700422 int uid = appUids[uidNum];
JP Abgrallb1d24092012-04-27 01:02:31 -0700423
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700424 iptCmd = makeIptablesSpecialAppCmd(op, uid, chain);
425 if (runIpxtablesCmd(iptCmd.c_str(), jumpHandling)) {
JP Abgrallaf476f72013-07-03 12:23:55 -0700426 ALOGE(failLogTemplate, appStrUids[uidNum], uid, chain);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700427 goto fail_with_uidNum;
428 }
429 }
430 return 0;
431
JP Abgrall26e0d492011-06-24 19:21:51 -0700432fail_with_uidNum:
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700433 /* Try to remove the uid that failed in any case*/
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700434 iptCmd = makeIptablesSpecialAppCmd(IptOpDelete, appUids[uidNum], chain);
435 runIpxtablesCmd(iptCmd.c_str(), jumpHandling);
JP Abgrall26e0d492011-06-24 19:21:51 -0700436fail_parse:
437 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700438}
439
JP Abgrall26e0d492011-06-24 19:21:51 -0700440std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700441 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700442 char *buff;
443 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700444
SynergyDev7776cea2014-03-16 15:48:51 -0700445 ALOGV("makeIptablesQuotaCmd(%d, %" PRId64")", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700446
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700447 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700448 case IptOpInsert:
449 opFlag = "-I";
450 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800451 case IptOpAppend:
452 opFlag = "-A";
453 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700454 case IptOpReplace:
455 opFlag = "-R";
456 break;
457 default:
458 case IptOpDelete:
459 opFlag = "-D";
460 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700461 }
JP Abgrall8a932722011-07-13 19:17:35 -0700462
JP Abgrallbfa74662011-06-29 19:23:04 -0700463 // The requried IP version specific --jump REJECT ... will be added later.
SynergyDev7776cea2014-03-16 15:48:51 -0700464 asprintf(&buff, "%s bw_costly_%s -m quota2 ! --quota %" PRId64" --name %s", opFlag, costName, quota,
JP Abgrall8a932722011-07-13 19:17:35 -0700465 costName);
466 res = buff;
467 free(buff);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700468 return res;
469}
470
JP Abgrall26e0d492011-06-24 19:21:51 -0700471int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700472 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700473 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700474 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700475 std::string costString;
476 const char *costCString;
477
JP Abgrall0dad7c22011-06-24 11:58:14 -0700478 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700479 switch (quotaType) {
480 case QuotaUnique:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700481 costString = "bw_costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700482 costString += ifn;
483 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700484 /*
JP Abgrall7e51cde2013-07-03 13:33:05 -0700485 * Flush the bw_costly_<iface> is allowed to fail in case it didn't exist.
JP Abgrall0031cea2012-04-17 16:38:23 -0700486 * Creating a new one is allowed to fail in case it existed.
487 * This helps with netd restarts.
488 */
489 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700490 res1 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700491 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700492 res2 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700493 res = (res1 && res2) || (!res1 && !res2);
494
JP Abgrall7e51cde2013-07-03 13:33:05 -0700495 snprintf(cmd, sizeof(cmd), "-A %s -j bw_penalty_box", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700496 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700497 break;
498 case QuotaShared:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700499 costCString = "bw_costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700500 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700501 default:
502 ALOGE("Unexpected quotatype %d", quotaType);
503 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700504 }
505
JP Abgrall8a932722011-07-13 19:17:35 -0700506 if (globalAlertBytes) {
507 /* The alert rule comes 1st */
508 ruleInsertPos = 2;
509 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700510
511 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700512 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700513
514 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700515 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700516
517 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700518 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700519
520 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700521 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
Erik Kline58a94482015-10-02 17:52:37 +0900522
523 snprintf(cmd, sizeof(cmd), "-D bw_FORWARD -o %s --jump %s", ifn, costCString);
524 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
525 snprintf(cmd, sizeof(cmd), "-A bw_FORWARD -o %s --jump %s", ifn, costCString);
526 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
527
JP Abgrall0dad7c22011-06-24 11:58:14 -0700528 return res;
529}
530
JP Abgrall26e0d492011-06-24 19:21:51 -0700531int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700532 char cmd[MAX_CMD_LEN];
533 int res = 0;
534 std::string costString;
535 const char *costCString;
536
JP Abgrall26e0d492011-06-24 19:21:51 -0700537 switch (quotaType) {
538 case QuotaUnique:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700539 costString = "bw_costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700540 costString += ifn;
541 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700542 break;
543 case QuotaShared:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700544 costCString = "bw_costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700545 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700546 default:
547 ALOGE("Unexpected quotatype %d", quotaType);
548 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700549 }
550
JP Abgrall0031cea2012-04-17 16:38:23 -0700551 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700552 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
Erik Kline58a94482015-10-02 17:52:37 +0900553 for (const auto tableName : {LOCAL_OUTPUT, LOCAL_FORWARD}) {
554 snprintf(cmd, sizeof(cmd), "-D %s -o %s --jump %s", tableName, ifn, costCString);
555 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
556 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700557
JP Abgrall7e51cde2013-07-03 13:33:05 -0700558 /* The "-N bw_costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700559 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700560 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700561 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700562 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700563 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700564 }
565 return res;
566}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700567
JP Abgrall0dad7c22011-06-24 11:58:14 -0700568int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700569 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700570 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700571 std::string quotaCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700572 std::string ifaceName;
573 ;
JP Abgrallbfa74662011-06-29 19:23:04 -0700574 const char *costName = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700575 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700576
JP Abgrall8a932722011-07-13 19:17:35 -0700577 if (!maxBytes) {
578 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000579 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700580 return -1;
581 }
JP Abgrall69261cb2014-06-19 18:35:24 -0700582 if (!isIfaceName(iface))
583 return -1;
JP Abgrall26e0d492011-06-24 19:21:51 -0700584 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000585 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700586 return -1;
587 }
588 ifaceName = ifn;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700589
590 if (maxBytes == -1) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700591 return removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700592 }
593
594 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700595 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
596 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700597 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700598 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700599
JP Abgrall0dad7c22011-06-24 11:58:14 -0700600 if (it == sharedQuotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700601 res |= prepCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700602 if (sharedQuotaIfaces.empty()) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700603 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700604 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700605 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000606 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700607 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700608 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700609 sharedQuotaBytes = maxBytes;
610 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700611 sharedQuotaIfaces.push_front(ifaceName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700612
613 }
614
615 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700616 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700617 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000618 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700619 goto fail;
620 }
621 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700622 }
623 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700624
625 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700626 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700627 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
628 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700629 * For now callers needs to choose if they want to "ndc bandwidth enable"
630 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700631 */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700632 removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700633 return -1;
634}
635
JP Abgrall8a932722011-07-13 19:17:35 -0700636/* It will also cleanup any shared alerts */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700637int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700638 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700639 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700640 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700641 std::list<std::string>::iterator it;
JP Abgrallbfa74662011-06-29 19:23:04 -0700642 const char *costName = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700643
JP Abgrall69261cb2014-06-19 18:35:24 -0700644 if (!isIfaceName(iface))
645 return -1;
JP Abgrall8a932722011-07-13 19:17:35 -0700646 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000647 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700648 return -1;
649 }
JP Abgrall8a932722011-07-13 19:17:35 -0700650 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700651
JP Abgrall0dad7c22011-06-24 11:58:14 -0700652 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
653 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700654 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700655 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700656 if (it == sharedQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000657 ALOGE("No such iface %s to delete", ifn);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700658 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700659 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700660
JP Abgrall26e0d492011-06-24 19:21:51 -0700661 res |= cleanupCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700662 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700663
JP Abgrall0dad7c22011-06-24 11:58:14 -0700664 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700665 std::string quotaCmd;
JP Abgrallbfa74662011-06-29 19:23:04 -0700666 quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700667 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall8a932722011-07-13 19:17:35 -0700668 sharedQuotaBytes = 0;
669 if (sharedAlertBytes) {
670 removeSharedAlert();
671 sharedAlertBytes = 0;
672 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700673 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700674 return res;
675}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700676
677int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
678 char ifn[MAX_IFACENAME_LEN];
679 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700680 std::string ifaceName;
681 const char *costName;
682 std::list<QuotaInfo>::iterator it;
683 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700684
JP Abgrall69261cb2014-06-19 18:35:24 -0700685 if (!isIfaceName(iface))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700686 return -1;
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700687
JP Abgrall8a932722011-07-13 19:17:35 -0700688 if (!maxBytes) {
689 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000690 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700691 return -1;
692 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700693 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700694 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700695 }
696
JP Abgrall8a932722011-07-13 19:17:35 -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;
702 costName = iface;
703
JP Abgrall0dad7c22011-06-24 11:58:14 -0700704 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700705 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700706 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700707 break;
708 }
709
710 if (it == quotaIfaces.end()) {
JP Abgralle4788732013-07-02 20:28:45 -0700711 /* Preparing the iface adds a penalty/happy box check */
JP Abgrall26e0d492011-06-24 19:21:51 -0700712 res |= prepCostlyIface(ifn, QuotaUnique);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700713 /*
JP Abgralle4788732013-07-02 20:28:45 -0700714 * The rejecting quota limit should go after the penalty/happy box checks
JP Abgrallbaeccc42013-06-25 09:44:10 -0700715 * or else a naughty app could just eat up the quota.
716 * So we append here.
717 */
JP Abgrall109899b2013-02-12 19:20:13 -0800718 quotaCmd = makeIptablesQuotaCmd(IptOpAppend, costName, maxBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700719 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700720 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000721 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700722 goto fail;
723 }
724
JP Abgrall8a932722011-07-13 19:17:35 -0700725 quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700726
727 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700728 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700729 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000730 ALOGE("Failed update quota for %s", iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700731 goto fail;
732 }
JP Abgrall8a932722011-07-13 19:17:35 -0700733 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700734 }
735 return 0;
736
737 fail:
738 /*
739 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
740 * rules in the kernel to see which ones need cleaning up.
741 * For now callers needs to choose if they want to "ndc bandwidth enable"
742 * which resets everything.
743 */
744 removeInterfaceSharedQuota(ifn);
745 return -1;
746}
747
JP Abgrall8a932722011-07-13 19:17:35 -0700748int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
749 return getInterfaceQuota("shared", bytes);
750}
751
752int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
753 FILE *fp;
754 char *fname;
755 int scanRes;
756
JP Abgrall69261cb2014-06-19 18:35:24 -0700757 if (!isIfaceName(costName))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700758 return -1;
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700759
JP Abgrall8a932722011-07-13 19:17:35 -0700760 asprintf(&fname, "/proc/net/xt_quota/%s", costName);
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800761 fp = fopen(fname, "re");
JP Abgrall8a932722011-07-13 19:17:35 -0700762 free(fname);
763 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000764 ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700765 return -1;
766 }
Mark Salyzynca0b5e22014-03-26 14:15:03 -0700767 scanRes = fscanf(fp, "%" SCNd64, bytes);
SynergyDev7776cea2014-03-16 15:48:51 -0700768 ALOGV("Read quota res=%d bytes=%" PRId64, scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700769 fclose(fp);
770 return scanRes == 1 ? 0 : -1;
771}
772
JP Abgrall0dad7c22011-06-24 11:58:14 -0700773int BandwidthController::removeInterfaceQuota(const char *iface) {
774
775 char ifn[MAX_IFACENAME_LEN];
776 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700777 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700778 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700779
JP Abgrall69261cb2014-06-19 18:35:24 -0700780 if (!isIfaceName(iface))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700781 return -1;
JP Abgrall8a932722011-07-13 19:17:35 -0700782 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000783 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700784 return -1;
785 }
786 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700787
JP Abgrall0dad7c22011-06-24 11:58:14 -0700788 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700789 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700790 break;
791 }
792
793 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000794 ALOGE("No such iface %s to delete", ifn);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700795 return -1;
796 }
797
798 /* This also removes the quota command of CostlyIface chain. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700799 res |= cleanupCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700800
801 quotaIfaces.erase(it);
802
803 return res;
804}
JP Abgrall8a932722011-07-13 19:17:35 -0700805
806int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
807 FILE *fp;
808 char *fname;
809
JP Abgrall69261cb2014-06-19 18:35:24 -0700810 if (!isIfaceName(quotaName)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700811 ALOGE("updateQuota: Invalid quotaName \"%s\"", quotaName);
812 return -1;
813 }
814
JP Abgrall8a932722011-07-13 19:17:35 -0700815 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
Nick Kralevich53ea9ca2015-01-31 13:54:00 -0800816 fp = fopen(fname, "we");
JP Abgrall8a932722011-07-13 19:17:35 -0700817 free(fname);
818 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000819 ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700820 return -1;
821 }
SynergyDev7776cea2014-03-16 15:48:51 -0700822 fprintf(fp, "%" PRId64"\n", bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700823 fclose(fp);
824 return 0;
825}
826
827int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
828 int res = 0;
829 const char *opFlag;
830 char *alertQuotaCmd;
831
832 switch (op) {
833 case IptOpInsert:
834 opFlag = "-I";
835 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800836 case IptOpAppend:
837 opFlag = "-A";
838 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700839 case IptOpReplace:
840 opFlag = "-R";
841 break;
842 default:
843 case IptOpDelete:
844 opFlag = "-D";
845 break;
846 }
847
JP Abgrall92009c82013-02-06 18:01:24 -0800848 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800849 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700850 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700851 free(alertQuotaCmd);
JP Abgrall92009c82013-02-06 18:01:24 -0800852 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800853 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700854 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700855 free(alertQuotaCmd);
856 return res;
857}
858
JP Abgrallc6c67342011-10-07 16:28:54 -0700859int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
860 int res = 0;
861 const char *opFlag;
JP Abgrall8a932722011-07-13 19:17:35 -0700862 char *alertQuotaCmd;
JP Abgrallc6c67342011-10-07 16:28:54 -0700863
864 switch (op) {
865 case IptOpInsert:
866 opFlag = "-I";
867 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800868 case IptOpAppend:
869 opFlag = "-A";
870 break;
JP Abgrallc6c67342011-10-07 16:28:54 -0700871 case IptOpReplace:
872 opFlag = "-R";
873 break;
874 default:
875 case IptOpDelete:
876 opFlag = "-D";
877 break;
878 }
879
JP Abgrall92009c82013-02-06 18:01:24 -0800880 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800881 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700882 res = runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrallc6c67342011-10-07 16:28:54 -0700883 free(alertQuotaCmd);
884 return res;
885}
886
887int BandwidthController::setGlobalAlert(int64_t bytes) {
888 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700889 int res = 0;
890
891 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000892 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700893 return -1;
894 }
895 if (globalAlertBytes) {
896 res = updateQuota(alertName, bytes);
897 } else {
898 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700899 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +0100900 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700901 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
902 }
JP Abgrall8a932722011-07-13 19:17:35 -0700903 }
904 globalAlertBytes = bytes;
905 return res;
906}
907
JP Abgrallc6c67342011-10-07 16:28:54 -0700908int BandwidthController::setGlobalAlertInForwardChain(void) {
909 const char *alertName = ALERT_GLOBAL_NAME;
910 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700911
JP Abgrallc6c67342011-10-07 16:28:54 -0700912 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +0100913 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700914
915 /*
916 * If there is no globalAlert active we are done.
917 * If there is an active globalAlert but this is not the 1st
918 * tether, we are also done.
919 */
920 if (!globalAlertBytes || globalAlertTetherCount != 1) {
921 return 0;
922 }
923
924 /* We only add the rule if this was the 1st tether added. */
925 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
926 return res;
927}
928
929int BandwidthController::removeGlobalAlert(void) {
930
931 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700932 int res = 0;
933
934 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000935 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700936 return -1;
937 }
938 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700939 if (globalAlertTetherCount) {
940 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
941 }
JP Abgrall8a932722011-07-13 19:17:35 -0700942 globalAlertBytes = 0;
943 return res;
944}
945
JP Abgrallc6c67342011-10-07 16:28:54 -0700946int BandwidthController::removeGlobalAlertInForwardChain(void) {
947 int res = 0;
948 const char *alertName = ALERT_GLOBAL_NAME;
949
950 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000951 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700952 return -1;
953 }
954
955 globalAlertTetherCount--;
956 /*
957 * If there is no globalAlert active we are done.
958 * If there is an active globalAlert but there are more
959 * tethers, we are also done.
960 */
961 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
962 return 0;
963 }
964
965 /* We only detete the rule if this was the last tether removed. */
966 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
967 return res;
968}
969
JP Abgrall8a932722011-07-13 19:17:35 -0700970int BandwidthController::setSharedAlert(int64_t bytes) {
971 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000972 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700973 return -1;
974 }
975 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000976 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700977 return -1;
978 }
979 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
980}
981
982int BandwidthController::removeSharedAlert(void) {
983 return removeCostlyAlert("shared", &sharedAlertBytes);
984}
985
986int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
987 std::list<QuotaInfo>::iterator it;
988
JP Abgrall69261cb2014-06-19 18:35:24 -0700989 if (!isIfaceName(iface)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700990 ALOGE("setInterfaceAlert: Invalid iface \"%s\"", iface);
991 return -1;
992 }
993
JP Abgrall8a932722011-07-13 19:17:35 -0700994 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000995 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700996 return -1;
997 }
998 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
999 if (it->ifaceName == iface)
1000 break;
1001 }
1002
1003 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +00001004 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -07001005 return -1;
1006 }
1007
1008 return setCostlyAlert(iface, bytes, &it->alert);
1009}
1010
1011int BandwidthController::removeInterfaceAlert(const char *iface) {
1012 std::list<QuotaInfo>::iterator it;
1013
JP Abgrall69261cb2014-06-19 18:35:24 -07001014 if (!isIfaceName(iface)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -07001015 ALOGE("removeInterfaceAlert: Invalid iface \"%s\"", iface);
1016 return -1;
1017 }
1018
JP Abgrall8a932722011-07-13 19:17:35 -07001019 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1020 if (it->ifaceName == iface)
1021 break;
1022 }
1023
1024 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +00001025 ALOGE("No prior alert set for interface %s", iface);
JP Abgrall8a932722011-07-13 19:17:35 -07001026 return -1;
1027 }
1028
1029 return removeCostlyAlert(iface, &it->alert);
1030}
1031
1032int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
1033 char *alertQuotaCmd;
JP Abgrall109899b2013-02-12 19:20:13 -08001034 char *chainName;
JP Abgrall8a932722011-07-13 19:17:35 -07001035 int res = 0;
1036 char *alertName;
1037
JP Abgrall69261cb2014-06-19 18:35:24 -07001038 if (!isIfaceName(costName)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -07001039 ALOGE("setCostlyAlert: Invalid costName \"%s\"", costName);
1040 return -1;
1041 }
1042
JP Abgrall8a932722011-07-13 19:17:35 -07001043 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001044 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -07001045 return -1;
1046 }
1047 asprintf(&alertName, "%sAlert", costName);
1048 if (*alertBytes) {
1049 res = updateQuota(alertName, *alertBytes);
1050 } else {
JP Abgrall7e51cde2013-07-03 13:33:05 -07001051 asprintf(&chainName, "bw_costly_%s", costName);
JP Abgrall109899b2013-02-12 19:20:13 -08001052 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-A", chainName, bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -07001053 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -07001054 free(alertQuotaCmd);
JP Abgrall109899b2013-02-12 19:20:13 -08001055 free(chainName);
JP Abgrall8a932722011-07-13 19:17:35 -07001056 }
1057 *alertBytes = bytes;
1058 free(alertName);
1059 return res;
1060}
1061
1062int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
1063 char *alertQuotaCmd;
1064 char *chainName;
1065 char *alertName;
1066 int res = 0;
1067
JP Abgrall69261cb2014-06-19 18:35:24 -07001068 if (!isIfaceName(costName)) {
Nick Kralevich0b2b9022014-05-01 13:10:45 -07001069 ALOGE("removeCostlyAlert: Invalid costName \"%s\"", costName);
1070 return -1;
1071 }
1072
JP Abgrall8a932722011-07-13 19:17:35 -07001073 if (!*alertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001074 ALOGE("No prior alert set for %s alert", costName);
JP Abgrall8a932722011-07-13 19:17:35 -07001075 return -1;
1076 }
1077
Jesper Hanssona9d791f2012-04-27 13:54:27 +02001078 asprintf(&alertName, "%sAlert", costName);
JP Abgrall7e51cde2013-07-03 13:33:05 -07001079 asprintf(&chainName, "bw_costly_%s", costName);
JP Abgrall92009c82013-02-06 18:01:24 -08001080 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -07001081 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -07001082 free(alertQuotaCmd);
1083 free(chainName);
1084
1085 *alertBytes = 0;
1086 free(alertName);
1087 return res;
1088}
JP Abgralldb7da582011-09-18 12:57:32 -07001089
1090/*
1091 * Parse the ptks and bytes out of:
JP Abgrallbaeccc42013-06-25 09:44:10 -07001092 * Chain natctrl_tether_counters (4 references)
1093 * pkts bytes target prot opt in out source destination
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001094 * 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
1095 * 27 2002 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0
1096 * 1040 107471 RETURN all -- bt-pan rmnet0 0.0.0.0/0 0.0.0.0/0
1097 * 1450 1708806 RETURN all -- rmnet0 bt-pan 0.0.0.0/0 0.0.0.0/0
1098 * It results in an error if invoked and no tethering counter rules exist. The constraint
1099 * helps detect complete parsing failure.
JP Abgralldb7da582011-09-18 12:57:32 -07001100 */
JP Abgrallbaeccc42013-06-25 09:44:10 -07001101int BandwidthController::parseForwardChainStats(SocketClient *cli, const TetherStats filter,
1102 FILE *fp, std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001103 int res;
1104 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1105 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
1106 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
1107 char rest[MAX_IPT_OUTPUT_LINE_LEN];
1108
JP Abgrallbaeccc42013-06-25 09:44:10 -07001109 TetherStats stats;
JP Abgralldb7da582011-09-18 12:57:32 -07001110 char *buffPtr;
1111 int64_t packets, bytes;
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001112 int statsFound = 0;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001113
1114 bool filterPair = filter.intIface[0] && filter.extIface[0];
1115
1116 char *filterMsg = filter.getStatsLine();
1117 ALOGV("filter: %s", filterMsg);
1118 free(filterMsg);
1119
1120 stats = filter;
JP Abgralldb7da582011-09-18 12:57:32 -07001121
1122 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1123 /* Clean up, so a failed parse can still print info */
1124 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
Mark Salyzynca0b5e22014-03-26 14:15:03 -07001125 res = sscanf(buffPtr, "%" SCNd64" %" SCNd64" RETURN all -- %s %s 0.%s",
JP Abgralldb7da582011-09-18 12:57:32 -07001126 &packets, &bytes, iface0, iface1, rest);
SynergyDev7776cea2014-03-16 15:48:51 -07001127 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 -07001128 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -08001129 extraProcessingInfo += buffPtr;
1130
JP Abgralldb7da582011-09-18 12:57:32 -07001131 if (res != 5) {
1132 continue;
1133 }
JP Abgrallbaeccc42013-06-25 09:44:10 -07001134 /*
1135 * The following assumes that the 1st rule has in:extIface out:intIface,
1136 * which is what NatController sets up.
1137 * If not filtering, the 1st match rx, and sets up the pair for the tx side.
1138 */
1139 if (filter.intIface[0] && filter.extIface[0]) {
1140 if (filter.intIface == iface0 && filter.extIface == iface1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001141 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 -07001142 stats.rxPackets = packets;
1143 stats.rxBytes = bytes;
1144 } else if (filter.intIface == iface1 && filter.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001145 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 -07001146 stats.txPackets = packets;
1147 stats.txBytes = bytes;
1148 }
1149 } else if (filter.intIface[0] || filter.extIface[0]) {
1150 if (filter.intIface == iface0 || filter.extIface == iface1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001151 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 -07001152 stats.intIface = iface0;
1153 stats.extIface = iface1;
1154 stats.rxPackets = packets;
1155 stats.rxBytes = bytes;
1156 } else if (filter.intIface == iface1 || filter.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001157 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 -07001158 stats.intIface = iface1;
1159 stats.extIface = iface0;
1160 stats.txPackets = packets;
1161 stats.txBytes = bytes;
1162 }
1163 } else /* if (!filter.intFace[0] && !filter.extIface[0]) */ {
1164 if (!stats.intIface[0]) {
SynergyDev7776cea2014-03-16 15:48:51 -07001165 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 -07001166 stats.intIface = iface0;
1167 stats.extIface = iface1;
1168 stats.rxPackets = packets;
1169 stats.rxBytes = bytes;
1170 } else if (stats.intIface == iface1 && stats.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -07001171 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 -07001172 stats.txPackets = packets;
1173 stats.txBytes = bytes;
1174 }
1175 }
1176 if (stats.rxBytes != -1 && stats.txBytes != -1) {
SynergyDev7776cea2014-03-16 15:48:51 -07001177 ALOGV("rx_bytes=%" PRId64" tx_bytes=%" PRId64" filterPair=%d", stats.rxBytes, stats.txBytes, filterPair);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001178 /* Send out stats, and prep for the next if needed. */
1179 char *msg = stats.getStatsLine();
1180 if (filterPair) {
1181 cli->sendMsg(ResponseCode::TetheringStatsResult, msg, false);
1182 return 0;
1183 } else {
1184 cli->sendMsg(ResponseCode::TetheringStatsListResult, msg, false);
1185 stats = filter;
1186 }
1187 free(msg);
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001188 statsFound++;
JP Abgralldb7da582011-09-18 12:57:32 -07001189 }
1190 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001191
1192 /* It is always an error to find only one side of the stats. */
1193 /* It is an error to find nothing when not filtering. */
1194 if (((stats.rxBytes == -1) != (stats.txBytes == -1)) ||
1195 (!statsFound && !filterPair)) {
1196 return -1;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001197 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -07001198 cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
1199 return 0;
JP Abgralldb7da582011-09-18 12:57:32 -07001200}
1201
JP Abgrallbaeccc42013-06-25 09:44:10 -07001202char *BandwidthController::TetherStats::getStatsLine(void) const {
JP Abgralldb7da582011-09-18 12:57:32 -07001203 char *msg;
SynergyDev7776cea2014-03-16 15:48:51 -07001204 asprintf(&msg, "%s %s %" PRId64" %" PRId64" %" PRId64" %" PRId64, intIface.c_str(), extIface.c_str(),
JP Abgralldb7da582011-09-18 12:57:32 -07001205 rxBytes, rxPackets, txBytes, txPackets);
1206 return msg;
1207}
1208
JP Abgrallbaeccc42013-06-25 09:44:10 -07001209int BandwidthController::getTetherStats(SocketClient *cli, TetherStats &stats, std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001210 int res;
1211 std::string fullCmd;
1212 FILE *iptOutput;
JP Abgralldb7da582011-09-18 12:57:32 -07001213
JP Abgralldb7da582011-09-18 12:57:32 -07001214 /*
1215 * Why not use some kind of lib to talk to iptables?
1216 * Because the only libs are libiptc and libip6tc in iptables, and they are
1217 * not easy to use. They require the known iptables match modules to be
1218 * preloaded/linked, and require apparently a lot of wrapper code to get
1219 * the wanted info.
1220 */
1221 fullCmd = IPTABLES_PATH;
Yusuke Sato99b40502015-08-19 13:47:30 -07001222 fullCmd += " -nvx -w -L ";
JP Abgrallbaeccc42013-06-25 09:44:10 -07001223 fullCmd += NatController::LOCAL_TETHER_COUNTERS_CHAIN;
Lorenzo Colitti86a47982016-03-18 17:52:25 +09001224 iptOutput = popenFunction(fullCmd.c_str(), "r");
JP Abgralldb7da582011-09-18 12:57:32 -07001225 if (!iptOutput) {
Steve Block5ea0c052012-01-06 19:18:11 +00001226 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
JP Abgralla2a64f02011-11-11 20:36:16 -08001227 extraProcessingInfo += "Failed to run iptables.";
JP Abgralldb7da582011-09-18 12:57:32 -07001228 return -1;
1229 }
JP Abgrallbaeccc42013-06-25 09:44:10 -07001230 res = parseForwardChainStats(cli, stats, iptOutput, extraProcessingInfo);
JP Abgralldb7da582011-09-18 12:57:32 -07001231 pclose(iptOutput);
1232
1233 /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1234 return res;
1235}
JP Abgrall0e540ec2013-08-26 15:13:10 -07001236
1237void BandwidthController::flushExistingCostlyTables(bool doClean) {
JP Abgrall0e540ec2013-08-26 15:13:10 -07001238 std::string fullCmd;
1239 FILE *iptOutput;
JP Abgrall0e540ec2013-08-26 15:13:10 -07001240
1241 /* Only lookup ip4 table names as ip6 will have the same tables ... */
1242 fullCmd = IPTABLES_PATH;
Yusuke Sato99b40502015-08-19 13:47:30 -07001243 fullCmd += " -w -S";
Lorenzo Colitti86a47982016-03-18 17:52:25 +09001244 iptOutput = popenFunction(fullCmd.c_str(), "r");
JP Abgrall0e540ec2013-08-26 15:13:10 -07001245 if (!iptOutput) {
1246 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
1247 return;
1248 }
1249 /* ... then flush/clean both ip4 and ip6 iptables. */
1250 parseAndFlushCostlyTables(iptOutput, doClean);
1251 pclose(iptOutput);
1252}
1253
1254void BandwidthController::parseAndFlushCostlyTables(FILE *fp, bool doRemove) {
1255 int res;
1256 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1257 char costlyIfaceName[MAX_IPT_OUTPUT_LINE_LEN];
1258 char cmd[MAX_CMD_LEN];
1259 char *buffPtr;
1260
1261 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1262 costlyIfaceName[0] = '\0'; /* So that debugging output always works */
1263 res = sscanf(buffPtr, "-N bw_costly_%s", costlyIfaceName);
1264 ALOGV("parse res=%d costly=<%s> orig line=<%s>", res,
1265 costlyIfaceName, buffPtr);
1266 if (res != 1) {
1267 continue;
1268 }
1269 /* Exclusions: "shared" is not an ifacename */
1270 if (!strcmp(costlyIfaceName, "shared")) {
1271 continue;
1272 }
1273
1274 snprintf(cmd, sizeof(cmd), "-F bw_costly_%s", costlyIfaceName);
1275 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1276 if (doRemove) {
1277 snprintf(cmd, sizeof(cmd), "-X bw_costly_%s", costlyIfaceName);
1278 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1279 }
1280 }
1281}