summaryrefslogtreecommitdiff
path: root/server/TetherController.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'server/TetherController.cpp')
-rw-r--r--server/TetherController.cpp145
1 files changed, 108 insertions, 37 deletions
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index c1d73081..6e805f56 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -138,7 +138,7 @@ TetherController::~TetherController() {
mInterfaces.clear();
mDnsForwarders.clear();
mForwardingRequests.clear();
- ifacePairList.clear();
+ mFwdIfaces.clear();
}
bool TetherController::setIpFwdEnabled() {
@@ -439,7 +439,7 @@ int TetherController::setupIptablesHooks() {
return res;
}
- ifacePairList.clear();
+ mFwdIfaces.clear();
return 0;
}
@@ -472,8 +472,6 @@ int TetherController::setDefaults() {
return res;
}
- natCount = 0;
-
return 0;
}
@@ -492,48 +490,127 @@ int TetherController::enableNat(const char* intIface, const char* extIface) {
return -1;
}
- // add this if we are the first added nat
- if (natCount == 0) {
+ if (isForwardingPairEnabled(intIface, extIface)) {
+ return 0;
+ }
+
+ // add this if we are the first enabled nat for this upstream
+ if (!isAnyForwardingEnabledOnUpstream(extIface)) {
std::vector<std::string> v4Cmds = {
"*nat",
StringPrintf("-A %s -o %s -j MASQUERADE", LOCAL_NAT_POSTROUTING, extIface),
"COMMIT\n"
};
- /*
- * IPv6 tethering doesn't need the state-based conntrack rules, so
- * it unconditionally jumps to the tether counters chain all the time.
- */
- std::vector<std::string> v6Cmds = {
- "*filter",
- StringPrintf("-A %s -g %s", LOCAL_FORWARD, LOCAL_TETHER_COUNTERS_CHAIN),
- "COMMIT\n"
- };
-
if (iptablesRestoreFunction(V4, Join(v4Cmds, '\n'), nullptr) ||
- iptablesRestoreFunction(V6, Join(v6Cmds, '\n'), nullptr)) {
+ setupIPv6CountersChain()) {
ALOGE("Error setting postroute rule: iface=%s", extIface);
- // unwind what's been done, but don't care about success - what more could we do?
- setDefaults();
+ if (!isAnyForwardingPairEnabled()) {
+ // unwind what's been done, but don't care about success - what more could we do?
+ setDefaults();
+ }
return -1;
}
}
if (setForwardRules(true, intIface, extIface) != 0) {
ALOGE("Error setting forward rules");
- if (natCount == 0) {
+ if (!isAnyForwardingPairEnabled()) {
setDefaults();
}
errno = ENODEV;
return -1;
}
- natCount++;
return 0;
}
-bool TetherController::checkTetherCountingRuleExist(const std::string& pair_name) {
- return std::find(ifacePairList.begin(), ifacePairList.end(), pair_name) != ifacePairList.end();
+int TetherController::setupIPv6CountersChain() {
+ // Only add this if we are the first enabled nat
+ if (isAnyForwardingPairEnabled()) {
+ return 0;
+ }
+
+ /*
+ * IPv6 tethering doesn't need the state-based conntrack rules, so
+ * it unconditionally jumps to the tether counters chain all the time.
+ */
+ std::vector<std::string> v6Cmds = {
+ "*filter",
+ StringPrintf("-A %s -g %s", LOCAL_FORWARD, LOCAL_TETHER_COUNTERS_CHAIN),
+ "COMMIT\n"
+ };
+
+ return iptablesRestoreFunction(V6, Join(v6Cmds, '\n'), nullptr);
+}
+
+// Gets a pointer to the ForwardingDownstream for an interface pair in the map, or nullptr
+TetherController::ForwardingDownstream* TetherController::findForwardingDownstream(
+ const std::string& intIface, const std::string& extIface) {
+ auto extIfaceMatches = mFwdIfaces.equal_range(extIface);
+ for (auto it = extIfaceMatches.first; it != extIfaceMatches.second; ++it) {
+ if (it->second.iface == intIface) {
+ return &(it->second);
+ }
+ }
+ return nullptr;
+}
+
+void TetherController::addForwardingPair(const std::string& intIface, const std::string& extIface) {
+ ForwardingDownstream* existingEntry = findForwardingDownstream(intIface, extIface);
+ if (existingEntry != nullptr) {
+ existingEntry->active = true;
+ return;
+ }
+
+ mFwdIfaces.insert(std::pair<std::string, ForwardingDownstream>(extIface, {
+ .iface = intIface,
+ .active = true
+ }));
+}
+
+void TetherController::markForwardingPairDisabled(
+ const std::string& intIface, const std::string& extIface) {
+ ForwardingDownstream* existingEntry = findForwardingDownstream(intIface, extIface);
+ if (existingEntry == nullptr) {
+ return;
+ }
+
+ existingEntry->active = false;
+}
+
+bool TetherController::isForwardingPairEnabled(
+ const std::string& intIface, const std::string& extIface) {
+ ForwardingDownstream* existingEntry = findForwardingDownstream(intIface, extIface);
+ return existingEntry != nullptr && existingEntry->active;
+}
+
+bool TetherController::isAnyForwardingEnabledOnUpstream(const std::string& extIface) {
+ auto extIfaceMatches = mFwdIfaces.equal_range(extIface);
+ for (auto it = extIfaceMatches.first; it != extIfaceMatches.second; ++it) {
+ if (it->second.active) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TetherController::isAnyForwardingPairEnabled() {
+ for (auto& it : mFwdIfaces) {
+ if (it.second.active) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TetherController::tetherCountingRuleExists(
+ const std::string& iface1, const std::string& iface2) {
+ // A counting rule exists if NAT was ever enabled for this interface pair, so if the pair
+ // is in the map regardless of its active status. Rules are added both ways so we check with
+ // the 2 combinations.
+ return findForwardingDownstream(iface1, iface2) != nullptr
+ || findForwardingDownstream(iface2, iface1) != nullptr;
}
/* static */
@@ -566,15 +643,11 @@ int TetherController::setForwardRules(bool add, const char *intIface, const char
"*filter",
};
- /* We only ever add tethering quota rules so that they stick. */
- std::string pair1 = StringPrintf("%s_%s", intIface, extIface);
- if (add && !checkTetherCountingRuleExist(pair1)) {
+ // We only ever add tethering quota rules so that they stick.
+ if (add && !tetherCountingRuleExists(intIface, extIface)) {
v4.push_back(makeTetherCountingRule(intIface, extIface));
- v6.push_back(makeTetherCountingRule(intIface, extIface));
- }
- std::string pair2 = StringPrintf("%s_%s", extIface, intIface);
- if (add && !checkTetherCountingRuleExist(pair2)) {
v4.push_back(makeTetherCountingRule(extIface, intIface));
+ v6.push_back(makeTetherCountingRule(intIface, extIface));
v6.push_back(makeTetherCountingRule(extIface, intIface));
}
@@ -599,11 +672,10 @@ int TetherController::setForwardRules(bool add, const char *intIface, const char
return -1;
}
- if (add && !checkTetherCountingRuleExist(pair1)) {
- ifacePairList.push_front(pair1);
- }
- if (add && !checkTetherCountingRuleExist(pair2)) {
- ifacePairList.push_front(pair2);
+ if (add) {
+ addForwardingPair(intIface, extIface);
+ } else {
+ markForwardingPairDisabled(intIface, extIface);
}
return 0;
@@ -616,8 +688,7 @@ int TetherController::disableNat(const char* intIface, const char* extIface) {
}
setForwardRules(false, intIface, extIface);
- if (--natCount <= 0) {
- // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
+ if (!isAnyForwardingPairEnabled()) {
setDefaults();
}
return 0;