blob: a83647520fb5b87e4271b0525fccde20f3d1d695 [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>
Rom Lemarchand14150212013-01-24 10:01:04 -080043#include <logwrap/logwrap.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070044
JP Abgrall0031cea2012-04-17 16:38:23 -070045#include "NetdConstants.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070046#include "BandwidthController.h"
47
JP Abgralldb7da582011-09-18 12:57:32 -070048/* Alphabetical */
Nick Kralevichc2b26cb2012-02-23 13:04:26 -080049#define ALERT_IPT_TEMPLATE "%s %s %s -m quota2 ! --quota %lld --name %s"
JP Abgralldb7da582011-09-18 12:57:32 -070050const int BandwidthController::ALERT_RULE_POS_IN_COSTLY_CHAIN = 4;
JP Abgrallc6c67342011-10-07 16:28:54 -070051const char BandwidthController::ALERT_GLOBAL_NAME[] = "globalAlert";
Jeff Sharkey8e188ed2012-07-12 18:32:03 -070052const char* BandwidthController::LOCAL_INPUT = "bw_INPUT";
53const char* BandwidthController::LOCAL_FORWARD = "bw_FORWARD";
54const char* BandwidthController::LOCAL_OUTPUT = "bw_OUTPUT";
55const char* BandwidthController::LOCAL_RAW_PREROUTING = "bw_raw_PREROUTING";
56const char* BandwidthController::LOCAL_MANGLE_POSTROUTING = "bw_mangle_POSTROUTING";
JP Abgralldb7da582011-09-18 12:57:32 -070057const int BandwidthController::MAX_CMD_ARGS = 32;
58const int BandwidthController::MAX_CMD_LEN = 1024;
59const int BandwidthController::MAX_IFACENAME_LEN = 64;
60const int BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
61
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070062/**
63 * Some comments about the rules:
64 * * Ordering
65 * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
JP Abgrall29e8de22012-05-03 12:52:15 -070066 * E.g. "-I bw_INPUT -i rmnet0 --jump costly"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070067 * - quota'd rules in the costly chain should be before penalty_box lookups.
JP Abgrall29e8de22012-05-03 12:52:15 -070068 * - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070069 *
70 * * global quota vs per interface quota
71 * - global quota for all costly interfaces uses a single costly chain:
72 * . initial rules
JP Abgrallbfa74662011-06-29 19:23:04 -070073 * iptables -N costly_shared
JP Abgrall29e8de22012-05-03 12:52:15 -070074 * iptables -I bw_INPUT -i iface0 --jump costly_shared
75 * iptables -I bw_OUTPUT -o iface0 --jump costly_shared
JP Abgrallbfa74662011-06-29 19:23:04 -070076 * iptables -I costly_shared -m quota \! --quota 500000 \
77 * --jump REJECT --reject-with icmp-net-prohibited
78 * iptables -A costly_shared --jump penalty_box
JP Abgrall8a932722011-07-13 19:17:35 -070079 *
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070080 * . adding a new iface to this, E.g.:
JP Abgrall29e8de22012-05-03 12:52:15 -070081 * iptables -I bw_INPUT -i iface1 --jump costly_shared
82 * iptables -I bw_OUTPUT -o iface1 --jump costly_shared
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070083 *
84 * - quota per interface. This is achieve by having "costly" chains per quota.
85 * E.g. adding a new costly interface iface0 with its own quota:
86 * iptables -N costly_iface0
JP Abgrall29e8de22012-05-03 12:52:15 -070087 * iptables -I bw_INPUT -i iface0 --jump costly_iface0
88 * iptables -I bw_OUTPUT -o iface0 --jump costly_iface0
JP Abgrallbfa74662011-06-29 19:23:04 -070089 * iptables -A costly_iface0 -m quota \! --quota 500000 \
90 * --jump REJECT --reject-with icmp-net-prohibited
91 * iptables -A costly_iface0 --jump penalty_box
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070092 *
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[] = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700117 "-X penalty_box",
118 "-X costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700119};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700120
JP Abgralldb7da582011-09-18 12:57:32 -0700121const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
JP Abgrallbfa74662011-06-29 19:23:04 -0700122 "-N costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700123 "-N penalty_box",
124};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700125
JP Abgralldb7da582011-09-18 12:57:32 -0700126const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700127 "-A bw_INPUT -i lo --jump RETURN",
128 "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700129
JP Abgrall0031cea2012-04-17 16:38:23 -0700130 "-A bw_OUTPUT -o lo --jump RETURN",
131 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700132
JP Abgrallbfa74662011-06-29 19:23:04 -0700133 "-A costly_shared --jump penalty_box",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700134
135 "-t raw -A bw_raw_PREROUTING ! -i lo+ -m owner --socket-exists", /* This is a tracking rule. */
136 "-t mangle -A bw_mangle_POSTROUTING ! -o lo+ -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700137};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700138
139BandwidthController::BandwidthController(void) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700140}
141
JP Abgrallad729ac2012-04-24 23:27:44 -0700142int BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling,
143 IptFailureLog failureHandling) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700144 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700145
Steve Block3fb42e02011-10-20 11:55:56 +0100146 ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
JP Abgrallad729ac2012-04-24 23:27:44 -0700147 res |= runIptablesCmd(cmd, rejectHandling, IptIpV4, failureHandling);
148 res |= runIptablesCmd(cmd, rejectHandling, IptIpV6, failureHandling);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700149 return res;
150}
151
JP Abgrall26e0d492011-06-24 19:21:51 -0700152int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
153
154 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
155 strncpy(buffer, src, buffSize);
156 return buffer[buffSize - 1];
157}
158
JP Abgrall8a932722011-07-13 19:17:35 -0700159int BandwidthController::runIptablesCmd(const char *cmd, IptRejectOp rejectHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700160 IptIpVer iptVer, IptFailureLog failureHandling) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700161 char buffer[MAX_CMD_LEN];
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700162 const char *argv[MAX_CMD_ARGS];
JP Abgrall26e0d492011-06-24 19:21:51 -0700163 int argc = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700164 char *next = buffer;
165 char *tmp;
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700166 int res;
Rom Lemarchand14150212013-01-24 10:01:04 -0800167 int status = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700168
JP Abgrall0dad7c22011-06-24 11:58:14 -0700169 std::string fullCmd = cmd;
JP Abgrall26e0d492011-06-24 19:21:51 -0700170
171 if (rejectHandling == IptRejectAdd) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700172 fullCmd += " --jump REJECT --reject-with";
JP Abgrall26e0d492011-06-24 19:21:51 -0700173 switch (iptVer) {
174 case IptIpV4:
JP Abgrall8a932722011-07-13 19:17:35 -0700175 fullCmd += " icmp-net-prohibited";
176 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700177 case IptIpV6:
JP Abgrall8a932722011-07-13 19:17:35 -0700178 fullCmd += " icmp6-adm-prohibited";
179 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700180 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700181 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700182
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700183 fullCmd.insert(0, " ");
184 fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700185
Rom Lemarchand14150212013-01-24 10:01:04 -0800186 if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
187 ALOGE("iptables command too long");
188 return -1;
189 }
190
191 argc = 0;
192 while ((tmp = strsep(&next, " "))) {
193 argv[argc++] = tmp;
194 if (argc >= MAX_CMD_ARGS) {
195 ALOGE("iptables argument overflow");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700196 return -1;
197 }
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700198 }
Rom Lemarchand14150212013-01-24 10:01:04 -0800199
200 argv[argc] = NULL;
201 res = android_fork_execvp(argc, (char **)argv, &status, false,
202 failureHandling == IptFailShow);
203
204 if ((res || !WIFEXITED(status) || WEXITSTATUS(status)) &&
205 failureHandling == IptFailShow) {
206 ALOGE("runIptablesCmd(): failed %s res=%d status=%d", fullCmd.c_str(),
207 res, status);
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700208 }
209 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700210}
211
JP Abgrall0031cea2012-04-17 16:38:23 -0700212int BandwidthController::setupIptablesHooks(void) {
213
214 /* Some of the initialCommands are allowed to fail */
215 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
216 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
217
218 runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
219 IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
220
221 runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
222 IPT_SETUP_COMMANDS, RunCmdFailureBad);
223
224 return 0;
JP Abgrall0031cea2012-04-17 16:38:23 -0700225}
226
227int BandwidthController::enableBandwidthControl(bool force) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700228 int res;
JP Abgrall0031cea2012-04-17 16:38:23 -0700229 char value[PROPERTY_VALUE_MAX];
230
231 if (!force) {
232 property_get("persist.bandwidth.enable", value, "1");
233 if (!strcmp(value, "0"))
234 return 0;
235 }
JP Abgrall8a932722011-07-13 19:17:35 -0700236
JP Abgralldb7da582011-09-18 12:57:32 -0700237 /* Let's pretend we started from scratch ... */
JP Abgrall8a932722011-07-13 19:17:35 -0700238 sharedQuotaIfaces.clear();
239 quotaIfaces.clear();
240 naughtyAppUids.clear();
JP Abgralldb7da582011-09-18 12:57:32 -0700241 globalAlertBytes = 0;
JP Abgrallc6c67342011-10-07 16:28:54 -0700242 globalAlertTetherCount = 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700243 sharedQuotaBytes = sharedAlertBytes = 0;
244
JP Abgrall0031cea2012-04-17 16:38:23 -0700245 res = runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
246 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgralldb7da582011-09-18 12:57:32 -0700247
JP Abgrall0031cea2012-04-17 16:38:23 -0700248 res |= runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
JP Abgralldb7da582011-09-18 12:57:32 -0700249 IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
JP Abgrall8a932722011-07-13 19:17:35 -0700250
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700251 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700252
253}
254
255int BandwidthController::disableBandwidthControl(void) {
JP Abgrall0031cea2012-04-17 16:38:23 -0700256 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
257 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700258 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700259}
260
JP Abgrall8a932722011-07-13 19:17:35 -0700261int BandwidthController::runCommands(int numCommands, const char *commands[],
262 RunCmdErrHandling cmdErrHandling) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700263 int res = 0;
JP Abgrallad729ac2012-04-24 23:27:44 -0700264 IptFailureLog failureLogging = IptFailShow;
265 if (cmdErrHandling == RunCmdFailureOk) {
266 failureLogging = IptFailHide;
267 }
Steve Block3fb42e02011-10-20 11:55:56 +0100268 ALOGV("runCommands(): %d commands", numCommands);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700269 for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
JP Abgrallad729ac2012-04-24 23:27:44 -0700270 res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd, failureLogging);
JP Abgrall0031cea2012-04-17 16:38:23 -0700271 if (res && cmdErrHandling != RunCmdFailureOk)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700272 return res;
273 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700274 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700275}
276
JP Abgrall0dad7c22011-06-24 11:58:14 -0700277std::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700278 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700279 char *buff;
280 const char *opFlag;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700281
282 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700283 case IptOpInsert:
284 opFlag = "-I";
285 break;
286 case IptOpReplace:
287 opFlag = "-R";
288 break;
289 default:
290 case IptOpDelete:
291 opFlag = "-D";
292 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700293 }
JP Abgrall8a932722011-07-13 19:17:35 -0700294 asprintf(&buff, "%s penalty_box -m owner --uid-owner %d", opFlag, uid);
295 res = buff;
296 free(buff);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700297 return res;
298}
299
300int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700301 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700302}
303
304int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700305 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpRemove);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700306}
307
JP Abgrall26e0d492011-06-24 19:21:51 -0700308int BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700309 char cmd[MAX_CMD_LEN];
310 int uidNum;
JP Abgrall26e0d492011-06-24 19:21:51 -0700311 const char *failLogTemplate;
312 IptOp op;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700313 int appUids[numUids];
JP Abgrall26e0d492011-06-24 19:21:51 -0700314 std::string naughtyCmd;
JP Abgrallb1d24092012-04-27 01:02:31 -0700315 std::list<int /*uid*/>::iterator it;
JP Abgrall8a932722011-07-13 19:17:35 -0700316
JP Abgrall26e0d492011-06-24 19:21:51 -0700317 switch (appOp) {
318 case NaughtyAppOpAdd:
JP Abgrall8a932722011-07-13 19:17:35 -0700319 op = IptOpInsert;
320 failLogTemplate = "Failed to add app uid %d to penalty box.";
321 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700322 case NaughtyAppOpRemove:
JP Abgrall8a932722011-07-13 19:17:35 -0700323 op = IptOpDelete;
324 failLogTemplate = "Failed to delete app uid %d from penalty box.";
325 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700326 default:
327 ALOGE("Unexpected app Op %d", appOp);
328 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700329 }
330
331 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700332 appUids[uidNum] = atol(appStrUids[uidNum]);
333 if (appUids[uidNum] == 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000334 ALOGE(failLogTemplate, appUids[uidNum]);
JP Abgrall26e0d492011-06-24 19:21:51 -0700335 goto fail_parse;
336 }
337 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700338
339 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700340 int uid = appUids[uidNum];
341 for (it = naughtyAppUids.begin(); it != naughtyAppUids.end(); it++) {
342 if (*it == uid)
343 break;
344 }
345 bool found = (it != naughtyAppUids.end());
346
347 if (appOp == NaughtyAppOpRemove) {
348 if (!found) {
349 ALOGE("No such appUid %d to remove", uid);
350 return -1;
351 }
352 naughtyAppUids.erase(it);
353 } else {
354 if (found) {
355 ALOGE("appUid %d exists already", uid);
356 return -1;
357 }
358 naughtyAppUids.push_front(uid);
359 }
360
361 naughtyCmd = makeIptablesNaughtyCmd(op, uid);
JP Abgrall26e0d492011-06-24 19:21:51 -0700362 if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700363 ALOGE(failLogTemplate, uid);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700364 goto fail_with_uidNum;
365 }
366 }
367 return 0;
368
JP Abgrall26e0d492011-06-24 19:21:51 -0700369fail_with_uidNum:
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700370 /* Try to remove the uid that failed in any case*/
JP Abgrall26e0d492011-06-24 19:21:51 -0700371 naughtyCmd = makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]);
372 runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd);
373fail_parse:
374 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700375}
376
JP Abgrall26e0d492011-06-24 19:21:51 -0700377std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700378 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700379 char *buff;
380 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700381
Steve Block3fb42e02011-10-20 11:55:56 +0100382 ALOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700383
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700384 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700385 case IptOpInsert:
386 opFlag = "-I";
387 break;
388 case IptOpReplace:
389 opFlag = "-R";
390 break;
391 default:
392 case IptOpDelete:
393 opFlag = "-D";
394 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700395 }
JP Abgrall8a932722011-07-13 19:17:35 -0700396
JP Abgrallbfa74662011-06-29 19:23:04 -0700397 // The requried IP version specific --jump REJECT ... will be added later.
JP Abgrall8a932722011-07-13 19:17:35 -0700398 asprintf(&buff, "%s costly_%s -m quota2 ! --quota %lld --name %s", opFlag, costName, quota,
399 costName);
400 res = buff;
401 free(buff);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700402 return res;
403}
404
JP Abgrall26e0d492011-06-24 19:21:51 -0700405int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700406 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700407 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700408 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700409 std::string costString;
410 const char *costCString;
411
JP Abgrall0dad7c22011-06-24 11:58:14 -0700412 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700413 switch (quotaType) {
414 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700415 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700416 costString += ifn;
417 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700418 /*
419 * Flush the costly_<iface> is allowed to fail in case it didn't exist.
420 * Creating a new one is allowed to fail in case it existed.
421 * This helps with netd restarts.
422 */
423 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700424 res1 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700425 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700426 res2 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700427 res = (res1 && res2) || (!res1 && !res2);
428
JP Abgrall0dad7c22011-06-24 11:58:14 -0700429 snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700430 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700431 break;
432 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700433 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700434 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700435 default:
436 ALOGE("Unexpected quotatype %d", quotaType);
437 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700438 }
439
JP Abgrall8a932722011-07-13 19:17:35 -0700440 if (globalAlertBytes) {
441 /* The alert rule comes 1st */
442 ruleInsertPos = 2;
443 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700444
445 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700446 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700447
448 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700449 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700450
451 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700452 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700453
454 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700455 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700456 return res;
457}
458
JP Abgrall26e0d492011-06-24 19:21:51 -0700459int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700460 char cmd[MAX_CMD_LEN];
461 int res = 0;
462 std::string costString;
463 const char *costCString;
464
JP Abgrall26e0d492011-06-24 19:21:51 -0700465 switch (quotaType) {
466 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700467 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700468 costString += ifn;
469 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700470 break;
471 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700472 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700473 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700474 default:
475 ALOGE("Unexpected quotatype %d", quotaType);
476 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700477 }
478
JP Abgrall0031cea2012-04-17 16:38:23 -0700479 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700480 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700481 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700482 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700483
JP Abgrallbfa74662011-06-29 19:23:04 -0700484 /* The "-N costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700485 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700486 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700487 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700488 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
489 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700490 }
491 return res;
492}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700493
JP Abgrall0dad7c22011-06-24 11:58:14 -0700494int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700495 char cmd[MAX_CMD_LEN];
496 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700497 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700498 std::string quotaCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700499 std::string ifaceName;
500 ;
JP Abgrallbfa74662011-06-29 19:23:04 -0700501 const char *costName = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700502 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700503
JP Abgrall8a932722011-07-13 19:17:35 -0700504 if (!maxBytes) {
505 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000506 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700507 return -1;
508 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700509 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000510 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700511 return -1;
512 }
513 ifaceName = ifn;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700514
515 if (maxBytes == -1) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700516 return removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700517 }
518
519 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700520 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
521 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700522 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700523 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700524
JP Abgrall0dad7c22011-06-24 11:58:14 -0700525 if (it == sharedQuotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700526 res |= prepCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700527 if (sharedQuotaIfaces.empty()) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700528 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700529 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700530 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000531 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700532 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700533 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700534 sharedQuotaBytes = maxBytes;
535 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700536 sharedQuotaIfaces.push_front(ifaceName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700537
538 }
539
540 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700541 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700542 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000543 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700544 goto fail;
545 }
546 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700547 }
548 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700549
550 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700551 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700552 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
553 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700554 * For now callers needs to choose if they want to "ndc bandwidth enable"
555 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700556 */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700557 removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700558 return -1;
559}
560
JP Abgrall8a932722011-07-13 19:17:35 -0700561/* It will also cleanup any shared alerts */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700562int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700563 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700564 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700565 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700566 std::list<std::string>::iterator it;
JP Abgrallbfa74662011-06-29 19:23:04 -0700567 const char *costName = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700568
JP Abgrall8a932722011-07-13 19:17:35 -0700569 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000570 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700571 return -1;
572 }
JP Abgrall8a932722011-07-13 19:17:35 -0700573 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700574
JP Abgrall0dad7c22011-06-24 11:58:14 -0700575 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
576 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700577 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700578 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700579 if (it == sharedQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000580 ALOGE("No such iface %s to delete", ifn);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700581 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700582 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700583
JP Abgrall26e0d492011-06-24 19:21:51 -0700584 res |= cleanupCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700585 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700586
JP Abgrall0dad7c22011-06-24 11:58:14 -0700587 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700588 std::string quotaCmd;
JP Abgrallbfa74662011-06-29 19:23:04 -0700589 quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700590 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700591 sharedQuotaBytes = 0;
592 if (sharedAlertBytes) {
593 removeSharedAlert();
594 sharedAlertBytes = 0;
595 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700596 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700597 return res;
598}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700599
600int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
601 char ifn[MAX_IFACENAME_LEN];
602 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700603 std::string ifaceName;
604 const char *costName;
605 std::list<QuotaInfo>::iterator it;
606 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700607
JP Abgrall8a932722011-07-13 19:17:35 -0700608 if (!maxBytes) {
609 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000610 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700611 return -1;
612 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700613 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700614 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700615 }
616
JP Abgrall8a932722011-07-13 19:17:35 -0700617 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000618 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700619 return -1;
620 }
621 ifaceName = ifn;
622 costName = iface;
623
JP Abgrall0dad7c22011-06-24 11:58:14 -0700624 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700625 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700626 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700627 break;
628 }
629
630 if (it == quotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700631 res |= prepCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700632 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700633 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700634 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000635 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700636 goto fail;
637 }
638
JP Abgrall8a932722011-07-13 19:17:35 -0700639 quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700640
641 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700642 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700643 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000644 ALOGE("Failed update quota for %s", iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700645 goto fail;
646 }
JP Abgrall8a932722011-07-13 19:17:35 -0700647 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700648 }
649 return 0;
650
651 fail:
652 /*
653 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
654 * rules in the kernel to see which ones need cleaning up.
655 * For now callers needs to choose if they want to "ndc bandwidth enable"
656 * which resets everything.
657 */
658 removeInterfaceSharedQuota(ifn);
659 return -1;
660}
661
JP Abgrall8a932722011-07-13 19:17:35 -0700662int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
663 return getInterfaceQuota("shared", bytes);
664}
665
666int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
667 FILE *fp;
668 char *fname;
669 int scanRes;
670
671 asprintf(&fname, "/proc/net/xt_quota/%s", costName);
672 fp = fopen(fname, "r");
673 free(fname);
674 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000675 ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700676 return -1;
677 }
678 scanRes = fscanf(fp, "%lld", bytes);
Steve Block3fb42e02011-10-20 11:55:56 +0100679 ALOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700680 fclose(fp);
681 return scanRes == 1 ? 0 : -1;
682}
683
JP Abgrall0dad7c22011-06-24 11:58:14 -0700684int BandwidthController::removeInterfaceQuota(const char *iface) {
685
686 char ifn[MAX_IFACENAME_LEN];
687 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700688 std::string ifaceName;
689 const char *costName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700690 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700691
JP Abgrall8a932722011-07-13 19:17:35 -0700692 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000693 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700694 return -1;
695 }
696 ifaceName = ifn;
697 costName = iface;
698
JP Abgrall0dad7c22011-06-24 11:58:14 -0700699 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700700 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700701 break;
702 }
703
704 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000705 ALOGE("No such iface %s to delete", ifn);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700706 return -1;
707 }
708
709 /* This also removes the quota command of CostlyIface chain. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700710 res |= cleanupCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700711
712 quotaIfaces.erase(it);
713
714 return res;
715}
JP Abgrall8a932722011-07-13 19:17:35 -0700716
717int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
718 FILE *fp;
719 char *fname;
720
721 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
722 fp = fopen(fname, "w");
723 free(fname);
724 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000725 ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700726 return -1;
727 }
728 fprintf(fp, "%lld\n", bytes);
729 fclose(fp);
730 return 0;
731}
732
733int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
734 int res = 0;
735 const char *opFlag;
JP Abgrall87666692011-09-08 13:44:10 -0700736 const char *ifaceLimiting;
JP Abgrall8a932722011-07-13 19:17:35 -0700737 char *alertQuotaCmd;
738
739 switch (op) {
740 case IptOpInsert:
741 opFlag = "-I";
742 break;
743 case IptOpReplace:
744 opFlag = "-R";
745 break;
746 default:
747 case IptOpDelete:
748 opFlag = "-D";
749 break;
750 }
751
JP Abgrall87666692011-09-08 13:44:10 -0700752 ifaceLimiting = "! -i lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700753 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_INPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800754 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700755 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
756 free(alertQuotaCmd);
JP Abgrall87666692011-09-08 13:44:10 -0700757 ifaceLimiting = "! -o lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700758 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_OUTPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800759 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700760 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
761 free(alertQuotaCmd);
762 return res;
763}
764
JP Abgrallc6c67342011-10-07 16:28:54 -0700765int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
766 int res = 0;
767 const char *opFlag;
768 const char *ifaceLimiting;
JP Abgrall8a932722011-07-13 19:17:35 -0700769 char *alertQuotaCmd;
JP Abgrallc6c67342011-10-07 16:28:54 -0700770
771 switch (op) {
772 case IptOpInsert:
773 opFlag = "-I";
774 break;
775 case IptOpReplace:
776 opFlag = "-R";
777 break;
778 default:
779 case IptOpDelete:
780 opFlag = "-D";
781 break;
782 }
783
784 ifaceLimiting = "! -i lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700785 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_FORWARD",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800786 bytes, alertName);
JP Abgrallc6c67342011-10-07 16:28:54 -0700787 res = runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
788 free(alertQuotaCmd);
789 return res;
790}
791
792int BandwidthController::setGlobalAlert(int64_t bytes) {
793 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700794 int res = 0;
795
796 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000797 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700798 return -1;
799 }
800 if (globalAlertBytes) {
801 res = updateQuota(alertName, bytes);
802 } else {
803 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700804 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +0100805 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700806 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
807 }
JP Abgrall8a932722011-07-13 19:17:35 -0700808 }
809 globalAlertBytes = bytes;
810 return res;
811}
812
JP Abgrallc6c67342011-10-07 16:28:54 -0700813int BandwidthController::setGlobalAlertInForwardChain(void) {
814 const char *alertName = ALERT_GLOBAL_NAME;
815 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700816
JP Abgrallc6c67342011-10-07 16:28:54 -0700817 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +0100818 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700819
820 /*
821 * If there is no globalAlert active we are done.
822 * If there is an active globalAlert but this is not the 1st
823 * tether, we are also done.
824 */
825 if (!globalAlertBytes || globalAlertTetherCount != 1) {
826 return 0;
827 }
828
829 /* We only add the rule if this was the 1st tether added. */
830 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
831 return res;
832}
833
834int BandwidthController::removeGlobalAlert(void) {
835
836 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700837 int res = 0;
838
839 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000840 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700841 return -1;
842 }
843 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700844 if (globalAlertTetherCount) {
845 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
846 }
JP Abgrall8a932722011-07-13 19:17:35 -0700847 globalAlertBytes = 0;
848 return res;
849}
850
JP Abgrallc6c67342011-10-07 16:28:54 -0700851int BandwidthController::removeGlobalAlertInForwardChain(void) {
852 int res = 0;
853 const char *alertName = ALERT_GLOBAL_NAME;
854
855 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000856 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700857 return -1;
858 }
859
860 globalAlertTetherCount--;
861 /*
862 * If there is no globalAlert active we are done.
863 * If there is an active globalAlert but there are more
864 * tethers, we are also done.
865 */
866 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
867 return 0;
868 }
869
870 /* We only detete the rule if this was the last tether removed. */
871 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
872 return res;
873}
874
JP Abgrall8a932722011-07-13 19:17:35 -0700875int BandwidthController::setSharedAlert(int64_t bytes) {
876 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000877 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700878 return -1;
879 }
880 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000881 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700882 return -1;
883 }
884 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
885}
886
887int BandwidthController::removeSharedAlert(void) {
888 return removeCostlyAlert("shared", &sharedAlertBytes);
889}
890
891int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
892 std::list<QuotaInfo>::iterator it;
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 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
899 if (it->ifaceName == iface)
900 break;
901 }
902
903 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000904 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700905 return -1;
906 }
907
908 return setCostlyAlert(iface, bytes, &it->alert);
909}
910
911int BandwidthController::removeInterfaceAlert(const char *iface) {
912 std::list<QuotaInfo>::iterator it;
913
914 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
915 if (it->ifaceName == iface)
916 break;
917 }
918
919 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000920 ALOGE("No prior alert set for interface %s", iface);
JP Abgrall8a932722011-07-13 19:17:35 -0700921 return -1;
922 }
923
924 return removeCostlyAlert(iface, &it->alert);
925}
926
927int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
928 char *alertQuotaCmd;
929 char *chainNameAndPos;
930 int res = 0;
931 char *alertName;
932
933 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000934 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700935 return -1;
936 }
937 asprintf(&alertName, "%sAlert", costName);
938 if (*alertBytes) {
939 res = updateQuota(alertName, *alertBytes);
940 } else {
941 asprintf(&chainNameAndPos, "costly_%s %d", costName, ALERT_RULE_POS_IN_COSTLY_CHAIN);
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800942 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-I", chainNameAndPos, bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700943 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
944 free(alertQuotaCmd);
945 free(chainNameAndPos);
946 }
947 *alertBytes = bytes;
948 free(alertName);
949 return res;
950}
951
952int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
953 char *alertQuotaCmd;
954 char *chainName;
955 char *alertName;
956 int res = 0;
957
958 asprintf(&alertName, "%sAlert", costName);
959 if (!*alertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000960 ALOGE("No prior alert set for %s alert", costName);
JP Abgrall8a932722011-07-13 19:17:35 -0700961 return -1;
962 }
963
964 asprintf(&chainName, "costly_%s", costName);
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800965 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-D", chainName, *alertBytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700966 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
967 free(alertQuotaCmd);
968 free(chainName);
969
970 *alertBytes = 0;
971 free(alertName);
972 return res;
973}
JP Abgralldb7da582011-09-18 12:57:32 -0700974
975/*
976 * Parse the ptks and bytes out of:
JP Abgrall0031cea2012-04-17 16:38:23 -0700977 * Chain FORWARD (policy RETURN 0 packets, 0 bytes)
JP Abgralldb7da582011-09-18 12:57:32 -0700978 * pkts bytes target prot opt in out source destination
JP Abgrall0031cea2012-04-17 16:38:23 -0700979 * 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 -0700980 * 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 -0700981 * 0 0 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
JP Abgralldb7da582011-09-18 12:57:32 -0700982 *
983 */
JP Abgralla2a64f02011-11-11 20:36:16 -0800984int BandwidthController::parseForwardChainStats(TetherStats &stats, FILE *fp,
985 std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -0700986 int res;
987 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
988 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
989 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
990 char rest[MAX_IPT_OUTPUT_LINE_LEN];
991
992 char *buffPtr;
993 int64_t packets, bytes;
994
995 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
996 /* Clean up, so a failed parse can still print info */
997 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
JP Abgrall0031cea2012-04-17 16:38:23 -0700998 res = sscanf(buffPtr, "%lld %lld RETURN all -- %s %s 0.%s",
JP Abgralldb7da582011-09-18 12:57:32 -0700999 &packets, &bytes, iface0, iface1, rest);
Steve Block3fb42e02011-10-20 11:55:56 +01001000 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 -07001001 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -08001002 extraProcessingInfo += buffPtr;
1003
JP Abgralldb7da582011-09-18 12:57:32 -07001004 if (res != 5) {
1005 continue;
1006 }
1007 if ((stats.ifaceIn == iface0) && (stats.ifaceOut == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001008 ALOGV("iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001009 stats.rxPackets = packets;
1010 stats.rxBytes = bytes;
1011 } else if ((stats.ifaceOut == iface0) && (stats.ifaceIn == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001012 ALOGV("iface_in=%s iface_out=%s tx_bytes=%lld tx_packets=%lld ", iface1, iface0, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001013 stats.txPackets = packets;
1014 stats.txBytes = bytes;
1015 }
1016 }
1017 /* Failure if rx or tx was not found */
1018 return (stats.rxBytes == -1 || stats.txBytes == -1) ? -1 : 0;
1019}
1020
1021
1022char *BandwidthController::TetherStats::getStatsLine(void) {
1023 char *msg;
1024 asprintf(&msg, "%s %s %lld %lld %lld %lld", ifaceIn.c_str(), ifaceOut.c_str(),
1025 rxBytes, rxPackets, txBytes, txPackets);
1026 return msg;
1027}
1028
JP Abgralla2a64f02011-11-11 20:36:16 -08001029int BandwidthController::getTetherStats(TetherStats &stats, std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001030 int res;
1031 std::string fullCmd;
1032 FILE *iptOutput;
1033 const char *cmd;
1034
1035 if (stats.rxBytes != -1 || stats.txBytes != -1) {
Steve Block5ea0c052012-01-06 19:18:11 +00001036 ALOGE("Unexpected input stats. Byte counts should be -1.");
JP Abgralldb7da582011-09-18 12:57:32 -07001037 return -1;
1038 }
1039
1040 /*
1041 * Why not use some kind of lib to talk to iptables?
1042 * Because the only libs are libiptc and libip6tc in iptables, and they are
1043 * not easy to use. They require the known iptables match modules to be
1044 * preloaded/linked, and require apparently a lot of wrapper code to get
1045 * the wanted info.
1046 */
1047 fullCmd = IPTABLES_PATH;
JP Abgrall0031cea2012-04-17 16:38:23 -07001048 fullCmd += " -nvx -L natctrl_FORWARD";
JP Abgralldb7da582011-09-18 12:57:32 -07001049 iptOutput = popen(fullCmd.c_str(), "r");
1050 if (!iptOutput) {
Steve Block5ea0c052012-01-06 19:18:11 +00001051 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
JP Abgralla2a64f02011-11-11 20:36:16 -08001052 extraProcessingInfo += "Failed to run iptables.";
JP Abgralldb7da582011-09-18 12:57:32 -07001053 return -1;
1054 }
JP Abgralla2a64f02011-11-11 20:36:16 -08001055 res = parseForwardChainStats(stats, iptOutput, extraProcessingInfo);
JP Abgralldb7da582011-09-18 12:57:32 -07001056 pclose(iptOutput);
1057
1058 /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1059 return res;
1060}