blob: d51ea254d7324352d9f9075255f998bfb645e00c [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 Abgrallc6c67342011-10-07 16:28:54 -070050const char BandwidthController::ALERT_GLOBAL_NAME[] = "globalAlert";
Jeff Sharkey8e188ed2012-07-12 18:32:03 -070051const char* BandwidthController::LOCAL_INPUT = "bw_INPUT";
52const char* BandwidthController::LOCAL_FORWARD = "bw_FORWARD";
53const char* BandwidthController::LOCAL_OUTPUT = "bw_OUTPUT";
54const char* BandwidthController::LOCAL_RAW_PREROUTING = "bw_raw_PREROUTING";
55const char* BandwidthController::LOCAL_MANGLE_POSTROUTING = "bw_mangle_POSTROUTING";
JP Abgralldb7da582011-09-18 12:57:32 -070056const int BandwidthController::MAX_CMD_ARGS = 32;
57const int BandwidthController::MAX_CMD_LEN = 1024;
58const int BandwidthController::MAX_IFACENAME_LEN = 64;
59const int BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
60
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070061/**
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[] = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700116 "-X penalty_box",
117 "-X costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700118};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700119
JP Abgralldb7da582011-09-18 12:57:32 -0700120const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
JP Abgrallbfa74662011-06-29 19:23:04 -0700121 "-N costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700122 "-N penalty_box",
123};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700124
JP Abgralldb7da582011-09-18 12:57:32 -0700125const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700126 "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700127
JP Abgrall0031cea2012-04-17 16:38:23 -0700128 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700129
JP Abgrallbfa74662011-06-29 19:23:04 -0700130 "-A costly_shared --jump penalty_box",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700131
JP Abgrall92009c82013-02-06 18:01:24 -0800132 "-t raw -A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
133 "-t mangle -A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700134};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700135
136BandwidthController::BandwidthController(void) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700137}
138
JP Abgrallad729ac2012-04-24 23:27:44 -0700139int BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling,
140 IptFailureLog failureHandling) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700141 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700142
Steve Block3fb42e02011-10-20 11:55:56 +0100143 ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
JP Abgrallad729ac2012-04-24 23:27:44 -0700144 res |= runIptablesCmd(cmd, rejectHandling, IptIpV4, failureHandling);
145 res |= runIptablesCmd(cmd, rejectHandling, IptIpV6, failureHandling);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700146 return res;
147}
148
JP Abgrall26e0d492011-06-24 19:21:51 -0700149int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
150
151 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
152 strncpy(buffer, src, buffSize);
153 return buffer[buffSize - 1];
154}
155
JP Abgrall8a932722011-07-13 19:17:35 -0700156int BandwidthController::runIptablesCmd(const char *cmd, IptRejectOp rejectHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700157 IptIpVer iptVer, IptFailureLog failureHandling) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700158 char buffer[MAX_CMD_LEN];
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700159 const char *argv[MAX_CMD_ARGS];
JP Abgrall26e0d492011-06-24 19:21:51 -0700160 int argc = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700161 char *next = buffer;
162 char *tmp;
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700163 int res;
Rom Lemarchand14150212013-01-24 10:01:04 -0800164 int status = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700165
JP Abgrall0dad7c22011-06-24 11:58:14 -0700166 std::string fullCmd = cmd;
JP Abgrall26e0d492011-06-24 19:21:51 -0700167
168 if (rejectHandling == IptRejectAdd) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700169 fullCmd += " --jump REJECT --reject-with";
JP Abgrall26e0d492011-06-24 19:21:51 -0700170 switch (iptVer) {
171 case IptIpV4:
JP Abgrall8a932722011-07-13 19:17:35 -0700172 fullCmd += " icmp-net-prohibited";
173 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700174 case IptIpV6:
JP Abgrall8a932722011-07-13 19:17:35 -0700175 fullCmd += " icmp6-adm-prohibited";
176 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700177 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700178 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700179
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700180 fullCmd.insert(0, " ");
181 fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700182
Rom Lemarchand14150212013-01-24 10:01:04 -0800183 if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
184 ALOGE("iptables command too long");
185 return -1;
186 }
187
188 argc = 0;
189 while ((tmp = strsep(&next, " "))) {
190 argv[argc++] = tmp;
191 if (argc >= MAX_CMD_ARGS) {
192 ALOGE("iptables argument overflow");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700193 return -1;
194 }
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700195 }
Rom Lemarchand14150212013-01-24 10:01:04 -0800196
197 argv[argc] = NULL;
198 res = android_fork_execvp(argc, (char **)argv, &status, false,
199 failureHandling == IptFailShow);
JP Abgrallc8dc63b2013-02-13 16:30:00 -0800200 res = res || !WIFEXITED(status) || WEXITSTATUS(status);
201 if (res && failureHandling == IptFailShow) {
202 ALOGE("runIptablesCmd(): res=%d status=%d failed %s", res, status,
203 fullCmd.c_str());
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700204 }
205 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700206}
207
JP Abgrall0031cea2012-04-17 16:38:23 -0700208int BandwidthController::setupIptablesHooks(void) {
209
210 /* Some of the initialCommands are allowed to fail */
211 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
212 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
213
214 runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
215 IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
216
217 runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
218 IPT_SETUP_COMMANDS, RunCmdFailureBad);
219
220 return 0;
JP Abgrall0031cea2012-04-17 16:38:23 -0700221}
222
223int BandwidthController::enableBandwidthControl(bool force) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700224 int res;
JP Abgrall0031cea2012-04-17 16:38:23 -0700225 char value[PROPERTY_VALUE_MAX];
226
227 if (!force) {
228 property_get("persist.bandwidth.enable", value, "1");
229 if (!strcmp(value, "0"))
230 return 0;
231 }
JP Abgrall8a932722011-07-13 19:17:35 -0700232
JP Abgralldb7da582011-09-18 12:57:32 -0700233 /* Let's pretend we started from scratch ... */
JP Abgrall8a932722011-07-13 19:17:35 -0700234 sharedQuotaIfaces.clear();
235 quotaIfaces.clear();
236 naughtyAppUids.clear();
JP Abgralldb7da582011-09-18 12:57:32 -0700237 globalAlertBytes = 0;
JP Abgrallc6c67342011-10-07 16:28:54 -0700238 globalAlertTetherCount = 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700239 sharedQuotaBytes = sharedAlertBytes = 0;
240
JP Abgrall0031cea2012-04-17 16:38:23 -0700241 res = runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
242 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgralldb7da582011-09-18 12:57:32 -0700243
JP Abgrall0031cea2012-04-17 16:38:23 -0700244 res |= runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
JP Abgralldb7da582011-09-18 12:57:32 -0700245 IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
JP Abgrall8a932722011-07-13 19:17:35 -0700246
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700247 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700248
249}
250
251int BandwidthController::disableBandwidthControl(void) {
JP Abgrall0031cea2012-04-17 16:38:23 -0700252 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
253 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700254 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700255}
256
JP Abgrall8a932722011-07-13 19:17:35 -0700257int BandwidthController::runCommands(int numCommands, const char *commands[],
258 RunCmdErrHandling cmdErrHandling) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700259 int res = 0;
JP Abgrallad729ac2012-04-24 23:27:44 -0700260 IptFailureLog failureLogging = IptFailShow;
261 if (cmdErrHandling == RunCmdFailureOk) {
262 failureLogging = IptFailHide;
263 }
Steve Block3fb42e02011-10-20 11:55:56 +0100264 ALOGV("runCommands(): %d commands", numCommands);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700265 for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
JP Abgrallad729ac2012-04-24 23:27:44 -0700266 res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd, failureLogging);
JP Abgrall0031cea2012-04-17 16:38:23 -0700267 if (res && cmdErrHandling != RunCmdFailureOk)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700268 return res;
269 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700270 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700271}
272
JP Abgrall0dad7c22011-06-24 11:58:14 -0700273std::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700274 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700275 char *buff;
276 const char *opFlag;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700277
278 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700279 case IptOpInsert:
280 opFlag = "-I";
281 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800282 case IptOpAppend:
283 opFlag = "-A";
284 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700285 case IptOpReplace:
286 opFlag = "-R";
287 break;
288 default:
289 case IptOpDelete:
290 opFlag = "-D";
291 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700292 }
JP Abgrall8a932722011-07-13 19:17:35 -0700293 asprintf(&buff, "%s penalty_box -m owner --uid-owner %d", opFlag, uid);
294 res = buff;
295 free(buff);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700296 return res;
297}
298
299int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700300 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700301}
302
303int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700304 return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpRemove);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700305}
306
JP Abgrall26e0d492011-06-24 19:21:51 -0700307int BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700308 char cmd[MAX_CMD_LEN];
309 int uidNum;
JP Abgrall26e0d492011-06-24 19:21:51 -0700310 const char *failLogTemplate;
311 IptOp op;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700312 int appUids[numUids];
JP Abgrall26e0d492011-06-24 19:21:51 -0700313 std::string naughtyCmd;
JP Abgrallb1d24092012-04-27 01:02:31 -0700314 std::list<int /*uid*/>::iterator it;
JP Abgrall8a932722011-07-13 19:17:35 -0700315
JP Abgrall26e0d492011-06-24 19:21:51 -0700316 switch (appOp) {
317 case NaughtyAppOpAdd:
JP Abgrall8a932722011-07-13 19:17:35 -0700318 op = IptOpInsert;
319 failLogTemplate = "Failed to add app uid %d to penalty box.";
320 break;
JP Abgrall26e0d492011-06-24 19:21:51 -0700321 case NaughtyAppOpRemove:
JP Abgrall8a932722011-07-13 19:17:35 -0700322 op = IptOpDelete;
323 failLogTemplate = "Failed to delete app uid %d from penalty box.";
324 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700325 default:
326 ALOGE("Unexpected app Op %d", appOp);
327 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700328 }
329
330 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700331 appUids[uidNum] = atol(appStrUids[uidNum]);
332 if (appUids[uidNum] == 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000333 ALOGE(failLogTemplate, appUids[uidNum]);
JP Abgrall26e0d492011-06-24 19:21:51 -0700334 goto fail_parse;
335 }
336 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700337
338 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700339 int uid = appUids[uidNum];
340 for (it = naughtyAppUids.begin(); it != naughtyAppUids.end(); it++) {
341 if (*it == uid)
342 break;
343 }
344 bool found = (it != naughtyAppUids.end());
345
346 if (appOp == NaughtyAppOpRemove) {
347 if (!found) {
348 ALOGE("No such appUid %d to remove", uid);
349 return -1;
350 }
351 naughtyAppUids.erase(it);
352 } else {
353 if (found) {
354 ALOGE("appUid %d exists already", uid);
355 return -1;
356 }
357 naughtyAppUids.push_front(uid);
358 }
359
360 naughtyCmd = makeIptablesNaughtyCmd(op, uid);
JP Abgrall26e0d492011-06-24 19:21:51 -0700361 if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700362 ALOGE(failLogTemplate, uid);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700363 goto fail_with_uidNum;
364 }
365 }
366 return 0;
367
JP Abgrall26e0d492011-06-24 19:21:51 -0700368fail_with_uidNum:
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700369 /* Try to remove the uid that failed in any case*/
JP Abgrall26e0d492011-06-24 19:21:51 -0700370 naughtyCmd = makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]);
371 runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd);
372fail_parse:
373 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700374}
375
JP Abgrall26e0d492011-06-24 19:21:51 -0700376std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700377 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700378 char *buff;
379 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700380
Steve Block3fb42e02011-10-20 11:55:56 +0100381 ALOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700382
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700383 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700384 case IptOpInsert:
385 opFlag = "-I";
386 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800387 case IptOpAppend:
388 opFlag = "-A";
389 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700390 case IptOpReplace:
391 opFlag = "-R";
392 break;
393 default:
394 case IptOpDelete:
395 opFlag = "-D";
396 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700397 }
JP Abgrall8a932722011-07-13 19:17:35 -0700398
JP Abgrallbfa74662011-06-29 19:23:04 -0700399 // The requried IP version specific --jump REJECT ... will be added later.
JP Abgrall8a932722011-07-13 19:17:35 -0700400 asprintf(&buff, "%s costly_%s -m quota2 ! --quota %lld --name %s", opFlag, costName, quota,
401 costName);
402 res = buff;
403 free(buff);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700404 return res;
405}
406
JP Abgrall26e0d492011-06-24 19:21:51 -0700407int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700408 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700409 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700410 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700411 std::string costString;
412 const char *costCString;
413
JP Abgrall0dad7c22011-06-24 11:58:14 -0700414 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700415 switch (quotaType) {
416 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700417 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700418 costString += ifn;
419 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700420 /*
421 * Flush the costly_<iface> is allowed to fail in case it didn't exist.
422 * Creating a new one is allowed to fail in case it existed.
423 * This helps with netd restarts.
424 */
425 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700426 res1 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700427 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700428 res2 = runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700429 res = (res1 && res2) || (!res1 && !res2);
430
JP Abgrall0dad7c22011-06-24 11:58:14 -0700431 snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700432 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700433 break;
434 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700435 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700436 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700437 default:
438 ALOGE("Unexpected quotatype %d", quotaType);
439 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700440 }
441
JP Abgrall8a932722011-07-13 19:17:35 -0700442 if (globalAlertBytes) {
443 /* The alert rule comes 1st */
444 ruleInsertPos = 2;
445 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700446
447 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700448 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700449
450 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700451 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700452
453 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrallad729ac2012-04-24 23:27:44 -0700454 runIpxtablesCmd(cmd, IptRejectNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700455
456 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700457 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700458 return res;
459}
460
JP Abgrall26e0d492011-06-24 19:21:51 -0700461int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700462 char cmd[MAX_CMD_LEN];
463 int res = 0;
464 std::string costString;
465 const char *costCString;
466
JP Abgrall26e0d492011-06-24 19:21:51 -0700467 switch (quotaType) {
468 case QuotaUnique:
JP Abgrallbfa74662011-06-29 19:23:04 -0700469 costString = "costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700470 costString += ifn;
471 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700472 break;
473 case QuotaShared:
JP Abgrallbfa74662011-06-29 19:23:04 -0700474 costCString = "costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700475 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700476 default:
477 ALOGE("Unexpected quotatype %d", quotaType);
478 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700479 }
480
JP Abgrall0031cea2012-04-17 16:38:23 -0700481 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700482 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700483 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700484 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700485
JP Abgrallbfa74662011-06-29 19:23:04 -0700486 /* The "-N costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700487 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700488 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgrall26e0d492011-06-24 19:21:51 -0700489 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700490 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
491 res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700492 }
493 return res;
494}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700495
JP Abgrall0dad7c22011-06-24 11:58:14 -0700496int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700497 char cmd[MAX_CMD_LEN];
498 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700499 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700500 std::string quotaCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700501 std::string ifaceName;
502 ;
JP Abgrallbfa74662011-06-29 19:23:04 -0700503 const char *costName = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700504 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700505
JP Abgrall8a932722011-07-13 19:17:35 -0700506 if (!maxBytes) {
507 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000508 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700509 return -1;
510 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700511 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000512 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700513 return -1;
514 }
515 ifaceName = ifn;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700516
517 if (maxBytes == -1) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700518 return removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700519 }
520
521 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700522 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
523 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700524 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700525 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700526
JP Abgrall0dad7c22011-06-24 11:58:14 -0700527 if (it == sharedQuotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700528 res |= prepCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700529 if (sharedQuotaIfaces.empty()) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700530 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700531 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700532 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000533 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700534 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700535 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700536 sharedQuotaBytes = maxBytes;
537 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700538 sharedQuotaIfaces.push_front(ifaceName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700539
540 }
541
542 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700543 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700544 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000545 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700546 goto fail;
547 }
548 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700549 }
550 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700551
552 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700553 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700554 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
555 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700556 * For now callers needs to choose if they want to "ndc bandwidth enable"
557 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700558 */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700559 removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700560 return -1;
561}
562
JP Abgrall8a932722011-07-13 19:17:35 -0700563/* It will also cleanup any shared alerts */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700564int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700565 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700566 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700567 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700568 std::list<std::string>::iterator it;
JP Abgrallbfa74662011-06-29 19:23:04 -0700569 const char *costName = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700570
JP Abgrall8a932722011-07-13 19:17:35 -0700571 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000572 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700573 return -1;
574 }
JP Abgrall8a932722011-07-13 19:17:35 -0700575 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700576
JP Abgrall0dad7c22011-06-24 11:58:14 -0700577 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
578 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700579 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700580 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700581 if (it == sharedQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000582 ALOGE("No such iface %s to delete", ifn);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700583 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700584 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700585
JP Abgrall26e0d492011-06-24 19:21:51 -0700586 res |= cleanupCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700587 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700588
JP Abgrall0dad7c22011-06-24 11:58:14 -0700589 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700590 std::string quotaCmd;
JP Abgrallbfa74662011-06-29 19:23:04 -0700591 quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700592 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700593 sharedQuotaBytes = 0;
594 if (sharedAlertBytes) {
595 removeSharedAlert();
596 sharedAlertBytes = 0;
597 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700598 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700599 return res;
600}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700601
602int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
603 char ifn[MAX_IFACENAME_LEN];
604 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700605 std::string ifaceName;
606 const char *costName;
607 std::list<QuotaInfo>::iterator it;
608 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700609
JP Abgrall8a932722011-07-13 19:17:35 -0700610 if (!maxBytes) {
611 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000612 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700613 return -1;
614 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700615 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700616 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700617 }
618
JP Abgrall8a932722011-07-13 19:17:35 -0700619 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000620 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700621 return -1;
622 }
623 ifaceName = ifn;
624 costName = iface;
625
JP Abgrall0dad7c22011-06-24 11:58:14 -0700626 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700627 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700628 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700629 break;
630 }
631
632 if (it == quotaIfaces.end()) {
JP Abgrall109899b2013-02-12 19:20:13 -0800633 /* Preparing the iface adds a penalty_box check */
JP Abgrall26e0d492011-06-24 19:21:51 -0700634 res |= prepCostlyIface(ifn, QuotaUnique);
JP Abgrall109899b2013-02-12 19:20:13 -0800635 /*
636 * The rejecting quota limit should go after the penalty box checks
637 * or else a naughty app could just eat up the quota.
638 * So we append here.
639 */
640 quotaCmd = makeIptablesQuotaCmd(IptOpAppend, costName, maxBytes);
JP Abgrall26e0d492011-06-24 19:21:51 -0700641 res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700642 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000643 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700644 goto fail;
645 }
646
JP Abgrall8a932722011-07-13 19:17:35 -0700647 quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700648
649 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700650 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700651 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000652 ALOGE("Failed update quota for %s", iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700653 goto fail;
654 }
JP Abgrall8a932722011-07-13 19:17:35 -0700655 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700656 }
657 return 0;
658
659 fail:
660 /*
661 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
662 * rules in the kernel to see which ones need cleaning up.
663 * For now callers needs to choose if they want to "ndc bandwidth enable"
664 * which resets everything.
665 */
666 removeInterfaceSharedQuota(ifn);
667 return -1;
668}
669
JP Abgrall8a932722011-07-13 19:17:35 -0700670int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
671 return getInterfaceQuota("shared", bytes);
672}
673
674int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
675 FILE *fp;
676 char *fname;
677 int scanRes;
678
679 asprintf(&fname, "/proc/net/xt_quota/%s", costName);
680 fp = fopen(fname, "r");
681 free(fname);
682 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000683 ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700684 return -1;
685 }
686 scanRes = fscanf(fp, "%lld", bytes);
Steve Block3fb42e02011-10-20 11:55:56 +0100687 ALOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700688 fclose(fp);
689 return scanRes == 1 ? 0 : -1;
690}
691
JP Abgrall0dad7c22011-06-24 11:58:14 -0700692int BandwidthController::removeInterfaceQuota(const char *iface) {
693
694 char ifn[MAX_IFACENAME_LEN];
695 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700696 std::string ifaceName;
697 const char *costName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700698 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700699
JP Abgrall8a932722011-07-13 19:17:35 -0700700 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000701 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700702 return -1;
703 }
704 ifaceName = ifn;
705 costName = iface;
706
JP Abgrall0dad7c22011-06-24 11:58:14 -0700707 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700708 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700709 break;
710 }
711
712 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000713 ALOGE("No such iface %s to delete", ifn);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700714 return -1;
715 }
716
717 /* This also removes the quota command of CostlyIface chain. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700718 res |= cleanupCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700719
720 quotaIfaces.erase(it);
721
722 return res;
723}
JP Abgrall8a932722011-07-13 19:17:35 -0700724
725int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
726 FILE *fp;
727 char *fname;
728
729 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
730 fp = fopen(fname, "w");
731 free(fname);
732 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000733 ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700734 return -1;
735 }
736 fprintf(fp, "%lld\n", bytes);
737 fclose(fp);
738 return 0;
739}
740
741int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
742 int res = 0;
743 const char *opFlag;
744 char *alertQuotaCmd;
745
746 switch (op) {
747 case IptOpInsert:
748 opFlag = "-I";
749 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800750 case IptOpAppend:
751 opFlag = "-A";
752 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700753 case IptOpReplace:
754 opFlag = "-R";
755 break;
756 default:
757 case IptOpDelete:
758 opFlag = "-D";
759 break;
760 }
761
JP Abgrall92009c82013-02-06 18:01:24 -0800762 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800763 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700764 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
765 free(alertQuotaCmd);
JP Abgrall92009c82013-02-06 18:01:24 -0800766 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800767 bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700768 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
769 free(alertQuotaCmd);
770 return res;
771}
772
JP Abgrallc6c67342011-10-07 16:28:54 -0700773int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
774 int res = 0;
775 const char *opFlag;
JP Abgrall8a932722011-07-13 19:17:35 -0700776 char *alertQuotaCmd;
JP Abgrallc6c67342011-10-07 16:28:54 -0700777
778 switch (op) {
779 case IptOpInsert:
780 opFlag = "-I";
781 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800782 case IptOpAppend:
783 opFlag = "-A";
784 break;
JP Abgrallc6c67342011-10-07 16:28:54 -0700785 case IptOpReplace:
786 opFlag = "-R";
787 break;
788 default:
789 case IptOpDelete:
790 opFlag = "-D";
791 break;
792 }
793
JP Abgrall92009c82013-02-06 18:01:24 -0800794 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800795 bytes, alertName);
JP Abgrallc6c67342011-10-07 16:28:54 -0700796 res = runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
797 free(alertQuotaCmd);
798 return res;
799}
800
801int BandwidthController::setGlobalAlert(int64_t bytes) {
802 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700803 int res = 0;
804
805 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000806 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700807 return -1;
808 }
809 if (globalAlertBytes) {
810 res = updateQuota(alertName, bytes);
811 } else {
812 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700813 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +0100814 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700815 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
816 }
JP Abgrall8a932722011-07-13 19:17:35 -0700817 }
818 globalAlertBytes = bytes;
819 return res;
820}
821
JP Abgrallc6c67342011-10-07 16:28:54 -0700822int BandwidthController::setGlobalAlertInForwardChain(void) {
823 const char *alertName = ALERT_GLOBAL_NAME;
824 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700825
JP Abgrallc6c67342011-10-07 16:28:54 -0700826 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +0100827 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700828
829 /*
830 * If there is no globalAlert active we are done.
831 * If there is an active globalAlert but this is not the 1st
832 * tether, we are also done.
833 */
834 if (!globalAlertBytes || globalAlertTetherCount != 1) {
835 return 0;
836 }
837
838 /* We only add the rule if this was the 1st tether added. */
839 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
840 return res;
841}
842
843int BandwidthController::removeGlobalAlert(void) {
844
845 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700846 int res = 0;
847
848 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000849 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700850 return -1;
851 }
852 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700853 if (globalAlertTetherCount) {
854 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
855 }
JP Abgrall8a932722011-07-13 19:17:35 -0700856 globalAlertBytes = 0;
857 return res;
858}
859
JP Abgrallc6c67342011-10-07 16:28:54 -0700860int BandwidthController::removeGlobalAlertInForwardChain(void) {
861 int res = 0;
862 const char *alertName = ALERT_GLOBAL_NAME;
863
864 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000865 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700866 return -1;
867 }
868
869 globalAlertTetherCount--;
870 /*
871 * If there is no globalAlert active we are done.
872 * If there is an active globalAlert but there are more
873 * tethers, we are also done.
874 */
875 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
876 return 0;
877 }
878
879 /* We only detete the rule if this was the last tether removed. */
880 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
881 return res;
882}
883
JP Abgrall8a932722011-07-13 19:17:35 -0700884int BandwidthController::setSharedAlert(int64_t bytes) {
885 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000886 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700887 return -1;
888 }
889 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000890 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700891 return -1;
892 }
893 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
894}
895
896int BandwidthController::removeSharedAlert(void) {
897 return removeCostlyAlert("shared", &sharedAlertBytes);
898}
899
900int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
901 std::list<QuotaInfo>::iterator it;
902
903 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000904 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700905 return -1;
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("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700914 return -1;
915 }
916
917 return setCostlyAlert(iface, bytes, &it->alert);
918}
919
920int BandwidthController::removeInterfaceAlert(const char *iface) {
921 std::list<QuotaInfo>::iterator it;
922
923 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
924 if (it->ifaceName == iface)
925 break;
926 }
927
928 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000929 ALOGE("No prior alert set for interface %s", iface);
JP Abgrall8a932722011-07-13 19:17:35 -0700930 return -1;
931 }
932
933 return removeCostlyAlert(iface, &it->alert);
934}
935
936int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
937 char *alertQuotaCmd;
JP Abgrall109899b2013-02-12 19:20:13 -0800938 char *chainName;
JP Abgrall8a932722011-07-13 19:17:35 -0700939 int res = 0;
940 char *alertName;
941
942 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000943 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700944 return -1;
945 }
946 asprintf(&alertName, "%sAlert", costName);
947 if (*alertBytes) {
948 res = updateQuota(alertName, *alertBytes);
949 } else {
JP Abgrall109899b2013-02-12 19:20:13 -0800950 asprintf(&chainName, "costly_%s", costName);
951 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-A", chainName, bytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700952 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
953 free(alertQuotaCmd);
JP Abgrall109899b2013-02-12 19:20:13 -0800954 free(chainName);
JP Abgrall8a932722011-07-13 19:17:35 -0700955 }
956 *alertBytes = bytes;
957 free(alertName);
958 return res;
959}
960
961int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
962 char *alertQuotaCmd;
963 char *chainName;
964 char *alertName;
965 int res = 0;
966
967 asprintf(&alertName, "%sAlert", costName);
968 if (!*alertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000969 ALOGE("No prior alert set for %s alert", costName);
JP Abgrall8a932722011-07-13 19:17:35 -0700970 return -1;
971 }
972
973 asprintf(&chainName, "costly_%s", costName);
JP Abgrall92009c82013-02-06 18:01:24 -0800974 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName);
JP Abgrall8a932722011-07-13 19:17:35 -0700975 res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
976 free(alertQuotaCmd);
977 free(chainName);
978
979 *alertBytes = 0;
980 free(alertName);
981 return res;
982}
JP Abgralldb7da582011-09-18 12:57:32 -0700983
984/*
985 * Parse the ptks and bytes out of:
JP Abgrall0031cea2012-04-17 16:38:23 -0700986 * Chain FORWARD (policy RETURN 0 packets, 0 bytes)
JP Abgralldb7da582011-09-18 12:57:32 -0700987 * pkts bytes target prot opt in out source destination
JP Abgrall0031cea2012-04-17 16:38:23 -0700988 * 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 -0700989 * 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 -0700990 * 0 0 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
JP Abgralldb7da582011-09-18 12:57:32 -0700991 *
992 */
JP Abgralla2a64f02011-11-11 20:36:16 -0800993int BandwidthController::parseForwardChainStats(TetherStats &stats, FILE *fp,
994 std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -0700995 int res;
996 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
997 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
998 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
999 char rest[MAX_IPT_OUTPUT_LINE_LEN];
1000
1001 char *buffPtr;
1002 int64_t packets, bytes;
1003
1004 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1005 /* Clean up, so a failed parse can still print info */
1006 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
JP Abgrall0031cea2012-04-17 16:38:23 -07001007 res = sscanf(buffPtr, "%lld %lld RETURN all -- %s %s 0.%s",
JP Abgralldb7da582011-09-18 12:57:32 -07001008 &packets, &bytes, iface0, iface1, rest);
Steve Block3fb42e02011-10-20 11:55:56 +01001009 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 -07001010 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -08001011 extraProcessingInfo += buffPtr;
1012
JP Abgralldb7da582011-09-18 12:57:32 -07001013 if (res != 5) {
1014 continue;
1015 }
1016 if ((stats.ifaceIn == iface0) && (stats.ifaceOut == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001017 ALOGV("iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001018 stats.rxPackets = packets;
1019 stats.rxBytes = bytes;
1020 } else if ((stats.ifaceOut == iface0) && (stats.ifaceIn == iface1)) {
Steve Block3fb42e02011-10-20 11:55:56 +01001021 ALOGV("iface_in=%s iface_out=%s tx_bytes=%lld tx_packets=%lld ", iface1, iface0, bytes, packets);
JP Abgralldb7da582011-09-18 12:57:32 -07001022 stats.txPackets = packets;
1023 stats.txBytes = bytes;
1024 }
1025 }
1026 /* Failure if rx or tx was not found */
1027 return (stats.rxBytes == -1 || stats.txBytes == -1) ? -1 : 0;
1028}
1029
1030
1031char *BandwidthController::TetherStats::getStatsLine(void) {
1032 char *msg;
1033 asprintf(&msg, "%s %s %lld %lld %lld %lld", ifaceIn.c_str(), ifaceOut.c_str(),
1034 rxBytes, rxPackets, txBytes, txPackets);
1035 return msg;
1036}
1037
JP Abgralla2a64f02011-11-11 20:36:16 -08001038int BandwidthController::getTetherStats(TetherStats &stats, std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001039 int res;
1040 std::string fullCmd;
1041 FILE *iptOutput;
1042 const char *cmd;
1043
1044 if (stats.rxBytes != -1 || stats.txBytes != -1) {
Steve Block5ea0c052012-01-06 19:18:11 +00001045 ALOGE("Unexpected input stats. Byte counts should be -1.");
JP Abgralldb7da582011-09-18 12:57:32 -07001046 return -1;
1047 }
1048
1049 /*
1050 * Why not use some kind of lib to talk to iptables?
1051 * Because the only libs are libiptc and libip6tc in iptables, and they are
1052 * not easy to use. They require the known iptables match modules to be
1053 * preloaded/linked, and require apparently a lot of wrapper code to get
1054 * the wanted info.
1055 */
1056 fullCmd = IPTABLES_PATH;
JP Abgrall0031cea2012-04-17 16:38:23 -07001057 fullCmd += " -nvx -L natctrl_FORWARD";
JP Abgralldb7da582011-09-18 12:57:32 -07001058 iptOutput = popen(fullCmd.c_str(), "r");
1059 if (!iptOutput) {
Steve Block5ea0c052012-01-06 19:18:11 +00001060 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
JP Abgralla2a64f02011-11-11 20:36:16 -08001061 extraProcessingInfo += "Failed to run iptables.";
JP Abgralldb7da582011-09-18 12:57:32 -07001062 return -1;
1063 }
JP Abgralla2a64f02011-11-11 20:36:16 -08001064 res = parseForwardChainStats(stats, iptOutput, extraProcessingInfo);
JP Abgralldb7da582011-09-18 12:57:32 -07001065 pclose(iptOutput);
1066
1067 /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1068 return res;
1069}