blob: e2c2fbe691a8b0a6a6c5c9c3fca74371f1b3e2fe [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 Abgralldb7da582011-09-18 12:57:32 -070017// #define LOG_NDEBUG 0
18
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>
30
31#include <sys/socket.h>
32#include <sys/stat.h>
33#include <sys/types.h>
34#include <sys/wait.h>
35
36#include <linux/netlink.h>
37#include <linux/rtnetlink.h>
38#include <linux/pkt_sched.h>
39
40#define LOG_TAG "BandwidthController"
41#include <cutils/log.h>
42#include <cutils/properties.h>
43
Glenn Kastenc4bbfa22012-03-05 15:13:58 -080044extern "C" int logwrap(int argc, const char **argv);
JP Abgrall9e5e0ce2011-12-14 15:20:59 -080045extern "C" int system_nosh(const char *command);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070046
JP Abgrall0031cea2012-04-17 16:38:23 -070047#include "NetdConstants.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070048#include "BandwidthController.h"
49
JP Abgralldb7da582011-09-18 12:57:32 -070050/* Alphabetical */
Nick Kralevichc2b26cb2012-02-23 13:04:26 -080051#define ALERT_IPT_TEMPLATE "%s %s %s -m quota2 ! --quota %lld --name %s"
JP Abgralldb7da582011-09-18 12:57:32 -070052const int BandwidthController::ALERT_RULE_POS_IN_COSTLY_CHAIN = 4;
JP Abgrallc6c67342011-10-07 16:28:54 -070053const char BandwidthController::ALERT_GLOBAL_NAME[] = "globalAlert";
JP Abgralldb7da582011-09-18 12:57:32 -070054const int BandwidthController::MAX_CMD_ARGS = 32;
55const int BandwidthController::MAX_CMD_LEN = 1024;
56const int BandwidthController::MAX_IFACENAME_LEN = 64;
57const int BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
58
JP Abgrall11b4e9b2011-08-11 15:34:49 -070059bool BandwidthController::useLogwrapCall = false;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070060
61/**
62 * Some comments about the rules:
63 * * Ordering
64 * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
JP Abgrall0031cea2012-04-17 16:38:23 -070065 * E.g. "-I INPUT -i rmnet0 --jump costly"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070066 * - quota'd rules in the costly chain should be before penalty_box lookups.
67 *
68 * * global quota vs per interface quota
69 * - global quota for all costly interfaces uses a single costly chain:
70 * . initial rules
JP Abgrallbfa74662011-06-29 19:23:04 -070071 * iptables -N costly_shared
JP Abgrall0031cea2012-04-17 16:38:23 -070072 * iptables -I INPUT -i iface0 --jump costly_shared
73 * iptables -I OUTPUT -o iface0 --jump costly_shared
JP Abgrallbfa74662011-06-29 19:23:04 -070074 * iptables -I costly_shared -m quota \! --quota 500000 \
75 * --jump REJECT --reject-with icmp-net-prohibited
76 * iptables -A costly_shared --jump penalty_box
77 * iptables -A costly_shared -m owner --socket-exists
JP Abgrall8a932722011-07-13 19:17:35 -070078 *
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070079 * . adding a new iface to this, E.g.:
JP Abgrall0031cea2012-04-17 16:38:23 -070080 * iptables -I INPUT -i iface1 --jump costly_shared
81 * iptables -I OUTPUT -o iface1 --jump costly_shared
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070082 *
83 * - quota per interface. This is achieve by having "costly" chains per quota.
84 * E.g. adding a new costly interface iface0 with its own quota:
85 * iptables -N costly_iface0
JP Abgrall0031cea2012-04-17 16:38:23 -070086 * iptables -I INPUT -i iface0 --jump costly_iface0
87 * iptables -I OUTPUT -o iface0 --jump costly_iface0
JP Abgrallbfa74662011-06-29 19:23:04 -070088 * iptables -A costly_iface0 -m quota \! --quota 500000 \
89 * --jump REJECT --reject-with icmp-net-prohibited
90 * iptables -A costly_iface0 --jump penalty_box
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070091 * iptables -A costly_iface0 -m owner --socket-exists
92 *
93 * * penalty_box handling:
94 * - only one penalty_box for all interfaces
95 * E.g Adding an app:
JP Abgrallbfa74662011-06-29 19:23:04 -070096 * iptables -A penalty_box -m owner --uid-owner app_3 \
97 * --jump REJECT --reject-with icmp-net-prohibited
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070098 */
JP Abgrall0031cea2012-04-17 16:38:23 -070099const char *BandwidthController::IPT_FLUSH_COMMANDS[] = {
100 /*
101 * Cleanup rules.
102 * Should normally include costly_<iface>, but we rely on the way they are setup
103 * to allow coexistance.
JP Abgrall39f8f242011-06-29 19:21:58 -0700104 */
JP Abgrall0031cea2012-04-17 16:38:23 -0700105 "-F bw_INPUT",
106 "-F bw_OUTPUT",
107 "-F bw_FORWARD",
108 "-F penalty_box",
109 "-F costly_shared",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700110
111 "-t raw -F bw_raw_PREROUTING",
112 "-t mangle -F bw_mangle_POSTROUTING",
JP Abgrall0031cea2012-04-17 16:38:23 -0700113};
114
115/* The cleanup commands assume flushing has been done. */
116const char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
117 /* Delete hooks to custom chains. */
118 "-D INPUT -j bw_INPUT",
119 "-D OUTPUT -j bw_OUTPUT",
120 "-D FORWARD -j bw_FORWARD",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700121
122 "-t raw -D bw_raw_PREROUTING",
123 "-t mangle -D bw_mangle_POSTROUTING",
124
JP Abgrall0031cea2012-04-17 16:38:23 -0700125 "-X bw_INPUT",
126 "-X bw_OUTPUT",
127 "-X bw_FORWARD",
128 "-X penalty_box",
129 "-X costly_shared",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700130
131 "-t raw -X bw_raw_PREROUTING",
132 "-t mangle -X bw_mangle_POSTROUTING",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700133};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700134
JP Abgralldb7da582011-09-18 12:57:32 -0700135const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700136 /* Created needed chains. */
JP Abgrall0031cea2012-04-17 16:38:23 -0700137 "-N bw_INPUT",
138 "-A INPUT -j bw_INPUT",
139
140 "-N bw_OUTPUT",
141 "-A OUTPUT -j bw_OUTPUT",
142
143 "-N bw_FORWARD",
144 "-I FORWARD -j bw_FORWARD",
145
JP Abgrallbfa74662011-06-29 19:23:04 -0700146 "-N costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700147 "-N penalty_box",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700148
149 "-t raw -N bw_raw_PREROUTING",
150 "-t raw -A PREROUTING -j bw_raw_PREROUTING",
151 "-t mangle -N bw_mangle_POSTROUTING",
152 "-t mangle -A POSTROUTING -j bw_mangle_POSTROUTING",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700153};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700154
JP Abgralldb7da582011-09-18 12:57:32 -0700155const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700156 "-A bw_INPUT -i lo --jump RETURN",
157 "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700158
JP Abgrall0031cea2012-04-17 16:38:23 -0700159 "-A bw_OUTPUT -o lo --jump RETURN",
160 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700161
JP Abgrallbfa74662011-06-29 19:23:04 -0700162 "-A costly_shared --jump penalty_box",
163 "-A costly_shared -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrallf66d6e92012-04-27 00:22:57 -0700164
165 "-t raw -A bw_raw_PREROUTING ! -i lo+ -m owner --socket-exists", /* This is a tracking rule. */
166 "-t mangle -A bw_mangle_POSTROUTING ! -o lo+ -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700167};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700168
169BandwidthController::BandwidthController(void) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700170 char value[PROPERTY_VALUE_MAX];
171
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700172 property_get("persist.bandwidth.uselogwrap", value, "0");
173 useLogwrapCall = !strcmp(value, "1");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700174}
175
JP Abgrallad729ac2012-04-24 23:27:44 -0700176int BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling,
177 IptFailureLog failureHandling) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700178 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700179
Steve Block3fb42e02011-10-20 11:55:56 +0100180 ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
JP Abgrallad729ac2012-04-24 23:27:44 -0700181 res |= runIptablesCmd(cmd, rejectHandling, IptIpV4, failureHandling);
182 res |= runIptablesCmd(cmd, rejectHandling, IptIpV6, failureHandling);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700183 return res;
184}
185
JP Abgrall26e0d492011-06-24 19:21:51 -0700186int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
187
188 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
189 strncpy(buffer, src, buffSize);
190 return buffer[buffSize - 1];
191}
192
JP Abgrall8a932722011-07-13 19:17:35 -0700193int BandwidthController::runIptablesCmd(const char *cmd, IptRejectOp rejectHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700194 IptIpVer iptVer, IptFailureLog failureHandling) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700195 char buffer[MAX_CMD_LEN];
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700196 const char *argv[MAX_CMD_ARGS];
JP Abgrall26e0d492011-06-24 19:21:51 -0700197 int argc = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700198 char *next = buffer;
199 char *tmp;
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700200 int res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700201
JP Abgrall0dad7c22011-06-24 11:58:14 -0700202 std::string fullCmd = cmd;
JP Abgrall26e0d492011-06-24 19:21:51 -0700203
204 if (rejectHandling == IptRejectAdd) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700205 fullCmd += " --jump REJECT --reject-with";
JP Abgrall26e0d492011-06-24 19:21:51 -0700206 switch (iptVer) {
207 case IptIpV4:
JP Abgrall8a932722011-07-13 19:17:35 -0700208 fullCmd += " icmp-net-prohibited";
209 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700210 case IptIpV6:
JP Abgrall8a932722011-07-13 19:17:35 -0700211 fullCmd += " icmp6-adm-prohibited";
212 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700213 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700214 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700215
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700216 fullCmd.insert(0, " ");
217 fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700218
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700219 if (!useLogwrapCall) {
JP Abgrall9e5e0ce2011-12-14 15:20:59 -0800220 res = system_nosh(fullCmd.c_str());
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700221 } else {
222 if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000223 ALOGE("iptables command too long");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700224 return -1;
225 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700226
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700227 argc = 0;
228 while ((tmp = strsep(&next, " "))) {
229 argv[argc++] = tmp;
230 if (argc >= MAX_CMD_ARGS) {
Steve Block5ea0c052012-01-06 19:18:11 +0000231 ALOGE("iptables argument overflow");
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700232 return -1;
233 }
234 }
235
236 argv[argc] = NULL;
Glenn Kastenc4bbfa22012-03-05 15:13:58 -0800237 res = logwrap(argc, argv);
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700238 }
JP Abgrallad729ac2012-04-24 23:27:44 -0700239 if (res && failureHandling == IptFailShow) {
Steve Block5ea0c052012-01-06 19:18:11 +0000240 ALOGE("runIptablesCmd(): failed %s res=%d", fullCmd.c_str(), res);
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700241 }
242 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700243}
244
JP Abgrall0031cea2012-04-17 16:38:23 -0700245int BandwidthController::setupIptablesHooks(void) {
246
247 /* Some of the initialCommands are allowed to fail */
248 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
249 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
250
251 runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
252 IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
253
254 runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
255 IPT_SETUP_COMMANDS, RunCmdFailureBad);
256
257 return 0;
258
259}
260
261int BandwidthController::enableBandwidthControl(bool force) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700262 int res;
JP Abgrall0031cea2012-04-17 16:38:23 -0700263 char value[PROPERTY_VALUE_MAX];
264
265 if (!force) {
266 property_get("persist.bandwidth.enable", value, "1");
267 if (!strcmp(value, "0"))
268 return 0;
269 }
JP Abgrall8a932722011-07-13 19:17:35 -0700270
JP Abgralldb7da582011-09-18 12:57:32 -0700271 /* Let's pretend we started from scratch ... */
JP Abgrall8a932722011-07-13 19:17:35 -0700272 sharedQuotaIfaces.clear();
273 quotaIfaces.clear();
274 naughtyAppUids.clear();
JP Abgralldb7da582011-09-18 12:57:32 -0700275 globalAlertBytes = 0;
JP Abgrallc6c67342011-10-07 16:28:54 -0700276 globalAlertTetherCount = 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700277 sharedQuotaBytes = sharedAlertBytes = 0;
278
JP Abgrall0031cea2012-04-17 16:38:23 -0700279 res = runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
280 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgralldb7da582011-09-18 12:57:32 -0700281
JP Abgrall0031cea2012-04-17 16:38:23 -0700282 res |= runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
JP Abgralldb7da582011-09-18 12:57:32 -0700283 IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
JP Abgrall8a932722011-07-13 19:17:35 -0700284
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700285 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700286
287}
288
289int BandwidthController::disableBandwidthControl(void) {
JP Abgrall0031cea2012-04-17 16:38:23 -0700290 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
291 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700292 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700293}
294
JP Abgrall8a932722011-07-13 19:17:35 -0700295int BandwidthController::runCommands(int numCommands, const char *commands[],
296 RunCmdErrHandling cmdErrHandling) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700297 int res = 0;
JP Abgrallad729ac2012-04-24 23:27:44 -0700298 IptFailureLog failureLogging = IptFailShow;
299 if (cmdErrHandling == RunCmdFailureOk) {
300 failureLogging = IptFailHide;
301 }
Steve Block3fb42e02011-10-20 11:55:56 +0100302 ALOGV("runCommands(): %d commands", numCommands);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700303 for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
JP Abgrallad729ac2012-04-24 23:27:44 -0700304 res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd, failureLogging);
JP Abgrall0031cea2012-04-17 16:38:23 -0700305 if (res && cmdErrHandling != RunCmdFailureOk)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700306 return res;
307 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700308 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700309}
310
JP Abgrall0dad7c22011-06-24 11:58:14 -0700311std::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700312 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700313 char *buff;
314 const char *opFlag;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700315
316 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700317 case IptOpInsert:
318 opFlag = "-I";
319 break;
320 case IptOpReplace:
321 opFlag = "-R";
322 break;
323 default:
324 case IptOpDelete:
325 opFlag = "-D";
326 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700327 }
JP Abgrall8a932722011-07-13 19:17:35 -0700328 asprintf(&buff, "%s penalty_box -m owner --uid-owner %d", opFlag, uid);
329 res = buff;
330 free(buff);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700331 return res;
332}
333
334int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700335 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700336}
337
338int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700339 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpRemove);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700340}
341
JP Abgrall26e0d492011-06-24 19:21:51 -0700342int BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700343 char cmd[MAX_CMD_LEN];
344 int uidNum;
JP Abgrall26e0d492011-06-24 19:21:51 -0700345 const char *failLogTemplate;
346 IptOp op;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700347 int appUids[numUids];
JP Abgrall26e0d492011-06-24 19:21:51 -0700348 std::string naughtyCmd;
JP Abgrallb1d24092012-04-27 01:02:31 -0700349 std::list<int /*uid*/>::iterator it;
JP Abgrall8a932722011-07-13 19:17:35 -0700350
JP Abgrall26e0d492011-06-24 19:21:51 -0700351 switch (appOp) {
352 case NaughtyAppOpAdd:
JP Abgrall8a932722011-07-13 19:17:35 -0700353 op = IptOpInsert;
354 failLogTemplate = "Failed to add app uid %d to penalty box.";
355 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700356 case NaughtyAppOpRemove:
JP Abgrall8a932722011-07-13 19:17:35 -0700357 op = IptOpDelete;
358 failLogTemplate = "Failed to delete app uid %d from penalty box.";
359 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700360 default:
361 ALOGE("Unexpected app Op %d", appOp);
362 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700363 }
364
365 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700366 appUids[uidNum] = atol(appStrUids[uidNum]);
367 if (appUids[uidNum] == 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000368 ALOGE(failLogTemplate, appUids[uidNum]);
JP Abgrall26e0d492011-06-24 19:21:51 -0700369 goto fail_parse;
370 }
371 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700372
373 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700374 int uid = appUids[uidNum];
375 for (it = naughtyAppUids.begin(); it != naughtyAppUids.end(); it++) {
376 if (*it == uid)
377 break;
378 }
379 bool found = (it != naughtyAppUids.end());
380
381 if (appOp == NaughtyAppOpRemove) {
382 if (!found) {
383 ALOGE("No such appUid %d to remove", uid);
384 return -1;
385 }
386 naughtyAppUids.erase(it);
387 } else {
388 if (found) {
389 ALOGE("appUid %d exists already", uid);
390 return -1;
391 }
392 naughtyAppUids.push_front(uid);
393 }
394
395 naughtyCmd = makeIptablesNaughtyCmd(op, uid);
JP Abgrall26e0d492011-06-24 19:21:51 -0700396 if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700397 ALOGE(failLogTemplate, uid);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700398 goto fail_with_uidNum;
399 }
400 }
401 return 0;
402
JP Abgrall26e0d492011-06-24 19:21:51 -0700403fail_with_uidNum:
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700404 /* Try to remove the uid that failed in any case*/
JP Abgrall26e0d492011-06-24 19:21:51 -0700405 naughtyCmd = makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]);
406 runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd);
407fail_parse:
408 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700409}
410
JP Abgrall26e0d492011-06-24 19:21:51 -0700411std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700412 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700413 char *buff;
414 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700415
Steve Block3fb42e02011-10-20 11:55:56 +0100416 ALOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700417
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700418 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700419 case IptOpInsert:
420 opFlag = "-I";
421 break;
422 case IptOpReplace:
423 opFlag = "-R";
424 break;
425 default:
426 case IptOpDelete:
427 opFlag = "-D";
428 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700429 }
JP Abgrall8a932722011-07-13 19:17:35 -0700430
JP Abgrallbfa74662011-06-29 19:23:04 -0700431 // The requried IP version specific --jump REJECT ... will be added later.
JP Abgrall8a932722011-07-13 19:17:35 -0700432 asprintf(&buff, "%s costly_%s -m quota2 ! --quota %lld --name %s", opFlag, costName, quota,
433 costName);
434 res = buff;
435 free(buff);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700436 return res;
437}
438
JP Abgrall26e0d492011-06-24 19:21:51 -0700439int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700440 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700441 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700442 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700443 std::string costString;
444 const char *costCString;
445
JP Abgrall0dad7c22011-06-24 11:58:14 -0700446 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700447 switch (quotaType) {
448 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700449 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700450 costString += ifn;
451 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700452 /*
453 * Flush the costly_<iface> is allowed to fail in case it didn't exist.
454 * Creating a new one is allowed to fail in case it existed.
455 * This helps with netd restarts.
456 */
457 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700458 res1 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700459 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700460 res2 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700461 res = (res1 && res2) || (!res1 && !res2);
462
JP Abgrall0dad7c22011-06-24 11:58:14 -0700463 snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700464 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700465 snprintf(cmd, sizeof(cmd), "-A %s -m owner --socket-exists", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700466 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700467 break;
468 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700469 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700470 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700471 default:
472 ALOGE("Unexpected quotatype %d", quotaType);
473 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700474 }
475
JP Abgrall8a932722011-07-13 19:17:35 -0700476 if (globalAlertBytes) {
477 /* The alert rule comes 1st */
478 ruleInsertPos = 2;
479 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700480
481 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700482 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700483
484 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700485 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700486
487 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700488 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700489
490 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700491 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700492 return res;
493}
494
JP Abgrall26e0d492011-06-24 19:21:51 -0700495int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700496 char cmd[MAX_CMD_LEN];
497 int res = 0;
498 std::string costString;
499 const char *costCString;
500
JP Abgrall26e0d492011-06-24 19:21:51 -0700501 switch (quotaType) {
502 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700503 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700504 costString += ifn;
505 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700506 break;
507 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700508 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700509 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700510 default:
511 ALOGE("Unexpected quotatype %d", quotaType);
512 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700513 }
514
JP Abgrall0031cea2012-04-17 16:38:23 -0700515 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700516 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700517 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700518 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700519
JP Abgrallbfa74662011-06-29 19:23:04 -0700520 /* The "-N costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700521 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700522 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700523 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700524 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
525 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700526 }
527 return res;
528}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700529
JP Abgrall0dad7c22011-06-24 11:58:14 -0700530int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700531 char cmd[MAX_CMD_LEN];
532 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700533 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700534 std::string quotaCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700535 std::string ifaceName;
536 ;
JP Abgrallbfa74662011-06-29 19:23:04 -0700537 const char *costName = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700538 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700539
JP Abgrall8a932722011-07-13 19:17:35 -0700540 if (!maxBytes) {
541 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000542 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700543 return -1;
544 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700545 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000546 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700547 return -1;
548 }
549 ifaceName = ifn;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700550
551 if (maxBytes == -1) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700552 return removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700553 }
554
555 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700556 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
557 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700558 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700559 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700560
JP Abgrall0dad7c22011-06-24 11:58:14 -0700561 if (it == sharedQuotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700562 res |= prepCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700563 if (sharedQuotaIfaces.empty()) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700564 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700565 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700566 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000567 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700568 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700569 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700570 sharedQuotaBytes = maxBytes;
571 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700572 sharedQuotaIfaces.push_front(ifaceName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700573
574 }
575
576 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700577 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700578 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000579 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700580 goto fail;
581 }
582 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700583 }
584 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700585
586 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700587 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700588 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
589 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700590 * For now callers needs to choose if they want to "ndc bandwidth enable"
591 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700592 */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700593 removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700594 return -1;
595}
596
JP Abgrall8a932722011-07-13 19:17:35 -0700597/* It will also cleanup any shared alerts */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700598int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700599 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700600 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700601 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700602 std::list<std::string>::iterator it;
JP Abgrallbfa74662011-06-29 19:23:04 -0700603 const char *costName = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700604
JP Abgrall8a932722011-07-13 19:17:35 -0700605 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000606 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700607 return -1;
608 }
JP Abgrall8a932722011-07-13 19:17:35 -0700609 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700610
JP Abgrall0dad7c22011-06-24 11:58:14 -0700611 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
612 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700613 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700614 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700615 if (it == sharedQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000616 ALOGE("No such iface %s to delete", ifn);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700617 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700618 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700619
JP Abgrall26e0d492011-06-24 19:21:51 -0700620 res |= cleanupCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700621 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700622
JP Abgrall0dad7c22011-06-24 11:58:14 -0700623 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700624 std::string quotaCmd;
JP Abgrallbfa74662011-06-29 19:23:04 -0700625 quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700626 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700627 sharedQuotaBytes = 0;
628 if (sharedAlertBytes) {
629 removeSharedAlert();
630 sharedAlertBytes = 0;
631 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700632 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700633 return res;
634}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700635
636int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
637 char ifn[MAX_IFACENAME_LEN];
638 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700639 std::string ifaceName;
640 const char *costName;
641 std::list<QuotaInfo>::iterator it;
642 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700643
JP Abgrall8a932722011-07-13 19:17:35 -0700644 if (!maxBytes) {
645 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000646 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700647 return -1;
648 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700649 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700650 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700651 }
652
JP Abgrall8a932722011-07-13 19:17:35 -0700653 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000654 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700655 return -1;
656 }
657 ifaceName = ifn;
658 costName = iface;
659
JP Abgrall0dad7c22011-06-24 11:58:14 -0700660 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700661 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700662 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700663 break;
664 }
665
666 if (it == quotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700667 res |= prepCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700668 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700669 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700670 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000671 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700672 goto fail;
673 }
674
JP Abgrall8a932722011-07-13 19:17:35 -0700675 quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700676
677 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700678 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700679 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000680 ALOGE("Failed update quota for %s", iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700681 goto fail;
682 }
JP Abgrall8a932722011-07-13 19:17:35 -0700683 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700684 }
685 return 0;
686
687 fail:
688 /*
689 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
690 * rules in the kernel to see which ones need cleaning up.
691 * For now callers needs to choose if they want to "ndc bandwidth enable"
692 * which resets everything.
693 */
694 removeInterfaceSharedQuota(ifn);
695 return -1;
696}
697
JP Abgrall8a932722011-07-13 19:17:35 -0700698int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
699 return getInterfaceQuota("shared", bytes);
700}
701
702int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
703 FILE *fp;
704 char *fname;
705 int scanRes;
706
707 asprintf(&fname, "/proc/net/xt_quota/%s", costName);
708 fp = fopen(fname, "r");
709 free(fname);
710 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000711 ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700712 return -1;
713 }
714 scanRes = fscanf(fp, "%lld", bytes);
Steve Block3fb42e02011-10-20 11:55:56 +0100715 ALOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700716 fclose(fp);
717 return scanRes == 1 ? 0 : -1;
718}
719
JP Abgrall0dad7c22011-06-24 11:58:14 -0700720int BandwidthController::removeInterfaceQuota(const char *iface) {
721
722 char ifn[MAX_IFACENAME_LEN];
723 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700724 std::string ifaceName;
725 const char *costName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700726 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700727
JP Abgrall8a932722011-07-13 19:17:35 -0700728 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000729 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700730 return -1;
731 }
732 ifaceName = ifn;
733 costName = iface;
734
JP Abgrall0dad7c22011-06-24 11:58:14 -0700735 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700736 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700737 break;
738 }
739
740 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000741 ALOGE("No such iface %s to delete", ifn);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700742 return -1;
743 }
744
745 /* This also removes the quota command of CostlyIface chain. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700746 res |= cleanupCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700747
748 quotaIfaces.erase(it);
749
750 return res;
751}
JP Abgrall8a932722011-07-13 19:17:35 -0700752
753int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
754 FILE *fp;
755 char *fname;
756
757 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
758 fp = fopen(fname, "w");
759 free(fname);
760 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000761 ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700762 return -1;
763 }
764 fprintf(fp, "%lld\n", bytes);
765 fclose(fp);
766 return 0;
767}
768
769int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
770 int res = 0;
771 const char *opFlag;
JP Abgrall87666692011-09-08 13:44:10 -0700772 const char *ifaceLimiting;
JP Abgrall8a932722011-07-13 19:17:35 -0700773 char *alertQuotaCmd;
774
775 switch (op) {
776 case IptOpInsert:
777 opFlag = "-I";
778 break;
779 case IptOpReplace:
780 opFlag = "-R";
781 break;
782 default:
783 case IptOpDelete:
784 opFlag = "-D";
785 break;
786 }
787
JP Abgrall87666692011-09-08 13:44:10 -0700788 ifaceLimiting = "! -i lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700789 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_INPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800790 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700791 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
792 free(alertQuotaCmd);
JP Abgrall87666692011-09-08 13:44:10 -0700793 ifaceLimiting = "! -o lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700794 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_OUTPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800795 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700796 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
797 free(alertQuotaCmd);
798 return res;
799}
800
JP Abgrallc6c67342011-10-07 16:28:54 -0700801int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
802 int res = 0;
803 const char *opFlag;
804 const char *ifaceLimiting;
JP Abgrall8a932722011-07-13 19:17:35 -0700805 char *alertQuotaCmd;
JP Abgrallc6c67342011-10-07 16:28:54 -0700806
807 switch (op) {
808 case IptOpInsert:
809 opFlag = "-I";
810 break;
811 case IptOpReplace:
812 opFlag = "-R";
813 break;
814 default:
815 case IptOpDelete:
816 opFlag = "-D";
817 break;
818 }
819
820 ifaceLimiting = "! -i lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700821 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_FORWARD",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800822 bytes, alertName);
JP Abgrallc6c67342011-10-07 16:28:54 -0700823 res = runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
824 free(alertQuotaCmd);
825 return res;
826}
827
828int BandwidthController::setGlobalAlert(int64_t bytes) {
829 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700830 int res = 0;
831
832 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000833 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700834 return -1;
835 }
836 if (globalAlertBytes) {
837 res = updateQuota(alertName, bytes);
838 } else {
839 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700840 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +0100841 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700842 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
843 }
JP Abgrall8a932722011-07-13 19:17:35 -0700844 }
845 globalAlertBytes = bytes;
846 return res;
847}
848
JP Abgrallc6c67342011-10-07 16:28:54 -0700849int BandwidthController::setGlobalAlertInForwardChain(void) {
850 const char *alertName = ALERT_GLOBAL_NAME;
851 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700852
JP Abgrallc6c67342011-10-07 16:28:54 -0700853 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +0100854 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700855
856 /*
857 * If there is no globalAlert active we are done.
858 * If there is an active globalAlert but this is not the 1st
859 * tether, we are also done.
860 */
861 if (!globalAlertBytes || globalAlertTetherCount != 1) {
862 return 0;
863 }
864
865 /* We only add the rule if this was the 1st tether added. */
866 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
867 return res;
868}
869
870int BandwidthController::removeGlobalAlert(void) {
871
872 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700873 int res = 0;
874
875 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000876 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700877 return -1;
878 }
879 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700880 if (globalAlertTetherCount) {
881 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
882 }
JP Abgrall8a932722011-07-13 19:17:35 -0700883 globalAlertBytes = 0;
884 return res;
885}
886
JP Abgrallc6c67342011-10-07 16:28:54 -0700887int BandwidthController::removeGlobalAlertInForwardChain(void) {
888 int res = 0;
889 const char *alertName = ALERT_GLOBAL_NAME;
890
891 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000892 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700893 return -1;
894 }
895
896 globalAlertTetherCount--;
897 /*
898 * If there is no globalAlert active we are done.
899 * If there is an active globalAlert but there are more
900 * tethers, we are also done.
901 */
902 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
903 return 0;
904 }
905
906 /* We only detete the rule if this was the last tether removed. */
907 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
908 return res;
909}
910
JP Abgrall8a932722011-07-13 19:17:35 -0700911int BandwidthController::setSharedAlert(int64_t bytes) {
912 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000913 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700914 return -1;
915 }
916 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000917 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700918 return -1;
919 }
920 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
921}
922
923int BandwidthController::removeSharedAlert(void) {
924 return removeCostlyAlert("shared", &sharedAlertBytes);
925}
926
927int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
928 std::list<QuotaInfo>::iterator it;
929
930 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000931 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700932 return -1;
933 }
934 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
935 if (it->ifaceName == iface)
936 break;
937 }
938
939 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000940 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700941 return -1;
942 }
943
944 return setCostlyAlert(iface, bytes, &it->alert);
945}
946
947int BandwidthController::removeInterfaceAlert(const char *iface) {
948 std::list<QuotaInfo>::iterator it;
949
950 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
951 if (it->ifaceName == iface)
952 break;
953 }
954
955 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000956 ALOGE("No prior alert set for interface %s", iface);
JP Abgrall8a932722011-07-13 19:17:35 -0700957 return -1;
958 }
959
960 return removeCostlyAlert(iface, &it->alert);
961}
962
963int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
964 char *alertQuotaCmd;
965 char *chainNameAndPos;
966 int res = 0;
967 char *alertName;
968
969 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000970 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700971 return -1;
972 }
973 asprintf(&alertName, "%sAlert", costName);
974 if (*alertBytes) {
975 res = updateQuota(alertName, *alertBytes);
976 } else {
977 asprintf(&chainNameAndPos, "costly_%s %d", costName, ALERT_RULE_POS_IN_COSTLY_CHAIN);
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800978 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-I", chainNameAndPos, bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700979 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
980 free(alertQuotaCmd);
981 free(chainNameAndPos);
982 }
983 *alertBytes = bytes;
984 free(alertName);
985 return res;
986}
987
988int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
989 char *alertQuotaCmd;
990 char *chainName;
991 char *alertName;
992 int res = 0;
993
994 asprintf(&alertName, "%sAlert", costName);
995 if (!*alertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000996 ALOGE("No prior alert set for %s alert", costName);
JP Abgrall8a932722011-07-13 19:17:35 -0700997 return -1;
998 }
999
1000 asprintf(&chainName, "costly_%s", costName);
Nick Kralevichc2b26cb2012-02-23 13:04:26 -08001001 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-D", chainName, *alertBytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -07001002 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
1003 free(alertQuotaCmd);
1004 free(chainName);
1005
1006 *alertBytes = 0;
1007 free(alertName);
1008 return res;
1009}
JP Abgralldb7da582011-09-18 12:57:32 -07001010
1011/*
1012 * Parse the ptks and bytes out of:
JP Abgrall0031cea2012-04-17 16:38:23 -07001013 * Chain FORWARD (policy RETURN 0 packets, 0 bytes)
JP Abgralldb7da582011-09-18 12:57:32 -07001014 * pkts bytes target prot opt in out source destination
JP Abgrall0031cea2012-04-17 16:38:23 -07001015 * 0 0 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
JP Abgralldb7da582011-09-18 12:57:32 -07001016 * 0 0 DROP all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0 state INVALID
JP Abgrall0031cea2012-04-17 16:38:23 -07001017 * 0 0 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
JP Abgralldb7da582011-09-18 12:57:32 -07001018 *
1019 */
JP Abgralla2a64f02011-11-11 20:36:16 -08001020int BandwidthController::parseForwardChainStats(TetherStats &stats, FILE *fp,
1021 std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001022 int res;
1023 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1024 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
1025 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
1026 char rest[MAX_IPT_OUTPUT_LINE_LEN];
1027
1028 char *buffPtr;
1029 int64_t packets, bytes;
1030
1031 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1032 /* Clean up, so a failed parse can still print info */
1033 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
JP Abgrall0031cea2012-04-17 16:38:23 -07001034 res = sscanf(buffPtr, "%lld %lld RETURN all -- %s %s 0.%s",
JP Abgralldb7da582011-09-18 12:57:32 -07001035 &packets, &bytes, iface0, iface1, rest);
Steve Block3fb42e02011-10-20 11:55:56 +01001036 ALOGV("parse res=%d iface0=<%s> iface1=<%s> pkts=%lld bytes=%lld rest=<%s> orig line=<%s>", res,
JP Abgralldb7da582011-09-18 12:57:32 -07001037 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -08001038 extraProcessingInfo += buffPtr;
1039
JP Abgralldb7da582011-09-18 12:57:32 -07001040 if (res != 5) {
1041 continue;
1042 }
1043 if ((stats.ifaceIn == iface0) && (stats.ifaceOut == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001044 ALOGV("iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001045 stats.rxPackets = packets;
1046 stats.rxBytes = bytes;
1047 } else if ((stats.ifaceOut == iface0) && (stats.ifaceIn == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001048 ALOGV("iface_in=%s iface_out=%s tx_bytes=%lld tx_packets=%lld ", iface1, iface0, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001049 stats.txPackets = packets;
1050 stats.txBytes = bytes;
1051 }
1052 }
1053 /* Failure if rx or tx was not found */
1054 return (stats.rxBytes == -1 || stats.txBytes == -1) ? -1 : 0;
1055}
1056
1057
1058char *BandwidthController::TetherStats::getStatsLine(void) {
1059 char *msg;
1060 asprintf(&msg, "%s %s %lld %lld %lld %lld", ifaceIn.c_str(), ifaceOut.c_str(),
1061 rxBytes, rxPackets, txBytes, txPackets);
1062 return msg;
1063}
1064
JP Abgralla2a64f02011-11-11 20:36:16 -08001065int BandwidthController::getTetherStats(TetherStats &stats, std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001066 int res;
1067 std::string fullCmd;
1068 FILE *iptOutput;
1069 const char *cmd;
1070
1071 if (stats.rxBytes != -1 || stats.txBytes != -1) {
Steve Block5ea0c052012-01-06 19:18:11 +00001072 ALOGE("Unexpected input stats. Byte counts should be -1.");
JP Abgralldb7da582011-09-18 12:57:32 -07001073 return -1;
1074 }
1075
1076 /*
1077 * Why not use some kind of lib to talk to iptables?
1078 * Because the only libs are libiptc and libip6tc in iptables, and they are
1079 * not easy to use. They require the known iptables match modules to be
1080 * preloaded/linked, and require apparently a lot of wrapper code to get
1081 * the wanted info.
1082 */
1083 fullCmd = IPTABLES_PATH;
JP Abgrall0031cea2012-04-17 16:38:23 -07001084 fullCmd += " -nvx -L natctrl_FORWARD";
JP Abgralldb7da582011-09-18 12:57:32 -07001085 iptOutput = popen(fullCmd.c_str(), "r");
1086 if (!iptOutput) {
Steve Block5ea0c052012-01-06 19:18:11 +00001087 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
JP Abgralla2a64f02011-11-11 20:36:16 -08001088 extraProcessingInfo += "Failed to run iptables.";
JP Abgralldb7da582011-09-18 12:57:32 -07001089 return -1;
1090 }
JP Abgralla2a64f02011-11-11 20:36:16 -08001091 res = parseForwardChainStats(stats, iptOutput, extraProcessingInfo);
JP Abgralldb7da582011-09-18 12:57:32 -07001092 pclose(iptOutput);
1093
1094 /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1095 return res;
1096}