blob: 980ecea3dcfad7d59f994940dfd99299afca9623 [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 Abgrall8a932722011-07-13 19:17:35 -0700349
JP Abgrall26e0d492011-06-24 19:21:51 -0700350 switch (appOp) {
351 case NaughtyAppOpAdd:
JP Abgrall8a932722011-07-13 19:17:35 -0700352 op = IptOpInsert;
353 failLogTemplate = "Failed to add app uid %d to penalty box.";
354 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700355 case NaughtyAppOpRemove:
JP Abgrall8a932722011-07-13 19:17:35 -0700356 op = IptOpDelete;
357 failLogTemplate = "Failed to delete app uid %d from penalty box.";
358 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700359 default:
360 ALOGE("Unexpected app Op %d", appOp);
361 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700362 }
363
364 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700365 appUids[uidNum] = atol(appStrUids[uidNum]);
366 if (appUids[uidNum] == 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000367 ALOGE(failLogTemplate, appUids[uidNum]);
JP Abgrall26e0d492011-06-24 19:21:51 -0700368 goto fail_parse;
369 }
370 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700371
372 for (uidNum = 0; uidNum < numUids; uidNum++) {
373 naughtyCmd = makeIptablesNaughtyCmd(op, appUids[uidNum]);
374 if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) {
Steve Block5ea0c052012-01-06 19:18:11 +0000375 ALOGE(failLogTemplate, appUids[uidNum]);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700376 goto fail_with_uidNum;
377 }
378 }
379 return 0;
380
JP Abgrall26e0d492011-06-24 19:21:51 -0700381fail_with_uidNum:
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700382 /* Try to remove the uid that failed in any case*/
JP Abgrall26e0d492011-06-24 19:21:51 -0700383 naughtyCmd = makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]);
384 runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd);
385fail_parse:
386 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700387}
388
JP Abgrall26e0d492011-06-24 19:21:51 -0700389std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700390 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700391 char *buff;
392 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700393
Steve Block3fb42e02011-10-20 11:55:56 +0100394 ALOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700395
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700396 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700397 case IptOpInsert:
398 opFlag = "-I";
399 break;
400 case IptOpReplace:
401 opFlag = "-R";
402 break;
403 default:
404 case IptOpDelete:
405 opFlag = "-D";
406 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700407 }
JP Abgrall8a932722011-07-13 19:17:35 -0700408
JP Abgrallbfa74662011-06-29 19:23:04 -0700409 // The requried IP version specific --jump REJECT ... will be added later.
JP Abgrall8a932722011-07-13 19:17:35 -0700410 asprintf(&buff, "%s costly_%s -m quota2 ! --quota %lld --name %s", opFlag, costName, quota,
411 costName);
412 res = buff;
413 free(buff);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700414 return res;
415}
416
JP Abgrall26e0d492011-06-24 19:21:51 -0700417int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700418 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700419 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700420 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700421 std::string costString;
422 const char *costCString;
423
JP Abgrall0dad7c22011-06-24 11:58:14 -0700424 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700425 switch (quotaType) {
426 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700427 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700428 costString += ifn;
429 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700430 /*
431 * Flush the costly_<iface> is allowed to fail in case it didn't exist.
432 * Creating a new one is allowed to fail in case it existed.
433 * This helps with netd restarts.
434 */
435 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700436 res1 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700437 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700438 res2 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700439 res = (res1 && res2) || (!res1 && !res2);
440
JP Abgrall0dad7c22011-06-24 11:58:14 -0700441 snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700442 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700443 snprintf(cmd, sizeof(cmd), "-A %s -m owner --socket-exists", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700444 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700445 break;
446 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700447 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700448 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700449 default:
450 ALOGE("Unexpected quotatype %d", quotaType);
451 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700452 }
453
JP Abgrall8a932722011-07-13 19:17:35 -0700454 if (globalAlertBytes) {
455 /* The alert rule comes 1st */
456 ruleInsertPos = 2;
457 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700458
459 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700460 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700461
462 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700463 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700464
465 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700466 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700467
468 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700469 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700470 return res;
471}
472
JP Abgrall26e0d492011-06-24 19:21:51 -0700473int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700474 char cmd[MAX_CMD_LEN];
475 int res = 0;
476 std::string costString;
477 const char *costCString;
478
JP Abgrall26e0d492011-06-24 19:21:51 -0700479 switch (quotaType) {
480 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700481 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700482 costString += ifn;
483 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700484 break;
485 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700486 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700487 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700488 default:
489 ALOGE("Unexpected quotatype %d", quotaType);
490 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700491 }
492
JP Abgrall0031cea2012-04-17 16:38:23 -0700493 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700494 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700495 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700496 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700497
JP Abgrallbfa74662011-06-29 19:23:04 -0700498 /* The "-N costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700499 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700500 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700501 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700502 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
503 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700504 }
505 return res;
506}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700507
JP Abgrall0dad7c22011-06-24 11:58:14 -0700508int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700509 char cmd[MAX_CMD_LEN];
510 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700511 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700512 std::string quotaCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700513 std::string ifaceName;
514 ;
JP Abgrallbfa74662011-06-29 19:23:04 -0700515 const char *costName = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700516 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700517
JP Abgrall8a932722011-07-13 19:17:35 -0700518 if (!maxBytes) {
519 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000520 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700521 return -1;
522 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700523 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000524 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700525 return -1;
526 }
527 ifaceName = ifn;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700528
529 if (maxBytes == -1) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700530 return removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700531 }
532
533 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700534 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
535 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700536 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700537 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700538
JP Abgrall0dad7c22011-06-24 11:58:14 -0700539 if (it == sharedQuotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700540 res |= prepCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700541 if (sharedQuotaIfaces.empty()) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700542 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700543 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700544 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000545 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700546 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700547 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700548 sharedQuotaBytes = maxBytes;
549 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700550 sharedQuotaIfaces.push_front(ifaceName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700551
552 }
553
554 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700555 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700556 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000557 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700558 goto fail;
559 }
560 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700561 }
562 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700563
564 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700565 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700566 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
567 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700568 * For now callers needs to choose if they want to "ndc bandwidth enable"
569 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700570 */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700571 removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700572 return -1;
573}
574
JP Abgrall8a932722011-07-13 19:17:35 -0700575/* It will also cleanup any shared alerts */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700576int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700577 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700578 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700579 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700580 std::list<std::string>::iterator it;
JP Abgrallbfa74662011-06-29 19:23:04 -0700581 const char *costName = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700582
JP Abgrall8a932722011-07-13 19:17:35 -0700583 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000584 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700585 return -1;
586 }
JP Abgrall8a932722011-07-13 19:17:35 -0700587 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700588
JP Abgrall0dad7c22011-06-24 11:58:14 -0700589 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
590 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700591 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700592 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700593 if (it == sharedQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000594 ALOGE("No such iface %s to delete", ifn);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700595 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700596 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700597
JP Abgrall26e0d492011-06-24 19:21:51 -0700598 res |= cleanupCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700599 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700600
JP Abgrall0dad7c22011-06-24 11:58:14 -0700601 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700602 std::string quotaCmd;
JP Abgrallbfa74662011-06-29 19:23:04 -0700603 quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700604 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700605 sharedQuotaBytes = 0;
606 if (sharedAlertBytes) {
607 removeSharedAlert();
608 sharedAlertBytes = 0;
609 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700610 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700611 return res;
612}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700613
614int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
615 char ifn[MAX_IFACENAME_LEN];
616 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700617 std::string ifaceName;
618 const char *costName;
619 std::list<QuotaInfo>::iterator it;
620 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700621
JP Abgrall8a932722011-07-13 19:17:35 -0700622 if (!maxBytes) {
623 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000624 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700625 return -1;
626 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700627 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700628 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700629 }
630
JP Abgrall8a932722011-07-13 19:17:35 -0700631 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000632 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700633 return -1;
634 }
635 ifaceName = ifn;
636 costName = iface;
637
JP Abgrall0dad7c22011-06-24 11:58:14 -0700638 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700639 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700640 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700641 break;
642 }
643
644 if (it == quotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700645 res |= prepCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700646 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700647 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700648 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000649 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700650 goto fail;
651 }
652
JP Abgrall8a932722011-07-13 19:17:35 -0700653 quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700654
655 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700656 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700657 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000658 ALOGE("Failed update quota for %s", iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700659 goto fail;
660 }
JP Abgrall8a932722011-07-13 19:17:35 -0700661 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700662 }
663 return 0;
664
665 fail:
666 /*
667 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
668 * rules in the kernel to see which ones need cleaning up.
669 * For now callers needs to choose if they want to "ndc bandwidth enable"
670 * which resets everything.
671 */
672 removeInterfaceSharedQuota(ifn);
673 return -1;
674}
675
JP Abgrall8a932722011-07-13 19:17:35 -0700676int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
677 return getInterfaceQuota("shared", bytes);
678}
679
680int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
681 FILE *fp;
682 char *fname;
683 int scanRes;
684
685 asprintf(&fname, "/proc/net/xt_quota/%s", costName);
686 fp = fopen(fname, "r");
687 free(fname);
688 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000689 ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700690 return -1;
691 }
692 scanRes = fscanf(fp, "%lld", bytes);
Steve Block3fb42e02011-10-20 11:55:56 +0100693 ALOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700694 fclose(fp);
695 return scanRes == 1 ? 0 : -1;
696}
697
JP Abgrall0dad7c22011-06-24 11:58:14 -0700698int BandwidthController::removeInterfaceQuota(const char *iface) {
699
700 char ifn[MAX_IFACENAME_LEN];
701 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700702 std::string ifaceName;
703 const char *costName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700704 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700705
JP Abgrall8a932722011-07-13 19:17:35 -0700706 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000707 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700708 return -1;
709 }
710 ifaceName = ifn;
711 costName = iface;
712
JP Abgrall0dad7c22011-06-24 11:58:14 -0700713 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700714 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700715 break;
716 }
717
718 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000719 ALOGE("No such iface %s to delete", ifn);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700720 return -1;
721 }
722
723 /* This also removes the quota command of CostlyIface chain. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700724 res |= cleanupCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700725
726 quotaIfaces.erase(it);
727
728 return res;
729}
JP Abgrall8a932722011-07-13 19:17:35 -0700730
731int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
732 FILE *fp;
733 char *fname;
734
735 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
736 fp = fopen(fname, "w");
737 free(fname);
738 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000739 ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700740 return -1;
741 }
742 fprintf(fp, "%lld\n", bytes);
743 fclose(fp);
744 return 0;
745}
746
747int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
748 int res = 0;
749 const char *opFlag;
JP Abgrall87666692011-09-08 13:44:10 -0700750 const char *ifaceLimiting;
JP Abgrall8a932722011-07-13 19:17:35 -0700751 char *alertQuotaCmd;
752
753 switch (op) {
754 case IptOpInsert:
755 opFlag = "-I";
756 break;
757 case IptOpReplace:
758 opFlag = "-R";
759 break;
760 default:
761 case IptOpDelete:
762 opFlag = "-D";
763 break;
764 }
765
JP Abgrall87666692011-09-08 13:44:10 -0700766 ifaceLimiting = "! -i lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700767 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_INPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800768 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700769 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
770 free(alertQuotaCmd);
JP Abgrall87666692011-09-08 13:44:10 -0700771 ifaceLimiting = "! -o lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700772 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_OUTPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800773 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700774 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
775 free(alertQuotaCmd);
776 return res;
777}
778
JP Abgrallc6c67342011-10-07 16:28:54 -0700779int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
780 int res = 0;
781 const char *opFlag;
782 const char *ifaceLimiting;
JP Abgrall8a932722011-07-13 19:17:35 -0700783 char *alertQuotaCmd;
JP Abgrallc6c67342011-10-07 16:28:54 -0700784
785 switch (op) {
786 case IptOpInsert:
787 opFlag = "-I";
788 break;
789 case IptOpReplace:
790 opFlag = "-R";
791 break;
792 default:
793 case IptOpDelete:
794 opFlag = "-D";
795 break;
796 }
797
798 ifaceLimiting = "! -i lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700799 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_FORWARD",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800800 bytes, alertName);
JP Abgrallc6c67342011-10-07 16:28:54 -0700801 res = runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
802 free(alertQuotaCmd);
803 return res;
804}
805
806int BandwidthController::setGlobalAlert(int64_t bytes) {
807 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700808 int res = 0;
809
810 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000811 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700812 return -1;
813 }
814 if (globalAlertBytes) {
815 res = updateQuota(alertName, bytes);
816 } else {
817 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700818 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +0100819 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700820 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
821 }
JP Abgrall8a932722011-07-13 19:17:35 -0700822 }
823 globalAlertBytes = bytes;
824 return res;
825}
826
JP Abgrallc6c67342011-10-07 16:28:54 -0700827int BandwidthController::setGlobalAlertInForwardChain(void) {
828 const char *alertName = ALERT_GLOBAL_NAME;
829 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700830
JP Abgrallc6c67342011-10-07 16:28:54 -0700831 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +0100832 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700833
834 /*
835 * If there is no globalAlert active we are done.
836 * If there is an active globalAlert but this is not the 1st
837 * tether, we are also done.
838 */
839 if (!globalAlertBytes || globalAlertTetherCount != 1) {
840 return 0;
841 }
842
843 /* We only add the rule if this was the 1st tether added. */
844 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
845 return res;
846}
847
848int BandwidthController::removeGlobalAlert(void) {
849
850 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700851 int res = 0;
852
853 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000854 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700855 return -1;
856 }
857 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700858 if (globalAlertTetherCount) {
859 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
860 }
JP Abgrall8a932722011-07-13 19:17:35 -0700861 globalAlertBytes = 0;
862 return res;
863}
864
JP Abgrallc6c67342011-10-07 16:28:54 -0700865int BandwidthController::removeGlobalAlertInForwardChain(void) {
866 int res = 0;
867 const char *alertName = ALERT_GLOBAL_NAME;
868
869 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000870 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700871 return -1;
872 }
873
874 globalAlertTetherCount--;
875 /*
876 * If there is no globalAlert active we are done.
877 * If there is an active globalAlert but there are more
878 * tethers, we are also done.
879 */
880 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
881 return 0;
882 }
883
884 /* We only detete the rule if this was the last tether removed. */
885 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
886 return res;
887}
888
JP Abgrall8a932722011-07-13 19:17:35 -0700889int BandwidthController::setSharedAlert(int64_t bytes) {
890 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000891 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700892 return -1;
893 }
894 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000895 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700896 return -1;
897 }
898 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
899}
900
901int BandwidthController::removeSharedAlert(void) {
902 return removeCostlyAlert("shared", &sharedAlertBytes);
903}
904
905int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
906 std::list<QuotaInfo>::iterator it;
907
908 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000909 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700910 return -1;
911 }
912 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
913 if (it->ifaceName == iface)
914 break;
915 }
916
917 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000918 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700919 return -1;
920 }
921
922 return setCostlyAlert(iface, bytes, &it->alert);
923}
924
925int BandwidthController::removeInterfaceAlert(const char *iface) {
926 std::list<QuotaInfo>::iterator it;
927
928 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
929 if (it->ifaceName == iface)
930 break;
931 }
932
933 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000934 ALOGE("No prior alert set for interface %s", iface);
JP Abgrall8a932722011-07-13 19:17:35 -0700935 return -1;
936 }
937
938 return removeCostlyAlert(iface, &it->alert);
939}
940
941int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
942 char *alertQuotaCmd;
943 char *chainNameAndPos;
944 int res = 0;
945 char *alertName;
946
947 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000948 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700949 return -1;
950 }
951 asprintf(&alertName, "%sAlert", costName);
952 if (*alertBytes) {
953 res = updateQuota(alertName, *alertBytes);
954 } else {
955 asprintf(&chainNameAndPos, "costly_%s %d", costName, ALERT_RULE_POS_IN_COSTLY_CHAIN);
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800956 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-I", chainNameAndPos, bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700957 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
958 free(alertQuotaCmd);
959 free(chainNameAndPos);
960 }
961 *alertBytes = bytes;
962 free(alertName);
963 return res;
964}
965
966int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
967 char *alertQuotaCmd;
968 char *chainName;
969 char *alertName;
970 int res = 0;
971
972 asprintf(&alertName, "%sAlert", costName);
973 if (!*alertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000974 ALOGE("No prior alert set for %s alert", costName);
JP Abgrall8a932722011-07-13 19:17:35 -0700975 return -1;
976 }
977
978 asprintf(&chainName, "costly_%s", costName);
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800979 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-D", chainName, *alertBytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700980 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
981 free(alertQuotaCmd);
982 free(chainName);
983
984 *alertBytes = 0;
985 free(alertName);
986 return res;
987}
JP Abgralldb7da582011-09-18 12:57:32 -0700988
989/*
990 * Parse the ptks and bytes out of:
JP Abgrall0031cea2012-04-17 16:38:23 -0700991 * Chain FORWARD (policy RETURN 0 packets, 0 bytes)
JP Abgralldb7da582011-09-18 12:57:32 -0700992 * pkts bytes target prot opt in out source destination
JP Abgrall0031cea2012-04-17 16:38:23 -0700993 * 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 -0700994 * 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 -0700995 * 0 0 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
JP Abgralldb7da582011-09-18 12:57:32 -0700996 *
997 */
JP Abgralla2a64f02011-11-11 20:36:16 -0800998int BandwidthController::parseForwardChainStats(TetherStats &stats, FILE *fp,
999 std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001000 int res;
1001 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1002 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
1003 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
1004 char rest[MAX_IPT_OUTPUT_LINE_LEN];
1005
1006 char *buffPtr;
1007 int64_t packets, bytes;
1008
1009 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1010 /* Clean up, so a failed parse can still print info */
1011 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
JP Abgrall0031cea2012-04-17 16:38:23 -07001012 res = sscanf(buffPtr, "%lld %lld RETURN all -- %s %s 0.%s",
JP Abgralldb7da582011-09-18 12:57:32 -07001013 &packets, &bytes, iface0, iface1, rest);
Steve Block3fb42e02011-10-20 11:55:56 +01001014 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 -07001015 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -08001016 extraProcessingInfo += buffPtr;
1017
JP Abgralldb7da582011-09-18 12:57:32 -07001018 if (res != 5) {
1019 continue;
1020 }
1021 if ((stats.ifaceIn == iface0) && (stats.ifaceOut == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001022 ALOGV("iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001023 stats.rxPackets = packets;
1024 stats.rxBytes = bytes;
1025 } else if ((stats.ifaceOut == iface0) && (stats.ifaceIn == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001026 ALOGV("iface_in=%s iface_out=%s tx_bytes=%lld tx_packets=%lld ", iface1, iface0, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001027 stats.txPackets = packets;
1028 stats.txBytes = bytes;
1029 }
1030 }
1031 /* Failure if rx or tx was not found */
1032 return (stats.rxBytes == -1 || stats.txBytes == -1) ? -1 : 0;
1033}
1034
1035
1036char *BandwidthController::TetherStats::getStatsLine(void) {
1037 char *msg;
1038 asprintf(&msg, "%s %s %lld %lld %lld %lld", ifaceIn.c_str(), ifaceOut.c_str(),
1039 rxBytes, rxPackets, txBytes, txPackets);
1040 return msg;
1041}
1042
JP Abgralla2a64f02011-11-11 20:36:16 -08001043int BandwidthController::getTetherStats(TetherStats &stats, std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001044 int res;
1045 std::string fullCmd;
1046 FILE *iptOutput;
1047 const char *cmd;
1048
1049 if (stats.rxBytes != -1 || stats.txBytes != -1) {
Steve Block5ea0c052012-01-06 19:18:11 +00001050 ALOGE("Unexpected input stats. Byte counts should be -1.");
JP Abgralldb7da582011-09-18 12:57:32 -07001051 return -1;
1052 }
1053
1054 /*
1055 * Why not use some kind of lib to talk to iptables?
1056 * Because the only libs are libiptc and libip6tc in iptables, and they are
1057 * not easy to use. They require the known iptables match modules to be
1058 * preloaded/linked, and require apparently a lot of wrapper code to get
1059 * the wanted info.
1060 */
1061 fullCmd = IPTABLES_PATH;
JP Abgrall0031cea2012-04-17 16:38:23 -07001062 fullCmd += " -nvx -L natctrl_FORWARD";
JP Abgralldb7da582011-09-18 12:57:32 -07001063 iptOutput = popen(fullCmd.c_str(), "r");
1064 if (!iptOutput) {
Steve Block5ea0c052012-01-06 19:18:11 +00001065 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
JP Abgralla2a64f02011-11-11 20:36:16 -08001066 extraProcessingInfo += "Failed to run iptables.";
JP Abgralldb7da582011-09-18 12:57:32 -07001067 return -1;
1068 }
JP Abgralla2a64f02011-11-11 20:36:16 -08001069 res = parseForwardChainStats(stats, iptOutput, extraProcessingInfo);
JP Abgralldb7da582011-09-18 12:57:32 -07001070 pclose(iptOutput);
1071
1072 /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1073 return res;
1074}