Merge "bandwidth-related commands porting"
diff --git a/server/BandwidthController.cpp b/server/BandwidthController.cpp
index 5b08819..a2e63c0 100644
--- a/server/BandwidthController.cpp
+++ b/server/BandwidthController.cpp
@@ -332,26 +332,46 @@
return ret;
}
+// TODO: Remove after removing these commands in CommandListener
int BandwidthController::addNaughtyApps(int numUids, const char* const appUids[]) {
return manipulateSpecialApps(toStrVec(numUids, appUids), NAUGHTY_CHAIN,
IptJumpReject, IptOpInsert);
}
+// TODO: Remove after removing these commands in CommandListener
int BandwidthController::removeNaughtyApps(int numUids, const char* const appUids[]) {
return manipulateSpecialApps(toStrVec(numUids, appUids), NAUGHTY_CHAIN,
IptJumpReject, IptOpDelete);
}
+// TODO: Remove after removing these commands in CommandListener
int BandwidthController::addNiceApps(int numUids, const char* const appUids[]) {
return manipulateSpecialApps(toStrVec(numUids, appUids), NICE_CHAIN,
IptJumpReturn, IptOpInsert);
}
+// TODO: Remove after removing these commands in CommandListener
int BandwidthController::removeNiceApps(int numUids, const char* const appUids[]) {
return manipulateSpecialApps(toStrVec(numUids, appUids), NICE_CHAIN,
IptJumpReturn, IptOpDelete);
}
+int BandwidthController::addNaughtyApps(const std::vector<std::string>& appStrUid) {
+ return manipulateSpecialApps(appStrUid, NAUGHTY_CHAIN, IptJumpReject, IptOpInsert);
+}
+
+int BandwidthController::removeNaughtyApps(const std::vector<std::string>& appStrUid) {
+ return manipulateSpecialApps(appStrUid, NAUGHTY_CHAIN, IptJumpReject, IptOpDelete);
+}
+
+int BandwidthController::addNiceApps(const std::vector<std::string>& appStrUid) {
+ return manipulateSpecialApps(appStrUid, NICE_CHAIN, IptJumpReturn, IptOpInsert);
+}
+
+int BandwidthController::removeNiceApps(const std::vector<std::string>& appStrUid) {
+ return manipulateSpecialApps(appStrUid, NICE_CHAIN, IptJumpReturn, IptOpDelete);
+}
+
int BandwidthController::manipulateSpecialApps(const std::vector<std::string>& appStrUids,
const std::string& chain, IptJumpOp jumpHandling,
IptOp op) {
@@ -482,13 +502,11 @@
int BandwidthController::setInterfaceQuota(const std::string& iface, int64_t maxBytes) {
const std::string& cost = iface;
- if (!isIfaceName(iface))
- return -1;
+ if (!isIfaceName(iface)) return -EINVAL;
if (!maxBytes) {
- /* Don't talk about -1, deprecate it. */
ALOGE("Invalid bytes value. 1..max_int64.");
- return -1;
+ return -ERANGE;
}
if (maxBytes == -1) {
return removeInterfaceQuota(iface);
@@ -498,10 +516,10 @@
auto it = mQuotaIfaces.find(iface);
if (it != mQuotaIfaces.end()) {
- if (updateQuota(cost, maxBytes) != 0) {
+ if (int res = updateQuota(cost, maxBytes)) {
ALOGE("Failed update quota for %s", iface.c_str());
removeInterfaceQuota(iface);
- return -1;
+ return res;
}
it->second.quota = maxBytes;
return 0;
@@ -523,11 +541,10 @@
chain.c_str(), maxBytes, cost.c_str()),
"COMMIT\n",
};
-
if (iptablesRestoreFunction(V4V6, Join(cmds, "\n"), nullptr) != 0) {
ALOGE("Failed set quota rule");
removeInterfaceQuota(iface);
- return -1;
+ return -EREMOTEIO;
}
mQuotaIfaces[iface] = QuotaInfo{maxBytes, 0};
@@ -559,14 +576,13 @@
}
int BandwidthController::removeInterfaceQuota(const std::string& iface) {
- if (!isIfaceName(iface))
- return -1;
+ if (!isIfaceName(iface)) return -EINVAL;
auto it = mQuotaIfaces.find(iface);
if (it == mQuotaIfaces.end()) {
ALOGE("No such iface %s to delete", iface.c_str());
- return -1;
+ return -ENODEV;
}
const std::string chain = "bw_costly_" + iface;
@@ -587,7 +603,7 @@
mQuotaIfaces.erase(it);
}
- return res;
+ return res ? -EREMOTEIO : 0;
}
int BandwidthController::updateQuota(const std::string& quotaName, int64_t bytes) {
@@ -596,13 +612,14 @@
if (!isIfaceName(quotaName)) {
ALOGE("updateQuota: Invalid quotaName \"%s\"", quotaName.c_str());
- return -1;
+ return -EINVAL;
}
StatusOr<UniqueFile> file = sys.fopen(fname, "we");
if (!isOk(file)) {
+ int res = errno;
ALOGE("Updating quota %s failed (%s)", quotaName.c_str(), toString(file).c_str());
- return -1;
+ return -res;
}
sys.fprintf(file.value().get(), "%" PRId64 "\n", bytes);
return 0;
@@ -641,7 +658,7 @@
if (!bytes) {
ALOGE("Invalid bytes value. 1..max_int64.");
- return -1;
+ return -ERANGE;
}
if (mGlobalAlertBytes) {
res = updateQuota(alertName, bytes);
@@ -651,6 +668,9 @@
ALOGV("setGlobalAlert for %d tether", mGlobalAlertTetherCount);
res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
}
+ if (res) {
+ res = -EREMOTEIO;
+ }
}
mGlobalAlertBytes = bytes;
return res;
@@ -737,18 +757,18 @@
int BandwidthController::setInterfaceAlert(const std::string& iface, int64_t bytes) {
if (!isIfaceName(iface)) {
ALOGE("setInterfaceAlert: Invalid iface \"%s\"", iface.c_str());
- return -1;
+ return -EINVAL;
}
if (!bytes) {
ALOGE("Invalid bytes value. 1..max_int64.");
- return -1;
+ return -ERANGE;
}
auto it = mQuotaIfaces.find(iface);
if (it == mQuotaIfaces.end()) {
ALOGE("Need to have a prior interface quota set to set an alert");
- return -1;
+ return -ENOENT;
}
return setCostlyAlert(iface, bytes, &it->second.alert);
@@ -757,14 +777,14 @@
int BandwidthController::removeInterfaceAlert(const std::string& iface) {
if (!isIfaceName(iface)) {
ALOGE("removeInterfaceAlert: Invalid iface \"%s\"", iface.c_str());
- return -1;
+ return -EINVAL;
}
auto it = mQuotaIfaces.find(iface);
if (it == mQuotaIfaces.end()) {
ALOGE("No prior alert set for interface %s", iface.c_str());
- return -1;
+ return -ENOENT;
}
return removeCostlyAlert(iface, &it->second.alert);
@@ -776,12 +796,12 @@
if (!isIfaceName(costName)) {
ALOGE("setCostlyAlert: Invalid costName \"%s\"", costName.c_str());
- return -1;
+ return -EINVAL;
}
if (!bytes) {
ALOGE("Invalid bytes value. 1..max_int64.");
- return -1;
+ return -ERANGE;
}
std::string alertName = costName + "Alert";
@@ -797,6 +817,7 @@
res = iptablesRestoreFunction(V4V6, Join(commands, ""), nullptr);
if (res) {
ALOGE("Failed to set costly alert for %s", costName.c_str());
+ res = -EREMOTEIO;
}
}
if (res == 0) {
@@ -808,12 +829,12 @@
int BandwidthController::removeCostlyAlert(const std::string& costName, int64_t* alertBytes) {
if (!isIfaceName(costName)) {
ALOGE("removeCostlyAlert: Invalid costName \"%s\"", costName.c_str());
- return -1;
+ return -EINVAL;
}
if (!*alertBytes) {
ALOGE("No prior alert set for %s alert", costName.c_str());
- return -1;
+ return -ENOENT;
}
std::string alertName = costName + "Alert";
@@ -825,7 +846,7 @@
};
if (iptablesRestoreFunction(V4V6, Join(commands, ""), nullptr) != 0) {
ALOGE("Failed to remove costly alert %s", costName.c_str());
- return -1;
+ return -EREMOTEIO;
}
*alertBytes = 0;
diff --git a/server/BandwidthController.h b/server/BandwidthController.h
index bc27c07..0b76134 100644
--- a/server/BandwidthController.h
+++ b/server/BandwidthController.h
@@ -46,11 +46,17 @@
int getInterfaceQuota(const std::string& iface, int64_t* bytes);
int removeInterfaceQuota(const std::string& iface);
+ // TODO: Remove after removing these commands in CommandListener
int addNaughtyApps(int numUids, const char* const appUids[]);
int removeNaughtyApps(int numUids, const char* const appUids[]);
int addNiceApps(int numUids, const char* const appUids[]);
int removeNiceApps(int numUids, const char* const appUids[]);
+ int addNaughtyApps(const std::vector<std::string>& appStrUid);
+ int removeNaughtyApps(const std::vector<std::string>& appStrUid);
+ int addNiceApps(const std::vector<std::string>& appStrUid);
+ int removeNiceApps(const std::vector<std::string>& appStrUid);
+
int setGlobalAlert(int64_t bytes);
int removeGlobalAlert();
int setGlobalAlertInForwardChain();
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index cb974ea..0563af4 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -208,6 +208,102 @@
return binder::Status::ok();
}
+binder::Status NetdNativeService::bandwidthSetInterfaceQuota(const std::string& ifName,
+ int64_t bytes) {
+ NETD_LOCKING_RPC(NETWORK_STACK, gCtls->bandwidthCtrl.lock);
+ auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(ifName).arg(bytes);
+
+ int res = gCtls->bandwidthCtrl.setInterfaceQuota(ifName, bytes);
+
+ gLog.log(entry.returns(res).withAutomaticDuration());
+ return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::bandwidthRemoveInterfaceQuota(const std::string& ifName) {
+ NETD_LOCKING_RPC(NETWORK_STACK, gCtls->bandwidthCtrl.lock);
+ auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(ifName);
+
+ int res = gCtls->bandwidthCtrl.removeInterfaceQuota(ifName);
+
+ gLog.log(entry.returns(res).withAutomaticDuration());
+ return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::bandwidthSetInterfaceAlert(const std::string& ifName,
+ int64_t bytes) {
+ NETD_LOCKING_RPC(NETWORK_STACK, gCtls->bandwidthCtrl.lock);
+ auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(ifName).arg(bytes);
+
+ int res = gCtls->bandwidthCtrl.setInterfaceAlert(ifName, bytes);
+
+ gLog.log(entry.returns(res).withAutomaticDuration());
+ return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::bandwidthRemoveInterfaceAlert(const std::string& ifName) {
+ NETD_LOCKING_RPC(NETWORK_STACK, gCtls->bandwidthCtrl.lock);
+ auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(ifName);
+
+ int res = gCtls->bandwidthCtrl.removeInterfaceAlert(ifName);
+
+ gLog.log(entry.returns(res).withAutomaticDuration());
+ return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::bandwidthSetGlobalAlert(int64_t bytes) {
+ NETD_LOCKING_RPC(NETWORK_STACK, gCtls->bandwidthCtrl.lock);
+ auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(bytes);
+
+ int res = gCtls->bandwidthCtrl.setGlobalAlert(bytes);
+
+ gLog.log(entry.returns(res).withAutomaticDuration());
+ return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::bandwidthAddNaughtyApp(int32_t uid) {
+ NETD_LOCKING_RPC(NETWORK_STACK, gCtls->bandwidthCtrl.lock);
+ auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(uid);
+
+ std::vector<std::string> appStrUids = {std::to_string(abs(uid))};
+ int res = gCtls->bandwidthCtrl.addNaughtyApps(appStrUids);
+
+ gLog.log(entry.returns(res).withAutomaticDuration());
+ return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::bandwidthRemoveNaughtyApp(int32_t uid) {
+ NETD_LOCKING_RPC(NETWORK_STACK, gCtls->bandwidthCtrl.lock);
+ auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(uid);
+
+ std::vector<std::string> appStrUids = {std::to_string(abs(uid))};
+ int res = gCtls->bandwidthCtrl.removeNaughtyApps(appStrUids);
+
+ gLog.log(entry.returns(res).withAutomaticDuration());
+ return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::bandwidthAddNiceApp(int32_t uid) {
+ NETD_LOCKING_RPC(NETWORK_STACK, gCtls->bandwidthCtrl.lock);
+ auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(uid);
+
+ std::vector<std::string> appStrUids = {std::to_string(abs(uid))};
+ int res = gCtls->bandwidthCtrl.addNiceApps(appStrUids);
+
+ gLog.log(entry.returns(res).withAutomaticDuration());
+ return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::bandwidthRemoveNiceApp(int32_t uid) {
+ NETD_LOCKING_RPC(NETWORK_STACK, gCtls->bandwidthCtrl.lock);
+ auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(uid);
+
+ std::vector<std::string> appStrUids = {std::to_string(abs(uid))};
+ int res = gCtls->bandwidthCtrl.removeNiceApps(appStrUids);
+
+ gLog.log(entry.returns(res).withAutomaticDuration());
+ return statusFromErrcode(res);
+}
+
binder::Status NetdNativeService::networkCreatePhysical(int32_t netId,
const std::string& permission) {
ENFORCE_PERMISSION(CONNECTIVITY_INTERNAL);
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index c8b85f0..57d99db 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -43,6 +43,15 @@
// Bandwidth control commands.
binder::Status bandwidthEnableDataSaver(bool enable, bool *ret) override;
+ binder::Status bandwidthSetInterfaceQuota(const std::string& ifName, int64_t bytes) override;
+ binder::Status bandwidthRemoveInterfaceQuota(const std::string& ifName) override;
+ binder::Status bandwidthSetInterfaceAlert(const std::string& ifName, int64_t bytes) override;
+ binder::Status bandwidthRemoveInterfaceAlert(const std::string& ifName) override;
+ binder::Status bandwidthSetGlobalAlert(int64_t bytes) override;
+ binder::Status bandwidthAddNaughtyApp(int32_t uid) override;
+ binder::Status bandwidthRemoveNaughtyApp(int32_t uid) override;
+ binder::Status bandwidthAddNiceApp(int32_t uid) override;
+ binder::Status bandwidthRemoveNiceApp(int32_t uid) override;
// Network and routing commands.
binder::Status networkCreatePhysical(int32_t netId, const std::string& permission)
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index 5e42770..e69025a 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -682,4 +682,87 @@
*/
void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ /**
+ * Set quota for interface
+ *
+ * @param ifName Name of target interface
+ * @param bytes Quota value in bytes
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the the failure.
+ */
+ void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
+
+ /**
+ * Remove quota for interface
+ *
+ * @param ifName Name of target interface
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the the failure.
+ */
+ void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
+
+ /**
+ * Set alert for interface
+ *
+ * @param ifName Name of target interface
+ * @param bytes Alert value in bytes
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the the failure.
+ */
+ void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
+
+ /**
+ * Remove alert for interface
+ *
+ * @param ifName Name of target interface
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the the failure.
+ */
+ void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
+
+ /**
+ * Set global alert
+ *
+ * @param bytes Alert value in bytes
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the the failure.
+ */
+ void bandwidthSetGlobalAlert(long bytes);
+
+ /**
+ * Add naughty app bandwidth rule for specific app
+ *
+ * @param uid uid of target app
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the the failure.
+ */
+ void bandwidthAddNaughtyApp(int uid);
+
+ /**
+ * Remove naughty app bandwidth rule for specific app
+ *
+ * @param uid uid of target app
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the the failure.
+ */
+ void bandwidthRemoveNaughtyApp(int uid);
+
+ /**
+ * Add nice app bandwidth rule for specific app
+ *
+ * @param uid uid of target app
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the the failure.
+ */
+ void bandwidthAddNiceApp(int uid);
+
+ /**
+ * Remove nice app bandwidth rule for specific app
+ *
+ * @param uid uid of target app
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the the failure.
+ */
+ void bandwidthRemoveNiceApp(int uid);
+
}
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index febe50b..5784d8e 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -34,6 +34,7 @@
#include <linux/if_tun.h>
#include <openssl/base64.h>
+#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -59,6 +60,7 @@
#define TUN_DEV "/dev/tun"
#define RAW_TABLE "raw"
#define MANGLE_TABLE "mangle"
+#define FILTER_TABLE "filter"
namespace binder = android::binder;
namespace netdutils = android::netdutils;
@@ -69,8 +71,10 @@
using android::String16;
using android::String8;
using android::base::Join;
+using android::base::ReadFileToString;
using android::base::StartsWith;
using android::base::StringPrintf;
+using android::base::Trim;
using android::bpf::hasBpfSupport;
using android::net::INetd;
using android::net::TunInterface;
@@ -1336,3 +1340,204 @@
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
expectIpfwdRuleNotExists(testFromIf, testToIf);
}
+
+namespace {
+
+constexpr char BANDWIDTH_INPUT[] = "bw_INPUT";
+constexpr char BANDWIDTH_OUTPUT[] = "bw_OUTPUT";
+constexpr char BANDWIDTH_FORWARD[] = "bw_FORWARD";
+constexpr char BANDWIDTH_NAUGHTY[] = "bw_penalty_box";
+constexpr char BANDWIDTH_NICE[] = "bw_happy_box";
+
+// TODO: move iptablesTargetsExists and listIptablesRuleByTable to the top.
+bool iptablesTargetsExists(const char* binary, int expectedCount, const char* table,
+ const char* chainName, const std::string& expectedTargetA,
+ const std::string& expectedTargetB) {
+ std::vector<std::string> rules = listIptablesRuleByTable(binary, table, chainName);
+ int matchCount = 0;
+
+ for (const auto& rule : rules) {
+ if (rule.find(expectedTargetA) != std::string::npos) {
+ if (rule.find(expectedTargetB) != std::string::npos) {
+ matchCount++;
+ }
+ }
+ }
+ return matchCount == expectedCount;
+}
+
+void expectXtQuotaValueEqual(const char* ifname, long quotaBytes) {
+ std::string path = StringPrintf("/proc/net/xt_quota/%s", ifname);
+ std::string result = "";
+
+ EXPECT_TRUE(ReadFileToString(path, &result));
+ EXPECT_EQ(std::to_string(quotaBytes), Trim(result));
+}
+
+void expectBandwidthInterfaceQuotaRuleExists(const char* ifname, long quotaBytes) {
+ std::string BANDWIDTH_COSTLY_IF = StringPrintf("bw_costly_%s", ifname);
+ std::string quotaRule = StringPrintf("quota %s", ifname);
+
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_TRUE(iptablesTargetsExists(binary, 1, FILTER_TABLE, BANDWIDTH_INPUT, ifname,
+ BANDWIDTH_COSTLY_IF));
+ EXPECT_TRUE(iptablesTargetsExists(binary, 1, FILTER_TABLE, BANDWIDTH_OUTPUT, ifname,
+ BANDWIDTH_COSTLY_IF));
+ EXPECT_TRUE(iptablesTargetsExists(binary, 2, FILTER_TABLE, BANDWIDTH_FORWARD, ifname,
+ BANDWIDTH_COSTLY_IF));
+ EXPECT_TRUE(iptablesRuleExists(binary, BANDWIDTH_COSTLY_IF.c_str(), BANDWIDTH_NAUGHTY));
+ EXPECT_TRUE(iptablesRuleExists(binary, BANDWIDTH_COSTLY_IF.c_str(), quotaRule));
+ }
+ expectXtQuotaValueEqual(ifname, quotaBytes);
+}
+
+void expectBandwidthInterfaceQuotaRuleDoesNotExist(const char* ifname) {
+ std::string BANDWIDTH_COSTLY_IF = StringPrintf("bw_costly_%s", ifname);
+ std::string quotaRule = StringPrintf("quota %s", ifname);
+
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_FALSE(iptablesTargetsExists(binary, 1, FILTER_TABLE, BANDWIDTH_INPUT, ifname,
+ BANDWIDTH_COSTLY_IF));
+ EXPECT_FALSE(iptablesTargetsExists(binary, 1, FILTER_TABLE, BANDWIDTH_OUTPUT, ifname,
+ BANDWIDTH_COSTLY_IF));
+ EXPECT_FALSE(iptablesTargetsExists(binary, 2, FILTER_TABLE, BANDWIDTH_FORWARD, ifname,
+ BANDWIDTH_COSTLY_IF));
+ EXPECT_FALSE(iptablesRuleExists(binary, BANDWIDTH_COSTLY_IF.c_str(), BANDWIDTH_NAUGHTY));
+ EXPECT_FALSE(iptablesRuleExists(binary, BANDWIDTH_COSTLY_IF.c_str(), quotaRule));
+ }
+}
+
+void expectBandwidthInterfaceAlertRuleExists(const char* ifname, long alertBytes) {
+ std::string BANDWIDTH_COSTLY_IF = StringPrintf("bw_costly_%s", ifname);
+ std::string alertRule = StringPrintf("quota %sAlert", ifname);
+ std::string alertName = StringPrintf("%sAlert", ifname);
+
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_TRUE(iptablesRuleExists(binary, BANDWIDTH_COSTLY_IF.c_str(), alertRule));
+ }
+ expectXtQuotaValueEqual(alertName.c_str(), alertBytes);
+}
+
+void expectBandwidthInterfaceAlertRuleDoesNotExist(const char* ifname) {
+ std::string BANDWIDTH_COSTLY_IF = StringPrintf("bw_costly_%s", ifname);
+ std::string alertRule = StringPrintf("quota %sAlert", ifname);
+
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_FALSE(iptablesRuleExists(binary, BANDWIDTH_COSTLY_IF.c_str(), alertRule));
+ }
+}
+
+void expectBandwidthGlobalAlertRuleExists(long alertBytes) {
+ static const char globalAlertRule[] = "quota globalAlert";
+ static const char globalAlertName[] = "globalAlert";
+
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_TRUE(iptablesRuleExists(binary, BANDWIDTH_INPUT, globalAlertRule));
+ EXPECT_TRUE(iptablesRuleExists(binary, BANDWIDTH_OUTPUT, globalAlertRule));
+ }
+ expectXtQuotaValueEqual(globalAlertName, alertBytes);
+}
+
+void expectBandwidthManipulateSpecialAppRuleExists(const char* chain, const char* target, int uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_TRUE(iptablesTargetsExists(binary, 1, FILTER_TABLE, chain, target, uidRule));
+ }
+}
+
+void expectBandwidthManipulateSpecialAppRuleDoesNotExist(const char* chain, int uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_FALSE(iptablesRuleExists(binary, chain, uidRule));
+ }
+}
+
+} // namespace
+
+TEST_F(BinderTest, BandwidthSetRemoveInterfaceQuota) {
+ long testQuotaBytes = 5550;
+
+ // Add test physical network
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, "").isOk());
+ EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
+
+ binder::Status status = mNetd->bandwidthSetInterfaceQuota(sTun.name(), testQuotaBytes);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthInterfaceQuotaRuleExists(sTun.name().c_str(), testQuotaBytes);
+
+ status = mNetd->bandwidthRemoveInterfaceQuota(sTun.name());
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthInterfaceQuotaRuleDoesNotExist(sTun.name().c_str());
+
+ // Remove test physical network
+ EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
+}
+
+TEST_F(BinderTest, BandwidthSetRemoveInterfaceAlert) {
+ long testAlertBytes = 373;
+
+ // Add test physical network
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, "").isOk());
+ EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
+
+ // Need to have a prior interface quota set to set an alert
+ binder::Status status = mNetd->bandwidthSetInterfaceQuota(sTun.name(), testAlertBytes);
+ status = mNetd->bandwidthSetInterfaceAlert(sTun.name(), testAlertBytes);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthInterfaceAlertRuleExists(sTun.name().c_str(), testAlertBytes);
+
+ status = mNetd->bandwidthRemoveInterfaceAlert(sTun.name());
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthInterfaceAlertRuleDoesNotExist(sTun.name().c_str());
+
+ // Remove interface quota
+ status = mNetd->bandwidthRemoveInterfaceQuota(sTun.name());
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthInterfaceQuotaRuleDoesNotExist(sTun.name().c_str());
+
+ // Remove test physical network
+ EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
+}
+
+TEST_F(BinderTest, BandwidthSetGlobalAlert) {
+ long testAlertBytes = 2097149;
+
+ binder::Status status = mNetd->bandwidthSetGlobalAlert(testAlertBytes);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthGlobalAlertRuleExists(testAlertBytes);
+
+ testAlertBytes = 2097152;
+ status = mNetd->bandwidthSetGlobalAlert(testAlertBytes);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthGlobalAlertRuleExists(testAlertBytes);
+}
+
+TEST_F(BinderTest, BandwidthManipulateSpecialApp) {
+ SKIP_IF_BPF_SUPPORTED;
+
+ int32_t uid = randomUid();
+ static const char targetReject[] = "REJECT";
+ static const char targetReturn[] = "RETURN";
+
+ // add NaughtyApp
+ binder::Status status = mNetd->bandwidthAddNaughtyApp(uid);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthManipulateSpecialAppRuleExists(BANDWIDTH_NAUGHTY, targetReject, uid);
+
+ // remove NaughtyApp
+ status = mNetd->bandwidthRemoveNaughtyApp(uid);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthManipulateSpecialAppRuleDoesNotExist(BANDWIDTH_NAUGHTY, uid);
+
+ // add NiceApp
+ status = mNetd->bandwidthAddNiceApp(uid);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthManipulateSpecialAppRuleExists(BANDWIDTH_NICE, targetReturn, uid);
+
+ // remove NiceApp
+ status = mNetd->bandwidthRemoveNiceApp(uid);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectBandwidthManipulateSpecialAppRuleDoesNotExist(BANDWIDTH_NICE, uid);
+}
diff --git a/tests/tun_interface.cpp b/tests/tun_interface.cpp
index 34896c7..0edea1c 100644
--- a/tests/tun_interface.cpp
+++ b/tests/tun_interface.cpp
@@ -59,12 +59,13 @@
return -EINVAL;
}
- // Create a tun interface with a name based on our PID and some randomness.
- // iptables will only accept interfaces whose name is up to IFNAMSIZ - 1 bytes long.
- mIfName = StringPrintf("netd%u_%u", getpid(), arc4random());
- if (mIfName.size() >= IFNAMSIZ) {
- mIfName.resize(IFNAMSIZ - 1);
- }
+ // Create a tun interface with a name based on a random number.
+ // In order to fit the size of interface alert name , resize ifname to 9
+ // Alert name format in netd: ("%sAlert", ifname)
+ // Limitation in kernel: char name[15] in struct xt_quota_mtinfo2
+ mIfName = StringPrintf("netd%x", arc4random());
+ mIfName.resize(9);
+
struct ifreq ifr = {
.ifr_ifru = { .ifru_flags = IFF_TUN },
};
@@ -89,11 +90,15 @@
mIfIndex = if_nametoindex(ifr.ifr_name);
+ if (int ret = ifc_enable(ifr.ifr_name)) {
+ return ret;
+ }
return 0;
}
void TunInterface::destroy() {
if (mFd != -1) {
+ ifc_disable(mIfName.c_str());
close(mFd);
mFd = -1;
}