Fix WiFi-Direct and Tethering.
A LocalNetwork object now always exists in the NetworkController, with a fixed
NetId that's guaranteed not to collide with NetIds created by the framework.
When routes are added on an interface tracked by the LocalNetwork, they are
added to a fixed "local_network" table.
When NAT is enabled, we add a special "iif -> oif" tethering rule.
Bug: 15413694
Bug: 15413741
Change-Id: I36effc438d5ac193a77174493bf196cb68a5b97a
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index f2a8745..1c060f7 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -62,6 +62,14 @@
return PERMISSION_NONE;
}
+unsigned stringToNetId(const char* arg) {
+ if (!strcmp(arg, "local")) {
+ return NetworkController::LOCAL_NET_ID;
+ }
+ // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
+ return strtoul(arg, NULL, 0);
+}
+
} // namespace
NetworkController *CommandListener::sNetCtrl = NULL;
@@ -174,9 +182,9 @@
if (!sSecondaryTableCtrl)
sSecondaryTableCtrl = new SecondaryTableController(sNetCtrl);
if (!sTetherCtrl)
- sTetherCtrl = new TetherController(sNetCtrl);
+ sTetherCtrl = new TetherController();
if (!sNatCtrl)
- sNatCtrl = new NatController(sNetCtrl);
+ sNatCtrl = new NatController();
if (!sPppCtrl)
sPppCtrl = new PppController();
if (!sSoftapCtrl)
@@ -237,7 +245,7 @@
sSecondaryTableCtrl->setupIptablesHooks();
- if (int ret = RouteController::Init()) {
+ if (int ret = RouteController::Init(NetworkController::LOCAL_NET_ID)) {
ALOGE("failed to initialize RouteController (%s)", strerror(-ret));
}
}
@@ -813,16 +821,19 @@
return 0;
}
- if (!strcmp(argv[1], "enable")) {
- rc = sNatCtrl->enableNat(argc, argv);
+ // 0 1 2 3
+ // nat enable intiface extiface
+ // nat disable intiface extiface
+ if (!strcmp(argv[1], "enable") && argc >= 4) {
+ rc = sNatCtrl->enableNat(argv[2], argv[3]);
if(!rc) {
/* Ignore ifaces for now. */
rc = sBandwidthCtrl->setGlobalAlertInForwardChain();
}
- } else if (!strcmp(argv[1], "disable")) {
+ } else if (!strcmp(argv[1], "disable") && argc >= 4) {
/* Ignore ifaces for now. */
rc = sBandwidthCtrl->removeGlobalAlertInForwardChain();
- rc |= sNatCtrl->disableNat(argc, argv);
+ rc |= sNatCtrl->disableNat(argv[2], argv[3]);
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
return 0;
@@ -1569,8 +1580,7 @@
}
++nextArg;
- // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
- unsigned netId = strtoul(argv[nextArg++], NULL, 0);
+ unsigned netId = stringToNetId(argv[nextArg++]);
const char* interface = argv[nextArg++];
const char* destination = argv[nextArg++];
const char* nexthop = argc > nextArg ? argv[nextArg] : NULL;
@@ -1588,23 +1598,24 @@
return success(client);
}
- // 0 1 2 3
- // network addiface <netId> <interface>
- // network removeiface <netId> <interface>
- if (!strcmp(argv[1], "addiface") || !strcmp(argv[1], "removeiface")) {
- if (argc != 4) {
+ // 0 1 2 3 4
+ // network interface add <netId> <interface>
+ // network interface remove <netId> <interface>
+ if (!strcmp(argv[1], "interface")) {
+ if (argc != 5) {
return syntaxError(client, "Missing argument");
}
- // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
- unsigned netId = strtoul(argv[2], NULL, 0);
- if (!strcmp(argv[1], "addiface")) {
- if (int ret = sNetCtrl->addInterfaceToNetwork(netId, argv[3])) {
+ unsigned netId = stringToNetId(argv[3]);
+ if (!strcmp(argv[2], "add")) {
+ if (int ret = sNetCtrl->addInterfaceToNetwork(netId, argv[4])) {
return operationError(client, "addInterfaceToNetwork() failed", ret);
}
- } else {
- if (int ret = sNetCtrl->removeInterfaceFromNetwork(netId, argv[3])) {
+ } else if (!strcmp(argv[2], "remove")) {
+ if (int ret = sNetCtrl->removeInterfaceFromNetwork(netId, argv[4])) {
return operationError(client, "removeInterfaceFromNetwork() failed", ret);
}
+ } else {
+ return syntaxError(client, "Unknown argument");
}
return success(client);
}
@@ -1618,8 +1629,7 @@
if (argc < 3) {
return syntaxError(client, "Missing argument");
}
- // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
- unsigned netId = strtoul(argv[2], NULL, 0);
+ unsigned netId = stringToNetId(argv[2]);
if (argc == 5 && !strcmp(argv[3], "vpn")) {
bool hasDns = atoi(argv[4]);
if (int ret = sNetCtrl->createVirtualNetwork(netId, hasDns)) {
@@ -1648,8 +1658,7 @@
if (argc != 3) {
return syntaxError(client, "Incorrect number of arguments");
}
- // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
- unsigned netId = strtoul(argv[2], NULL, 0);
+ unsigned netId = stringToNetId(argv[2]);
if (int ret = sNetCtrl->destroyNetwork(netId)) {
return operationError(client, "destroyNetwork() failed", ret);
}
@@ -1668,8 +1677,7 @@
if (argc < 4) {
return syntaxError(client, "Missing netId");
}
- // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
- netId = strtoul(argv[3], NULL, 0);
+ netId = stringToNetId(argv[3]);
} else if (strcmp(argv[2], "clear")) {
return syntaxError(client, "Unknown argument");
}
@@ -1730,8 +1738,7 @@
if (argc < 4) {
return syntaxError(client, "Missing argument");
}
- // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
- unsigned netId = strtoul(argv[3], NULL, 0);
+ unsigned netId = stringToNetId(argv[3]);
UidRanges uidRanges;
if (!uidRanges.parseFrom(argc - 4, argv + 4)) {
return syntaxError(client, "Invalid UIDs");
@@ -1771,9 +1778,5 @@
return success(client);
}
- // TODO:
- // o tethering
- // o p2p
-
return syntaxError(client, "Unknown argument");
}
diff --git a/server/NatController.cpp b/server/NatController.cpp
index 8340b73..3594a5d 100644
--- a/server/NatController.cpp
+++ b/server/NatController.cpp
@@ -32,14 +32,14 @@
#include <logwrap/logwrap.h>
#include "NatController.h"
-#include "NetworkController.h"
#include "NetdConstants.h"
+#include "RouteController.h"
const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
const char* NatController::LOCAL_TETHER_COUNTERS_CHAIN = "natctrl_tether_counters";
-NatController::NatController(NetworkController* net_ctrl) : mNetCtrl(net_ctrl) {
+NatController::NatController() {
}
NatController::~NatController() {
@@ -112,7 +112,6 @@
{{IPTABLES_PATH, "-F", LOCAL_FORWARD,}, 1},
{{IPTABLES_PATH, "-A", LOCAL_FORWARD, "-j", "DROP"}, 1},
{{IPTABLES_PATH, "-t", "nat", "-F", LOCAL_NAT_POSTROUTING}, 1},
- {{IP_PATH, "route", "flush", "cache"}, 0},
};
for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) {
if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) &&
@@ -126,34 +125,7 @@
return 0;
}
-int NatController::routesOp(bool add, const char *intIface, char **argv, int addrCount) {
- unsigned netId = mNetCtrl->getNetworkForInterface(intIface);
- int ret = 0;
-
- for (int i = 0; i < addrCount; i++) {
- if (add) {
- ret |= mNetCtrl->addRoute(netId, intIface, argv[5+i], NULL, false, INVALID_UID);
- } else {
- ret |= mNetCtrl->addRoute(netId, intIface, argv[5+i], NULL, false, INVALID_UID);
- }
- }
- const char *cmd[] = {
- IP_PATH,
- "route",
- "flush",
- "cache"
- };
- runCmd(ARRAY_SIZE(cmd), cmd);
- return ret;
-}
-
-// 0 1 2 3 4 5
-// nat enable intface extface addrcnt nated-ipaddr/prelength
-int NatController::enableNat(const int argc, char **argv) {
- int addrCount = atoi(argv[4]);
- const char *intIface = argv[2];
- const char *extIface = argv[3];
-
+int NatController::enableNat(const char* intIface, const char* extIface) {
ALOGV("enableNat(intIface=<%s>, extIface=<%s>)",intIface, extIface);
if (!isIfaceName(intIface) || !isIfaceName(extIface)) {
@@ -168,18 +140,6 @@
return -1;
}
- if (argc < 5 + addrCount) {
- ALOGE("Missing Argument");
- errno = EINVAL;
- return -1;
- }
- if (routesOp(true, intIface, argv, addrCount)) {
- ALOGE("Error setting route rules");
- routesOp(false, intIface, argv, addrCount);
- errno = ENODEV;
- return -1;
- }
-
// add this if we are the first added nat
if (natCount == 0) {
const char *cmd[] = {
@@ -194,18 +154,15 @@
"MASQUERADE"
};
if (runCmd(ARRAY_SIZE(cmd), cmd)) {
- ALOGE("Error seting postroute rule: iface=%s", extIface);
+ ALOGE("Error setting postroute rule: iface=%s", extIface);
// unwind what's been done, but don't care about success - what more could we do?
- routesOp(false, intIface, argv, addrCount);
setDefaults();
return -1;
}
}
-
if (setForwardRules(true, intIface, extIface) != 0) {
ALOGE("Error setting forward rules");
- routesOp(false, intIface, argv, addrCount);
if (natCount == 0) {
setDefaults();
}
@@ -231,6 +188,12 @@
};
runCmd(ARRAY_SIZE(cmd2), cmd2);
+ if (int ret = RouteController::enableTethering(intIface, extIface)) {
+ ALOGE("failed to add tethering rule for iif=%s oif=%s", intIface, extIface);
+ errno = -ret;
+ return -1;
+ }
+
natCount++;
return 0;
}
@@ -385,27 +348,19 @@
return rc;
}
-// nat disable intface extface
-// 0 1 2 3 4 5
-// nat enable intface extface addrcnt nated-ipaddr/prelength
-int NatController::disableNat(const int argc, char **argv) {
- int addrCount = atoi(argv[4]);
- const char *intIface = argv[2];
- const char *extIface = argv[3];
-
+int NatController::disableNat(const char* intIface, const char* extIface) {
if (!isIfaceName(intIface) || !isIfaceName(extIface)) {
errno = ENODEV;
return -1;
}
- if (argc < 5 + addrCount) {
- ALOGE("Missing Argument");
- errno = EINVAL;
+ if (int ret = RouteController::disableTethering(intIface, extIface)) {
+ ALOGE("failed to remove tethering rule for iif=%s oif=%s", intIface, extIface);
+ errno = -ret;
return -1;
}
setForwardRules(false, intIface, extIface);
- routesOp(false, intIface, argv, addrCount);
if (--natCount <= 0) {
// handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
setDefaults();
diff --git a/server/NatController.h b/server/NatController.h
index e3cc394..9102f46 100644
--- a/server/NatController.h
+++ b/server/NatController.h
@@ -21,16 +21,13 @@
#include <list>
#include <string>
-class NetworkController;
-
class NatController {
-
public:
- explicit NatController(NetworkController* net_ctrl);
+ NatController();
virtual ~NatController();
- int enableNat(const int argc, char **argv);
- int disableNat(const int argc, char **argv);
+ int enableNat(const char* intIface, const char* extIface);
+ int disableNat(const char* intIface, const char* extIface);
int setupIptablesHooks();
static const char* LOCAL_FORWARD;
@@ -42,7 +39,6 @@
private:
int natCount;
- NetworkController *mNetCtrl;
bool checkTetherCountingRuleExist(const char *pair_name);
@@ -50,7 +46,6 @@
int runCmd(int argc, const char **argv);
int setForwardRules(bool set, const char *intIface, const char *extIface);
int setTetherCountingRules(bool add, const char *intIface, const char *extIface);
- int routesOp(bool add, const char *intIface, char **argv, int addrCount);
};
#endif
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index 44eb2ef..90b7682 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -51,6 +51,7 @@
} // namespace
NetworkController::NetworkController() : mDefaultNetId(NETID_UNSET) {
+ mNetworks[LOCAL_NET_ID] = new LocalNetwork(LOCAL_NET_ID);
}
unsigned NetworkController::getDefaultNetwork() const {
@@ -117,29 +118,6 @@
return network && network->getType() == Network::VIRTUAL;
}
-unsigned NetworkController::getNetIdForLocalNetwork() const {
- return MIN_NET_ID - 1;
-}
-
-int NetworkController::createLocalNetwork(unsigned netId) {
- // TODO: Enable this check after removing the getNetIdForLocalNetwork() hack.
- if (false) {
- if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
- ALOGE("invalid netId %u", netId);
- return -EINVAL;
- }
- }
-
- if (isValidNetwork(netId)) {
- ALOGE("duplicate netId %u", netId);
- return -EEXIST;
- }
-
- android::RWLock::AutoWLock lock(mRWLock);
- mNetworks[netId] = new LocalNetwork(netId);
- return 0;
-}
-
int NetworkController::createPhysicalNetwork(unsigned netId, Permission permission) {
if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
ALOGE("invalid netId %u", netId);
@@ -180,7 +158,7 @@
}
int NetworkController::destroyNetwork(unsigned netId) {
- if (!isValidNetwork(netId)) {
+ if (netId == LOCAL_NET_ID || !isValidNetwork(netId)) {
ALOGE("invalid netId %u", netId);
return -EINVAL;
}
@@ -377,7 +355,9 @@
}
RouteController::TableType tableType;
- if (legacy) {
+ if (netId == LOCAL_NET_ID) {
+ tableType = RouteController::LOCAL_NETWORK;
+ } else if (legacy) {
if ((getPermissionForUser(uid) & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) {
tableType = RouteController::LEGACY_SYSTEM;
} else {
diff --git a/server/NetworkController.h b/server/NetworkController.h
index 479af5e..f0b42c4 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -40,6 +40,8 @@
*/
class NetworkController {
public:
+ static const int LOCAL_NET_ID = 9;
+
NetworkController();
unsigned getDefaultNetwork() const;
@@ -53,10 +55,6 @@
unsigned getNetworkForInterface(const char* interface) const;
bool isVirtualNetwork(unsigned netId) const;
- // TODO: Remove this hack.
- unsigned getNetIdForLocalNetwork() const;
-
- int createLocalNetwork(unsigned netId) WARN_UNUSED_RESULT;
int createPhysicalNetwork(unsigned netId, Permission permission) WARN_UNUSED_RESULT;
int createVirtualNetwork(unsigned netId, bool hasDns) WARN_UNUSED_RESULT;
int destroyNetwork(unsigned netId) WARN_UNUSED_RESULT;
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index 8ad10d7..ec51613 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -43,7 +43,7 @@
const uint32_t RULE_PRIORITY_LEGACY_SYSTEM = 15000;
const uint32_t RULE_PRIORITY_LEGACY_NETWORK = 16000;
const uint32_t RULE_PRIORITY_LOCAL_NETWORK = 17000;
-// const uint32_t RULE_PRIORITY_TETHERING = 18000;
+const uint32_t RULE_PRIORITY_TETHERING = 18000;
const uint32_t RULE_PRIORITY_IMPLICIT_NETWORK = 19000;
// const uint32_t RULE_PRIORITY_BYPASSABLE_VPN = 20000;
// const uint32_t RULE_PRIORITY_VPN_FALLTHROUGH = 21000;
@@ -51,9 +51,11 @@
const uint32_t RULE_PRIORITY_DIRECTLY_CONNECTED = 23000;
const uint32_t RULE_PRIORITY_UNREACHABLE = 24000;
+const uint32_t ROUTE_TABLE_LOCAL_NETWORK = 97;
const uint32_t ROUTE_TABLE_LEGACY_NETWORK = 98;
const uint32_t ROUTE_TABLE_LEGACY_SYSTEM = 99;
+const char* const ROUTE_TABLE_NAME_LOCAL_NETWORK = "local_network";
const char* const ROUTE_TABLE_NAME_LEGACY_NETWORK = "legacy_network";
const char* const ROUTE_TABLE_NAME_LEGACY_SYSTEM = "legacy_system";
@@ -80,6 +82,7 @@
const char* const IP_VERSIONS[] = {"-4", "-6"};
const uid_t UID_ROOT = 0;
+const char* const IIF_NONE = NULL;
const char* const OIF_NONE = NULL;
const bool ACTION_ADD = true;
const bool ACTION_DEL = false;
@@ -147,6 +150,7 @@
addTableName(RT_TABLE_LOCAL, ROUTE_TABLE_NAME_LOCAL, &contents);
addTableName(RT_TABLE_MAIN, ROUTE_TABLE_NAME_MAIN, &contents);
+ addTableName(ROUTE_TABLE_LOCAL_NETWORK, ROUTE_TABLE_NAME_LOCAL_NETWORK, &contents);
addTableName(ROUTE_TABLE_LEGACY_NETWORK, ROUTE_TABLE_NAME_LEGACY_NETWORK, &contents);
addTableName(ROUTE_TABLE_LEGACY_SYSTEM, ROUTE_TABLE_NAME_LEGACY_SYSTEM, &contents);
@@ -219,36 +223,53 @@
return ret;
}
+// Returns 0 on success or negative errno on failure.
+int padInterfaceName(const char* input, char* name, size_t* length, uint16_t* padding) {
+ if (!input) {
+ *length = 0;
+ *padding = 0;
+ return 0;
+ }
+ *length = strlcpy(name, input, IFNAMSIZ) + 1;
+ if (*length > IFNAMSIZ) {
+ ALOGE("interface name too long (%zu > %u)", *length, IFNAMSIZ);
+ return -ENAMETOOLONG;
+ }
+ *padding = RTA_SPACE(*length) - RTA_LENGTH(*length);
+ return 0;
+}
+
// Adds or removes a routing rule for IPv4 and IPv6.
//
// + If |table| is non-zero, the rule points at the specified routing table. Otherwise, the rule
// returns ENETUNREACH.
// + If |mask| is non-zero, the rule matches the specified fwmark and mask. Otherwise, |fwmark| is
// ignored.
-// + If |interface| is non-NULL, the rule matches the specified outgoing interface.
+// + If |iif| is non-NULL, the rule matches the specified incoming interface.
+// + If |oif| is non-NULL, the rule matches the specified outgoing interface.
+// + If |uidStart| and |uidEnd| are not INVALID_UID, the rule matches packets from UIDs in that
+// range (inclusive). Otherwise, the rule matches packets from all UIDs.
//
// Returns 0 on success or negative errno on failure.
WARN_UNUSED_RESULT int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table,
- uint32_t fwmark, uint32_t mask, const char* interface,
- uid_t uidStart, uid_t uidEnd) {
+ uint32_t fwmark, uint32_t mask, const char* iif,
+ const char* oif, uid_t uidStart, uid_t uidEnd) {
// Ensure that if you set a bit in the fwmark, it's not being ignored by the mask.
if (fwmark & ~mask) {
ALOGE("mask 0x%x does not select all the bits set in fwmark 0x%x", mask, fwmark);
return -ERANGE;
}
- // The interface name must include exactly one terminating NULL and be properly padded, or older
+ // Interface names must include exactly one terminating NULL and be properly padded, or older
// kernels will refuse to delete rules.
- uint16_t paddingLength = 0;
- size_t interfaceLength = 0;
- char oifname[IFNAMSIZ];
- if (interface != OIF_NONE) {
- interfaceLength = strlcpy(oifname, interface, IFNAMSIZ) + 1;
- if (interfaceLength > IFNAMSIZ) {
- ALOGE("interface name too long (%zu > %u)", interfaceLength, IFNAMSIZ);
- return -ENAMETOOLONG;
- }
- paddingLength = RTA_SPACE(interfaceLength) - RTA_LENGTH(interfaceLength);
+ char iifName[IFNAMSIZ], oifName[IFNAMSIZ];
+ size_t iifLength, oifLength;
+ uint16_t iifPadding, oifPadding;
+ if (int ret = padInterfaceName(iif, iifName, &iifLength, &iifPadding)) {
+ return ret;
+ }
+ if (int ret = padInterfaceName(oif, oifName, &oifLength, &oifPadding)) {
+ return ret;
}
// Either both start and end UID must be specified, or neither.
@@ -264,7 +285,8 @@
FR_ACT_UNREACHABLE),
};
- rtattr fraOifname = { U16_RTA_LENGTH(interfaceLength), FRA_OIFNAME };
+ rtattr fraIifName = { U16_RTA_LENGTH(iifLength), FRA_IIFNAME };
+ rtattr fraOifName = { U16_RTA_LENGTH(oifLength), FRA_OIFNAME };
iovec iov[] = {
{ NULL, 0 },
@@ -281,9 +303,12 @@
{ &uidStart, isUidRule ? sizeof(uidStart) : 0 },
{ &FRATTR_UID_END, isUidRule ? sizeof(FRATTR_UID_END) : 0 },
{ &uidEnd, isUidRule ? sizeof(uidEnd) : 0 },
- { &fraOifname, interface != OIF_NONE ? sizeof(fraOifname) : 0 },
- { oifname, interfaceLength },
- { PADDING_BUFFER, paddingLength },
+ { &fraIifName, iif != IIF_NONE ? sizeof(fraIifName) : 0 },
+ { iifName, iifLength },
+ { PADDING_BUFFER, iifPadding },
+ { &fraOifName, oif != OIF_NONE ? sizeof(fraOifName) : 0 },
+ { oifName, oifLength },
+ { PADDING_BUFFER, oifPadding },
};
uint16_t flags = (action == RTM_NEWRULE) ? NETLINK_CREATE_REQUEST_FLAGS : NETLINK_REQUEST_FLAGS;
@@ -297,6 +322,12 @@
return 0;
}
+WARN_UNUSED_RESULT int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table,
+ uint32_t fwmark, uint32_t mask) {
+ return modifyIpRule(action, priority, table, fwmark, mask, IIF_NONE, OIF_NONE, INVALID_UID,
+ INVALID_UID);
+}
+
// Adds or deletes an IPv4 or IPv6 route.
// Returns 0 on success or negative errno on failure.
WARN_UNUSED_RESULT int modifyIpRoute(uint16_t action, uint32_t table, const char* interface,
@@ -370,7 +401,7 @@
}
// Add rules to allow legacy routes added through the requestRouteToHost() API.
-WARN_UNUSED_RESULT int AddLegacyRouteRules() {
+WARN_UNUSED_RESULT int addLegacyRouteRules() {
Fwmark fwmark;
Fwmark mask;
@@ -379,13 +410,11 @@
// Rules to allow legacy routes to override the default network.
if (int ret = modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_LEGACY_SYSTEM, ROUTE_TABLE_LEGACY_SYSTEM,
- fwmark.intValue, mask.intValue, OIF_NONE, INVALID_UID,
- INVALID_UID)) {
+ fwmark.intValue, mask.intValue)) {
return ret;
}
if (int ret = modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_LEGACY_NETWORK,
- ROUTE_TABLE_LEGACY_NETWORK, fwmark.intValue,
- mask.intValue, OIF_NONE, INVALID_UID, INVALID_UID)) {
+ ROUTE_TABLE_LEGACY_NETWORK, fwmark.intValue, mask.intValue)) {
return ret;
}
@@ -394,7 +423,7 @@
// A rule to allow legacy routes from system apps to override VPNs.
return modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_VPN_OVERRIDE_SYSTEM, ROUTE_TABLE_LEGACY_SYSTEM,
- fwmark.intValue, mask.intValue, OIF_NONE, INVALID_UID, INVALID_UID);
+ fwmark.intValue, mask.intValue);
}
// Add a new rule to look up the 'main' table, with the same selectors as the "default network"
@@ -402,7 +431,7 @@
// route, the rule we're adding will never be used for normal routing lookups. However, the kernel
// may fall-through to it to find directly-connected routes when it validates that a nexthop (in a
// route being added) is reachable.
-WARN_UNUSED_RESULT int AddDirectlyConnectedRule() {
+WARN_UNUSED_RESULT int addDirectlyConnectedRule() {
Fwmark fwmark;
Fwmark mask;
@@ -410,14 +439,26 @@
mask.netId = FWMARK_NET_ID_MASK;
return modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_DIRECTLY_CONNECTED, RT_TABLE_MAIN,
- fwmark.intValue, mask.intValue, OIF_NONE, UID_ROOT, UID_ROOT);
+ fwmark.intValue, mask.intValue, IIF_NONE, OIF_NONE, UID_ROOT, UID_ROOT);
}
// Add a rule to preempt the pre-defined "from all lookup main" rule. Packets that reach this rule
// will be null-routed, and won't fall-through to the main table.
-WARN_UNUSED_RESULT int AddUnreachableRule() {
+WARN_UNUSED_RESULT int addUnreachableRule() {
return modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_UNREACHABLE, RT_TABLE_UNSPEC, MARK_UNSET,
- MARK_UNSET, OIF_NONE, INVALID_UID, INVALID_UID);
+ MARK_UNSET);
+}
+
+// A rule to lookup the local network before looking up the default network.
+WARN_UNUSED_RESULT int addImplicitLocalNetworkRule() {
+ Fwmark fwmark;
+ Fwmark mask;
+
+ fwmark.explicitlySelected = false;
+ mask.explicitlySelected = true;
+
+ return modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_LOCAL_NETWORK, ROUTE_TABLE_LOCAL_NETWORK,
+ fwmark.intValue, mask.intValue);
}
// An iptables rule to mark incoming packets on a network with the netId of the network.
@@ -471,7 +512,7 @@
mask.permission = permission;
return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_EXPLICIT_NETWORK, table,
- fwmark.intValue, mask.intValue, OIF_NONE, uidStart, uidEnd);
+ fwmark.intValue, mask.intValue, IIF_NONE, OIF_NONE, uidStart, uidEnd);
}
// A rule to route traffic based on a chosen outgoing interface.
@@ -488,7 +529,7 @@
mask.permission = permission;
return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_OUTPUT_INTERFACE, table,
- fwmark.intValue, mask.intValue, interface, uidStart, uidEnd);
+ fwmark.intValue, mask.intValue, IIF_NONE, interface, uidStart, uidEnd);
}
// A rule to route traffic based on the chosen network.
@@ -511,7 +552,7 @@
mask.permission = permission;
return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_IMPLICIT_NETWORK, table,
- fwmark.intValue, mask.intValue, OIF_NONE, INVALID_UID, INVALID_UID);
+ fwmark.intValue, mask.intValue);
}
// A rule to route all traffic from a given set of UIDs to go over the VPN.
@@ -528,7 +569,7 @@
mask.protectedFromVpn = true;
return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_SECURE_VPN, table,
- fwmark.intValue, mask.intValue, OIF_NONE, uidStart, uidEnd);
+ fwmark.intValue, mask.intValue, IIF_NONE, OIF_NONE, uidStart, uidEnd);
}
// A rule to allow system apps to send traffic over this VPN even if they are not part of the target
@@ -547,39 +588,26 @@
mask.permission = PERMISSION_SYSTEM;
return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_SECURE_VPN, table,
- fwmark.intValue, mask.intValue, OIF_NONE, INVALID_UID, INVALID_UID);
+ fwmark.intValue, mask.intValue);
}
-// A rule to allow local network routes to override the default network.
-WARN_UNUSED_RESULT int modifyLocalOverrideRule(uint32_t table, bool add) {
- Fwmark fwmark;
- Fwmark mask;
-
- fwmark.explicitlySelected = false;
- mask.explicitlySelected = true;
-
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_LOCAL_NETWORK, table,
- fwmark.intValue, mask.intValue, OIF_NONE, INVALID_UID, INVALID_UID);
-}
-
-WARN_UNUSED_RESULT int modifyLocalNetwork(unsigned netId, const char* interface, bool add) {
- uint32_t table = getRouteTableForInterface(interface);
+WARN_UNUSED_RESULT int modifyTetheringRule(uint16_t action, const char* inputInterface,
+ const char* outputInterface) {
+ uint32_t table = getRouteTableForInterface(outputInterface);
if (table == RT_TABLE_UNSPEC) {
return -ESRCH;
}
+ return modifyIpRule(action, RULE_PRIORITY_TETHERING, table, MARK_UNSET, MARK_UNSET,
+ inputInterface, outputInterface, INVALID_UID, INVALID_UID);
+}
+
+WARN_UNUSED_RESULT int modifyLocalNetwork(unsigned netId, const char* interface, bool add) {
if (int ret = modifyIncomingPacketMark(netId, interface, PERMISSION_NONE, add)) {
return ret;
}
- if (int ret = modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, INVALID_UID, INVALID_UID,
- add)) {
- return ret;
- }
- if (int ret = modifyOutputInterfaceRule(interface, table, PERMISSION_NONE, INVALID_UID,
- INVALID_UID, add)) {
- return ret;
- }
- return modifyLocalOverrideRule(table, add);
+ return modifyOutputInterfaceRule(interface, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
+ INVALID_UID, INVALID_UID, add);
}
WARN_UNUSED_RESULT int modifyPhysicalNetwork(unsigned netId, const char* interface,
@@ -656,7 +684,7 @@
mask.permission = permission;
return modifyIpRule(action, RULE_PRIORITY_DEFAULT_NETWORK, table, fwmark.intValue,
- mask.intValue, OIF_NONE, INVALID_UID, INVALID_UID);
+ mask.intValue);
}
// Adds or removes an IPv4 or IPv6 route to the specified table and, if it's a directly-connected
@@ -673,6 +701,10 @@
}
break;
}
+ case RouteController::LOCAL_NETWORK: {
+ table = ROUTE_TABLE_LOCAL_NETWORK;
+ break;
+ }
case RouteController::LEGACY_NETWORK: {
table = ROUTE_TABLE_LEGACY_NETWORK;
break;
@@ -687,7 +719,8 @@
// We allow apps to call requestRouteToHost() multiple times with the same route, so ignore
// EEXIST failures when adding routes to legacy tables.
if (ret && !(action == RTM_NEWROUTE && ret == -EEXIST &&
- tableType != RouteController::INTERFACE)) {
+ (tableType == RouteController::LEGACY_NETWORK ||
+ tableType == RouteController::LEGACY_SYSTEM))) {
return ret;
}
@@ -737,40 +770,37 @@
} // namespace
-int RouteController::Init() {
- if (int ret = AddDirectlyConnectedRule()) {
+int RouteController::Init(unsigned localNetId) {
+ if (int ret = addDirectlyConnectedRule()) {
return ret;
}
- if (int ret = AddLegacyRouteRules()) {
+ if (int ret = addLegacyRouteRules()) {
return ret;
}
// TODO: Enable once we are sure everything works.
if (false) {
- if (int ret = AddUnreachableRule()) {
+ if (int ret = addUnreachableRule()) {
return ret;
}
}
+ if (int ret = addImplicitLocalNetworkRule()) {
+ return ret;
+ }
+ // Add a rule to lookup the local network it has been explicitly selected.
+ if (int ret = modifyExplicitNetworkRule(localNetId, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
+ INVALID_UID, INVALID_UID, ACTION_ADD)) {
+ return ret;
+ }
updateTableNamesFile();
return 0;
}
int RouteController::addInterfaceToLocalNetwork(unsigned netId, const char* interface) {
- if (int ret = modifyLocalNetwork(netId, interface, ACTION_ADD)) {
- return ret;
- }
- updateTableNamesFile();
- return 0;
+ return modifyLocalNetwork(netId, interface, ACTION_ADD);
}
int RouteController::removeInterfaceFromLocalNetwork(unsigned netId, const char* interface) {
- if (int ret = modifyLocalNetwork(netId, interface, ACTION_DEL)) {
- return ret;
- }
- if (int ret = flushRoutes(interface)) {
- return ret;
- }
- updateTableNamesFile();
- return 0;
+ return modifyLocalNetwork(netId, interface, ACTION_DEL);
}
int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
@@ -857,3 +887,11 @@
const char* nexthop, TableType tableType) {
return modifyRoute(RTM_DELROUTE, interface, destination, nexthop, tableType);
}
+
+int RouteController::enableTethering(const char* inputInterface, const char* outputInterface) {
+ return modifyTetheringRule(RTM_NEWRULE, inputInterface, outputInterface);
+}
+
+int RouteController::disableTethering(const char* inputInterface, const char* outputInterface) {
+ return modifyTetheringRule(RTM_DELRULE, inputInterface, outputInterface);
+}
diff --git a/server/RouteController.h b/server/RouteController.h
index a3010de..1d6075d 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -29,13 +29,14 @@
// How the routing table number is determined for route modification requests.
enum TableType {
INTERFACE, // Compute the table number based on the interface index.
+ LOCAL_NETWORK, // A fixed table used for routes to directly-connected clients/peers.
LEGACY_NETWORK, // Use a fixed table that's used to override the default network.
LEGACY_SYSTEM, // A fixed table, only modifiable by system apps; overrides VPNs too.
};
static const int ROUTE_TABLE_OFFSET_FROM_INDEX = 1000;
- static int Init() WARN_UNUSED_RESULT;
+ static int Init(unsigned localNetId) WARN_UNUSED_RESULT;
static int addInterfaceToLocalNetwork(unsigned netId, const char* interface) WARN_UNUSED_RESULT;
static int removeInterfaceFromLocalNetwork(unsigned netId,
@@ -69,6 +70,11 @@
TableType tableType) WARN_UNUSED_RESULT;
static int removeRoute(const char* interface, const char* destination, const char* nexthop,
TableType tableType) WARN_UNUSED_RESULT;
+
+ static int enableTethering(const char* inputInterface,
+ const char* outputInterface) WARN_UNUSED_RESULT;
+ static int disableTethering(const char* inputInterface,
+ const char* outputInterface) WARN_UNUSED_RESULT;
};
#endif // NETD_SERVER_ROUTE_CONTROLLER_H
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index 47b620d..fbee5a2 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -33,10 +33,8 @@
#include "NetdConstants.h"
#include "TetherController.h"
-#include "NetworkController.h"
-TetherController::TetherController(NetworkController* networkController) :
- mNetworkController(networkController) {
+TetherController::TetherController() {
mInterfaces = new InterfaceCollection();
mDnsForwarders = new NetAddressCollection();
mDaemonFd = -1;
@@ -172,17 +170,6 @@
ALOGD("Tethering services running");
}
- unsigned netId = mNetworkController->getNetIdForLocalNetwork();
- if (int ret = mNetworkController->createLocalNetwork(netId)) {
- return ret;
- }
- // If any interfaces have already been configured, add them to the local network now.
- for (InterfaceCollection::iterator it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
- if (int ret = mNetworkController->addInterfaceToNetwork(netId, *it)) {
- return ret;
- }
- }
-
return 0;
}
@@ -195,9 +182,6 @@
ALOGD("Stopping tethering services");
- // Ignore any error.
- (void) mNetworkController->destroyNetwork(mNetworkController->getNetIdForLocalNetwork());
-
kill(mDaemonPid, SIGTERM);
waitpid(mDaemonPid, NULL, 0);
mDaemonPid = 0;
@@ -307,10 +291,6 @@
}
return -1;
} else {
- if (isTetheringStarted()) {
- unsigned netId = mNetworkController->getNetIdForLocalNetwork();
- return mNetworkController->addInterfaceToNetwork(netId, interface);
- }
return 0;
}
}
@@ -320,12 +300,6 @@
ALOGD("untetherInterface(%s)", interface);
- if (isTetheringStarted()) {
- unsigned netId = mNetworkController->getNetIdForLocalNetwork();
- // Ignore any error.
- (void) mNetworkController->removeInterfaceFromNetwork(netId, interface);
- }
-
for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
if (!strcmp(interface, *it)) {
free(*it);
diff --git a/server/TetherController.h b/server/TetherController.h
index 38f7593..4da10b0 100644
--- a/server/TetherController.h
+++ b/server/TetherController.h
@@ -24,17 +24,14 @@
typedef android::netd::List<char *> InterfaceCollection;
typedef android::netd::List<struct in_addr> NetAddressCollection;
-class NetworkController;
-
class TetherController {
InterfaceCollection *mInterfaces;
NetAddressCollection *mDnsForwarders;
pid_t mDaemonPid;
int mDaemonFd;
- NetworkController* const mNetworkController;
public:
- explicit TetherController(NetworkController* networkController);
+ TetherController();
virtual ~TetherController();
int setIpFwdEnabled(bool enable);