blob: 972691a6c3942b5d4dc4bb0b77e368cc79c940de [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 Abgralle4788732013-07-02 20:28:45 -070017// #define LOG_NDEBUG 0
JP Abgralldb7da582011-09-18 12:57:32 -070018
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
Joel Scherpelzdd5d2192017-06-16 10:45:14 +090025#include <ctype.h>
JP Abgrall8a932722011-07-13 19:17:35 -070026#include <errno.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070027#include <fcntl.h>
JP Abgralldb7da582011-09-18 12:57:32 -070028#include <stdio.h>
JP Abgrall8a932722011-07-13 19:17:35 -070029#include <stdlib.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070030#include <string.h>
Joel Scherpelzdd5d2192017-06-16 10:45:14 +090031#include <string>
32#include <vector>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070033
Matthew Leach2a54d962013-01-14 15:07:12 +000034#define __STDC_FORMAT_MACROS 1
35#include <inttypes.h>
36
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070037#include <sys/socket.h>
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <sys/wait.h>
41
42#include <linux/netlink.h>
43#include <linux/rtnetlink.h>
44#include <linux/pkt_sched.h>
45
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090046#include "android-base/stringprintf.h"
Lorenzo Colitti13debb82016-03-27 17:46:30 +090047#include "android-base/strings.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070048#define LOG_TAG "BandwidthController"
49#include <cutils/log.h>
50#include <cutils/properties.h>
Rom Lemarchand14150212013-01-24 10:01:04 -080051#include <logwrap/logwrap.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070052
Joel Scherpelzdd5d2192017-06-16 10:45:14 +090053#include <netdutils/Syscalls.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070054#include "BandwidthController.h"
Joel Scherpelzdd5d2192017-06-16 10:45:14 +090055#include "NatController.h" /* For LOCAL_TETHER_COUNTERS_CHAIN */
56#include "NetdConstants.h"
JP Abgrallbaeccc42013-06-25 09:44:10 -070057#include "ResponseCode.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070058
JP Abgralldb7da582011-09-18 12:57:32 -070059/* Alphabetical */
Lorenzo Colitti3c272702017-04-26 15:48:13 +090060#define ALERT_IPT_TEMPLATE "%s %s -m quota2 ! --quota %" PRId64" --name %s\n"
Joel Scherpelzbcad6612017-05-30 10:55:11 +090061const char BandwidthController::LOCAL_INPUT[] = "bw_INPUT";
62const char BandwidthController::LOCAL_FORWARD[] = "bw_FORWARD";
63const char BandwidthController::LOCAL_OUTPUT[] = "bw_OUTPUT";
64const char BandwidthController::LOCAL_RAW_PREROUTING[] = "bw_raw_PREROUTING";
65const char BandwidthController::LOCAL_MANGLE_POSTROUTING[] = "bw_mangle_POSTROUTING";
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090066
Lorenzo Colitti86a47982016-03-18 17:52:25 +090067auto BandwidthController::execFunction = android_fork_execvp;
68auto BandwidthController::popenFunction = popen;
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +090069auto BandwidthController::iptablesRestoreFunction = execIptablesRestoreWithOutput;
Lorenzo Colitti86a47982016-03-18 17:52:25 +090070
Joel Scherpelz001ecad2017-06-28 16:24:09 +090071using android::base::Join;
Lorenzo Colitti3c272702017-04-26 15:48:13 +090072using android::base::StringAppendF;
73using android::base::StringPrintf;
Joel Scherpelzdd5d2192017-06-16 10:45:14 +090074using android::netdutils::StatusOr;
75using android::netdutils::UniqueFile;
Lorenzo Colitti3c272702017-04-26 15:48:13 +090076
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090077namespace {
78
79const char ALERT_GLOBAL_NAME[] = "globalAlert";
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +090080const int MAX_IPT_OUTPUT_LINE_LEN = 256;
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +090081const std::string NEW_CHAIN_COMMAND = "-N ";
Lorenzo Colitti3c272702017-04-26 15:48:13 +090082const std::string GET_TETHER_STATS_COMMAND = StringPrintf(
Lorenzo Colittice6748a2017-02-02 01:34:33 +090083 "*filter\n"
84 "-nvx -L %s\n"
85 "COMMIT\n", NatController::LOCAL_TETHER_COUNTERS_CHAIN);
86
Joel Scherpelzbcad6612017-05-30 10:55:11 +090087const char NAUGHTY_CHAIN[] = "bw_penalty_box";
88const char NICE_CHAIN[] = "bw_happy_box";
JP Abgralldb7da582011-09-18 12:57:32 -070089
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070090/**
91 * Some comments about the rules:
92 * * Ordering
93 * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
JP Abgrall29e8de22012-05-03 12:52:15 -070094 * E.g. "-I bw_INPUT -i rmnet0 --jump costly"
JP Abgrall7e51cde2013-07-03 13:33:05 -070095 * - quota'd rules in the costly chain should be before bw_penalty_box lookups.
JP Abgrall29e8de22012-05-03 12:52:15 -070096 * - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070097 *
98 * * global quota vs per interface quota
99 * - global quota for all costly interfaces uses a single costly chain:
100 * . initial rules
JP Abgrall7e51cde2013-07-03 13:33:05 -0700101 * iptables -N bw_costly_shared
102 * iptables -I bw_INPUT -i iface0 --jump bw_costly_shared
103 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_shared
104 * iptables -I bw_costly_shared -m quota \! --quota 500000 \
JP Abgrallbfa74662011-06-29 19:23:04 -0700105 * --jump REJECT --reject-with icmp-net-prohibited
JP Abgrall7e51cde2013-07-03 13:33:05 -0700106 * iptables -A bw_costly_shared --jump bw_penalty_box
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900107 * iptables -A bw_penalty_box --jump bw_happy_box
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900108 * iptables -A bw_happy_box --jump bw_data_saver
JP Abgrall8a932722011-07-13 19:17:35 -0700109 *
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700110 * . adding a new iface to this, E.g.:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700111 * iptables -I bw_INPUT -i iface1 --jump bw_costly_shared
112 * iptables -I bw_OUTPUT -o iface1 --jump bw_costly_shared
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700113 *
114 * - quota per interface. This is achieve by having "costly" chains per quota.
115 * E.g. adding a new costly interface iface0 with its own quota:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700116 * iptables -N bw_costly_iface0
117 * iptables -I bw_INPUT -i iface0 --jump bw_costly_iface0
118 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_iface0
119 * iptables -A bw_costly_iface0 -m quota \! --quota 500000 \
JP Abgralle4788732013-07-02 20:28:45 -0700120 * --jump REJECT --reject-with icmp-port-unreachable
JP Abgrall7e51cde2013-07-03 13:33:05 -0700121 * iptables -A bw_costly_iface0 --jump bw_penalty_box
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700122 *
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900123 * * Penalty box, happy box and data saver.
124 * - bw_penalty box is a blacklist of apps that are rejected.
125 * - bw_happy_box is a whitelist of apps. It always includes all system apps
126 * - bw_data_saver implements data usage restrictions.
127 * - Via the UI the user can add and remove apps from the whitelist and
128 * blacklist, and turn on/off data saver.
129 * - The blacklist takes precedence over the whitelist and the whitelist
130 * takes precedence over data saver.
131 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700132 * * bw_penalty_box handling:
133 * - only one bw_penalty_box for all interfaces
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900134 * E.g Adding an app:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700135 * iptables -I bw_penalty_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700136 * --jump REJECT --reject-with icmp-port-unreachable
137 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700138 * * bw_happy_box handling:
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900139 * - The bw_happy_box comes after the penalty box.
JP Abgralle4788732013-07-02 20:28:45 -0700140 * E.g Adding a happy app,
JP Abgrall7e51cde2013-07-03 13:33:05 -0700141 * iptables -I bw_happy_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700142 * --jump RETURN
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900143 *
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900144 * * bw_data_saver handling:
145 * - The bw_data_saver comes after the happy box.
146 * Enable data saver:
147 * iptables -R 1 bw_data_saver --jump REJECT --reject-with icmp-port-unreachable
148 * Disable data saver:
149 * iptables -R 1 bw_data_saver --jump RETURN
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700150 */
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900151
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900152const std::string COMMIT_AND_CLOSE = "COMMIT\n";
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900153const std::string HAPPY_BOX_WHITELIST_COMMAND = StringPrintf(
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900154 "-I bw_happy_box -m owner --uid-owner %d-%d --jump RETURN", 0, MAX_SYSTEM_UID);
155
156static const std::vector<std::string> IPT_FLUSH_COMMANDS = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700157 /*
158 * Cleanup rules.
JP Abgrall7e51cde2013-07-03 13:33:05 -0700159 * Should normally include bw_costly_<iface>, but we rely on the way they are setup
JP Abgrall0031cea2012-04-17 16:38:23 -0700160 * to allow coexistance.
JP Abgrall39f8f242011-06-29 19:21:58 -0700161 */
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900162 "*filter",
163 ":bw_INPUT -",
164 ":bw_OUTPUT -",
165 ":bw_FORWARD -",
166 ":bw_happy_box -",
167 ":bw_penalty_box -",
168 ":bw_data_saver -",
169 ":bw_costly_shared -",
170 "COMMIT",
171 "*raw",
172 ":bw_raw_PREROUTING -",
173 "COMMIT",
174 "*mangle",
175 ":bw_mangle_POSTROUTING -",
176 COMMIT_AND_CLOSE
JP Abgrall0031cea2012-04-17 16:38:23 -0700177};
178
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900179static const std::vector<std::string> IPT_BASIC_ACCOUNTING_COMMANDS = {
180 "*filter",
JP Abgrall0031cea2012-04-17 16:38:23 -0700181 "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0031cea2012-04-17 16:38:23 -0700182 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900183 "-A bw_costly_shared --jump bw_penalty_box",
Lorenzo Colitti464eabe2016-03-25 13:38:19 +0900184 "-A bw_penalty_box --jump bw_happy_box",
185 "-A bw_happy_box --jump bw_data_saver",
186 "-A bw_data_saver -j RETURN",
Lorenzo Colitti13debb82016-03-27 17:46:30 +0900187 HAPPY_BOX_WHITELIST_COMMAND,
188 "COMMIT",
189
190 "*raw",
191 "-A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
192 "COMMIT",
193
194 "*mangle",
195 "-A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
196 COMMIT_AND_CLOSE
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900197};
198
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900199std::vector<std::string> toStrVec(int num, char* strs[]) {
200 std::vector<std::string> tmp;
201 for (int i = 0; i < num; ++i) {
202 tmp.emplace_back(strs[i]);
203 }
204 return tmp;
205}
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900206
207} // namespace
208
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900209BandwidthController::BandwidthController() {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700210}
211
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900212int BandwidthController::StrncpyAndCheck(char* buffer, const std::string& src, size_t buffSize) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700213 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900214 strncpy(buffer, src.c_str(), buffSize);
JP Abgrall26e0d492011-06-24 19:21:51 -0700215 return buffer[buffSize - 1];
216}
217
JP Abgrall0e540ec2013-08-26 15:13:10 -0700218void BandwidthController::flushCleanTables(bool doClean) {
219 /* Flush and remove the bw_costly_<iface> tables */
220 flushExistingCostlyTables(doClean);
JP Abgrall0031cea2012-04-17 16:38:23 -0700221
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900222 std::string commands = Join(IPT_FLUSH_COMMANDS, '\n');
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900223 iptablesRestoreFunction(V4V6, commands, nullptr);
JP Abgrall0e540ec2013-08-26 15:13:10 -0700224}
JP Abgrall0031cea2012-04-17 16:38:23 -0700225
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900226int BandwidthController::setupIptablesHooks() {
JP Abgrall0e540ec2013-08-26 15:13:10 -0700227 /* flush+clean is allowed to fail */
228 flushCleanTables(true);
JP Abgrall0031cea2012-04-17 16:38:23 -0700229 return 0;
JP Abgrall0031cea2012-04-17 16:38:23 -0700230}
231
232int BandwidthController::enableBandwidthControl(bool force) {
JP Abgrall0031cea2012-04-17 16:38:23 -0700233 char value[PROPERTY_VALUE_MAX];
234
235 if (!force) {
236 property_get("persist.bandwidth.enable", value, "1");
237 if (!strcmp(value, "0"))
238 return 0;
239 }
JP Abgrall8a932722011-07-13 19:17:35 -0700240
JP Abgralldb7da582011-09-18 12:57:32 -0700241 /* Let's pretend we started from scratch ... */
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900242 mSharedQuotaIfaces.clear();
243 mQuotaIfaces.clear();
244 mGlobalAlertBytes = 0;
245 mGlobalAlertTetherCount = 0;
246 mSharedQuotaBytes = mSharedAlertBytes = 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700247
JP Abgrall0e540ec2013-08-26 15:13:10 -0700248 flushCleanTables(false);
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900249 std::string commands = Join(IPT_BASIC_ACCOUNTING_COMMANDS, '\n');
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900250 return iptablesRestoreFunction(V4V6, commands, nullptr);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700251}
252
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900253int BandwidthController::disableBandwidthControl() {
JP Abgrall0e540ec2013-08-26 15:13:10 -0700254
255 flushCleanTables(false);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700256 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700257}
258
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900259int BandwidthController::enableDataSaver(bool enable) {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900260 std::string cmd = StringPrintf(
261 "*filter\n"
262 "-R bw_data_saver 1%s\n"
263 "COMMIT\n", jumpToString(enable ? IptJumpReject : IptJumpReturn));
264 return iptablesRestoreFunction(V4V6, cmd, nullptr);
Lorenzo Colitti7618ccb2016-03-18 12:36:03 +0900265}
266
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700267int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900268 return manipulateSpecialApps(toStrVec(numUids, appUids), NAUGHTY_CHAIN,
269 IptJumpReject, IptOpInsert);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700270}
271
272int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900273 return manipulateSpecialApps(toStrVec(numUids, appUids), NAUGHTY_CHAIN,
274 IptJumpReject, IptOpDelete);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700275}
276
JP Abgralle4788732013-07-02 20:28:45 -0700277int BandwidthController::addNiceApps(int numUids, char *appUids[]) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900278 return manipulateSpecialApps(toStrVec(numUids, appUids), NICE_CHAIN,
279 IptJumpReturn, IptOpInsert);
JP Abgralle4788732013-07-02 20:28:45 -0700280}
281
282int BandwidthController::removeNiceApps(int numUids, char *appUids[]) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900283 return manipulateSpecialApps(toStrVec(numUids, appUids), NICE_CHAIN,
284 IptJumpReturn, IptOpDelete);
JP Abgralle4788732013-07-02 20:28:45 -0700285}
286
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900287int BandwidthController::manipulateSpecialApps(const std::vector<std::string>& appStrUids,
288 const std::string& chain, IptJumpOp jumpHandling,
289 IptOp op) {
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900290 std::string cmd = "*filter\n";
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900291 for (const auto& appStrUid : appStrUids) {
292 StringAppendF(&cmd, "%s %s -m owner --uid-owner %s%s\n", opToString(op), chain.c_str(),
293 appStrUid.c_str(), jumpToString(jumpHandling));
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700294 }
Lorenzo Colitti911bc4c2017-04-28 14:34:01 +0900295 StringAppendF(&cmd, "COMMIT\n");
296 return iptablesRestoreFunction(V4V6, cmd, nullptr);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700297}
298
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900299int BandwidthController::setInterfaceSharedQuota(const std::string& iface, int64_t maxBytes) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700300 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700301 std::string quotaCmd;
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900302 constexpr char cost[] = "shared";
303 constexpr char chain[] = "bw_costly_shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700304
JP Abgrall8a932722011-07-13 19:17:35 -0700305 if (!maxBytes) {
306 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000307 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700308 return -1;
309 }
JP Abgrall69261cb2014-06-19 18:35:24 -0700310 if (!isIfaceName(iface))
311 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700312
313 if (maxBytes == -1) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900314 return removeInterfaceSharedQuota(iface);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700315 }
316
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900317 auto it = mSharedQuotaIfaces.find(iface);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700318
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900319 if (it == mSharedQuotaIfaces.end()) {
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900320 const int ruleInsertPos = (mGlobalAlertBytes) ? 2 : 1;
321 std::vector<std::string> cmds = {
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900322 "*filter",
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900323 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, iface.c_str(), chain),
324 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, iface.c_str(), chain),
325 StringPrintf("-A bw_FORWARD -o %s --jump %s", iface.c_str(), chain),
326 };
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900327 if (mSharedQuotaIfaces.empty()) {
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900328 cmds.push_back(StringPrintf("-I %s -m quota2 ! --quota %" PRId64
329 " --name %s --jump REJECT",
330 chain, maxBytes, cost));
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900331 }
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900332 cmds.push_back("COMMIT\n");
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900333
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900334 res |= iptablesRestoreFunction(V4V6, Join(cmds, "\n"), nullptr);
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900335 if (res) {
336 ALOGE("Failed set quota rule");
337 removeInterfaceSharedQuota(iface);
338 return -1;
339 }
340 mSharedQuotaBytes = maxBytes;
341 mSharedQuotaIfaces.insert(iface);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700342 }
343
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900344 if (maxBytes != mSharedQuotaBytes) {
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900345 res |= updateQuota(cost, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700346 if (res) {
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900347 ALOGE("Failed update quota for %s", cost);
348 removeInterfaceSharedQuota(iface);
349 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700350 }
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900351 mSharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700352 }
353 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700354}
355
JP Abgrall8a932722011-07-13 19:17:35 -0700356/* It will also cleanup any shared alerts */
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900357int BandwidthController::removeInterfaceSharedQuota(const std::string& iface) {
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900358 constexpr char cost[] = "shared";
359 constexpr char chain[] = "bw_costly_shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700360
JP Abgrall69261cb2014-06-19 18:35:24 -0700361 if (!isIfaceName(iface))
362 return -1;
JP Abgrall26e0d492011-06-24 19:21:51 -0700363
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900364 auto it = mSharedQuotaIfaces.find(iface);
365
366 if (it == mSharedQuotaIfaces.end()) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900367 ALOGE("No such iface %s to delete", iface.c_str());
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700368 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700369 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700370
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900371 std::vector<std::string> cmds = {
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900372 "*filter",
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900373 StringPrintf("-D bw_INPUT -i %s --jump %s", iface.c_str(), chain),
374 StringPrintf("-D bw_OUTPUT -o %s --jump %s", iface.c_str(), chain),
375 StringPrintf("-D bw_FORWARD -o %s --jump %s", iface.c_str(), chain),
376 };
Lorenzo Colitti25616062017-07-06 16:52:52 +0900377 if (mSharedQuotaIfaces.size() == 1) {
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900378 cmds.push_back(StringPrintf("-D %s -m quota2 ! --quota %" PRIu64
379 " --name %s --jump REJECT",
380 chain, mSharedQuotaBytes, cost));
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700381 }
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900382 cmds.push_back("COMMIT\n");
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900383
Lorenzo Colitti25616062017-07-06 16:52:52 +0900384 if (iptablesRestoreFunction(V4V6, Join(cmds, "\n"), nullptr) != 0) {
385 ALOGE("Failed to remove shared quota on %s", iface.c_str());
386 return -1;
387 }
388
389 int res = 0;
390 mSharedQuotaIfaces.erase(it);
391 if (mSharedQuotaIfaces.empty()) {
392 mSharedQuotaBytes = 0;
393 if (mSharedAlertBytes) {
394 res = removeSharedAlert();
395 if (res == 0) {
396 mSharedAlertBytes = 0;
397 }
398 }
399 }
400
401 return res;
402
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700403}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700404
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900405int BandwidthController::setInterfaceQuota(const std::string& iface, int64_t maxBytes) {
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900406 const std::string& cost = iface;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700407
JP Abgrall69261cb2014-06-19 18:35:24 -0700408 if (!isIfaceName(iface))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700409 return -1;
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700410
JP Abgrall8a932722011-07-13 19:17:35 -0700411 if (!maxBytes) {
412 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000413 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700414 return -1;
415 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700416 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700417 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700418 }
419
JP Abgrall0dad7c22011-06-24 11:58:14 -0700420 /* Insert ingress quota. */
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900421 auto it = mQuotaIfaces.find(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700422
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900423 if (it != mQuotaIfaces.end()) {
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900424 if (updateQuota(cost, maxBytes) != 0) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900425 ALOGE("Failed update quota for %s", iface.c_str());
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900426 removeInterfaceQuota(iface);
427 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700428 }
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900429 it->second.quota = maxBytes;
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900430 return 0;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700431 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700432
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900433 const std::string chain = "bw_costly_" + iface;
434 const int ruleInsertPos = (mGlobalAlertBytes) ? 2 : 1;
435 std::vector<std::string> cmds = {
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900436 "*filter",
437 StringPrintf(":%s -", chain.c_str()),
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900438 StringPrintf("-A %s -j bw_penalty_box", chain.c_str()),
439 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, iface.c_str(),
440 chain.c_str()),
441 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, iface.c_str(),
442 chain.c_str()),
443 StringPrintf("-A bw_FORWARD -o %s --jump %s", iface.c_str(), chain.c_str()),
444 StringPrintf("-A %s -m quota2 ! --quota %" PRId64 " --name %s --jump REJECT",
445 chain.c_str(), maxBytes, cost.c_str()),
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900446 "COMMIT\n",
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900447 };
448
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900449 if (iptablesRestoreFunction(V4V6, Join(cmds, "\n"), nullptr) != 0) {
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900450 ALOGE("Failed set quota rule");
451 removeInterfaceQuota(iface);
452 return -1;
453 }
454
455 mQuotaIfaces[iface] = QuotaInfo{maxBytes, 0};
456 return 0;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700457}
458
JP Abgrall8a932722011-07-13 19:17:35 -0700459int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
460 return getInterfaceQuota("shared", bytes);
461}
462
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900463int BandwidthController::getInterfaceQuota(const std::string& iface, int64_t* bytes) {
Joel Scherpelzdd5d2192017-06-16 10:45:14 +0900464 const auto& sys = android::netdutils::sSyscalls.get();
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900465 const std::string fname = "/proc/net/xt_quota/" + iface;
JP Abgrall8a932722011-07-13 19:17:35 -0700466
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900467 if (!isIfaceName(iface)) return -1;
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700468
Joel Scherpelzdd5d2192017-06-16 10:45:14 +0900469 StatusOr<UniqueFile> file = sys.fopen(fname, "re");
470 if (!isOk(file)) {
471 ALOGE("Reading quota %s failed (%s)", iface.c_str(), toString(file).c_str());
JP Abgrall8a932722011-07-13 19:17:35 -0700472 return -1;
473 }
Joel Scherpelzdd5d2192017-06-16 10:45:14 +0900474 auto rv = sys.fscanf(file.value().get(), "%" SCNd64, bytes);
475 if (!isOk(rv)) {
476 ALOGE("Reading quota %s failed (%s)", iface.c_str(), toString(rv).c_str());
477 return -1;
478 }
479 ALOGV("Read quota res=%d bytes=%" PRId64, rv.value(), *bytes);
480 return rv.value() == 1 ? 0 : -1;
JP Abgrall8a932722011-07-13 19:17:35 -0700481}
482
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900483int BandwidthController::removeInterfaceQuota(const std::string& iface) {
JP Abgrall69261cb2014-06-19 18:35:24 -0700484 if (!isIfaceName(iface))
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700485 return -1;
JP Abgrall26e0d492011-06-24 19:21:51 -0700486
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900487 auto it = mQuotaIfaces.find(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700488
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900489 if (it == mQuotaIfaces.end()) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900490 ALOGE("No such iface %s to delete", iface.c_str());
JP Abgrall0dad7c22011-06-24 11:58:14 -0700491 return -1;
492 }
493
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900494 const std::string chain = "bw_costly_" + iface;
495 std::vector<std::string> cmds = {
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900496 "*filter",
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900497 StringPrintf("-D bw_INPUT -i %s --jump %s", iface.c_str(), chain.c_str()),
498 StringPrintf("-D bw_OUTPUT -o %s --jump %s", iface.c_str(), chain.c_str()),
499 StringPrintf("-D bw_FORWARD -o %s --jump %s", iface.c_str(), chain.c_str()),
500 StringPrintf("-F %s", chain.c_str()),
501 StringPrintf("-X %s", chain.c_str()),
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900502 "COMMIT\n",
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900503 };
Lorenzo Colitti6b85aa62017-07-06 15:06:04 +0900504
505 const int res = iptablesRestoreFunction(V4V6, Join(cmds, "\n"), nullptr);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700506
Lorenzo Colitti25616062017-07-06 16:52:52 +0900507 if (res == 0) {
508 mQuotaIfaces.erase(it);
509 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700510
511 return res;
512}
JP Abgrall8a932722011-07-13 19:17:35 -0700513
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900514int BandwidthController::updateQuota(const std::string& quotaName, int64_t bytes) {
Joel Scherpelzdd5d2192017-06-16 10:45:14 +0900515 const auto& sys = android::netdutils::sSyscalls.get();
516 const std::string fname = "/proc/net/xt_quota/" + quotaName;
JP Abgrall8a932722011-07-13 19:17:35 -0700517
JP Abgrall69261cb2014-06-19 18:35:24 -0700518 if (!isIfaceName(quotaName)) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900519 ALOGE("updateQuota: Invalid quotaName \"%s\"", quotaName.c_str());
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700520 return -1;
521 }
522
Joel Scherpelzdd5d2192017-06-16 10:45:14 +0900523 StatusOr<UniqueFile> file = sys.fopen(fname, "we");
524 if (!isOk(file)) {
525 ALOGE("Updating quota %s failed (%s)", quotaName.c_str(), toString(file).c_str());
JP Abgrall8a932722011-07-13 19:17:35 -0700526 return -1;
527 }
Joel Scherpelzdd5d2192017-06-16 10:45:14 +0900528 sys.fprintf(file.value().get(), "%" PRId64 "\n", bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700529 return 0;
530}
531
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900532int BandwidthController::runIptablesAlertCmd(IptOp op, const std::string& alertName,
533 int64_t bytes) {
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900534 const char *opFlag = opToString(op);
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900535 std::string alertQuotaCmd = "*filter\n";
JP Abgrall8a932722011-07-13 19:17:35 -0700536
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900537 // TODO: consider using an alternate template for the delete that does not include the --quota
538 // value. This code works because the --quota value is ignored by deletes
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900539 StringAppendF(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT", bytes,
540 alertName.c_str());
541 StringAppendF(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT", bytes,
542 alertName.c_str());
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900543 StringAppendF(&alertQuotaCmd, "COMMIT\n");
544
Lorenzo Colitti4773cb42017-04-27 14:03:25 +0900545 return iptablesRestoreFunction(V4V6, alertQuotaCmd, nullptr);
JP Abgrall8a932722011-07-13 19:17:35 -0700546}
547
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900548int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const std::string& alertName,
549 int64_t bytes) {
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900550 const char *opFlag = opToString(op);
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900551 std::string alertQuotaCmd = "*filter\n";
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900552 StringAppendF(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD", bytes,
553 alertName.c_str());
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900554 StringAppendF(&alertQuotaCmd, "COMMIT\n");
555
556 return iptablesRestoreFunction(V4V6, alertQuotaCmd, nullptr);
JP Abgrallc6c67342011-10-07 16:28:54 -0700557}
558
559int BandwidthController::setGlobalAlert(int64_t bytes) {
560 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700561 int res = 0;
562
563 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000564 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700565 return -1;
566 }
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900567 if (mGlobalAlertBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700568 res = updateQuota(alertName, bytes);
569 } else {
570 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900571 if (mGlobalAlertTetherCount) {
572 ALOGV("setGlobalAlert for %d tether", mGlobalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700573 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
574 }
JP Abgrall8a932722011-07-13 19:17:35 -0700575 }
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900576 mGlobalAlertBytes = bytes;
JP Abgrall8a932722011-07-13 19:17:35 -0700577 return res;
578}
579
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900580int BandwidthController::setGlobalAlertInForwardChain() {
JP Abgrallc6c67342011-10-07 16:28:54 -0700581 const char *alertName = ALERT_GLOBAL_NAME;
582 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700583
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900584 mGlobalAlertTetherCount++;
585 ALOGV("setGlobalAlertInForwardChain(): %d tether", mGlobalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700586
587 /*
588 * If there is no globalAlert active we are done.
589 * If there is an active globalAlert but this is not the 1st
590 * tether, we are also done.
591 */
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900592 if (!mGlobalAlertBytes || mGlobalAlertTetherCount != 1) {
JP Abgrallc6c67342011-10-07 16:28:54 -0700593 return 0;
594 }
595
596 /* We only add the rule if this was the 1st tether added. */
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900597 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, mGlobalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700598 return res;
599}
600
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900601int BandwidthController::removeGlobalAlert() {
JP Abgrallc6c67342011-10-07 16:28:54 -0700602
603 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700604 int res = 0;
605
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900606 if (!mGlobalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000607 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700608 return -1;
609 }
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900610 res = runIptablesAlertCmd(IptOpDelete, alertName, mGlobalAlertBytes);
611 if (mGlobalAlertTetherCount) {
612 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, mGlobalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700613 }
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900614 mGlobalAlertBytes = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700615 return res;
616}
617
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900618int BandwidthController::removeGlobalAlertInForwardChain() {
JP Abgrallc6c67342011-10-07 16:28:54 -0700619 int res = 0;
620 const char *alertName = ALERT_GLOBAL_NAME;
621
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900622 if (!mGlobalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000623 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700624 return -1;
625 }
626
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900627 mGlobalAlertTetherCount--;
JP Abgrallc6c67342011-10-07 16:28:54 -0700628 /*
629 * If there is no globalAlert active we are done.
630 * If there is an active globalAlert but there are more
631 * tethers, we are also done.
632 */
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900633 if (!mGlobalAlertBytes || mGlobalAlertTetherCount >= 1) {
JP Abgrallc6c67342011-10-07 16:28:54 -0700634 return 0;
635 }
636
637 /* We only detete the rule if this was the last tether removed. */
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900638 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, mGlobalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700639 return res;
640}
641
JP Abgrall8a932722011-07-13 19:17:35 -0700642int BandwidthController::setSharedAlert(int64_t bytes) {
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900643 if (!mSharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000644 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700645 return -1;
646 }
647 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000648 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700649 return -1;
650 }
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900651 return setCostlyAlert("shared", bytes, &mSharedAlertBytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700652}
653
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900654int BandwidthController::removeSharedAlert() {
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900655 return removeCostlyAlert("shared", &mSharedAlertBytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700656}
657
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900658int BandwidthController::setInterfaceAlert(const std::string& iface, int64_t bytes) {
JP Abgrall69261cb2014-06-19 18:35:24 -0700659 if (!isIfaceName(iface)) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900660 ALOGE("setInterfaceAlert: Invalid iface \"%s\"", iface.c_str());
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700661 return -1;
662 }
663
JP Abgrall8a932722011-07-13 19:17:35 -0700664 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000665 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700666 return -1;
667 }
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900668 auto it = mQuotaIfaces.find(iface);
JP Abgrall8a932722011-07-13 19:17:35 -0700669
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900670 if (it == mQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000671 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700672 return -1;
673 }
674
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900675 return setCostlyAlert(iface, bytes, &it->second.alert);
JP Abgrall8a932722011-07-13 19:17:35 -0700676}
677
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900678int BandwidthController::removeInterfaceAlert(const std::string& iface) {
JP Abgrall69261cb2014-06-19 18:35:24 -0700679 if (!isIfaceName(iface)) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900680 ALOGE("removeInterfaceAlert: Invalid iface \"%s\"", iface.c_str());
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700681 return -1;
682 }
683
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900684 auto it = mQuotaIfaces.find(iface);
JP Abgrall8a932722011-07-13 19:17:35 -0700685
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900686 if (it == mQuotaIfaces.end()) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900687 ALOGE("No prior alert set for interface %s", iface.c_str());
JP Abgrall8a932722011-07-13 19:17:35 -0700688 return -1;
689 }
690
Joel Scherpelz5a9a0902017-06-28 10:19:52 +0900691 return removeCostlyAlert(iface, &it->second.alert);
JP Abgrall8a932722011-07-13 19:17:35 -0700692}
693
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900694int BandwidthController::setCostlyAlert(const std::string& costName, int64_t bytes,
695 int64_t* alertBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700696 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700697
JP Abgrall69261cb2014-06-19 18:35:24 -0700698 if (!isIfaceName(costName)) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900699 ALOGE("setCostlyAlert: Invalid costName \"%s\"", costName.c_str());
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700700 return -1;
701 }
702
JP Abgrall8a932722011-07-13 19:17:35 -0700703 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000704 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700705 return -1;
706 }
Lorenzo Colittie0bd37f2017-07-06 17:25:37 +0900707
708 std::string alertName = costName + "Alert";
709 std::string chainName = "bw_costly_" + costName;
JP Abgrall8a932722011-07-13 19:17:35 -0700710 if (*alertBytes) {
711 res = updateQuota(alertName, *alertBytes);
712 } else {
Lorenzo Colittie0bd37f2017-07-06 17:25:37 +0900713 std::vector<std::string> commands = {
714 "*filter\n",
715 StringPrintf(ALERT_IPT_TEMPLATE, "-A", chainName.c_str(), bytes, alertName.c_str()),
716 "COMMIT\n"
717 };
718 res = iptablesRestoreFunction(V4V6, Join(commands, ""), nullptr);
719 if (res) {
720 ALOGE("Failed to set costly alert for %s", costName.c_str());
721 }
JP Abgrall8a932722011-07-13 19:17:35 -0700722 }
Lorenzo Colittie0bd37f2017-07-06 17:25:37 +0900723 if (res == 0) {
724 *alertBytes = bytes;
725 }
JP Abgrall8a932722011-07-13 19:17:35 -0700726 return res;
727}
728
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900729int BandwidthController::removeCostlyAlert(const std::string& costName, int64_t* alertBytes) {
JP Abgrall69261cb2014-06-19 18:35:24 -0700730 if (!isIfaceName(costName)) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900731 ALOGE("removeCostlyAlert: Invalid costName \"%s\"", costName.c_str());
Nick Kralevich0b2b9022014-05-01 13:10:45 -0700732 return -1;
733 }
734
JP Abgrall8a932722011-07-13 19:17:35 -0700735 if (!*alertBytes) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900736 ALOGE("No prior alert set for %s alert", costName.c_str());
JP Abgrall8a932722011-07-13 19:17:35 -0700737 return -1;
738 }
739
Lorenzo Colittie0bd37f2017-07-06 17:25:37 +0900740 std::string alertName = costName + "Alert";
741 std::string chainName = "bw_costly_" + costName;
742 std::vector<std::string> commands = {
743 "*filter\n",
744 StringPrintf(ALERT_IPT_TEMPLATE, "-D", chainName.c_str(), *alertBytes, alertName.c_str()),
745 "COMMIT\n"
746 };
747 if (iptablesRestoreFunction(V4V6, Join(commands, ""), nullptr) != 0) {
748 ALOGE("Failed to remove costly alert %s", costName.c_str());
749 return -1;
750 }
JP Abgrall8a932722011-07-13 19:17:35 -0700751
752 *alertBytes = 0;
Lorenzo Colittie0bd37f2017-07-06 17:25:37 +0900753 return 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700754}
JP Abgralldb7da582011-09-18 12:57:32 -0700755
Lorenzo Colitti7364b752016-07-08 18:24:53 +0900756void BandwidthController::addStats(TetherStatsList& statsList, const TetherStats& stats) {
757 for (TetherStats& existing : statsList) {
758 if (existing.addStatsIfMatch(stats)) {
759 return;
760 }
761 }
762 // No match. Insert a new interface pair.
763 statsList.push_back(stats);
764}
765
JP Abgralldb7da582011-09-18 12:57:32 -0700766/*
767 * Parse the ptks and bytes out of:
JP Abgrallbaeccc42013-06-25 09:44:10 -0700768 * Chain natctrl_tether_counters (4 references)
769 * pkts bytes target prot opt in out source destination
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700770 * 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
771 * 27 2002 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0
772 * 1040 107471 RETURN all -- bt-pan rmnet0 0.0.0.0/0 0.0.0.0/0
773 * 1450 1708806 RETURN all -- rmnet0 bt-pan 0.0.0.0/0 0.0.0.0/0
Lorenzo Colitti26c91322016-07-11 11:36:25 +0900774 * or:
775 * Chain natctrl_tether_counters (0 references)
776 * pkts bytes target prot opt in out source destination
777 * 0 0 RETURN all wlan0 rmnet_data0 ::/0 ::/0
778 * 0 0 RETURN all rmnet_data0 wlan0 ::/0 ::/0
779 *
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700780 * It results in an error if invoked and no tethering counter rules exist. The constraint
781 * helps detect complete parsing failure.
JP Abgralldb7da582011-09-18 12:57:32 -0700782 */
Lorenzo Colitti7364b752016-07-08 18:24:53 +0900783int BandwidthController::addForwardChainStats(const TetherStats& filter,
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900784 TetherStatsList& statsList,
785 const std::string& statsOutput,
Lorenzo Colitti7364b752016-07-08 18:24:53 +0900786 std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -0700787 int res;
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900788 std::string statsLine;
JP Abgralldb7da582011-09-18 12:57:32 -0700789 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
790 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
791 char rest[MAX_IPT_OUTPUT_LINE_LEN];
792
JP Abgrallbaeccc42013-06-25 09:44:10 -0700793 TetherStats stats;
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900794 const char *buffPtr;
JP Abgralldb7da582011-09-18 12:57:32 -0700795 int64_t packets, bytes;
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700796 int statsFound = 0;
JP Abgrallbaeccc42013-06-25 09:44:10 -0700797
798 bool filterPair = filter.intIface[0] && filter.extIface[0];
799
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900800 ALOGV("filter: %s", filter.getStatsLine().c_str());
JP Abgrallbaeccc42013-06-25 09:44:10 -0700801
802 stats = filter;
JP Abgralldb7da582011-09-18 12:57:32 -0700803
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900804 std::stringstream stream(statsOutput);
805 while (std::getline(stream, statsLine, '\n')) {
806 buffPtr = statsLine.c_str();
807
JP Abgralldb7da582011-09-18 12:57:32 -0700808 /* Clean up, so a failed parse can still print info */
809 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
Lorenzo Colitti26c91322016-07-11 11:36:25 +0900810 if (strstr(buffPtr, "0.0.0.0")) {
811 // IPv4 has -- indicating what to do with fragments...
812 // 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0
813 res = sscanf(buffPtr, "%" SCNd64" %" SCNd64" RETURN all -- %s %s 0.%s",
814 &packets, &bytes, iface0, iface1, rest);
815 } else {
816 // ... but IPv6 does not.
817 // 26 2373 RETURN all wlan0 rmnet0 ::/0 ::/0
818 res = sscanf(buffPtr, "%" SCNd64" %" SCNd64" RETURN all %s %s ::/%s",
819 &packets, &bytes, iface0, iface1, rest);
820 }
SynergyDev7776cea2014-03-16 15:48:51 -0700821 ALOGV("parse res=%d iface0=<%s> iface1=<%s> pkts=%" PRId64" bytes=%" PRId64" rest=<%s> orig line=<%s>", res,
JP Abgralldb7da582011-09-18 12:57:32 -0700822 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -0800823 extraProcessingInfo += buffPtr;
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900824 extraProcessingInfo += "\n";
JP Abgralla2a64f02011-11-11 20:36:16 -0800825
JP Abgralldb7da582011-09-18 12:57:32 -0700826 if (res != 5) {
827 continue;
828 }
JP Abgrallbaeccc42013-06-25 09:44:10 -0700829 /*
830 * The following assumes that the 1st rule has in:extIface out:intIface,
831 * which is what NatController sets up.
832 * If not filtering, the 1st match rx, and sets up the pair for the tx side.
833 */
834 if (filter.intIface[0] && filter.extIface[0]) {
835 if (filter.intIface == iface0 && filter.extIface == iface1) {
SynergyDev7776cea2014-03-16 15:48:51 -0700836 ALOGV("2Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700837 stats.rxPackets = packets;
838 stats.rxBytes = bytes;
839 } else if (filter.intIface == iface1 && filter.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -0700840 ALOGV("2Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700841 stats.txPackets = packets;
842 stats.txBytes = bytes;
843 }
844 } else if (filter.intIface[0] || filter.extIface[0]) {
845 if (filter.intIface == iface0 || filter.extIface == iface1) {
SynergyDev7776cea2014-03-16 15:48:51 -0700846 ALOGV("1Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700847 stats.intIface = iface0;
848 stats.extIface = iface1;
849 stats.rxPackets = packets;
850 stats.rxBytes = bytes;
851 } else if (filter.intIface == iface1 || filter.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -0700852 ALOGV("1Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700853 stats.intIface = iface1;
854 stats.extIface = iface0;
855 stats.txPackets = packets;
856 stats.txBytes = bytes;
857 }
858 } else /* if (!filter.intFace[0] && !filter.extIface[0]) */ {
859 if (!stats.intIface[0]) {
SynergyDev7776cea2014-03-16 15:48:51 -0700860 ALOGV("0Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700861 stats.intIface = iface0;
862 stats.extIface = iface1;
863 stats.rxPackets = packets;
864 stats.rxBytes = bytes;
865 } else if (stats.intIface == iface1 && stats.extIface == iface0) {
SynergyDev7776cea2014-03-16 15:48:51 -0700866 ALOGV("0Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700867 stats.txPackets = packets;
868 stats.txBytes = bytes;
869 }
870 }
871 if (stats.rxBytes != -1 && stats.txBytes != -1) {
SynergyDev7776cea2014-03-16 15:48:51 -0700872 ALOGV("rx_bytes=%" PRId64" tx_bytes=%" PRId64" filterPair=%d", stats.rxBytes, stats.txBytes, filterPair);
Lorenzo Colitti7364b752016-07-08 18:24:53 +0900873 addStats(statsList, stats);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700874 if (filterPair) {
JP Abgrallbaeccc42013-06-25 09:44:10 -0700875 return 0;
876 } else {
Lorenzo Colitti7364b752016-07-08 18:24:53 +0900877 statsFound++;
JP Abgrallbaeccc42013-06-25 09:44:10 -0700878 stats = filter;
879 }
JP Abgralldb7da582011-09-18 12:57:32 -0700880 }
881 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700882
883 /* It is always an error to find only one side of the stats. */
884 /* It is an error to find nothing when not filtering. */
885 if (((stats.rxBytes == -1) != (stats.txBytes == -1)) ||
886 (!statsFound && !filterPair)) {
887 return -1;
JP Abgrallbaeccc42013-06-25 09:44:10 -0700888 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700889 return 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700890}
891
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900892std::string BandwidthController::TetherStats::getStatsLine() const {
893 std::string msg;
894 StringAppendF(&msg, "%s %s %" PRId64" %" PRId64" %" PRId64" %" PRId64, intIface.c_str(),
895 extIface.c_str(), rxBytes, rxPackets, txBytes, txPackets);
JP Abgralldb7da582011-09-18 12:57:32 -0700896 return msg;
897}
898
Lorenzo Colitti26c91322016-07-11 11:36:25 +0900899int BandwidthController::getTetherStats(SocketClient *cli, TetherStats& filter,
900 std::string &extraProcessingInfo) {
901 int res = 0;
Lorenzo Colitti26c91322016-07-11 11:36:25 +0900902
903 TetherStatsList statsList;
904
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900905 for (const IptablesTarget target : {V4, V6}) {
906 std::string statsString;
907 res = iptablesRestoreFunction(target, GET_TETHER_STATS_COMMAND, &statsString);
908 if (res != 0) {
909 ALOGE("Failed to run %s err=%d", GET_TETHER_STATS_COMMAND.c_str(), res);
Lorenzo Colitti26c91322016-07-11 11:36:25 +0900910 return -1;
911 }
912
Lorenzo Colittice6748a2017-02-02 01:34:33 +0900913 res = addForwardChainStats(filter, statsList, statsString, extraProcessingInfo);
Lorenzo Colitti26c91322016-07-11 11:36:25 +0900914 if (res != 0) {
915 return res;
916 }
917 }
JP Abgralldb7da582011-09-18 12:57:32 -0700918
Lorenzo Colitti7364b752016-07-08 18:24:53 +0900919 if (filter.intIface[0] && filter.extIface[0] && statsList.size() == 1) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900920 cli->sendMsg(ResponseCode::TetheringStatsResult,
921 statsList[0].getStatsLine().c_str(), false);
Lorenzo Colitti7364b752016-07-08 18:24:53 +0900922 } else {
923 for (const auto& stats: statsList) {
Joel Scherpelzbcad6612017-05-30 10:55:11 +0900924 cli->sendMsg(ResponseCode::TetheringStatsListResult,
925 stats.getStatsLine().c_str(), false);
Lorenzo Colitti7364b752016-07-08 18:24:53 +0900926 }
927 if (res == 0) {
928 cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
929 }
930 }
931
JP Abgralldb7da582011-09-18 12:57:32 -0700932 return res;
933}
JP Abgrall0e540ec2013-08-26 15:13:10 -0700934
935void BandwidthController::flushExistingCostlyTables(bool doClean) {
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900936 std::string fullCmd = "*filter\n-S\nCOMMIT\n";
937 std::string ruleList;
JP Abgrall0e540ec2013-08-26 15:13:10 -0700938
939 /* Only lookup ip4 table names as ip6 will have the same tables ... */
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900940 if (int ret = iptablesRestoreFunction(V4, fullCmd, &ruleList)) {
941 ALOGE("Failed to list existing costly tables ret=%d", ret);
JP Abgrall0e540ec2013-08-26 15:13:10 -0700942 return;
943 }
944 /* ... then flush/clean both ip4 and ip6 iptables. */
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900945 parseAndFlushCostlyTables(ruleList, doClean);
JP Abgrall0e540ec2013-08-26 15:13:10 -0700946}
947
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900948void BandwidthController::parseAndFlushCostlyTables(const std::string& ruleList, bool doRemove) {
949 std::stringstream stream(ruleList);
950 std::string rule;
951 std::vector<std::string> clearCommands = { "*filter" };
952 std::string chainName;
JP Abgrall0e540ec2013-08-26 15:13:10 -0700953
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900954 // Find and flush all rules starting with "-N bw_costly_<iface>" except "-N bw_costly_shared".
955 while (std::getline(stream, rule, '\n')) {
956 if (rule.find(NEW_CHAIN_COMMAND) != 0) continue;
957 chainName = rule.substr(NEW_CHAIN_COMMAND.size());
958 ALOGV("parse chainName=<%s> orig line=<%s>", chainName.c_str(), rule.c_str());
959
960 if (chainName.find("bw_costly_") != 0 || chainName == std::string("bw_costly_shared")) {
JP Abgrall0e540ec2013-08-26 15:13:10 -0700961 continue;
962 }
963
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900964 clearCommands.push_back(StringPrintf(":%s -", chainName.c_str()));
JP Abgrall0e540ec2013-08-26 15:13:10 -0700965 if (doRemove) {
Lorenzo Colitti3c272702017-04-26 15:48:13 +0900966 clearCommands.push_back(StringPrintf("-X %s", chainName.c_str()));
JP Abgrall0e540ec2013-08-26 15:13:10 -0700967 }
968 }
Lorenzo Colitti56c4b1e2017-02-01 02:45:10 +0900969
970 if (clearCommands.size() == 1) {
971 // No rules found.
972 return;
973 }
974
975 clearCommands.push_back("COMMIT\n");
Joel Scherpelz001ecad2017-06-28 16:24:09 +0900976 iptablesRestoreFunction(V4V6, Join(clearCommands, '\n'), nullptr);
JP Abgrall0e540ec2013-08-26 15:13:10 -0700977}
Lorenzo Colittid9db08c2017-04-28 11:06:40 +0900978
979inline const char *BandwidthController::opToString(IptOp op) {
980 switch (op) {
981 case IptOpInsert:
982 return "-I";
983 case IptOpDelete:
984 return "-D";
985 }
986}
987
988inline const char *BandwidthController::jumpToString(IptJumpOp jumpHandling) {
989 /*
990 * Must be careful what one rejects with, as upper layer protocols will just
991 * keep on hammering the device until the number of retries are done.
992 * For port-unreachable (default), TCP should consider as an abort (RFC1122).
993 */
994 switch (jumpHandling) {
995 case IptJumpNoAdd:
996 return "";
997 case IptJumpReject:
998 return " --jump REJECT";
999 case IptJumpReturn:
1000 return " --jump RETURN";
1001 }
1002}