blob: 8f3a738104895a5c9367af69d4740b1b39fd10a6 [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 */
JP Abgrall92009c82013-02-06 18:01:24 -080049#define ALERT_IPT_TEMPLATE "%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 -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700128
JP Abgrall0031cea2012-04-17 16:38:23 -0700129 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700130
JP Abgrallbfa74662011-06-29 19:23:04 -0700131 "-A costly_shared --jump penalty_box",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700132
JP Abgrall92009c82013-02-06 18:01:24 -0800133 "-t raw -A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
134 "-t mangle -A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700135};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700136
137BandwidthController::BandwidthController(void) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700138}
139
JP Abgrallad729ac2012-04-24 23:27:44 -0700140int BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling,
141 IptFailureLog failureHandling) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700142 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700143
Steve Block3fb42e02011-10-20 11:55:56 +0100144 ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
JP Abgrallad729ac2012-04-24 23:27:44 -0700145 res |= runIptablesCmd(cmd, rejectHandling, IptIpV4, failureHandling);
146 res |= runIptablesCmd(cmd, rejectHandling, IptIpV6, failureHandling);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700147 return res;
148}
149
JP Abgrall26e0d492011-06-24 19:21:51 -0700150int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
151
152 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
153 strncpy(buffer, src, buffSize);
154 return buffer[buffSize - 1];
155}
156
JP Abgrall8a932722011-07-13 19:17:35 -0700157int BandwidthController::runIptablesCmd(const char *cmd, IptRejectOp rejectHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700158 IptIpVer iptVer, IptFailureLog failureHandling) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700159 char buffer[MAX_CMD_LEN];
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700160 const char *argv[MAX_CMD_ARGS];
JP Abgrall26e0d492011-06-24 19:21:51 -0700161 int argc = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700162 char *next = buffer;
163 char *tmp;
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700164 int res;
Rom Lemarchand14150212013-01-24 10:01:04 -0800165 int status = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700166
JP Abgrall0dad7c22011-06-24 11:58:14 -0700167 std::string fullCmd = cmd;
JP Abgrall26e0d492011-06-24 19:21:51 -0700168
169 if (rejectHandling == IptRejectAdd) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700170 fullCmd += " --jump REJECT --reject-with";
JP Abgrall26e0d492011-06-24 19:21:51 -0700171 switch (iptVer) {
172 case IptIpV4:
JP Abgrall8a932722011-07-13 19:17:35 -0700173 fullCmd += " icmp-net-prohibited";
174 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700175 case IptIpV6:
JP Abgrall8a932722011-07-13 19:17:35 -0700176 fullCmd += " icmp6-adm-prohibited";
177 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700178 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700179 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700180
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700181 fullCmd.insert(0, " ");
182 fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700183
Rom Lemarchand14150212013-01-24 10:01:04 -0800184 if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
185 ALOGE("iptables command too long");
186 return -1;
187 }
188
189 argc = 0;
190 while ((tmp = strsep(&next, " "))) {
191 argv[argc++] = tmp;
192 if (argc >= MAX_CMD_ARGS) {
193 ALOGE("iptables argument overflow");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700194 return -1;
195 }
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700196 }
Rom Lemarchand14150212013-01-24 10:01:04 -0800197
198 argv[argc] = NULL;
199 res = android_fork_execvp(argc, (char **)argv, &status, false,
200 failureHandling == IptFailShow);
201
202 if ((res || !WIFEXITED(status) || WEXITSTATUS(status)) &&
203 failureHandling == IptFailShow) {
204 ALOGE("runIptablesCmd(): failed %s res=%d status=%d", fullCmd.c_str(),
205 res, status);
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700206 }
207 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700208}
209
JP Abgrall0031cea2012-04-17 16:38:23 -0700210int BandwidthController::setupIptablesHooks(void) {
211
212 /* Some of the initialCommands are allowed to fail */
213 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
214 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
215
216 runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
217 IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
218
219 runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
220 IPT_SETUP_COMMANDS, RunCmdFailureBad);
221
222 return 0;
JP Abgrall0031cea2012-04-17 16:38:23 -0700223}
224
225int BandwidthController::enableBandwidthControl(bool force) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700226 int res;
JP Abgrall0031cea2012-04-17 16:38:23 -0700227 char value[PROPERTY_VALUE_MAX];
228
229 if (!force) {
230 property_get("persist.bandwidth.enable", value, "1");
231 if (!strcmp(value, "0"))
232 return 0;
233 }
JP Abgrall8a932722011-07-13 19:17:35 -0700234
JP Abgralldb7da582011-09-18 12:57:32 -0700235 /* Let's pretend we started from scratch ... */
JP Abgrall8a932722011-07-13 19:17:35 -0700236 sharedQuotaIfaces.clear();
237 quotaIfaces.clear();
238 naughtyAppUids.clear();
JP Abgralldb7da582011-09-18 12:57:32 -0700239 globalAlertBytes = 0;
JP Abgrallc6c67342011-10-07 16:28:54 -0700240 globalAlertTetherCount = 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700241 sharedQuotaBytes = sharedAlertBytes = 0;
242
JP Abgrall0031cea2012-04-17 16:38:23 -0700243 res = runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
244 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgralldb7da582011-09-18 12:57:32 -0700245
JP Abgrall0031cea2012-04-17 16:38:23 -0700246 res |= runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
JP Abgralldb7da582011-09-18 12:57:32 -0700247 IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
JP Abgrall8a932722011-07-13 19:17:35 -0700248
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700249 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700250
251}
252
253int BandwidthController::disableBandwidthControl(void) {
JP Abgrall0031cea2012-04-17 16:38:23 -0700254 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
255 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700256 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700257}
258
JP Abgrall8a932722011-07-13 19:17:35 -0700259int BandwidthController::runCommands(int numCommands, const char *commands[],
260 RunCmdErrHandling cmdErrHandling) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700261 int res = 0;
JP Abgrallad729ac2012-04-24 23:27:44 -0700262 IptFailureLog failureLogging = IptFailShow;
263 if (cmdErrHandling == RunCmdFailureOk) {
264 failureLogging = IptFailHide;
265 }
Steve Block3fb42e02011-10-20 11:55:56 +0100266 ALOGV("runCommands(): %d commands", numCommands);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700267 for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
JP Abgrallad729ac2012-04-24 23:27:44 -0700268 res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd, failureLogging);
JP Abgrall0031cea2012-04-17 16:38:23 -0700269 if (res && cmdErrHandling != RunCmdFailureOk)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700270 return res;
271 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700272 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700273}
274
JP Abgrall0dad7c22011-06-24 11:58:14 -0700275std::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700276 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700277 char *buff;
278 const char *opFlag;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700279
280 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700281 case IptOpInsert:
282 opFlag = "-I";
283 break;
284 case IptOpReplace:
285 opFlag = "-R";
286 break;
287 default:
288 case IptOpDelete:
289 opFlag = "-D";
290 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700291 }
JP Abgrall8a932722011-07-13 19:17:35 -0700292 asprintf(&buff, "%s penalty_box -m owner --uid-owner %d", opFlag, uid);
293 res = buff;
294 free(buff);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700295 return res;
296}
297
298int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700299 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700300}
301
302int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700303 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpRemove);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700304}
305
JP Abgrall26e0d492011-06-24 19:21:51 -0700306int BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700307 char cmd[MAX_CMD_LEN];
308 int uidNum;
JP Abgrall26e0d492011-06-24 19:21:51 -0700309 const char *failLogTemplate;
310 IptOp op;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700311 int appUids[numUids];
JP Abgrall26e0d492011-06-24 19:21:51 -0700312 std::string naughtyCmd;
JP Abgrallb1d24092012-04-27 01:02:31 -0700313 std::list<int /*uid*/>::iterator it;
JP Abgrall8a932722011-07-13 19:17:35 -0700314
JP Abgrall26e0d492011-06-24 19:21:51 -0700315 switch (appOp) {
316 case NaughtyAppOpAdd:
JP Abgrall8a932722011-07-13 19:17:35 -0700317 op = IptOpInsert;
318 failLogTemplate = "Failed to add app uid %d to penalty box.";
319 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700320 case NaughtyAppOpRemove:
JP Abgrall8a932722011-07-13 19:17:35 -0700321 op = IptOpDelete;
322 failLogTemplate = "Failed to delete app uid %d from penalty box.";
323 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700324 default:
325 ALOGE("Unexpected app Op %d", appOp);
326 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700327 }
328
329 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700330 appUids[uidNum] = atol(appStrUids[uidNum]);
331 if (appUids[uidNum] == 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000332 ALOGE(failLogTemplate, appUids[uidNum]);
JP Abgrall26e0d492011-06-24 19:21:51 -0700333 goto fail_parse;
334 }
335 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700336
337 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700338 int uid = appUids[uidNum];
339 for (it = naughtyAppUids.begin(); it != naughtyAppUids.end(); it++) {
340 if (*it == uid)
341 break;
342 }
343 bool found = (it != naughtyAppUids.end());
344
345 if (appOp == NaughtyAppOpRemove) {
346 if (!found) {
347 ALOGE("No such appUid %d to remove", uid);
348 return -1;
349 }
350 naughtyAppUids.erase(it);
351 } else {
352 if (found) {
353 ALOGE("appUid %d exists already", uid);
354 return -1;
355 }
356 naughtyAppUids.push_front(uid);
357 }
358
359 naughtyCmd = makeIptablesNaughtyCmd(op, uid);
JP Abgrall26e0d492011-06-24 19:21:51 -0700360 if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700361 ALOGE(failLogTemplate, uid);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700362 goto fail_with_uidNum;
363 }
364 }
365 return 0;
366
JP Abgrall26e0d492011-06-24 19:21:51 -0700367fail_with_uidNum:
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700368 /* Try to remove the uid that failed in any case*/
JP Abgrall26e0d492011-06-24 19:21:51 -0700369 naughtyCmd = makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]);
370 runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd);
371fail_parse:
372 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700373}
374
JP Abgrall26e0d492011-06-24 19:21:51 -0700375std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700376 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700377 char *buff;
378 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700379
Steve Block3fb42e02011-10-20 11:55:56 +0100380 ALOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700381
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700382 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700383 case IptOpInsert:
384 opFlag = "-I";
385 break;
386 case IptOpReplace:
387 opFlag = "-R";
388 break;
389 default:
390 case IptOpDelete:
391 opFlag = "-D";
392 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700393 }
JP Abgrall8a932722011-07-13 19:17:35 -0700394
JP Abgrallbfa74662011-06-29 19:23:04 -0700395 // The requried IP version specific --jump REJECT ... will be added later.
JP Abgrall8a932722011-07-13 19:17:35 -0700396 asprintf(&buff, "%s costly_%s -m quota2 ! --quota %lld --name %s", opFlag, costName, quota,
397 costName);
398 res = buff;
399 free(buff);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700400 return res;
401}
402
JP Abgrall26e0d492011-06-24 19:21:51 -0700403int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700404 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700405 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700406 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700407 std::string costString;
408 const char *costCString;
409
JP Abgrall0dad7c22011-06-24 11:58:14 -0700410 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700411 switch (quotaType) {
412 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700413 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700414 costString += ifn;
415 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700416 /*
417 * Flush the costly_<iface> is allowed to fail in case it didn't exist.
418 * Creating a new one is allowed to fail in case it existed.
419 * This helps with netd restarts.
420 */
421 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700422 res1 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700423 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700424 res2 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700425 res = (res1 && res2) || (!res1 && !res2);
426
JP Abgrall0dad7c22011-06-24 11:58:14 -0700427 snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700428 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700429 break;
430 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700431 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700432 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700433 default:
434 ALOGE("Unexpected quotatype %d", quotaType);
435 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700436 }
437
JP Abgrall8a932722011-07-13 19:17:35 -0700438 if (globalAlertBytes) {
439 /* The alert rule comes 1st */
440 ruleInsertPos = 2;
441 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700442
443 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700444 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700445
446 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700447 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700448
449 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700450 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700451
452 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700453 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700454 return res;
455}
456
JP Abgrall26e0d492011-06-24 19:21:51 -0700457int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700458 char cmd[MAX_CMD_LEN];
459 int res = 0;
460 std::string costString;
461 const char *costCString;
462
JP Abgrall26e0d492011-06-24 19:21:51 -0700463 switch (quotaType) {
464 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700465 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700466 costString += ifn;
467 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700468 break;
469 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700470 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700471 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700472 default:
473 ALOGE("Unexpected quotatype %d", quotaType);
474 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700475 }
476
JP Abgrall0031cea2012-04-17 16:38:23 -0700477 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700478 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700479 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700480 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700481
JP Abgrallbfa74662011-06-29 19:23:04 -0700482 /* The "-N costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700483 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700484 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700485 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700486 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
487 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700488 }
489 return res;
490}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700491
JP Abgrall0dad7c22011-06-24 11:58:14 -0700492int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700493 char cmd[MAX_CMD_LEN];
494 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700495 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700496 std::string quotaCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700497 std::string ifaceName;
498 ;
JP Abgrallbfa74662011-06-29 19:23:04 -0700499 const char *costName = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700500 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700501
JP Abgrall8a932722011-07-13 19:17:35 -0700502 if (!maxBytes) {
503 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000504 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700505 return -1;
506 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700507 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000508 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700509 return -1;
510 }
511 ifaceName = ifn;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700512
513 if (maxBytes == -1) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700514 return removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700515 }
516
517 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700518 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
519 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700520 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700521 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700522
JP Abgrall0dad7c22011-06-24 11:58:14 -0700523 if (it == sharedQuotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700524 res |= prepCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700525 if (sharedQuotaIfaces.empty()) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700526 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700527 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700528 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000529 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700530 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700531 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700532 sharedQuotaBytes = maxBytes;
533 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700534 sharedQuotaIfaces.push_front(ifaceName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700535
536 }
537
538 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700539 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700540 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000541 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700542 goto fail;
543 }
544 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700545 }
546 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700547
548 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700549 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700550 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
551 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700552 * For now callers needs to choose if they want to "ndc bandwidth enable"
553 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700554 */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700555 removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700556 return -1;
557}
558
JP Abgrall8a932722011-07-13 19:17:35 -0700559/* It will also cleanup any shared alerts */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700560int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700561 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700562 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700563 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700564 std::list<std::string>::iterator it;
JP Abgrallbfa74662011-06-29 19:23:04 -0700565 const char *costName = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700566
JP Abgrall8a932722011-07-13 19:17:35 -0700567 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000568 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700569 return -1;
570 }
JP Abgrall8a932722011-07-13 19:17:35 -0700571 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700572
JP Abgrall0dad7c22011-06-24 11:58:14 -0700573 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
574 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700575 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700576 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700577 if (it == sharedQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000578 ALOGE("No such iface %s to delete", ifn);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700579 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700580 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700581
JP Abgrall26e0d492011-06-24 19:21:51 -0700582 res |= cleanupCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700583 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700584
JP Abgrall0dad7c22011-06-24 11:58:14 -0700585 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700586 std::string quotaCmd;
JP Abgrallbfa74662011-06-29 19:23:04 -0700587 quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700588 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700589 sharedQuotaBytes = 0;
590 if (sharedAlertBytes) {
591 removeSharedAlert();
592 sharedAlertBytes = 0;
593 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700594 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700595 return res;
596}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700597
598int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
599 char ifn[MAX_IFACENAME_LEN];
600 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700601 std::string ifaceName;
602 const char *costName;
603 std::list<QuotaInfo>::iterator it;
604 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700605
JP Abgrall8a932722011-07-13 19:17:35 -0700606 if (!maxBytes) {
607 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000608 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700609 return -1;
610 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700611 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700612 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700613 }
614
JP Abgrall8a932722011-07-13 19:17:35 -0700615 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000616 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700617 return -1;
618 }
619 ifaceName = ifn;
620 costName = iface;
621
JP Abgrall0dad7c22011-06-24 11:58:14 -0700622 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700623 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700624 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700625 break;
626 }
627
628 if (it == quotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700629 res |= prepCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700630 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700631 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700632 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000633 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700634 goto fail;
635 }
636
JP Abgrall8a932722011-07-13 19:17:35 -0700637 quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700638
639 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700640 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700641 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000642 ALOGE("Failed update quota for %s", iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700643 goto fail;
644 }
JP Abgrall8a932722011-07-13 19:17:35 -0700645 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700646 }
647 return 0;
648
649 fail:
650 /*
651 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
652 * rules in the kernel to see which ones need cleaning up.
653 * For now callers needs to choose if they want to "ndc bandwidth enable"
654 * which resets everything.
655 */
656 removeInterfaceSharedQuota(ifn);
657 return -1;
658}
659
JP Abgrall8a932722011-07-13 19:17:35 -0700660int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
661 return getInterfaceQuota("shared", bytes);
662}
663
664int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
665 FILE *fp;
666 char *fname;
667 int scanRes;
668
669 asprintf(&fname, "/proc/net/xt_quota/%s", costName);
670 fp = fopen(fname, "r");
671 free(fname);
672 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000673 ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700674 return -1;
675 }
676 scanRes = fscanf(fp, "%lld", bytes);
Steve Block3fb42e02011-10-20 11:55:56 +0100677 ALOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700678 fclose(fp);
679 return scanRes == 1 ? 0 : -1;
680}
681
JP Abgrall0dad7c22011-06-24 11:58:14 -0700682int BandwidthController::removeInterfaceQuota(const char *iface) {
683
684 char ifn[MAX_IFACENAME_LEN];
685 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700686 std::string ifaceName;
687 const char *costName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700688 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700689
JP Abgrall8a932722011-07-13 19:17:35 -0700690 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000691 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700692 return -1;
693 }
694 ifaceName = ifn;
695 costName = iface;
696
JP Abgrall0dad7c22011-06-24 11:58:14 -0700697 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700698 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700699 break;
700 }
701
702 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000703 ALOGE("No such iface %s to delete", ifn);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700704 return -1;
705 }
706
707 /* This also removes the quota command of CostlyIface chain. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700708 res |= cleanupCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700709
710 quotaIfaces.erase(it);
711
712 return res;
713}
JP Abgrall8a932722011-07-13 19:17:35 -0700714
715int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
716 FILE *fp;
717 char *fname;
718
719 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
720 fp = fopen(fname, "w");
721 free(fname);
722 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000723 ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700724 return -1;
725 }
726 fprintf(fp, "%lld\n", bytes);
727 fclose(fp);
728 return 0;
729}
730
731int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
732 int res = 0;
733 const char *opFlag;
734 char *alertQuotaCmd;
735
736 switch (op) {
737 case IptOpInsert:
738 opFlag = "-I";
739 break;
740 case IptOpReplace:
741 opFlag = "-R";
742 break;
743 default:
744 case IptOpDelete:
745 opFlag = "-D";
746 break;
747 }
748
JP Abgrall92009c82013-02-06 18:01:24 -0800749 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800750 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700751 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
752 free(alertQuotaCmd);
JP Abgrall92009c82013-02-06 18:01:24 -0800753 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT",
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);
757 return res;
758}
759
JP Abgrallc6c67342011-10-07 16:28:54 -0700760int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
761 int res = 0;
762 const char *opFlag;
JP Abgrall8a932722011-07-13 19:17:35 -0700763 char *alertQuotaCmd;
JP Abgrallc6c67342011-10-07 16:28:54 -0700764
765 switch (op) {
766 case IptOpInsert:
767 opFlag = "-I";
768 break;
769 case IptOpReplace:
770 opFlag = "-R";
771 break;
772 default:
773 case IptOpDelete:
774 opFlag = "-D";
775 break;
776 }
777
JP Abgrall92009c82013-02-06 18:01:24 -0800778 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800779 bytes, alertName);
JP Abgrallc6c67342011-10-07 16:28:54 -0700780 res = runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
781 free(alertQuotaCmd);
782 return res;
783}
784
785int BandwidthController::setGlobalAlert(int64_t bytes) {
786 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700787 int res = 0;
788
789 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000790 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700791 return -1;
792 }
793 if (globalAlertBytes) {
794 res = updateQuota(alertName, bytes);
795 } else {
796 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700797 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +0100798 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700799 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
800 }
JP Abgrall8a932722011-07-13 19:17:35 -0700801 }
802 globalAlertBytes = bytes;
803 return res;
804}
805
JP Abgrallc6c67342011-10-07 16:28:54 -0700806int BandwidthController::setGlobalAlertInForwardChain(void) {
807 const char *alertName = ALERT_GLOBAL_NAME;
808 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700809
JP Abgrallc6c67342011-10-07 16:28:54 -0700810 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +0100811 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700812
813 /*
814 * If there is no globalAlert active we are done.
815 * If there is an active globalAlert but this is not the 1st
816 * tether, we are also done.
817 */
818 if (!globalAlertBytes || globalAlertTetherCount != 1) {
819 return 0;
820 }
821
822 /* We only add the rule if this was the 1st tether added. */
823 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
824 return res;
825}
826
827int BandwidthController::removeGlobalAlert(void) {
828
829 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700830 int res = 0;
831
832 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000833 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700834 return -1;
835 }
836 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700837 if (globalAlertTetherCount) {
838 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
839 }
JP Abgrall8a932722011-07-13 19:17:35 -0700840 globalAlertBytes = 0;
841 return res;
842}
843
JP Abgrallc6c67342011-10-07 16:28:54 -0700844int BandwidthController::removeGlobalAlertInForwardChain(void) {
845 int res = 0;
846 const char *alertName = ALERT_GLOBAL_NAME;
847
848 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000849 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700850 return -1;
851 }
852
853 globalAlertTetherCount--;
854 /*
855 * If there is no globalAlert active we are done.
856 * If there is an active globalAlert but there are more
857 * tethers, we are also done.
858 */
859 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
860 return 0;
861 }
862
863 /* We only detete the rule if this was the last tether removed. */
864 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
865 return res;
866}
867
JP Abgrall8a932722011-07-13 19:17:35 -0700868int BandwidthController::setSharedAlert(int64_t bytes) {
869 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000870 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700871 return -1;
872 }
873 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000874 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700875 return -1;
876 }
877 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
878}
879
880int BandwidthController::removeSharedAlert(void) {
881 return removeCostlyAlert("shared", &sharedAlertBytes);
882}
883
884int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
885 std::list<QuotaInfo>::iterator it;
886
887 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000888 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700889 return -1;
890 }
891 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
892 if (it->ifaceName == iface)
893 break;
894 }
895
896 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000897 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700898 return -1;
899 }
900
901 return setCostlyAlert(iface, bytes, &it->alert);
902}
903
904int BandwidthController::removeInterfaceAlert(const char *iface) {
905 std::list<QuotaInfo>::iterator it;
906
907 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
908 if (it->ifaceName == iface)
909 break;
910 }
911
912 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000913 ALOGE("No prior alert set for interface %s", iface);
JP Abgrall8a932722011-07-13 19:17:35 -0700914 return -1;
915 }
916
917 return removeCostlyAlert(iface, &it->alert);
918}
919
920int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
921 char *alertQuotaCmd;
922 char *chainNameAndPos;
923 int res = 0;
924 char *alertName;
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 asprintf(&alertName, "%sAlert", costName);
931 if (*alertBytes) {
932 res = updateQuota(alertName, *alertBytes);
933 } else {
934 asprintf(&chainNameAndPos, "costly_%s %d", costName, ALERT_RULE_POS_IN_COSTLY_CHAIN);
JP Abgrall92009c82013-02-06 18:01:24 -0800935 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-I", chainNameAndPos, bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700936 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
937 free(alertQuotaCmd);
938 free(chainNameAndPos);
939 }
940 *alertBytes = bytes;
941 free(alertName);
942 return res;
943}
944
945int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
946 char *alertQuotaCmd;
947 char *chainName;
948 char *alertName;
949 int res = 0;
950
951 asprintf(&alertName, "%sAlert", costName);
952 if (!*alertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000953 ALOGE("No prior alert set for %s alert", costName);
JP Abgrall8a932722011-07-13 19:17:35 -0700954 return -1;
955 }
956
957 asprintf(&chainName, "costly_%s", costName);
JP Abgrall92009c82013-02-06 18:01:24 -0800958 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700959 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
960 free(alertQuotaCmd);
961 free(chainName);
962
963 *alertBytes = 0;
964 free(alertName);
965 return res;
966}
JP Abgralldb7da582011-09-18 12:57:32 -0700967
968/*
969 * Parse the ptks and bytes out of:
JP Abgrall0031cea2012-04-17 16:38:23 -0700970 * Chain FORWARD (policy RETURN 0 packets, 0 bytes)
JP Abgralldb7da582011-09-18 12:57:32 -0700971 * pkts bytes target prot opt in out source destination
JP Abgrall0031cea2012-04-17 16:38:23 -0700972 * 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 -0700973 * 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 -0700974 * 0 0 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
JP Abgralldb7da582011-09-18 12:57:32 -0700975 *
976 */
JP Abgralla2a64f02011-11-11 20:36:16 -0800977int BandwidthController::parseForwardChainStats(TetherStats &stats, FILE *fp,
978 std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -0700979 int res;
980 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
981 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
982 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
983 char rest[MAX_IPT_OUTPUT_LINE_LEN];
984
985 char *buffPtr;
986 int64_t packets, bytes;
987
988 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
989 /* Clean up, so a failed parse can still print info */
990 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
JP Abgrall0031cea2012-04-17 16:38:23 -0700991 res = sscanf(buffPtr, "%lld %lld RETURN all -- %s %s 0.%s",
JP Abgralldb7da582011-09-18 12:57:32 -0700992 &packets, &bytes, iface0, iface1, rest);
Steve Block3fb42e02011-10-20 11:55:56 +0100993 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 -0700994 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -0800995 extraProcessingInfo += buffPtr;
996
JP Abgralldb7da582011-09-18 12:57:32 -0700997 if (res != 5) {
998 continue;
999 }
1000 if ((stats.ifaceIn == iface0) && (stats.ifaceOut == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001001 ALOGV("iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001002 stats.rxPackets = packets;
1003 stats.rxBytes = bytes;
1004 } else if ((stats.ifaceOut == iface0) && (stats.ifaceIn == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001005 ALOGV("iface_in=%s iface_out=%s tx_bytes=%lld tx_packets=%lld ", iface1, iface0, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001006 stats.txPackets = packets;
1007 stats.txBytes = bytes;
1008 }
1009 }
1010 /* Failure if rx or tx was not found */
1011 return (stats.rxBytes == -1 || stats.txBytes == -1) ? -1 : 0;
1012}
1013
1014
1015char *BandwidthController::TetherStats::getStatsLine(void) {
1016 char *msg;
1017 asprintf(&msg, "%s %s %lld %lld %lld %lld", ifaceIn.c_str(), ifaceOut.c_str(),
1018 rxBytes, rxPackets, txBytes, txPackets);
1019 return msg;
1020}
1021
JP Abgralla2a64f02011-11-11 20:36:16 -08001022int BandwidthController::getTetherStats(TetherStats &stats, std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001023 int res;
1024 std::string fullCmd;
1025 FILE *iptOutput;
1026 const char *cmd;
1027
1028 if (stats.rxBytes != -1 || stats.txBytes != -1) {
Steve Block5ea0c052012-01-06 19:18:11 +00001029 ALOGE("Unexpected input stats. Byte counts should be -1.");
JP Abgralldb7da582011-09-18 12:57:32 -07001030 return -1;
1031 }
1032
1033 /*
1034 * Why not use some kind of lib to talk to iptables?
1035 * Because the only libs are libiptc and libip6tc in iptables, and they are
1036 * not easy to use. They require the known iptables match modules to be
1037 * preloaded/linked, and require apparently a lot of wrapper code to get
1038 * the wanted info.
1039 */
1040 fullCmd = IPTABLES_PATH;
JP Abgrall0031cea2012-04-17 16:38:23 -07001041 fullCmd += " -nvx -L natctrl_FORWARD";
JP Abgralldb7da582011-09-18 12:57:32 -07001042 iptOutput = popen(fullCmd.c_str(), "r");
1043 if (!iptOutput) {
Steve Block5ea0c052012-01-06 19:18:11 +00001044 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
JP Abgralla2a64f02011-11-11 20:36:16 -08001045 extraProcessingInfo += "Failed to run iptables.";
JP Abgralldb7da582011-09-18 12:57:32 -07001046 return -1;
1047 }
JP Abgralla2a64f02011-11-11 20:36:16 -08001048 res = parseForwardChainStats(stats, iptOutput, extraProcessingInfo);
JP Abgralldb7da582011-09-18 12:57:32 -07001049 pclose(iptOutput);
1050
1051 /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1052 return res;
1053}