blob: e5d30544f188d301b3234539597cea715bec1bb3 [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";
Jeff Sharkey8e188ed2012-07-12 18:32:03 -070054const char* BandwidthController::LOCAL_INPUT = "bw_INPUT";
55const char* BandwidthController::LOCAL_FORWARD = "bw_FORWARD";
56const char* BandwidthController::LOCAL_OUTPUT = "bw_OUTPUT";
57const char* BandwidthController::LOCAL_RAW_PREROUTING = "bw_raw_PREROUTING";
58const char* BandwidthController::LOCAL_MANGLE_POSTROUTING = "bw_mangle_POSTROUTING";
JP Abgralldb7da582011-09-18 12:57:32 -070059const int BandwidthController::MAX_CMD_ARGS = 32;
60const int BandwidthController::MAX_CMD_LEN = 1024;
61const int BandwidthController::MAX_IFACENAME_LEN = 64;
62const int BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
63
JP Abgrall11b4e9b2011-08-11 15:34:49 -070064bool BandwidthController::useLogwrapCall = false;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070065
66/**
67 * Some comments about the rules:
68 * * Ordering
69 * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
JP Abgrall29e8de22012-05-03 12:52:15 -070070 * E.g. "-I bw_INPUT -i rmnet0 --jump costly"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070071 * - quota'd rules in the costly chain should be before penalty_box lookups.
JP Abgrall29e8de22012-05-03 12:52:15 -070072 * - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070073 *
74 * * global quota vs per interface quota
75 * - global quota for all costly interfaces uses a single costly chain:
76 * . initial rules
JP Abgrallbfa74662011-06-29 19:23:04 -070077 * iptables -N costly_shared
JP Abgrall29e8de22012-05-03 12:52:15 -070078 * iptables -I bw_INPUT -i iface0 --jump costly_shared
79 * iptables -I bw_OUTPUT -o iface0 --jump costly_shared
JP Abgrallbfa74662011-06-29 19:23:04 -070080 * iptables -I costly_shared -m quota \! --quota 500000 \
81 * --jump REJECT --reject-with icmp-net-prohibited
82 * iptables -A costly_shared --jump penalty_box
JP Abgrall8a932722011-07-13 19:17:35 -070083 *
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070084 * . adding a new iface to this, E.g.:
JP Abgrall29e8de22012-05-03 12:52:15 -070085 * iptables -I bw_INPUT -i iface1 --jump costly_shared
86 * iptables -I bw_OUTPUT -o iface1 --jump costly_shared
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070087 *
88 * - quota per interface. This is achieve by having "costly" chains per quota.
89 * E.g. adding a new costly interface iface0 with its own quota:
90 * iptables -N costly_iface0
JP Abgrall29e8de22012-05-03 12:52:15 -070091 * iptables -I bw_INPUT -i iface0 --jump costly_iface0
92 * iptables -I bw_OUTPUT -o iface0 --jump costly_iface0
JP Abgrallbfa74662011-06-29 19:23:04 -070093 * iptables -A costly_iface0 -m quota \! --quota 500000 \
94 * --jump REJECT --reject-with icmp-net-prohibited
95 * iptables -A costly_iface0 --jump penalty_box
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070096 *
97 * * penalty_box handling:
98 * - only one penalty_box for all interfaces
99 * E.g Adding an app:
JP Abgrallbfa74662011-06-29 19:23:04 -0700100 * iptables -A penalty_box -m owner --uid-owner app_3 \
101 * --jump REJECT --reject-with icmp-net-prohibited
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700102 */
JP Abgrall0031cea2012-04-17 16:38:23 -0700103const char *BandwidthController::IPT_FLUSH_COMMANDS[] = {
104 /*
105 * Cleanup rules.
106 * Should normally include costly_<iface>, but we rely on the way they are setup
107 * to allow coexistance.
JP Abgrall39f8f242011-06-29 19:21:58 -0700108 */
JP Abgrall0031cea2012-04-17 16:38:23 -0700109 "-F bw_INPUT",
110 "-F bw_OUTPUT",
111 "-F bw_FORWARD",
112 "-F penalty_box",
113 "-F costly_shared",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700114
115 "-t raw -F bw_raw_PREROUTING",
116 "-t mangle -F bw_mangle_POSTROUTING",
JP Abgrall0031cea2012-04-17 16:38:23 -0700117};
118
119/* The cleanup commands assume flushing has been done. */
120const char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700121 "-X penalty_box",
122 "-X costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700123};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700124
JP Abgralldb7da582011-09-18 12:57:32 -0700125const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
JP Abgrallbfa74662011-06-29 19:23:04 -0700126 "-N costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700127 "-N penalty_box",
128};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700129
JP Abgralldb7da582011-09-18 12:57:32 -0700130const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700131 "-A bw_INPUT -i lo --jump RETURN",
132 "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700133
JP Abgrall0031cea2012-04-17 16:38:23 -0700134 "-A bw_OUTPUT -o lo --jump RETURN",
135 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700136
JP Abgrallbfa74662011-06-29 19:23:04 -0700137 "-A costly_shared --jump penalty_box",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700138
139 "-t raw -A bw_raw_PREROUTING ! -i lo+ -m owner --socket-exists", /* This is a tracking rule. */
140 "-t mangle -A bw_mangle_POSTROUTING ! -o lo+ -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700141};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700142
143BandwidthController::BandwidthController(void) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700144 char value[PROPERTY_VALUE_MAX];
145
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700146 property_get("persist.bandwidth.uselogwrap", value, "0");
147 useLogwrapCall = !strcmp(value, "1");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700148}
149
JP Abgrallad729ac2012-04-24 23:27:44 -0700150int BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling,
151 IptFailureLog failureHandling) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700152 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700153
Steve Block3fb42e02011-10-20 11:55:56 +0100154 ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
JP Abgrallad729ac2012-04-24 23:27:44 -0700155 res |= runIptablesCmd(cmd, rejectHandling, IptIpV4, failureHandling);
156 res |= runIptablesCmd(cmd, rejectHandling, IptIpV6, failureHandling);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700157 return res;
158}
159
JP Abgrall26e0d492011-06-24 19:21:51 -0700160int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
161
162 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
163 strncpy(buffer, src, buffSize);
164 return buffer[buffSize - 1];
165}
166
JP Abgrall8a932722011-07-13 19:17:35 -0700167int BandwidthController::runIptablesCmd(const char *cmd, IptRejectOp rejectHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700168 IptIpVer iptVer, IptFailureLog failureHandling) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700169 char buffer[MAX_CMD_LEN];
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700170 const char *argv[MAX_CMD_ARGS];
JP Abgrall26e0d492011-06-24 19:21:51 -0700171 int argc = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700172 char *next = buffer;
173 char *tmp;
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700174 int res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700175
JP Abgrall0dad7c22011-06-24 11:58:14 -0700176 std::string fullCmd = cmd;
JP Abgrall26e0d492011-06-24 19:21:51 -0700177
178 if (rejectHandling == IptRejectAdd) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700179 fullCmd += " --jump REJECT --reject-with";
JP Abgrall26e0d492011-06-24 19:21:51 -0700180 switch (iptVer) {
181 case IptIpV4:
JP Abgrall8a932722011-07-13 19:17:35 -0700182 fullCmd += " icmp-net-prohibited";
183 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700184 case IptIpV6:
JP Abgrall8a932722011-07-13 19:17:35 -0700185 fullCmd += " icmp6-adm-prohibited";
186 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700187 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700188 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700189
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700190 fullCmd.insert(0, " ");
191 fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700192
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700193 if (!useLogwrapCall) {
JP Abgrall9e5e0ce2011-12-14 15:20:59 -0800194 res = system_nosh(fullCmd.c_str());
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700195 } else {
196 if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000197 ALOGE("iptables command too long");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700198 return -1;
199 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700200
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700201 argc = 0;
202 while ((tmp = strsep(&next, " "))) {
203 argv[argc++] = tmp;
204 if (argc >= MAX_CMD_ARGS) {
Steve Block5ea0c052012-01-06 19:18:11 +0000205 ALOGE("iptables argument overflow");
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700206 return -1;
207 }
208 }
209
210 argv[argc] = NULL;
Glenn Kastenc4bbfa22012-03-05 15:13:58 -0800211 res = logwrap(argc, argv);
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700212 }
JP Abgrallad729ac2012-04-24 23:27:44 -0700213 if (res && failureHandling == IptFailShow) {
Steve Block5ea0c052012-01-06 19:18:11 +0000214 ALOGE("runIptablesCmd(): failed %s res=%d", fullCmd.c_str(), res);
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700215 }
216 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700217}
218
JP Abgrall0031cea2012-04-17 16:38:23 -0700219int BandwidthController::setupIptablesHooks(void) {
220
221 /* Some of the initialCommands are allowed to fail */
222 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
223 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
224
225 runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
226 IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
227
228 runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
229 IPT_SETUP_COMMANDS, RunCmdFailureBad);
230
231 return 0;
JP Abgrall0031cea2012-04-17 16:38:23 -0700232}
233
234int BandwidthController::enableBandwidthControl(bool force) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700235 int res;
JP Abgrall0031cea2012-04-17 16:38:23 -0700236 char value[PROPERTY_VALUE_MAX];
237
238 if (!force) {
239 property_get("persist.bandwidth.enable", value, "1");
240 if (!strcmp(value, "0"))
241 return 0;
242 }
JP Abgrall8a932722011-07-13 19:17:35 -0700243
JP Abgralldb7da582011-09-18 12:57:32 -0700244 /* Let's pretend we started from scratch ... */
JP Abgrall8a932722011-07-13 19:17:35 -0700245 sharedQuotaIfaces.clear();
246 quotaIfaces.clear();
247 naughtyAppUids.clear();
JP Abgralldb7da582011-09-18 12:57:32 -0700248 globalAlertBytes = 0;
JP Abgrallc6c67342011-10-07 16:28:54 -0700249 globalAlertTetherCount = 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700250 sharedQuotaBytes = sharedAlertBytes = 0;
251
JP Abgrall0031cea2012-04-17 16:38:23 -0700252 res = runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
253 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgralldb7da582011-09-18 12:57:32 -0700254
JP Abgrall0031cea2012-04-17 16:38:23 -0700255 res |= runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
JP Abgralldb7da582011-09-18 12:57:32 -0700256 IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
JP Abgrall8a932722011-07-13 19:17:35 -0700257
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700258 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700259
260}
261
262int BandwidthController::disableBandwidthControl(void) {
JP Abgrall0031cea2012-04-17 16:38:23 -0700263 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
264 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700265 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700266}
267
JP Abgrall8a932722011-07-13 19:17:35 -0700268int BandwidthController::runCommands(int numCommands, const char *commands[],
269 RunCmdErrHandling cmdErrHandling) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700270 int res = 0;
JP Abgrallad729ac2012-04-24 23:27:44 -0700271 IptFailureLog failureLogging = IptFailShow;
272 if (cmdErrHandling == RunCmdFailureOk) {
273 failureLogging = IptFailHide;
274 }
Steve Block3fb42e02011-10-20 11:55:56 +0100275 ALOGV("runCommands(): %d commands", numCommands);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700276 for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
JP Abgrallad729ac2012-04-24 23:27:44 -0700277 res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd, failureLogging);
JP Abgrall0031cea2012-04-17 16:38:23 -0700278 if (res && cmdErrHandling != RunCmdFailureOk)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700279 return res;
280 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700281 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700282}
283
JP Abgrall0dad7c22011-06-24 11:58:14 -0700284std::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700285 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700286 char *buff;
287 const char *opFlag;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700288
289 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700290 case IptOpInsert:
291 opFlag = "-I";
292 break;
293 case IptOpReplace:
294 opFlag = "-R";
295 break;
296 default:
297 case IptOpDelete:
298 opFlag = "-D";
299 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700300 }
JP Abgrall8a932722011-07-13 19:17:35 -0700301 asprintf(&buff, "%s penalty_box -m owner --uid-owner %d", opFlag, uid);
302 res = buff;
303 free(buff);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700304 return res;
305}
306
307int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700308 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700309}
310
311int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700312 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpRemove);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700313}
314
JP Abgrall26e0d492011-06-24 19:21:51 -0700315int BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700316 char cmd[MAX_CMD_LEN];
317 int uidNum;
JP Abgrall26e0d492011-06-24 19:21:51 -0700318 const char *failLogTemplate;
319 IptOp op;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700320 int appUids[numUids];
JP Abgrall26e0d492011-06-24 19:21:51 -0700321 std::string naughtyCmd;
JP Abgrallb1d24092012-04-27 01:02:31 -0700322 std::list<int /*uid*/>::iterator it;
JP Abgrall8a932722011-07-13 19:17:35 -0700323
JP Abgrall26e0d492011-06-24 19:21:51 -0700324 switch (appOp) {
325 case NaughtyAppOpAdd:
JP Abgrall8a932722011-07-13 19:17:35 -0700326 op = IptOpInsert;
327 failLogTemplate = "Failed to add app uid %d to penalty box.";
328 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700329 case NaughtyAppOpRemove:
JP Abgrall8a932722011-07-13 19:17:35 -0700330 op = IptOpDelete;
331 failLogTemplate = "Failed to delete app uid %d from penalty box.";
332 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700333 default:
334 ALOGE("Unexpected app Op %d", appOp);
335 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700336 }
337
338 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700339 appUids[uidNum] = atol(appStrUids[uidNum]);
340 if (appUids[uidNum] == 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000341 ALOGE(failLogTemplate, appUids[uidNum]);
JP Abgrall26e0d492011-06-24 19:21:51 -0700342 goto fail_parse;
343 }
344 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700345
346 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700347 int uid = appUids[uidNum];
348 for (it = naughtyAppUids.begin(); it != naughtyAppUids.end(); it++) {
349 if (*it == uid)
350 break;
351 }
352 bool found = (it != naughtyAppUids.end());
353
354 if (appOp == NaughtyAppOpRemove) {
355 if (!found) {
356 ALOGE("No such appUid %d to remove", uid);
357 return -1;
358 }
359 naughtyAppUids.erase(it);
360 } else {
361 if (found) {
362 ALOGE("appUid %d exists already", uid);
363 return -1;
364 }
365 naughtyAppUids.push_front(uid);
366 }
367
368 naughtyCmd = makeIptablesNaughtyCmd(op, uid);
JP Abgrall26e0d492011-06-24 19:21:51 -0700369 if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700370 ALOGE(failLogTemplate, uid);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700371 goto fail_with_uidNum;
372 }
373 }
374 return 0;
375
JP Abgrall26e0d492011-06-24 19:21:51 -0700376fail_with_uidNum:
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700377 /* Try to remove the uid that failed in any case*/
JP Abgrall26e0d492011-06-24 19:21:51 -0700378 naughtyCmd = makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]);
379 runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd);
380fail_parse:
381 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700382}
383
JP Abgrall26e0d492011-06-24 19:21:51 -0700384std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700385 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700386 char *buff;
387 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700388
Steve Block3fb42e02011-10-20 11:55:56 +0100389 ALOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700390
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700391 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700392 case IptOpInsert:
393 opFlag = "-I";
394 break;
395 case IptOpReplace:
396 opFlag = "-R";
397 break;
398 default:
399 case IptOpDelete:
400 opFlag = "-D";
401 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700402 }
JP Abgrall8a932722011-07-13 19:17:35 -0700403
JP Abgrallbfa74662011-06-29 19:23:04 -0700404 // The requried IP version specific --jump REJECT ... will be added later.
JP Abgrall8a932722011-07-13 19:17:35 -0700405 asprintf(&buff, "%s costly_%s -m quota2 ! --quota %lld --name %s", opFlag, costName, quota,
406 costName);
407 res = buff;
408 free(buff);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700409 return res;
410}
411
JP Abgrall26e0d492011-06-24 19:21:51 -0700412int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700413 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700414 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700415 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700416 std::string costString;
417 const char *costCString;
418
JP Abgrall0dad7c22011-06-24 11:58:14 -0700419 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700420 switch (quotaType) {
421 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700422 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700423 costString += ifn;
424 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700425 /*
426 * Flush the costly_<iface> is allowed to fail in case it didn't exist.
427 * Creating a new one is allowed to fail in case it existed.
428 * This helps with netd restarts.
429 */
430 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700431 res1 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700432 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700433 res2 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700434 res = (res1 && res2) || (!res1 && !res2);
435
JP Abgrall0dad7c22011-06-24 11:58:14 -0700436 snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700437 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700438 break;
439 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700440 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700441 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700442 default:
443 ALOGE("Unexpected quotatype %d", quotaType);
444 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700445 }
446
JP Abgrall8a932722011-07-13 19:17:35 -0700447 if (globalAlertBytes) {
448 /* The alert rule comes 1st */
449 ruleInsertPos = 2;
450 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700451
452 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700453 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700454
455 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700456 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700457
458 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700459 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700460
461 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700462 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700463 return res;
464}
465
JP Abgrall26e0d492011-06-24 19:21:51 -0700466int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700467 char cmd[MAX_CMD_LEN];
468 int res = 0;
469 std::string costString;
470 const char *costCString;
471
JP Abgrall26e0d492011-06-24 19:21:51 -0700472 switch (quotaType) {
473 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700474 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700475 costString += ifn;
476 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700477 break;
478 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700479 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700480 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700481 default:
482 ALOGE("Unexpected quotatype %d", quotaType);
483 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700484 }
485
JP Abgrall0031cea2012-04-17 16:38:23 -0700486 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700487 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700488 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700489 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700490
JP Abgrallbfa74662011-06-29 19:23:04 -0700491 /* The "-N costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700492 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700493 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700494 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700495 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
496 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700497 }
498 return res;
499}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700500
JP Abgrall0dad7c22011-06-24 11:58:14 -0700501int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700502 char cmd[MAX_CMD_LEN];
503 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700504 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700505 std::string quotaCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700506 std::string ifaceName;
507 ;
JP Abgrallbfa74662011-06-29 19:23:04 -0700508 const char *costName = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700509 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700510
JP Abgrall8a932722011-07-13 19:17:35 -0700511 if (!maxBytes) {
512 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000513 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700514 return -1;
515 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700516 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000517 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700518 return -1;
519 }
520 ifaceName = ifn;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700521
522 if (maxBytes == -1) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700523 return removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700524 }
525
526 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700527 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
528 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700529 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700530 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700531
JP Abgrall0dad7c22011-06-24 11:58:14 -0700532 if (it == sharedQuotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700533 res |= prepCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700534 if (sharedQuotaIfaces.empty()) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700535 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700536 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700537 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000538 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700539 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700540 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700541 sharedQuotaBytes = maxBytes;
542 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700543 sharedQuotaIfaces.push_front(ifaceName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700544
545 }
546
547 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700548 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700549 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000550 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700551 goto fail;
552 }
553 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700554 }
555 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700556
557 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700558 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700559 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
560 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700561 * For now callers needs to choose if they want to "ndc bandwidth enable"
562 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700563 */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700564 removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700565 return -1;
566}
567
JP Abgrall8a932722011-07-13 19:17:35 -0700568/* It will also cleanup any shared alerts */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700569int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700570 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700571 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700572 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700573 std::list<std::string>::iterator it;
JP Abgrallbfa74662011-06-29 19:23:04 -0700574 const char *costName = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700575
JP Abgrall8a932722011-07-13 19:17:35 -0700576 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000577 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700578 return -1;
579 }
JP Abgrall8a932722011-07-13 19:17:35 -0700580 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700581
JP Abgrall0dad7c22011-06-24 11:58:14 -0700582 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
583 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700584 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700585 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700586 if (it == sharedQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000587 ALOGE("No such iface %s to delete", ifn);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700588 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700589 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700590
JP Abgrall26e0d492011-06-24 19:21:51 -0700591 res |= cleanupCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700592 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700593
JP Abgrall0dad7c22011-06-24 11:58:14 -0700594 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700595 std::string quotaCmd;
JP Abgrallbfa74662011-06-29 19:23:04 -0700596 quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700597 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700598 sharedQuotaBytes = 0;
599 if (sharedAlertBytes) {
600 removeSharedAlert();
601 sharedAlertBytes = 0;
602 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700603 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700604 return res;
605}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700606
607int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
608 char ifn[MAX_IFACENAME_LEN];
609 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700610 std::string ifaceName;
611 const char *costName;
612 std::list<QuotaInfo>::iterator it;
613 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700614
JP Abgrall8a932722011-07-13 19:17:35 -0700615 if (!maxBytes) {
616 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000617 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700618 return -1;
619 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700620 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700621 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700622 }
623
JP Abgrall8a932722011-07-13 19:17:35 -0700624 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000625 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700626 return -1;
627 }
628 ifaceName = ifn;
629 costName = iface;
630
JP Abgrall0dad7c22011-06-24 11:58:14 -0700631 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700632 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700633 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700634 break;
635 }
636
637 if (it == quotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700638 res |= prepCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700639 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700640 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700641 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000642 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700643 goto fail;
644 }
645
JP Abgrall8a932722011-07-13 19:17:35 -0700646 quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700647
648 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700649 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700650 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000651 ALOGE("Failed update quota for %s", iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700652 goto fail;
653 }
JP Abgrall8a932722011-07-13 19:17:35 -0700654 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700655 }
656 return 0;
657
658 fail:
659 /*
660 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
661 * rules in the kernel to see which ones need cleaning up.
662 * For now callers needs to choose if they want to "ndc bandwidth enable"
663 * which resets everything.
664 */
665 removeInterfaceSharedQuota(ifn);
666 return -1;
667}
668
JP Abgrall8a932722011-07-13 19:17:35 -0700669int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
670 return getInterfaceQuota("shared", bytes);
671}
672
673int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
674 FILE *fp;
675 char *fname;
676 int scanRes;
677
678 asprintf(&fname, "/proc/net/xt_quota/%s", costName);
679 fp = fopen(fname, "r");
680 free(fname);
681 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000682 ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700683 return -1;
684 }
685 scanRes = fscanf(fp, "%lld", bytes);
Steve Block3fb42e02011-10-20 11:55:56 +0100686 ALOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700687 fclose(fp);
688 return scanRes == 1 ? 0 : -1;
689}
690
JP Abgrall0dad7c22011-06-24 11:58:14 -0700691int BandwidthController::removeInterfaceQuota(const char *iface) {
692
693 char ifn[MAX_IFACENAME_LEN];
694 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700695 std::string ifaceName;
696 const char *costName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700697 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700698
JP Abgrall8a932722011-07-13 19:17:35 -0700699 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000700 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700701 return -1;
702 }
703 ifaceName = ifn;
704 costName = iface;
705
JP Abgrall0dad7c22011-06-24 11:58:14 -0700706 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700707 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700708 break;
709 }
710
711 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000712 ALOGE("No such iface %s to delete", ifn);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700713 return -1;
714 }
715
716 /* This also removes the quota command of CostlyIface chain. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700717 res |= cleanupCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700718
719 quotaIfaces.erase(it);
720
721 return res;
722}
JP Abgrall8a932722011-07-13 19:17:35 -0700723
724int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
725 FILE *fp;
726 char *fname;
727
728 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
729 fp = fopen(fname, "w");
730 free(fname);
731 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000732 ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700733 return -1;
734 }
735 fprintf(fp, "%lld\n", bytes);
736 fclose(fp);
737 return 0;
738}
739
740int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
741 int res = 0;
742 const char *opFlag;
JP Abgrall87666692011-09-08 13:44:10 -0700743 const char *ifaceLimiting;
JP Abgrall8a932722011-07-13 19:17:35 -0700744 char *alertQuotaCmd;
745
746 switch (op) {
747 case IptOpInsert:
748 opFlag = "-I";
749 break;
750 case IptOpReplace:
751 opFlag = "-R";
752 break;
753 default:
754 case IptOpDelete:
755 opFlag = "-D";
756 break;
757 }
758
JP Abgrall87666692011-09-08 13:44:10 -0700759 ifaceLimiting = "! -i lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700760 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_INPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800761 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700762 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
763 free(alertQuotaCmd);
JP Abgrall87666692011-09-08 13:44:10 -0700764 ifaceLimiting = "! -o lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700765 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_OUTPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800766 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700767 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
768 free(alertQuotaCmd);
769 return res;
770}
771
JP Abgrallc6c67342011-10-07 16:28:54 -0700772int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
773 int res = 0;
774 const char *opFlag;
775 const char *ifaceLimiting;
JP Abgrall8a932722011-07-13 19:17:35 -0700776 char *alertQuotaCmd;
JP Abgrallc6c67342011-10-07 16:28:54 -0700777
778 switch (op) {
779 case IptOpInsert:
780 opFlag = "-I";
781 break;
782 case IptOpReplace:
783 opFlag = "-R";
784 break;
785 default:
786 case IptOpDelete:
787 opFlag = "-D";
788 break;
789 }
790
791 ifaceLimiting = "! -i lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700792 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_FORWARD",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800793 bytes, alertName);
JP Abgrallc6c67342011-10-07 16:28:54 -0700794 res = runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
795 free(alertQuotaCmd);
796 return res;
797}
798
799int BandwidthController::setGlobalAlert(int64_t bytes) {
800 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700801 int res = 0;
802
803 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000804 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700805 return -1;
806 }
807 if (globalAlertBytes) {
808 res = updateQuota(alertName, bytes);
809 } else {
810 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700811 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +0100812 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700813 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
814 }
JP Abgrall8a932722011-07-13 19:17:35 -0700815 }
816 globalAlertBytes = bytes;
817 return res;
818}
819
JP Abgrallc6c67342011-10-07 16:28:54 -0700820int BandwidthController::setGlobalAlertInForwardChain(void) {
821 const char *alertName = ALERT_GLOBAL_NAME;
822 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700823
JP Abgrallc6c67342011-10-07 16:28:54 -0700824 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +0100825 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700826
827 /*
828 * If there is no globalAlert active we are done.
829 * If there is an active globalAlert but this is not the 1st
830 * tether, we are also done.
831 */
832 if (!globalAlertBytes || globalAlertTetherCount != 1) {
833 return 0;
834 }
835
836 /* We only add the rule if this was the 1st tether added. */
837 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
838 return res;
839}
840
841int BandwidthController::removeGlobalAlert(void) {
842
843 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700844 int res = 0;
845
846 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000847 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700848 return -1;
849 }
850 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700851 if (globalAlertTetherCount) {
852 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
853 }
JP Abgrall8a932722011-07-13 19:17:35 -0700854 globalAlertBytes = 0;
855 return res;
856}
857
JP Abgrallc6c67342011-10-07 16:28:54 -0700858int BandwidthController::removeGlobalAlertInForwardChain(void) {
859 int res = 0;
860 const char *alertName = ALERT_GLOBAL_NAME;
861
862 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000863 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700864 return -1;
865 }
866
867 globalAlertTetherCount--;
868 /*
869 * If there is no globalAlert active we are done.
870 * If there is an active globalAlert but there are more
871 * tethers, we are also done.
872 */
873 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
874 return 0;
875 }
876
877 /* We only detete the rule if this was the last tether removed. */
878 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
879 return res;
880}
881
JP Abgrall8a932722011-07-13 19:17:35 -0700882int BandwidthController::setSharedAlert(int64_t bytes) {
883 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000884 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700885 return -1;
886 }
887 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000888 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700889 return -1;
890 }
891 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
892}
893
894int BandwidthController::removeSharedAlert(void) {
895 return removeCostlyAlert("shared", &sharedAlertBytes);
896}
897
898int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
899 std::list<QuotaInfo>::iterator it;
900
901 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000902 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700903 return -1;
904 }
905 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
906 if (it->ifaceName == iface)
907 break;
908 }
909
910 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000911 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700912 return -1;
913 }
914
915 return setCostlyAlert(iface, bytes, &it->alert);
916}
917
918int BandwidthController::removeInterfaceAlert(const char *iface) {
919 std::list<QuotaInfo>::iterator it;
920
921 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
922 if (it->ifaceName == iface)
923 break;
924 }
925
926 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000927 ALOGE("No prior alert set for interface %s", iface);
JP Abgrall8a932722011-07-13 19:17:35 -0700928 return -1;
929 }
930
931 return removeCostlyAlert(iface, &it->alert);
932}
933
934int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
935 char *alertQuotaCmd;
936 char *chainNameAndPos;
937 int res = 0;
938 char *alertName;
939
940 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000941 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700942 return -1;
943 }
944 asprintf(&alertName, "%sAlert", costName);
945 if (*alertBytes) {
946 res = updateQuota(alertName, *alertBytes);
947 } else {
948 asprintf(&chainNameAndPos, "costly_%s %d", costName, ALERT_RULE_POS_IN_COSTLY_CHAIN);
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800949 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-I", chainNameAndPos, bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700950 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
951 free(alertQuotaCmd);
952 free(chainNameAndPos);
953 }
954 *alertBytes = bytes;
955 free(alertName);
956 return res;
957}
958
959int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
960 char *alertQuotaCmd;
961 char *chainName;
962 char *alertName;
963 int res = 0;
964
965 asprintf(&alertName, "%sAlert", costName);
966 if (!*alertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000967 ALOGE("No prior alert set for %s alert", costName);
JP Abgrall8a932722011-07-13 19:17:35 -0700968 return -1;
969 }
970
971 asprintf(&chainName, "costly_%s", costName);
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800972 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-D", chainName, *alertBytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700973 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
974 free(alertQuotaCmd);
975 free(chainName);
976
977 *alertBytes = 0;
978 free(alertName);
979 return res;
980}
JP Abgralldb7da582011-09-18 12:57:32 -0700981
982/*
983 * Parse the ptks and bytes out of:
JP Abgrall0031cea2012-04-17 16:38:23 -0700984 * Chain FORWARD (policy RETURN 0 packets, 0 bytes)
JP Abgralldb7da582011-09-18 12:57:32 -0700985 * pkts bytes target prot opt in out source destination
JP Abgrall0031cea2012-04-17 16:38:23 -0700986 * 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 -0700987 * 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 -0700988 * 0 0 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
JP Abgralldb7da582011-09-18 12:57:32 -0700989 *
990 */
JP Abgralla2a64f02011-11-11 20:36:16 -0800991int BandwidthController::parseForwardChainStats(TetherStats &stats, FILE *fp,
992 std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -0700993 int res;
994 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
995 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
996 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
997 char rest[MAX_IPT_OUTPUT_LINE_LEN];
998
999 char *buffPtr;
1000 int64_t packets, bytes;
1001
1002 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1003 /* Clean up, so a failed parse can still print info */
1004 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
JP Abgrall0031cea2012-04-17 16:38:23 -07001005 res = sscanf(buffPtr, "%lld %lld RETURN all -- %s %s 0.%s",
JP Abgralldb7da582011-09-18 12:57:32 -07001006 &packets, &bytes, iface0, iface1, rest);
Steve Block3fb42e02011-10-20 11:55:56 +01001007 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 -07001008 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -08001009 extraProcessingInfo += buffPtr;
1010
JP Abgralldb7da582011-09-18 12:57:32 -07001011 if (res != 5) {
1012 continue;
1013 }
1014 if ((stats.ifaceIn == iface0) && (stats.ifaceOut == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001015 ALOGV("iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001016 stats.rxPackets = packets;
1017 stats.rxBytes = bytes;
1018 } else if ((stats.ifaceOut == iface0) && (stats.ifaceIn == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001019 ALOGV("iface_in=%s iface_out=%s tx_bytes=%lld tx_packets=%lld ", iface1, iface0, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001020 stats.txPackets = packets;
1021 stats.txBytes = bytes;
1022 }
1023 }
1024 /* Failure if rx or tx was not found */
1025 return (stats.rxBytes == -1 || stats.txBytes == -1) ? -1 : 0;
1026}
1027
1028
1029char *BandwidthController::TetherStats::getStatsLine(void) {
1030 char *msg;
1031 asprintf(&msg, "%s %s %lld %lld %lld %lld", ifaceIn.c_str(), ifaceOut.c_str(),
1032 rxBytes, rxPackets, txBytes, txPackets);
1033 return msg;
1034}
1035
JP Abgralla2a64f02011-11-11 20:36:16 -08001036int BandwidthController::getTetherStats(TetherStats &stats, std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001037 int res;
1038 std::string fullCmd;
1039 FILE *iptOutput;
1040 const char *cmd;
1041
1042 if (stats.rxBytes != -1 || stats.txBytes != -1) {
Steve Block5ea0c052012-01-06 19:18:11 +00001043 ALOGE("Unexpected input stats. Byte counts should be -1.");
JP Abgralldb7da582011-09-18 12:57:32 -07001044 return -1;
1045 }
1046
1047 /*
1048 * Why not use some kind of lib to talk to iptables?
1049 * Because the only libs are libiptc and libip6tc in iptables, and they are
1050 * not easy to use. They require the known iptables match modules to be
1051 * preloaded/linked, and require apparently a lot of wrapper code to get
1052 * the wanted info.
1053 */
1054 fullCmd = IPTABLES_PATH;
JP Abgrall0031cea2012-04-17 16:38:23 -07001055 fullCmd += " -nvx -L natctrl_FORWARD";
JP Abgralldb7da582011-09-18 12:57:32 -07001056 iptOutput = popen(fullCmd.c_str(), "r");
1057 if (!iptOutput) {
Steve Block5ea0c052012-01-06 19:18:11 +00001058 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
JP Abgralla2a64f02011-11-11 20:36:16 -08001059 extraProcessingInfo += "Failed to run iptables.";
JP Abgralldb7da582011-09-18 12:57:32 -07001060 return -1;
1061 }
JP Abgralla2a64f02011-11-11 20:36:16 -08001062 res = parseForwardChainStats(stats, iptOutput, extraProcessingInfo);
JP Abgralldb7da582011-09-18 12:57:32 -07001063 pclose(iptOutput);
1064
1065 /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1066 return res;
1067}