netd: bandwidth: tethering global alert support
Now, when nat is enabled/disabled it will let the bandwidthcontroller
know that it might need to add/remove the matching global alert into
the tethering rules in the FORWARD chain of iptables.
Bug: 5336638
Change-Id: I1843f3f6601f371537f754a31db792e054b36a1d
diff --git a/BandwidthController.cpp b/BandwidthController.cpp
index 1761145..f0a856e 100644
--- a/BandwidthController.cpp
+++ b/BandwidthController.cpp
@@ -48,6 +48,7 @@
/* Alphabetical */
const char BandwidthController::ALERT_IPT_TEMPLATE[] = "%s %s %s -m quota2 ! --quota %lld --name %s";
const int BandwidthController::ALERT_RULE_POS_IN_COSTLY_CHAIN = 4;
+const char BandwidthController::ALERT_GLOBAL_NAME[] = "globalAlert";
const char BandwidthController::IP6TABLES_PATH[] = "/system/bin/ip6tables";
const char BandwidthController::IPTABLES_PATH[] = "/system/bin/iptables";
const int BandwidthController::MAX_CMD_ARGS = 32;
@@ -217,6 +218,7 @@
quotaIfaces.clear();
naughtyAppUids.clear();
globalAlertBytes = 0;
+ globalAlertTetherCount = 0;
sharedQuotaBytes = sharedAlertBytes = 0;
@@ -698,9 +700,35 @@
return res;
}
-int BandwidthController::setGlobalAlert(int64_t bytes) {
+int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
+ int res = 0;
+ const char *opFlag;
+ const char *ifaceLimiting;
char *alertQuotaCmd;
- const char *alertName = "globalAlert";
+
+ switch (op) {
+ case IptOpInsert:
+ opFlag = "-I";
+ break;
+ case IptOpReplace:
+ opFlag = "-R";
+ break;
+ default:
+ case IptOpDelete:
+ opFlag = "-D";
+ break;
+ }
+
+ ifaceLimiting = "! -i lo+";
+ asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "FORWARD",
+ bytes, alertName, alertName);
+ res = runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
+ free(alertQuotaCmd);
+ return res;
+}
+
+int BandwidthController::setGlobalAlert(int64_t bytes) {
+ const char *alertName = ALERT_GLOBAL_NAME;
int res = 0;
if (!bytes) {
@@ -711,15 +739,39 @@
res = updateQuota(alertName, bytes);
} else {
res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
+ if (globalAlertTetherCount) {
+ LOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
+ res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
+ }
}
globalAlertBytes = bytes;
return res;
}
-int BandwidthController::removeGlobalAlert(void) {
- char *alertQuotaCmd;
+int BandwidthController::setGlobalAlertInForwardChain(void) {
+ const char *alertName = ALERT_GLOBAL_NAME;
+ int res = 0;
- const char *alertName = "globalAlert";
+ globalAlertTetherCount++;
+ LOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
+
+ /*
+ * If there is no globalAlert active we are done.
+ * If there is an active globalAlert but this is not the 1st
+ * tether, we are also done.
+ */
+ if (!globalAlertBytes || globalAlertTetherCount != 1) {
+ return 0;
+ }
+
+ /* We only add the rule if this was the 1st tether added. */
+ res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
+ return res;
+}
+
+int BandwidthController::removeGlobalAlert(void) {
+
+ const char *alertName = ALERT_GLOBAL_NAME;
int res = 0;
if (!globalAlertBytes) {
@@ -727,10 +779,37 @@
return -1;
}
res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
+ if (globalAlertTetherCount) {
+ res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
+ }
globalAlertBytes = 0;
return res;
}
+int BandwidthController::removeGlobalAlertInForwardChain(void) {
+ int res = 0;
+ const char *alertName = ALERT_GLOBAL_NAME;
+
+ if (!globalAlertTetherCount) {
+ LOGE("No prior alert set");
+ return -1;
+ }
+
+ globalAlertTetherCount--;
+ /*
+ * If there is no globalAlert active we are done.
+ * If there is an active globalAlert but there are more
+ * tethers, we are also done.
+ */
+ if (!globalAlertBytes || globalAlertTetherCount >= 1) {
+ return 0;
+ }
+
+ /* We only detete the rule if this was the last tether removed. */
+ res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
+ return res;
+}
+
int BandwidthController::setSharedAlert(int64_t bytes) {
if (!sharedQuotaBytes) {
LOGE("Need to have a prior shared quota set to set an alert");
diff --git a/BandwidthController.h b/BandwidthController.h
index 401609f..861c63e 100644
--- a/BandwidthController.h
+++ b/BandwidthController.h
@@ -62,6 +62,8 @@
int setGlobalAlert(int64_t bytes);
int removeGlobalAlert(void);
+ int setGlobalAlertInForwardChain(void);
+ int removeGlobalAlertInForwardChain(void);
int setSharedAlert(int64_t bytes);
int removeSharedAlert(void);
@@ -101,6 +103,7 @@
std::string makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota);
int runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes);
+ int runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes);
/* Runs for both ipv4 and ipv6 iptables */
int runCommands(int numCommands, const char *commands[], RunCmdErrHandling cmdErrHandling);
@@ -128,6 +131,16 @@
int64_t sharedQuotaBytes;
int64_t sharedAlertBytes;
int64_t globalAlertBytes;
+ /*
+ * This tracks the number of tethers setup.
+ * The FORWARD chain is updated in the following cases:
+ * - The 1st time a globalAlert is setup and there are tethers setup.
+ * - Anytime a globalAlert is removed and there are tethers setup.
+ * - The 1st tether is setup and there is a globalAlert active.
+ * - The last tether is removed and there is a globalAlert active.
+ */
+ int globalAlertTetherCount;
+
std::list<QuotaInfo> quotaIfaces;
std::list<int /*appUid*/> naughtyAppUids;
@@ -139,6 +152,7 @@
/* Alphabetical */
static const char ALERT_IPT_TEMPLATE[];
static const int ALERT_RULE_POS_IN_COSTLY_CHAIN;
+ static const char ALERT_GLOBAL_NAME[];
static const char IP6TABLES_PATH[];
static const char IPTABLES_PATH[];
static const int MAX_CMD_ARGS;
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 68a1309..21efadd 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -582,8 +582,16 @@
if (!strcmp(argv[1], "enable")) {
rc = sNatCtrl->enableNat(argv[2], argv[3]);
+ if(!rc) {
+ /* Ignore ifaces for now. */
+ rc = sBandwidthCtrl->setGlobalAlertInForwardChain();
+ }
} else if (!strcmp(argv[1], "disable")) {
rc = sNatCtrl->disableNat(argv[2], argv[3]);
+ if(!rc) {
+ /* Ignore ifaces for now. */
+ rc = sBandwidthCtrl->removeGlobalAlertInForwardChain();
+ }
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
return 0;
@@ -1047,6 +1055,17 @@
return 0;
}
+ if (!strcmp(argv[1], "debugsettetherglobalalert") || !strcmp(argv[1], "dstga")) {
+ if (argc != 4) {
+ sendGenericSyntaxError(cli, "debugsettetherglobalalert <interface0> <interface1>");
+ return 0;
+ }
+ /* We ignore the interfaces for now. */
+ int rc = sBandwidthCtrl->setGlobalAlertInForwardChain();
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
if (!strcmp(argv[1], "removeglobalalert") || !strcmp(argv[1], "rga")) {
if (argc != 2) {
sendGenericSyntaxError(cli, "removeglobalalert");
@@ -1057,6 +1076,17 @@
return 0;
}
+ if (!strcmp(argv[1], "debugremovetetherglobalalert") || !strcmp(argv[1], "drtga")) {
+ if (argc != 4) {
+ sendGenericSyntaxError(cli, "debugremovetetherglobalalert <interface0> <interface1>");
+ return 0;
+ }
+ /* We ignore the interfaces for now. */
+ int rc = sBandwidthCtrl->removeGlobalAlertInForwardChain();
+ sendGenericOkFail(cli, rc);
+ return 0;
+
+ }
if (!strcmp(argv[1], "setsharedalert") || !strcmp(argv[1], "ssa")) {
if (argc != 3) {
sendGenericSyntaxError(cli, "setsharedalert <bytes>");