summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--client/Android.mk3
-rw-r--r--server/Android.mk2
-rw-r--r--server/CommandListener.cpp110
-rw-r--r--server/DummyNetwork.cpp43
-rw-r--r--server/DummyNetwork.h34
-rw-r--r--server/NatController.cpp15
-rw-r--r--server/NetlinkHandler.cpp32
-rw-r--r--server/NetlinkHandler.h5
-rw-r--r--server/Network.h1
-rw-r--r--server/NetworkController.cpp5
-rw-r--r--server/NetworkController.h1
-rw-r--r--server/RouteController.cpp107
-rw-r--r--server/SoftapController.cpp4
-rw-r--r--server/TetherController.cpp68
-rw-r--r--server/TetherController.h10
16 files changed, 329 insertions, 112 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 00000000..5053e7d6
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/client/Android.mk b/client/Android.mk
index 0c5e7ea3..d3393d04 100644
--- a/client/Android.mk
+++ b/client/Android.mk
@@ -16,10 +16,11 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := bionic/libc/dns/include external/libcxx/include system/netd/include
+LOCAL_C_INCLUDES := bionic/libc/dns/include system/netd/include
LOCAL_CLANG := true
LOCAL_CPPFLAGS := -std=c++11 -Wall -Werror
LOCAL_MODULE := libnetd_client
LOCAL_SRC_FILES := FwmarkClient.cpp NetdClient.cpp
+include external/libcxx/libcxx.mk
include $(BUILD_SHARED_LIBRARY)
diff --git a/server/Android.mk b/server/Android.mk
index 35e34f55..cdf25994 100644
--- a/server/Android.mk
+++ b/server/Android.mk
@@ -47,6 +47,7 @@ LOCAL_SRC_FILES := \
ClatdController.cpp \
CommandListener.cpp \
DnsProxyListener.cpp \
+ DummyNetwork.cpp \
FirewallController.cpp \
FwmarkServer.cpp \
IdletimerController.cpp \
@@ -72,6 +73,7 @@ LOCAL_SRC_FILES := \
main.cpp \
oem_iptables_hook.cpp \
+include external/libcxx/libcxx.mk
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index b508d3fc..d7953966 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -507,37 +507,59 @@ CommandListener::IpFwdCmd::IpFwdCmd() :
NetdCommand("ipfwd") {
}
-int CommandListener::IpFwdCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
- int rc = 0;
-
- if (argc < 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
- return 0;
- }
-
- if (!strcmp(argv[1], "status")) {
- char *tmp = NULL;
-
- asprintf(&tmp, "Forwarding %s", (sTetherCtrl->getIpFwdEnabled() ? "enabled" : "disabled"));
- cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false);
- free(tmp);
- return 0;
- } else if (!strcmp(argv[1], "enable")) {
- rc = sTetherCtrl->setIpFwdEnabled(true);
- } else if (!strcmp(argv[1], "disable")) {
- rc = sTetherCtrl->setIpFwdEnabled(false);
- } else {
+int CommandListener::IpFwdCmd::runCommand(SocketClient *cli, int argc, char **argv) {
+ bool matched = false;
+ bool success;
+
+ if (argc == 2) {
+ // 0 1
+ // ipfwd status
+ if (!strcmp(argv[1], "status")) {
+ char *tmp = NULL;
+
+ asprintf(&tmp, "Forwarding %s",
+ ((sTetherCtrl->forwardingRequestCount() > 0) ? "enabled" : "disabled"));
+ cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false);
+ free(tmp);
+ return 0;
+ }
+ } else if (argc == 3) {
+ // 0 1 2
+ // ipfwd enable <requester>
+ // ipfwd disable <requester>
+ if (!strcmp(argv[1], "enable")) {
+ matched = true;
+ success = sTetherCtrl->enableForwarding(argv[2]);
+ } else if (!strcmp(argv[1], "disable")) {
+ matched = true;
+ success = sTetherCtrl->disableForwarding(argv[2]);
+ }
+ } else if (argc == 4) {
+ // 0 1 2 3
+ // ipfwd add wlan0 dummy0
+ // ipfwd remove wlan0 dummy0
+ int ret = 0;
+ if (!strcmp(argv[1], "add")) {
+ matched = true;
+ ret = RouteController::enableTethering(argv[2], argv[3]);
+ } else if (!strcmp(argv[1], "remove")) {
+ matched = true;
+ ret = RouteController::disableTethering(argv[2], argv[3]);
+ }
+ success = (ret == 0);
+ errno = -ret;
+ }
+
+ if (!matched) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
return 0;
}
- if (!rc) {
+ if (success) {
cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
} else {
cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
}
-
return 0;
}
@@ -797,15 +819,19 @@ int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char *
int rc = 0;
const char **argv = const_cast<const char **>(margv);
- if (argc < 2) {
+ if (argc < 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments", false);
return 0;
}
+ unsigned netId = stringToNetId(argv[2]);
+ // TODO: Consider making NetworkController.isValidNetwork() public
+ // and making that check here.
+
if (!strcmp(argv[1], "setnetdns")) {
// "resolver setnetdns <netId> <domains> <dns1> <dns2> ..."
if (argc >= 5) {
- rc = sResolverCtrl->setDnsServers(strtoul(argv[2], NULL, 0), argv[3], &argv[4], argc - 4);
+ rc = sResolverCtrl->setDnsServers(netId, argv[3], &argv[4], argc - 4);
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Wrong number of arguments to resolver setnetdns", false);
@@ -813,7 +839,7 @@ int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char *
}
} else if (!strcmp(argv[1], "clearnetdns")) { // "resolver clearnetdns <netId>"
if (argc == 3) {
- rc = sResolverCtrl->clearDnsServers(strtoul(argv[2], NULL, 0));
+ rc = sResolverCtrl->clearDnsServers(netId);
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Wrong number of arguments to resolver clearnetdns", false);
@@ -821,7 +847,7 @@ int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char *
}
} else if (!strcmp(argv[1], "flushnet")) { // "resolver flushnet <netId>"
if (argc == 3) {
- rc = sResolverCtrl->flushDnsCache(strtoul(argv[2], NULL, 0));
+ rc = sResolverCtrl->flushDnsCache(netId);
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Wrong number of arguments to resolver flushnet", false);
@@ -1633,24 +1659,36 @@ int CommandListener::NetworkCommand::runCommand(SocketClient* client, int argc,
if (nextArg == argc) {
return syntaxError(client, "Missing id");
}
+
+ bool userPermissions = !strcmp(argv[2], "user");
+ bool networkPermissions = !strcmp(argv[2], "network");
+ if (!userPermissions && !networkPermissions) {
+ return syntaxError(client, "Unknown argument");
+ }
+
std::vector<unsigned> ids;
for (; nextArg < argc; ++nextArg) {
- char* endPtr;
- unsigned id = strtoul(argv[nextArg], &endPtr, 0);
- if (!*argv[nextArg] || *endPtr) {
- return syntaxError(client, "Invalid id");
+ if (userPermissions) {
+ char* endPtr;
+ unsigned id = strtoul(argv[nextArg], &endPtr, 0);
+ if (!*argv[nextArg] || *endPtr) {
+ return syntaxError(client, "Invalid id");
+ }
+ ids.push_back(id);
+ } else {
+ // networkPermissions
+ ids.push_back(stringToNetId(argv[nextArg]));
}
- ids.push_back(id);
}
- if (!strcmp(argv[2], "user")) {
+ if (userPermissions) {
sNetCtrl->setPermissionForUsers(permission, ids);
- } else if (!strcmp(argv[2], "network")) {
+ } else {
+ // networkPermissions
if (int ret = sNetCtrl->setPermissionForNetworks(permission, ids)) {
return operationError(client, "setPermissionForNetworks() failed", ret);
}
- } else {
- return syntaxError(client, "Unknown argument");
}
+
return success(client);
}
diff --git a/server/DummyNetwork.cpp b/server/DummyNetwork.cpp
new file mode 100644
index 00000000..ff2cb412
--- /dev/null
+++ b/server/DummyNetwork.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DummyNetwork.h"
+
+#include "RouteController.h"
+
+#define LOG_TAG "Netd"
+#include "log/log.h"
+
+const char* DummyNetwork::INTERFACE_NAME = "dummy0";
+
+DummyNetwork::DummyNetwork(unsigned netId) : Network(netId) {
+ mInterfaces.insert(INTERFACE_NAME);
+}
+
+DummyNetwork::~DummyNetwork() {
+}
+
+Network::Type DummyNetwork::getType() const {
+ return DUMMY;
+}
+
+int DummyNetwork::addInterface(const std::string& /* interface */) {
+ return -EINVAL;
+}
+
+int DummyNetwork::removeInterface(const std::string& /* interface */) {
+ return -EINVAL;
+}
diff --git a/server/DummyNetwork.h b/server/DummyNetwork.h
new file mode 100644
index 00000000..7bc0d3d4
--- /dev/null
+++ b/server/DummyNetwork.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NETD_SERVER_DUMMY_NETWORK_H
+#define NETD_SERVER_DUMMY_NETWORK_H
+
+#include "Network.h"
+
+class DummyNetwork : public Network {
+public:
+ static const char* INTERFACE_NAME;
+ explicit DummyNetwork(unsigned netId);
+ virtual ~DummyNetwork();
+
+private:
+ Type getType() const override;
+ int addInterface(const std::string& interface) override WARN_UNUSED_RESULT;
+ int removeInterface(const std::string& interface) override WARN_UNUSED_RESULT;
+};
+
+#endif // NETD_SERVER_DUMMY_NETWORK_H
diff --git a/server/NatController.cpp b/server/NatController.cpp
index e66d9715..5a15afa9 100644
--- a/server/NatController.cpp
+++ b/server/NatController.cpp
@@ -199,15 +199,6 @@ int NatController::enableNat(const char* intIface, const char* extIface) {
};
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);
- if (natCount == 0) {
- setDefaults();
- }
- errno = -ret;
- return -1;
- }
-
natCount++;
return 0;
}
@@ -368,12 +359,6 @@ int NatController::disableNat(const char* intIface, const char* extIface) {
return -1;
}
- 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);
if (--natCount <= 0) {
// handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
diff --git a/server/NetlinkHandler.cpp b/server/NetlinkHandler.cpp
index 0a5a3f02..55351190 100644
--- a/server/NetlinkHandler.cpp
+++ b/server/NetlinkHandler.cpp
@@ -58,26 +58,26 @@ void NetlinkHandler::onEvent(NetlinkEvent *evt) {
}
if (!strcmp(subsys, "net")) {
- int action = evt->getAction();
+ NetlinkEvent::Action action = evt->getAction();
const char *iface = evt->findParam("INTERFACE");
- if (action == evt->NlActionAdd) {
+ if (action == NetlinkEvent::Action::kAdd) {
notifyInterfaceAdded(iface);
- } else if (action == evt->NlActionRemove) {
+ } else if (action == NetlinkEvent::Action::kRemove) {
notifyInterfaceRemoved(iface);
- } else if (action == evt->NlActionChange) {
+ } else if (action == NetlinkEvent::Action::kChange) {
evt->dump();
notifyInterfaceChanged("nana", true);
- } else if (action == evt->NlActionLinkUp) {
+ } else if (action == NetlinkEvent::Action::kLinkUp) {
notifyInterfaceLinkChanged(iface, true);
- } else if (action == evt->NlActionLinkDown) {
+ } else if (action == NetlinkEvent::Action::kLinkDown) {
notifyInterfaceLinkChanged(iface, false);
- } else if (action == evt->NlActionAddressUpdated ||
- action == evt->NlActionAddressRemoved) {
+ } else if (action == NetlinkEvent::Action::kAddressUpdated ||
+ action == NetlinkEvent::Action::kAddressRemoved) {
const char *address = evt->findParam("ADDRESS");
const char *flags = evt->findParam("FLAGS");
const char *scope = evt->findParam("SCOPE");
- if (action == evt->NlActionAddressRemoved && iface && address) {
+ if (action == NetlinkEvent::Action::kAddressRemoved && iface && address) {
int resetMask = strchr(address, ':') ? RESET_IPV6_ADDRESSES : RESET_IPV4_ADDRESSES;
resetMask |= RESET_IGNORE_INTERFACE_ADDRESS;
if (int ret = ifc_reset_connections(iface, resetMask)) {
@@ -88,14 +88,14 @@ void NetlinkHandler::onEvent(NetlinkEvent *evt) {
if (iface && flags && scope) {
notifyAddressChanged(action, address, iface, flags, scope);
}
- } else if (action == evt->NlActionRdnss) {
+ } else if (action == NetlinkEvent::Action::kRdnss) {
const char *lifetime = evt->findParam("LIFETIME");
const char *servers = evt->findParam("SERVERS");
if (lifetime && servers) {
notifyInterfaceDnsServers(iface, lifetime, servers);
}
- } else if (action == evt->NlActionRouteUpdated ||
- action == evt->NlActionRouteRemoved) {
+ } else if (action == NetlinkEvent::Action::kRouteUpdated ||
+ action == NetlinkEvent::Action::kRouteRemoved) {
const char *route = evt->findParam("ROUTE");
const char *gateway = evt->findParam("GATEWAY");
const char *iface = evt->findParam("INTERFACE");
@@ -174,12 +174,12 @@ void NetlinkHandler::notifyInterfaceClassActivity(const char *name,
"IfaceClass %s %s %s", isActive ? "active" : "idle", name, timestamp);
}
-void NetlinkHandler::notifyAddressChanged(int action, const char *addr,
+void NetlinkHandler::notifyAddressChanged(NetlinkEvent::Action action, const char *addr,
const char *iface, const char *flags,
const char *scope) {
notify(ResponseCode::InterfaceAddressChange,
"Address %s %s %s %s %s",
- (action == NetlinkEvent::NlActionAddressUpdated) ? kUpdated : kRemoved,
+ (action == NetlinkEvent::Action::kAddressUpdated) ? kUpdated : kRemoved,
addr, iface, flags, scope);
}
@@ -190,11 +190,11 @@ void NetlinkHandler::notifyInterfaceDnsServers(const char *iface,
iface, lifetime, servers);
}
-void NetlinkHandler::notifyRouteChange(int action, const char *route,
+void NetlinkHandler::notifyRouteChange(NetlinkEvent::Action action, const char *route,
const char *gateway, const char *iface) {
notify(ResponseCode::RouteChange,
"Route %s %s%s%s%s%s",
- (action == NetlinkEvent::NlActionRouteUpdated) ? kUpdated : kRemoved,
+ (action == NetlinkEvent::Action::kRouteUpdated) ? kUpdated : kRemoved,
route,
*gateway ? " via " : "",
gateway,
diff --git a/server/NetlinkHandler.h b/server/NetlinkHandler.h
index bee52dcb..c70867e2 100644
--- a/server/NetlinkHandler.h
+++ b/server/NetlinkHandler.h
@@ -17,6 +17,7 @@
#ifndef _NETLINKHANDLER_H
#define _NETLINKHANDLER_H
+#include <sysutils/NetlinkEvent.h>
#include <sysutils/NetlinkListener.h>
#include "NetlinkManager.h"
@@ -41,11 +42,11 @@ protected:
void notifyQuotaLimitReached(const char *name, const char *iface);
void notifyInterfaceClassActivity(const char *name, bool isActive,
const char *timestamp);
- void notifyAddressChanged(int action, const char *addr, const char *iface,
+ void notifyAddressChanged(NetlinkEvent::Action action, const char *addr, const char *iface,
const char *flags, const char *scope);
void notifyInterfaceDnsServers(const char *iface, const char *lifetime,
const char *servers);
- void notifyRouteChange(int action, const char *route, const char *gateway, const char *iface);
+ void notifyRouteChange(NetlinkEvent::Action action, const char *route, const char *gateway, const char *iface);
void notifyStrictCleartext(const char* uid, const char* hex);
};
#endif
diff --git a/server/Network.h b/server/Network.h
index 115997ad..3af53d97 100644
--- a/server/Network.h
+++ b/server/Network.h
@@ -26,6 +26,7 @@
class Network {
public:
enum Type {
+ DUMMY,
LOCAL,
PHYSICAL,
VIRTUAL,
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index 20d8e977..76e4a6af 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -32,6 +32,7 @@
#include "NetworkController.h"
+#include "DummyNetwork.h"
#include "Fwmark.h"
#include "LocalNetwork.h"
#include "PhysicalNetwork.h"
@@ -53,7 +54,8 @@ const unsigned MAX_NET_ID = 65535;
const unsigned NetworkController::MIN_OEM_ID = 1;
const unsigned NetworkController::MAX_OEM_ID = 50;
-// NetIds 51..98 are reserved for future use.
+const unsigned NetworkController::DUMMY_NET_ID = 51;
+// NetIds 52..98 are reserved for future use.
const unsigned NetworkController::LOCAL_NET_ID = 99;
// All calls to methods here are made while holding a write lock on mRWLock.
@@ -132,6 +134,7 @@ int NetworkController::DelegateImpl::modifyFallthrough(const std::string& physic
NetworkController::NetworkController() :
mDelegateImpl(new NetworkController::DelegateImpl(this)), mDefaultNetId(NETID_UNSET) {
mNetworks[LOCAL_NET_ID] = new LocalNetwork(LOCAL_NET_ID);
+ mNetworks[DUMMY_NET_ID] = new DummyNetwork(DUMMY_NET_ID);
}
unsigned NetworkController::getDefaultNetwork() const {
diff --git a/server/NetworkController.h b/server/NetworkController.h
index 5596f0c0..073745da 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -43,6 +43,7 @@ public:
static const unsigned MIN_OEM_ID;
static const unsigned MAX_OEM_ID;
static const unsigned LOCAL_NET_ID;
+ static const unsigned DUMMY_NET_ID;
NetworkController();
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index b47acd4a..98a965e7 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -29,10 +29,12 @@
#include "Fwmark.h"
#include "UidRanges.h"
+#include "DummyNetwork.h"
#define LOG_TAG "Netd"
#include "log/log.h"
#include "logwrap/logwrap.h"
+#include "netutils/ifc.h"
#include "utils/file.h"
#include "resolv_netid.h"
@@ -41,6 +43,7 @@ namespace {
// BEGIN CONSTANTS --------------------------------------------------------------------------------
const uint32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM = 10000;
+const uint32_t RULE_PRIORITY_VPN_OVERRIDE_OIF = 10500;
const uint32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL = 11000;
const uint32_t RULE_PRIORITY_SECURE_VPN = 12000;
const uint32_t RULE_PRIORITY_EXPLICIT_NETWORK = 13000;
@@ -87,6 +90,7 @@ const uint8_t AF_FAMILIES[] = {AF_INET, AF_INET6};
const char* const IP_VERSIONS[] = {"-4", "-6"};
const uid_t UID_ROOT = 0;
+const char* const IIF_LOOPBACK = "lo";
const char* const IIF_NONE = NULL;
const char* const OIF_NONE = NULL;
const bool ACTION_ADD = true;
@@ -236,8 +240,10 @@ int padInterfaceName(const char* input, char* name, size_t* length, uint16_t* pa
// 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 |priority| is RULE_PRIORITY_UNREACHABLE, the rule returns ENETUNREACH (i.e., specifies an
+// action of FR_ACT_UNREACHABLE). Otherwise, the rule specifies an action of FR_ACT_TO_TBL.
+// + If |table| is non-zero, the rule points at the specified routing table. Otherwise, the table is
+// unspecified. An unspecified table is only allowed when deleting a rule.
// + If |mask| is non-zero, the rule matches the specified fwmark and mask. Otherwise, |fwmark| is
// ignored.
// + If |iif| is non-NULL, the rule matches the specified incoming interface.
@@ -276,10 +282,20 @@ WARN_UNUSED_RESULT int modifyIpRule(uint16_t action, uint32_t priority, uint32_t
// Assemble a rule request and put it in an array of iovec structures.
fib_rule_hdr rule = {
- .action = static_cast<uint8_t>(table != RT_TABLE_UNSPEC ? FR_ACT_TO_TBL :
- FR_ACT_UNREACHABLE),
+ .action = static_cast<uint8_t>(priority != RULE_PRIORITY_UNREACHABLE ? FR_ACT_TO_TBL :
+ FR_ACT_UNREACHABLE),
+ // Note that here we're implicitly setting rule.table to 0. When we want to specify a
+ // non-zero table, we do this via the FRATTR_TABLE attribute.
};
+ // Don't ever create a rule that looks up table 0, because table 0 is the local table.
+ // It's OK to specify a table ID of 0 when deleting a rule, because that doesn't actually select
+ // table 0, it's a wildcard that matches anything.
+ if (table == RT_TABLE_UNSPEC && rule.action == FR_ACT_TO_TBL && action != RTM_DELRULE) {
+ ALOGE("RT_TABLE_UNSPEC only allowed when deleting rules");
+ return -ENOTUNIQ;
+ }
+
rtattr fraIifName = { U16_RTA_LENGTH(iifLength), FRA_IIFNAME };
rtattr fraOifName = { U16_RTA_LENGTH(oifLength), FRA_OIFNAME };
@@ -474,7 +490,7 @@ WARN_UNUSED_RESULT int modifyVpnUidRangeRule(uint32_t table, uid_t uidStart, uid
}
return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, priority, table, fwmark.intValue,
- mask.intValue, IIF_NONE, OIF_NONE, uidStart, uidEnd);
+ mask.intValue, IIF_LOOPBACK, 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
@@ -529,15 +545,25 @@ WARN_UNUSED_RESULT int modifyExplicitNetworkRule(unsigned netId, uint32_t table,
//
// Supports apps that use SO_BINDTODEVICE or IP_PKTINFO options and the kernel that already knows
// the outgoing interface (typically for link-local communications).
-WARN_UNUSED_RESULT int modifyOutputInterfaceRule(const char* interface, uint32_t table,
- Permission permission, uid_t uidStart,
- uid_t uidEnd, bool add) {
+WARN_UNUSED_RESULT int modifyOutputInterfaceRules(const char* interface, uint32_t table,
+ Permission permission, uid_t uidStart,
+ uid_t uidEnd, bool add) {
Fwmark fwmark;
Fwmark mask;
fwmark.permission = permission;
mask.permission = permission;
+ // If this rule does not specify a UID range, then also add a corresponding high-priority rule
+ // for UID. This covers forwarded packets and system daemons such as the tethering DHCP server.
+ if (uidStart == INVALID_UID && uidEnd == INVALID_UID) {
+ if (int ret = modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_VPN_OVERRIDE_OIF,
+ table, fwmark.intValue, mask.intValue, IIF_NONE, interface,
+ UID_ROOT, UID_ROOT)) {
+ return ret;
+ }
+ }
+
return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_OUTPUT_INTERFACE, table,
fwmark.intValue, mask.intValue, IIF_NONE, interface, uidStart, uidEnd);
}
@@ -637,6 +663,41 @@ WARN_UNUSED_RESULT int addLocalNetworkRules(unsigned localNetId) {
fwmark.intValue, mask.intValue);
}
+int configureDummyNetwork() {
+ const char *interface = DummyNetwork::INTERFACE_NAME;
+ uint32_t table = getRouteTableForInterface(interface);
+ if (table == RT_TABLE_UNSPEC) {
+ // getRouteTableForInterface has already looged an error.
+ return -ESRCH;
+ }
+
+ ifc_init();
+ int ret = ifc_up(interface);
+ ifc_close();
+ if (ret) {
+ ALOGE("Can't bring up %s: %s", interface, strerror(errno));
+ return -errno;
+ }
+
+ if ((ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE,
+ INVALID_UID, INVALID_UID, ACTION_ADD))) {
+ ALOGE("Can't create oif rules for %s: %s", interface, strerror(-ret));
+ return ret;
+ }
+
+ if ((ret = modifyIpRoute(RTM_NEWROUTE, table, interface, "0.0.0.0/0", NULL))) {
+ ALOGE("Can't add IPv4 default route to %s: %s", interface, strerror(-ret));
+ return ret;
+ }
+
+ if ((ret = modifyIpRoute(RTM_NEWROUTE, table, interface, "::/0", NULL))) {
+ ALOGE("Can't add IPv6 default route to %s: %s", interface, strerror(-ret));
+ return ret;
+ }
+
+ return 0;
+}
+
// Add a new rule to look up the 'main' table, with the same selectors as the "default network"
// rule, but with a lower priority. We will never create routes in the main table; it should only be
// used for directly-connected routes implicitly created by the kernel when adding IP addresses.
@@ -666,8 +727,8 @@ WARN_UNUSED_RESULT int modifyLocalNetwork(unsigned netId, const char* interface,
if (int ret = modifyIncomingPacketMark(netId, interface, PERMISSION_NONE, add)) {
return ret;
}
- return modifyOutputInterfaceRule(interface, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
- INVALID_UID, INVALID_UID, add);
+ return modifyOutputInterfaceRules(interface, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
+ INVALID_UID, INVALID_UID, add);
}
WARN_UNUSED_RESULT int modifyPhysicalNetwork(unsigned netId, const char* interface,
@@ -684,7 +745,7 @@ WARN_UNUSED_RESULT int modifyPhysicalNetwork(unsigned netId, const char* interfa
add)) {
return ret;
}
- if (int ret = modifyOutputInterfaceRule(interface, table, permission, INVALID_UID, INVALID_UID,
+ if (int ret = modifyOutputInterfaceRules(interface, table, permission, INVALID_UID, INVALID_UID,
add)) {
return ret;
}
@@ -707,8 +768,8 @@ WARN_UNUSED_RESULT int modifyVirtualNetwork(unsigned netId, const char* interfac
range.second, add)) {
return ret;
}
- if (int ret = modifyOutputInterfaceRule(interface, table, PERMISSION_NONE, range.first,
- range.second, add)) {
+ if (int ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE, range.first,
+ range.second, add)) {
return ret;
}
}
@@ -864,6 +925,20 @@ WARN_UNUSED_RESULT int flushRoutes(const char* interface) {
return ret;
}
+WARN_UNUSED_RESULT int clearTetheringRules(const char* inputInterface) {
+ int ret = 0;
+ while (ret == 0) {
+ ret = modifyIpRule(RTM_DELRULE, RULE_PRIORITY_TETHERING, 0, MARK_UNSET, MARK_UNSET,
+ inputInterface, OIF_NONE, INVALID_UID, INVALID_UID);
+ }
+
+ if (ret == -ENOENT) {
+ return 0;
+ } else {
+ return ret;
+ }
+}
+
} // namespace
int RouteController::Init(unsigned localNetId) {
@@ -882,6 +957,9 @@ int RouteController::Init(unsigned localNetId) {
if (int ret = addUnreachableRule()) {
return ret;
}
+ // Don't complain if we can't add the dummy network, since not all devices support it.
+ configureDummyNetwork();
+
updateTableNamesFile();
return 0;
}
@@ -911,6 +989,9 @@ int RouteController::removeInterfaceFromPhysicalNetwork(unsigned netId, const ch
if (int ret = flushRoutes(interface)) {
return ret;
}
+ if (int ret = clearTetheringRules(interface)) {
+ return ret;
+ }
updateTableNamesFile();
return 0;
}
diff --git a/server/SoftapController.cpp b/server/SoftapController.cpp
index 0759bde7..24655291 100644
--- a/server/SoftapController.cpp
+++ b/server/SoftapController.cpp
@@ -142,10 +142,10 @@ int SoftapController::setSoftap(int argc, char *argv[]) {
"ssid=%s\n"
"channel=%d\n"
"ieee80211n=1\n"
- "hw_mode=g\n"
+ "hw_mode=%c\n"
"ignore_broadcast_ssid=%d\n"
"wowlan_triggers=any\n",
- argv[2], argv[3], channel, hidden));
+ argv[2], argv[3], channel, (channel <= 14) ? 'g' : 'a', hidden));
std::string fbuf;
if (argc > 7) {
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index c9a93fd6..5a08ed21 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -37,12 +37,36 @@
#include "Permission.h"
#include "TetherController.h"
+namespace {
+
+static const char BP_TOOLS_MODE[] = "bp-tools";
+static const char IPV4_FORWARDING_PROC_FILE[] = "/proc/sys/net/ipv4/ip_forward";
+static const char IPV6_FORWARDING_PROC_FILE[] = "/proc/sys/net/ipv6/conf/all/forwarding";
+
+bool writeToFile(const char* filename, const char* value) {
+ return WriteStringToFile(value, file);
+}
+
+bool inBpToolsMode() {
+ // In BP tools mode, do not disable IP forwarding
+ char bootmode[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.bootmode", bootmode, "unknown");
+ return !strcmp(BP_TOOLS_MODE, bootmode);
+}
+
+} // namespace
+
TetherController::TetherController() {
mInterfaces = new InterfaceCollection();
mDnsNetId = 0;
mDnsForwarders = new NetAddressCollection();
mDaemonFd = -1;
mDaemonPid = 0;
+ if (inBpToolsMode()) {
+ enableForwarding(BP_TOOLS_MODE);
+ } else {
+ setIpFwdEnabled();
+ }
}
TetherController::~TetherController() {
@@ -54,35 +78,33 @@ TetherController::~TetherController() {
mInterfaces->clear();
mDnsForwarders->clear();
+ mForwardingRequests.clear();
}
-int TetherController::setIpFwdEnabled(bool enable) {
-
- ALOGD("Setting IP forward enable = %d", enable);
-
- // In BP tools mode, do not disable IP forwarding
- char bootmode[PROPERTY_VALUE_MAX] = {0};
- property_get("ro.bootmode", bootmode, "unknown");
- if ((enable == false) && (0 == strcmp("bp-tools", bootmode))) {
- return 0;
- }
-
- if (!android::WriteStringToFile(enable ? "1" : "0", "/proc/sys/net/ipv4/ip_forward")) {
- ALOGE("Failed to write ip_forward (%s)", strerror(errno));
- return -1;
- }
+bool TetherController::setIpFwdEnabled() {
+ bool success = true;
+ const char* value = mForwardingRequests.empty() ? "0" : "1";
+ ALOGD("Setting IP forward enable = %s", value);
+ success &= writeToFile(IPV4_FORWARDING_PROC_FILE, value);
+ success &= writeToFile(IPV6_FORWARDING_PROC_FILE, value);
+ return success;
+}
- return 0;
+bool TetherController::enableForwarding(const char* requester) {
+ // Don't return an error if this requester already requested forwarding. Only return errors for
+ // things that the caller caller needs to care about, such as "couldn't write to the file to
+ // enable forwarding".
+ mForwardingRequests.insert(requester);
+ return setIpFwdEnabled();
}
-bool TetherController::getIpFwdEnabled() {
- std::string enabled;
- if (!android::ReadFileToString("/proc/sys/net/ipv4/ip_forward", &enabled)) {
- ALOGE("Failed to read ip_forward (%s)", strerror(errno));
- return -1;
- }
+bool TetherController::disableForwarding(const char* requester) {
+ mForwardingRequests.erase(requester);
+ return setIpFwdEnabled();
+}
- return (enabled == "1" ? true : false);
+size_t TetherController::forwardingRequestCount() {
+ return mForwardingRequests.size();
}
#define TETHER_START_CONST_ARG 8
diff --git a/server/TetherController.h b/server/TetherController.h
index 1c326270..91ffb9cc 100644
--- a/server/TetherController.h
+++ b/server/TetherController.h
@@ -18,6 +18,8 @@
#define _TETHER_CONTROLLER_H
#include <netinet/in.h>
+#include <set>
+#include <string>
#include "List.h"
@@ -32,16 +34,17 @@ class TetherController {
NetAddressCollection *mDnsForwarders;
pid_t mDaemonPid;
int mDaemonFd;
+ std::set<std::string> mForwardingRequests;
public:
TetherController();
virtual ~TetherController();
- int setIpFwdEnabled(bool enable);
- bool getIpFwdEnabled();
+ bool enableForwarding(const char* requester);
+ bool disableForwarding(const char* requester);
+ size_t forwardingRequestCount();
int startTethering(int num_addrs, struct in_addr* addrs);
-
int stopTethering();
bool isTetheringStarted();
@@ -55,6 +58,7 @@ public:
private:
int applyDnsInterfaces();
+ bool setIpFwdEnabled();
};
#endif