blob: 31cdcab7a0be42606a99e37d90567c967e7d9ac7 [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 Abgrall29e8de22012-05-03 12:52:15 -070065 * E.g. "-I bw_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.
JP Abgrall29e8de22012-05-03 12:52:15 -070067 * - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070068 *
69 * * global quota vs per interface quota
70 * - global quota for all costly interfaces uses a single costly chain:
71 * . initial rules
JP Abgrallbfa74662011-06-29 19:23:04 -070072 * iptables -N costly_shared
JP Abgrall29e8de22012-05-03 12:52:15 -070073 * iptables -I bw_INPUT -i iface0 --jump costly_shared
74 * iptables -I bw_OUTPUT -o iface0 --jump costly_shared
JP Abgrallbfa74662011-06-29 19:23:04 -070075 * iptables -I costly_shared -m quota \! --quota 500000 \
76 * --jump REJECT --reject-with icmp-net-prohibited
77 * iptables -A costly_shared --jump penalty_box
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 Abgrall29e8de22012-05-03 12:52:15 -070080 * iptables -I bw_INPUT -i iface1 --jump costly_shared
81 * iptables -I bw_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 Abgrall29e8de22012-05-03 12:52:15 -070086 * iptables -I bw_INPUT -i iface0 --jump costly_iface0
87 * iptables -I bw_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 *
92 * * penalty_box handling:
93 * - only one penalty_box for all interfaces
94 * E.g Adding an app:
JP Abgrallbfa74662011-06-29 19:23:04 -070095 * iptables -A penalty_box -m owner --uid-owner app_3 \
96 * --jump REJECT --reject-with icmp-net-prohibited
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070097 */
JP Abgrall0031cea2012-04-17 16:38:23 -070098const char *BandwidthController::IPT_FLUSH_COMMANDS[] = {
99 /*
100 * Cleanup rules.
101 * Should normally include costly_<iface>, but we rely on the way they are setup
102 * to allow coexistance.
JP Abgrall39f8f242011-06-29 19:21:58 -0700103 */
JP Abgrall0031cea2012-04-17 16:38:23 -0700104 "-F bw_INPUT",
105 "-F bw_OUTPUT",
106 "-F bw_FORWARD",
107 "-F penalty_box",
108 "-F costly_shared",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700109
110 "-t raw -F bw_raw_PREROUTING",
111 "-t mangle -F bw_mangle_POSTROUTING",
JP Abgrall0031cea2012-04-17 16:38:23 -0700112};
113
114/* The cleanup commands assume flushing has been done. */
115const char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
116 /* Delete hooks to custom chains. */
117 "-D INPUT -j bw_INPUT",
118 "-D OUTPUT -j bw_OUTPUT",
119 "-D FORWARD -j bw_FORWARD",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700120
121 "-t raw -D bw_raw_PREROUTING",
122 "-t mangle -D bw_mangle_POSTROUTING",
123
JP Abgrall0031cea2012-04-17 16:38:23 -0700124 "-X bw_INPUT",
125 "-X bw_OUTPUT",
126 "-X bw_FORWARD",
127 "-X penalty_box",
128 "-X costly_shared",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700129
130 "-t raw -X bw_raw_PREROUTING",
131 "-t mangle -X bw_mangle_POSTROUTING",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700132};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700133
JP Abgralldb7da582011-09-18 12:57:32 -0700134const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700135 /* Created needed chains. */
JP Abgrall0031cea2012-04-17 16:38:23 -0700136 "-N bw_INPUT",
137 "-A INPUT -j bw_INPUT",
138
139 "-N bw_OUTPUT",
140 "-A OUTPUT -j bw_OUTPUT",
141
142 "-N bw_FORWARD",
143 "-I FORWARD -j bw_FORWARD",
144
JP Abgrallbfa74662011-06-29 19:23:04 -0700145 "-N costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700146 "-N penalty_box",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700147
148 "-t raw -N bw_raw_PREROUTING",
149 "-t raw -A PREROUTING -j bw_raw_PREROUTING",
150 "-t mangle -N bw_mangle_POSTROUTING",
151 "-t mangle -A POSTROUTING -j bw_mangle_POSTROUTING",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700152};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700153
JP Abgralldb7da582011-09-18 12:57:32 -0700154const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700155 "-A bw_INPUT -i lo --jump RETURN",
156 "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700157
JP Abgrall0031cea2012-04-17 16:38:23 -0700158 "-A bw_OUTPUT -o lo --jump RETURN",
159 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700160
JP Abgrallbfa74662011-06-29 19:23:04 -0700161 "-A costly_shared --jump penalty_box",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700162
163 "-t raw -A bw_raw_PREROUTING ! -i lo+ -m owner --socket-exists", /* This is a tracking rule. */
164 "-t mangle -A bw_mangle_POSTROUTING ! -o lo+ -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700165};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700166
167BandwidthController::BandwidthController(void) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700168 char value[PROPERTY_VALUE_MAX];
169
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700170 property_get("persist.bandwidth.uselogwrap", value, "0");
171 useLogwrapCall = !strcmp(value, "1");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700172}
173
JP Abgrallad729ac2012-04-24 23:27:44 -0700174int BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling,
175 IptFailureLog failureHandling) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700176 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700177
Steve Block3fb42e02011-10-20 11:55:56 +0100178 ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
JP Abgrallad729ac2012-04-24 23:27:44 -0700179 res |= runIptablesCmd(cmd, rejectHandling, IptIpV4, failureHandling);
180 res |= runIptablesCmd(cmd, rejectHandling, IptIpV6, failureHandling);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700181 return res;
182}
183
JP Abgrall26e0d492011-06-24 19:21:51 -0700184int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
185
186 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
187 strncpy(buffer, src, buffSize);
188 return buffer[buffSize - 1];
189}
190
JP Abgrall8a932722011-07-13 19:17:35 -0700191int BandwidthController::runIptablesCmd(const char *cmd, IptRejectOp rejectHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700192 IptIpVer iptVer, IptFailureLog failureHandling) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700193 char buffer[MAX_CMD_LEN];
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700194 const char *argv[MAX_CMD_ARGS];
JP Abgrall26e0d492011-06-24 19:21:51 -0700195 int argc = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700196 char *next = buffer;
197 char *tmp;
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700198 int res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700199
JP Abgrall0dad7c22011-06-24 11:58:14 -0700200 std::string fullCmd = cmd;
JP Abgrall26e0d492011-06-24 19:21:51 -0700201
202 if (rejectHandling == IptRejectAdd) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700203 fullCmd += " --jump REJECT --reject-with";
JP Abgrall26e0d492011-06-24 19:21:51 -0700204 switch (iptVer) {
205 case IptIpV4:
JP Abgrall8a932722011-07-13 19:17:35 -0700206 fullCmd += " icmp-net-prohibited";
207 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700208 case IptIpV6:
JP Abgrall8a932722011-07-13 19:17:35 -0700209 fullCmd += " icmp6-adm-prohibited";
210 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700211 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700212 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700213
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700214 fullCmd.insert(0, " ");
215 fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700216
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700217 if (!useLogwrapCall) {
JP Abgrall9e5e0ce2011-12-14 15:20:59 -0800218 res = system_nosh(fullCmd.c_str());
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700219 } else {
220 if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000221 ALOGE("iptables command too long");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700222 return -1;
223 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700224
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700225 argc = 0;
226 while ((tmp = strsep(&next, " "))) {
227 argv[argc++] = tmp;
228 if (argc >= MAX_CMD_ARGS) {
Steve Block5ea0c052012-01-06 19:18:11 +0000229 ALOGE("iptables argument overflow");
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700230 return -1;
231 }
232 }
233
234 argv[argc] = NULL;
Glenn Kastenc4bbfa22012-03-05 15:13:58 -0800235 res = logwrap(argc, argv);
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700236 }
JP Abgrallad729ac2012-04-24 23:27:44 -0700237 if (res && failureHandling == IptFailShow) {
Steve Block5ea0c052012-01-06 19:18:11 +0000238 ALOGE("runIptablesCmd(): failed %s res=%d", fullCmd.c_str(), res);
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700239 }
240 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700241}
242
JP Abgrall0031cea2012-04-17 16:38:23 -0700243int BandwidthController::setupIptablesHooks(void) {
244
245 /* Some of the initialCommands are allowed to fail */
246 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
247 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
248
249 runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
250 IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
251
252 runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
253 IPT_SETUP_COMMANDS, RunCmdFailureBad);
254
255 return 0;
256
257}
258
259int BandwidthController::enableBandwidthControl(bool force) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700260 int res;
JP Abgrall0031cea2012-04-17 16:38:23 -0700261 char value[PROPERTY_VALUE_MAX];
262
263 if (!force) {
264 property_get("persist.bandwidth.enable", value, "1");
265 if (!strcmp(value, "0"))
266 return 0;
267 }
JP Abgrall8a932722011-07-13 19:17:35 -0700268
JP Abgralldb7da582011-09-18 12:57:32 -0700269 /* Let's pretend we started from scratch ... */
JP Abgrall8a932722011-07-13 19:17:35 -0700270 sharedQuotaIfaces.clear();
271 quotaIfaces.clear();
272 naughtyAppUids.clear();
JP Abgralldb7da582011-09-18 12:57:32 -0700273 globalAlertBytes = 0;
JP Abgrallc6c67342011-10-07 16:28:54 -0700274 globalAlertTetherCount = 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700275 sharedQuotaBytes = sharedAlertBytes = 0;
276
JP Abgrall0031cea2012-04-17 16:38:23 -0700277 res = runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
278 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgralldb7da582011-09-18 12:57:32 -0700279
JP Abgrall0031cea2012-04-17 16:38:23 -0700280 res |= runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
JP Abgralldb7da582011-09-18 12:57:32 -0700281 IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
JP Abgrall8a932722011-07-13 19:17:35 -0700282
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700283 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700284
285}
286
287int BandwidthController::disableBandwidthControl(void) {
JP Abgrall0031cea2012-04-17 16:38:23 -0700288 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
289 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700290 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700291}
292
JP Abgrall8a932722011-07-13 19:17:35 -0700293int BandwidthController::runCommands(int numCommands, const char *commands[],
294 RunCmdErrHandling cmdErrHandling) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700295 int res = 0;
JP Abgrallad729ac2012-04-24 23:27:44 -0700296 IptFailureLog failureLogging = IptFailShow;
297 if (cmdErrHandling == RunCmdFailureOk) {
298 failureLogging = IptFailHide;
299 }
Steve Block3fb42e02011-10-20 11:55:56 +0100300 ALOGV("runCommands(): %d commands", numCommands);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700301 for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
JP Abgrallad729ac2012-04-24 23:27:44 -0700302 res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd, failureLogging);
JP Abgrall0031cea2012-04-17 16:38:23 -0700303 if (res && cmdErrHandling != RunCmdFailureOk)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700304 return res;
305 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700306 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700307}
308
JP Abgrall0dad7c22011-06-24 11:58:14 -0700309std::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700310 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700311 char *buff;
312 const char *opFlag;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700313
314 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700315 case IptOpInsert:
316 opFlag = "-I";
317 break;
318 case IptOpReplace:
319 opFlag = "-R";
320 break;
321 default:
322 case IptOpDelete:
323 opFlag = "-D";
324 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700325 }
JP Abgrall8a932722011-07-13 19:17:35 -0700326 asprintf(&buff, "%s penalty_box -m owner --uid-owner %d", opFlag, uid);
327 res = buff;
328 free(buff);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700329 return res;
330}
331
332int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700333 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700334}
335
336int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700337 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpRemove);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700338}
339
JP Abgrall26e0d492011-06-24 19:21:51 -0700340int BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700341 char cmd[MAX_CMD_LEN];
342 int uidNum;
JP Abgrall26e0d492011-06-24 19:21:51 -0700343 const char *failLogTemplate;
344 IptOp op;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700345 int appUids[numUids];
JP Abgrall26e0d492011-06-24 19:21:51 -0700346 std::string naughtyCmd;
JP Abgrallb1d24092012-04-27 01:02:31 -0700347 std::list<int /*uid*/>::iterator it;
JP Abgrall8a932722011-07-13 19:17:35 -0700348
JP Abgrall26e0d492011-06-24 19:21:51 -0700349 switch (appOp) {
350 case NaughtyAppOpAdd:
JP Abgrall8a932722011-07-13 19:17:35 -0700351 op = IptOpInsert;
352 failLogTemplate = "Failed to add app uid %d to penalty box.";
353 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700354 case NaughtyAppOpRemove:
JP Abgrall8a932722011-07-13 19:17:35 -0700355 op = IptOpDelete;
356 failLogTemplate = "Failed to delete app uid %d from penalty box.";
357 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700358 default:
359 ALOGE("Unexpected app Op %d", appOp);
360 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700361 }
362
363 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700364 appUids[uidNum] = atol(appStrUids[uidNum]);
365 if (appUids[uidNum] == 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000366 ALOGE(failLogTemplate, appUids[uidNum]);
JP Abgrall26e0d492011-06-24 19:21:51 -0700367 goto fail_parse;
368 }
369 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700370
371 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700372 int uid = appUids[uidNum];
373 for (it = naughtyAppUids.begin(); it != naughtyAppUids.end(); it++) {
374 if (*it == uid)
375 break;
376 }
377 bool found = (it != naughtyAppUids.end());
378
379 if (appOp == NaughtyAppOpRemove) {
380 if (!found) {
381 ALOGE("No such appUid %d to remove", uid);
382 return -1;
383 }
384 naughtyAppUids.erase(it);
385 } else {
386 if (found) {
387 ALOGE("appUid %d exists already", uid);
388 return -1;
389 }
390 naughtyAppUids.push_front(uid);
391 }
392
393 naughtyCmd = makeIptablesNaughtyCmd(op, uid);
JP Abgrall26e0d492011-06-24 19:21:51 -0700394 if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700395 ALOGE(failLogTemplate, uid);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700396 goto fail_with_uidNum;
397 }
398 }
399 return 0;
400
JP Abgrall26e0d492011-06-24 19:21:51 -0700401fail_with_uidNum:
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700402 /* Try to remove the uid that failed in any case*/
JP Abgrall26e0d492011-06-24 19:21:51 -0700403 naughtyCmd = makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]);
404 runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd);
405fail_parse:
406 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700407}
408
JP Abgrall26e0d492011-06-24 19:21:51 -0700409std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700410 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700411 char *buff;
412 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700413
Steve Block3fb42e02011-10-20 11:55:56 +0100414 ALOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700415
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700416 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700417 case IptOpInsert:
418 opFlag = "-I";
419 break;
420 case IptOpReplace:
421 opFlag = "-R";
422 break;
423 default:
424 case IptOpDelete:
425 opFlag = "-D";
426 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700427 }
JP Abgrall8a932722011-07-13 19:17:35 -0700428
JP Abgrallbfa74662011-06-29 19:23:04 -0700429 // The requried IP version specific --jump REJECT ... will be added later.
JP Abgrall8a932722011-07-13 19:17:35 -0700430 asprintf(&buff, "%s costly_%s -m quota2 ! --quota %lld --name %s", opFlag, costName, quota,
431 costName);
432 res = buff;
433 free(buff);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700434 return res;
435}
436
JP Abgrall26e0d492011-06-24 19:21:51 -0700437int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700438 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700439 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700440 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700441 std::string costString;
442 const char *costCString;
443
JP Abgrall0dad7c22011-06-24 11:58:14 -0700444 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700445 switch (quotaType) {
446 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700447 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700448 costString += ifn;
449 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700450 /*
451 * Flush the costly_<iface> is allowed to fail in case it didn't exist.
452 * Creating a new one is allowed to fail in case it existed.
453 * This helps with netd restarts.
454 */
455 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700456 res1 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700457 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700458 res2 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700459 res = (res1 && res2) || (!res1 && !res2);
460
JP Abgrall0dad7c22011-06-24 11:58:14 -0700461 snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700462 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700463 break;
464 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700465 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700466 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700467 default:
468 ALOGE("Unexpected quotatype %d", quotaType);
469 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700470 }
471
JP Abgrall8a932722011-07-13 19:17:35 -0700472 if (globalAlertBytes) {
473 /* The alert rule comes 1st */
474 ruleInsertPos = 2;
475 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700476
477 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700478 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700479
480 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700481 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700482
483 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700484 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700485
486 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700487 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700488 return res;
489}
490
JP Abgrall26e0d492011-06-24 19:21:51 -0700491int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700492 char cmd[MAX_CMD_LEN];
493 int res = 0;
494 std::string costString;
495 const char *costCString;
496
JP Abgrall26e0d492011-06-24 19:21:51 -0700497 switch (quotaType) {
498 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700499 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700500 costString += ifn;
501 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700502 break;
503 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700504 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700505 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700506 default:
507 ALOGE("Unexpected quotatype %d", quotaType);
508 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700509 }
510
JP Abgrall0031cea2012-04-17 16:38:23 -0700511 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700512 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700513 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700514 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700515
JP Abgrallbfa74662011-06-29 19:23:04 -0700516 /* The "-N costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700517 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700518 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700519 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700520 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
521 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700522 }
523 return res;
524}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700525
JP Abgrall0dad7c22011-06-24 11:58:14 -0700526int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700527 char cmd[MAX_CMD_LEN];
528 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700529 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700530 std::string quotaCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700531 std::string ifaceName;
532 ;
JP Abgrallbfa74662011-06-29 19:23:04 -0700533 const char *costName = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700534 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700535
JP Abgrall8a932722011-07-13 19:17:35 -0700536 if (!maxBytes) {
537 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000538 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700539 return -1;
540 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700541 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000542 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700543 return -1;
544 }
545 ifaceName = ifn;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700546
547 if (maxBytes == -1) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700548 return removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700549 }
550
551 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700552 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
553 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700554 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700555 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700556
JP Abgrall0dad7c22011-06-24 11:58:14 -0700557 if (it == sharedQuotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700558 res |= prepCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700559 if (sharedQuotaIfaces.empty()) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700560 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700561 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700562 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000563 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700564 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700565 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700566 sharedQuotaBytes = maxBytes;
567 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700568 sharedQuotaIfaces.push_front(ifaceName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700569
570 }
571
572 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700573 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700574 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000575 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700576 goto fail;
577 }
578 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700579 }
580 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700581
582 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700583 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700584 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
585 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700586 * For now callers needs to choose if they want to "ndc bandwidth enable"
587 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700588 */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700589 removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700590 return -1;
591}
592
JP Abgrall8a932722011-07-13 19:17:35 -0700593/* It will also cleanup any shared alerts */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700594int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700595 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700596 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700597 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700598 std::list<std::string>::iterator it;
JP Abgrallbfa74662011-06-29 19:23:04 -0700599 const char *costName = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700600
JP Abgrall8a932722011-07-13 19:17:35 -0700601 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000602 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700603 return -1;
604 }
JP Abgrall8a932722011-07-13 19:17:35 -0700605 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700606
JP Abgrall0dad7c22011-06-24 11:58:14 -0700607 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
608 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700609 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700610 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700611 if (it == sharedQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000612 ALOGE("No such iface %s to delete", ifn);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700613 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700614 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700615
JP Abgrall26e0d492011-06-24 19:21:51 -0700616 res |= cleanupCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700617 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700618
JP Abgrall0dad7c22011-06-24 11:58:14 -0700619 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700620 std::string quotaCmd;
JP Abgrallbfa74662011-06-29 19:23:04 -0700621 quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700622 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700623 sharedQuotaBytes = 0;
624 if (sharedAlertBytes) {
625 removeSharedAlert();
626 sharedAlertBytes = 0;
627 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700628 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700629 return res;
630}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700631
632int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
633 char ifn[MAX_IFACENAME_LEN];
634 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700635 std::string ifaceName;
636 const char *costName;
637 std::list<QuotaInfo>::iterator it;
638 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700639
JP Abgrall8a932722011-07-13 19:17:35 -0700640 if (!maxBytes) {
641 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000642 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700643 return -1;
644 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700645 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700646 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700647 }
648
JP Abgrall8a932722011-07-13 19:17:35 -0700649 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000650 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700651 return -1;
652 }
653 ifaceName = ifn;
654 costName = iface;
655
JP Abgrall0dad7c22011-06-24 11:58:14 -0700656 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700657 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700658 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700659 break;
660 }
661
662 if (it == quotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700663 res |= prepCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700664 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700665 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700666 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000667 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700668 goto fail;
669 }
670
JP Abgrall8a932722011-07-13 19:17:35 -0700671 quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700672
673 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700674 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700675 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000676 ALOGE("Failed update quota for %s", iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700677 goto fail;
678 }
JP Abgrall8a932722011-07-13 19:17:35 -0700679 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700680 }
681 return 0;
682
683 fail:
684 /*
685 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
686 * rules in the kernel to see which ones need cleaning up.
687 * For now callers needs to choose if they want to "ndc bandwidth enable"
688 * which resets everything.
689 */
690 removeInterfaceSharedQuota(ifn);
691 return -1;
692}
693
JP Abgrall8a932722011-07-13 19:17:35 -0700694int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
695 return getInterfaceQuota("shared", bytes);
696}
697
698int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
699 FILE *fp;
700 char *fname;
701 int scanRes;
702
703 asprintf(&fname, "/proc/net/xt_quota/%s", costName);
704 fp = fopen(fname, "r");
705 free(fname);
706 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000707 ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700708 return -1;
709 }
710 scanRes = fscanf(fp, "%lld", bytes);
Steve Block3fb42e02011-10-20 11:55:56 +0100711 ALOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700712 fclose(fp);
713 return scanRes == 1 ? 0 : -1;
714}
715
JP Abgrall0dad7c22011-06-24 11:58:14 -0700716int BandwidthController::removeInterfaceQuota(const char *iface) {
717
718 char ifn[MAX_IFACENAME_LEN];
719 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700720 std::string ifaceName;
721 const char *costName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700722 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700723
JP Abgrall8a932722011-07-13 19:17:35 -0700724 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000725 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700726 return -1;
727 }
728 ifaceName = ifn;
729 costName = iface;
730
JP Abgrall0dad7c22011-06-24 11:58:14 -0700731 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700732 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700733 break;
734 }
735
736 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000737 ALOGE("No such iface %s to delete", ifn);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700738 return -1;
739 }
740
741 /* This also removes the quota command of CostlyIface chain. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700742 res |= cleanupCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700743
744 quotaIfaces.erase(it);
745
746 return res;
747}
JP Abgrall8a932722011-07-13 19:17:35 -0700748
749int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
750 FILE *fp;
751 char *fname;
752
753 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
754 fp = fopen(fname, "w");
755 free(fname);
756 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000757 ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700758 return -1;
759 }
760 fprintf(fp, "%lld\n", bytes);
761 fclose(fp);
762 return 0;
763}
764
765int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
766 int res = 0;
767 const char *opFlag;
JP Abgrall87666692011-09-08 13:44:10 -0700768 const char *ifaceLimiting;
JP Abgrall8a932722011-07-13 19:17:35 -0700769 char *alertQuotaCmd;
770
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
JP Abgrall87666692011-09-08 13:44:10 -0700784 ifaceLimiting = "! -i lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700785 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_INPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800786 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700787 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
788 free(alertQuotaCmd);
JP Abgrall87666692011-09-08 13:44:10 -0700789 ifaceLimiting = "! -o lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700790 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_OUTPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800791 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700792 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
793 free(alertQuotaCmd);
794 return res;
795}
796
JP Abgrallc6c67342011-10-07 16:28:54 -0700797int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
798 int res = 0;
799 const char *opFlag;
800 const char *ifaceLimiting;
JP Abgrall8a932722011-07-13 19:17:35 -0700801 char *alertQuotaCmd;
JP Abgrallc6c67342011-10-07 16:28:54 -0700802
803 switch (op) {
804 case IptOpInsert:
805 opFlag = "-I";
806 break;
807 case IptOpReplace:
808 opFlag = "-R";
809 break;
810 default:
811 case IptOpDelete:
812 opFlag = "-D";
813 break;
814 }
815
816 ifaceLimiting = "! -i lo+";
JP Abgrall0031cea2012-04-17 16:38:23 -0700817 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_FORWARD",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800818 bytes, alertName);
JP Abgrallc6c67342011-10-07 16:28:54 -0700819 res = runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
820 free(alertQuotaCmd);
821 return res;
822}
823
824int BandwidthController::setGlobalAlert(int64_t bytes) {
825 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700826 int res = 0;
827
828 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000829 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700830 return -1;
831 }
832 if (globalAlertBytes) {
833 res = updateQuota(alertName, bytes);
834 } else {
835 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700836 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +0100837 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700838 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
839 }
JP Abgrall8a932722011-07-13 19:17:35 -0700840 }
841 globalAlertBytes = bytes;
842 return res;
843}
844
JP Abgrallc6c67342011-10-07 16:28:54 -0700845int BandwidthController::setGlobalAlertInForwardChain(void) {
846 const char *alertName = ALERT_GLOBAL_NAME;
847 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700848
JP Abgrallc6c67342011-10-07 16:28:54 -0700849 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +0100850 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700851
852 /*
853 * If there is no globalAlert active we are done.
854 * If there is an active globalAlert but this is not the 1st
855 * tether, we are also done.
856 */
857 if (!globalAlertBytes || globalAlertTetherCount != 1) {
858 return 0;
859 }
860
861 /* We only add the rule if this was the 1st tether added. */
862 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
863 return res;
864}
865
866int BandwidthController::removeGlobalAlert(void) {
867
868 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700869 int res = 0;
870
871 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000872 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700873 return -1;
874 }
875 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700876 if (globalAlertTetherCount) {
877 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
878 }
JP Abgrall8a932722011-07-13 19:17:35 -0700879 globalAlertBytes = 0;
880 return res;
881}
882
JP Abgrallc6c67342011-10-07 16:28:54 -0700883int BandwidthController::removeGlobalAlertInForwardChain(void) {
884 int res = 0;
885 const char *alertName = ALERT_GLOBAL_NAME;
886
887 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000888 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700889 return -1;
890 }
891
892 globalAlertTetherCount--;
893 /*
894 * If there is no globalAlert active we are done.
895 * If there is an active globalAlert but there are more
896 * tethers, we are also done.
897 */
898 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
899 return 0;
900 }
901
902 /* We only detete the rule if this was the last tether removed. */
903 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
904 return res;
905}
906
JP Abgrall8a932722011-07-13 19:17:35 -0700907int BandwidthController::setSharedAlert(int64_t bytes) {
908 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000909 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700910 return -1;
911 }
912 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000913 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700914 return -1;
915 }
916 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
917}
918
919int BandwidthController::removeSharedAlert(void) {
920 return removeCostlyAlert("shared", &sharedAlertBytes);
921}
922
923int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
924 std::list<QuotaInfo>::iterator it;
925
926 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000927 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700928 return -1;
929 }
930 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
931 if (it->ifaceName == iface)
932 break;
933 }
934
935 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000936 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700937 return -1;
938 }
939
940 return setCostlyAlert(iface, bytes, &it->alert);
941}
942
943int BandwidthController::removeInterfaceAlert(const char *iface) {
944 std::list<QuotaInfo>::iterator it;
945
946 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
947 if (it->ifaceName == iface)
948 break;
949 }
950
951 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000952 ALOGE("No prior alert set for interface %s", iface);
JP Abgrall8a932722011-07-13 19:17:35 -0700953 return -1;
954 }
955
956 return removeCostlyAlert(iface, &it->alert);
957}
958
959int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
960 char *alertQuotaCmd;
961 char *chainNameAndPos;
962 int res = 0;
963 char *alertName;
964
965 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000966 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700967 return -1;
968 }
969 asprintf(&alertName, "%sAlert", costName);
970 if (*alertBytes) {
971 res = updateQuota(alertName, *alertBytes);
972 } else {
973 asprintf(&chainNameAndPos, "costly_%s %d", costName, ALERT_RULE_POS_IN_COSTLY_CHAIN);
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800974 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-I", chainNameAndPos, bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700975 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
976 free(alertQuotaCmd);
977 free(chainNameAndPos);
978 }
979 *alertBytes = bytes;
980 free(alertName);
981 return res;
982}
983
984int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
985 char *alertQuotaCmd;
986 char *chainName;
987 char *alertName;
988 int res = 0;
989
990 asprintf(&alertName, "%sAlert", costName);
991 if (!*alertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000992 ALOGE("No prior alert set for %s alert", costName);
JP Abgrall8a932722011-07-13 19:17:35 -0700993 return -1;
994 }
995
996 asprintf(&chainName, "costly_%s", costName);
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800997 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-D", chainName, *alertBytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700998 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
999 free(alertQuotaCmd);
1000 free(chainName);
1001
1002 *alertBytes = 0;
1003 free(alertName);
1004 return res;
1005}
JP Abgralldb7da582011-09-18 12:57:32 -07001006
1007/*
1008 * Parse the ptks and bytes out of:
JP Abgrall0031cea2012-04-17 16:38:23 -07001009 * Chain FORWARD (policy RETURN 0 packets, 0 bytes)
JP Abgralldb7da582011-09-18 12:57:32 -07001010 * pkts bytes target prot opt in out source destination
JP Abgrall0031cea2012-04-17 16:38:23 -07001011 * 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 -07001012 * 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 -07001013 * 0 0 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
JP Abgralldb7da582011-09-18 12:57:32 -07001014 *
1015 */
JP Abgralla2a64f02011-11-11 20:36:16 -08001016int BandwidthController::parseForwardChainStats(TetherStats &stats, FILE *fp,
1017 std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001018 int res;
1019 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1020 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
1021 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
1022 char rest[MAX_IPT_OUTPUT_LINE_LEN];
1023
1024 char *buffPtr;
1025 int64_t packets, bytes;
1026
1027 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1028 /* Clean up, so a failed parse can still print info */
1029 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
JP Abgrall0031cea2012-04-17 16:38:23 -07001030 res = sscanf(buffPtr, "%lld %lld RETURN all -- %s %s 0.%s",
JP Abgralldb7da582011-09-18 12:57:32 -07001031 &packets, &bytes, iface0, iface1, rest);
Steve Block3fb42e02011-10-20 11:55:56 +01001032 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 -07001033 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -08001034 extraProcessingInfo += buffPtr;
1035
JP Abgralldb7da582011-09-18 12:57:32 -07001036 if (res != 5) {
1037 continue;
1038 }
1039 if ((stats.ifaceIn == iface0) && (stats.ifaceOut == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001040 ALOGV("iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001041 stats.rxPackets = packets;
1042 stats.rxBytes = bytes;
1043 } else if ((stats.ifaceOut == iface0) && (stats.ifaceIn == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001044 ALOGV("iface_in=%s iface_out=%s tx_bytes=%lld tx_packets=%lld ", iface1, iface0, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001045 stats.txPackets = packets;
1046 stats.txBytes = bytes;
1047 }
1048 }
1049 /* Failure if rx or tx was not found */
1050 return (stats.rxBytes == -1 || stats.txBytes == -1) ? -1 : 0;
1051}
1052
1053
1054char *BandwidthController::TetherStats::getStatsLine(void) {
1055 char *msg;
1056 asprintf(&msg, "%s %s %lld %lld %lld %lld", ifaceIn.c_str(), ifaceOut.c_str(),
1057 rxBytes, rxPackets, txBytes, txPackets);
1058 return msg;
1059}
1060
JP Abgralla2a64f02011-11-11 20:36:16 -08001061int BandwidthController::getTetherStats(TetherStats &stats, std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001062 int res;
1063 std::string fullCmd;
1064 FILE *iptOutput;
1065 const char *cmd;
1066
1067 if (stats.rxBytes != -1 || stats.txBytes != -1) {
Steve Block5ea0c052012-01-06 19:18:11 +00001068 ALOGE("Unexpected input stats. Byte counts should be -1.");
JP Abgralldb7da582011-09-18 12:57:32 -07001069 return -1;
1070 }
1071
1072 /*
1073 * Why not use some kind of lib to talk to iptables?
1074 * Because the only libs are libiptc and libip6tc in iptables, and they are
1075 * not easy to use. They require the known iptables match modules to be
1076 * preloaded/linked, and require apparently a lot of wrapper code to get
1077 * the wanted info.
1078 */
1079 fullCmd = IPTABLES_PATH;
JP Abgrall0031cea2012-04-17 16:38:23 -07001080 fullCmd += " -nvx -L natctrl_FORWARD";
JP Abgralldb7da582011-09-18 12:57:32 -07001081 iptOutput = popen(fullCmd.c_str(), "r");
1082 if (!iptOutput) {
Steve Block5ea0c052012-01-06 19:18:11 +00001083 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
JP Abgralla2a64f02011-11-11 20:36:16 -08001084 extraProcessingInfo += "Failed to run iptables.";
JP Abgralldb7da582011-09-18 12:57:32 -07001085 return -1;
1086 }
JP Abgralla2a64f02011-11-11 20:36:16 -08001087 res = parseForwardChainStats(stats, iptOutput, extraProcessingInfo);
JP Abgralldb7da582011-09-18 12:57:32 -07001088 pclose(iptOutput);
1089
1090 /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1091 return res;
1092}