summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2018-06-07 03:01:58 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2018-06-07 03:01:58 +0000
commit4aa84ab2111f8ba3bc6f6e2d3e0cd176ba3de903 (patch)
tree0a4d286e98ca1efd883636473129406214d4785e
parentd6178afc766582d9e379925ddc78fbfd874e48bb (diff)
parent33ef503e865d634a10f4a788f9713160141f6dd4 (diff)
downloadnetd-4aa84ab2111f8ba3bc6f6e2d3e0cd176ba3de903.tar.gz
Snap for 4826407 from 33ef503e865d634a10f4a788f9713160141f6dd4 to pi-dr1-release
Change-Id: I99218ba406d1019a6ad8fe4a4b1018b82953858a
-rw-r--r--server/NetlinkHandler.cpp66
-rw-r--r--server/NetworkController.cpp106
-rw-r--r--server/NetworkController.h26
-rw-r--r--server/RouteController.cpp12
-rw-r--r--server/RouteController.h9
-rw-r--r--server/XfrmController.cpp31
6 files changed, 210 insertions, 40 deletions
diff --git a/server/NetlinkHandler.cpp b/server/NetlinkHandler.cpp
index 9b033ff7..2bc9c279 100644
--- a/server/NetlinkHandler.cpp
+++ b/server/NetlinkHandler.cpp
@@ -55,6 +55,18 @@ int NetlinkHandler::stop() {
return this->stopListener();
}
+static long parseIfIndex(const char* ifIndex) {
+ if (ifIndex == nullptr) {
+ return 0;
+ }
+ long ifaceIndex = strtol(ifIndex, NULL, 10);
+ // strtol returns 0 on error, which is fine because 0 is not a valid ifindex.
+ if (errno == ERANGE && (ifaceIndex == LONG_MAX || ifaceIndex == LONG_MIN)) {
+ return 0;
+ }
+ return ifaceIndex;
+}
+
void NetlinkHandler::onEvent(NetlinkEvent *evt) {
const char *subsys = evt->getSubsystem();
if (!subsys) {
@@ -69,15 +81,11 @@ void NetlinkHandler::onEvent(NetlinkEvent *evt) {
(action == NetlinkEvent::Action::kLinkUp) ||
(action == NetlinkEvent::Action::kLinkDown)) {
const char *ifIndex = evt->findParam("IFINDEX");
- if (ifIndex) {
- // strtol returns 0 on error, which is fine because 0 is not a valid ifindex.
- long ifaceIndex = strtol(ifIndex, NULL, 10);
- if (ifaceIndex == 0 ||
- (errno == ERANGE && (ifaceIndex == LONG_MAX || ifaceIndex == LONG_MIN))) {
- ALOGE("invalid interface index: %s(%s)", iface, ifIndex);
- } else {
- gCtls->trafficCtrl.addInterface(iface, ifaceIndex);
- }
+ long ifaceIndex = parseIfIndex(ifIndex);
+ if (ifaceIndex) {
+ gCtls->trafficCtrl.addInterface(iface, ifaceIndex);
+ } else {
+ ALOGE("invalid interface index: %s(%s)", iface, ifIndex);
}
}
@@ -97,25 +105,35 @@ void NetlinkHandler::onEvent(NetlinkEvent *evt) {
const char *address = evt->findParam("ADDRESS");
const char *flags = evt->findParam("FLAGS");
const char *scope = evt->findParam("SCOPE");
- if (action == NetlinkEvent::Action::kAddressRemoved && iface && address) {
- // Note: if this interface was deleted, iface is "" and we don't notify.
- SockDiag sd;
- if (sd.open()) {
- char addrstr[INET6_ADDRSTRLEN];
- strncpy(addrstr, address, sizeof(addrstr));
- char *slash = strchr(addrstr, '/');
- if (slash) {
- *slash = '\0';
- }
+ const char *ifIndex = evt->findParam("IFINDEX");
+ char addrstr[INET6_ADDRSTRLEN + strlen("/128")];
+ strlcpy(addrstr, address, sizeof(addrstr));
+ char *slash = strchr(addrstr, '/');
+ if (slash) {
+ *slash = '\0';
+ }
- int ret = sd.destroySockets(addrstr);
- if (ret < 0) {
- ALOGE("Error destroying sockets: %s", strerror(ret));
+ long ifaceIndex = parseIfIndex(ifIndex);
+ if (!ifaceIndex) {
+ ALOGE("invalid interface index: %s(%s)", iface, ifIndex);
+ }
+ if (action == NetlinkEvent::Action::kAddressUpdated) {
+ gCtls->netCtrl.addInterfaceAddress(ifaceIndex, address);
+ } else { // action == NetlinkEvent::Action::kAddressRemoved
+ bool shouldDestroy = gCtls->netCtrl.removeInterfaceAddress(ifaceIndex, address);
+ if (shouldDestroy) {
+ SockDiag sd;
+ if (sd.open()) {
+ int ret = sd.destroySockets(addrstr);
+ if (ret < 0) {
+ ALOGE("Error destroying sockets: %s", strerror(-ret));
+ }
+ } else {
+ ALOGE("Error opening NETLINK_SOCK_DIAG socket: %s", strerror(errno));
}
- } else {
- ALOGE("Error opening NETLINK_SOCK_DIAG socket: %s", strerror(errno));
}
}
+ // Note: if this interface was deleted, iface is "" and we don't notify.
if (iface && iface[0] && address && flags && scope) {
notifyAddressChanged(action, address, iface, flags, scope);
}
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index 5b2cd892..5bbfe3f2 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -28,6 +28,8 @@
#define LOG_TAG "Netd"
#include "log/log.h"
+#include <android-base/strings.h>
+
#include "cutils/misc.h"
#include "resolv_netid.h"
@@ -192,6 +194,19 @@ uint32_t NetworkController::getNetworkForDnsLocked(unsigned* netId, uid_t uid) c
Fwmark fwmark;
fwmark.protectedFromVpn = true;
fwmark.permission = PERMISSION_SYSTEM;
+
+ // Common case: there is no VPN that applies to the user, and the query did not specify a netId.
+ // Therefore, it is safe to set the explicit bit on this query and skip all the complex logic
+ // below. While this looks like a special case, it is actually the one that handles the vast
+ // majority of DNS queries.
+ // TODO: untangle this code.
+ if (*netId == NETID_UNSET && getVirtualNetworkForUserLocked(uid) == nullptr) {
+ *netId = mDefaultNetId;
+ fwmark.netId = *netId;
+ fwmark.explicitlySelected = true;
+ return fwmark.intValue;
+ }
+
if (checkUserNetworkAccessLocked(uid, *netId) == 0) {
// If a non-zero NetId was explicitly specified, and the user has permission for that
// network, use that network's DNS servers. Do not fall through to the default network even
@@ -210,7 +225,8 @@ uint32_t NetworkController::getNetworkForDnsLocked(unsigned* netId, uid_t uid) c
} else {
// If the user is subject to a VPN and the VPN provides DNS servers, use those servers
// (possibly falling through to the default network if the VPN doesn't provide a route to
- // them). Otherwise, use the default network's DNS servers.
+ // them). Otherwise, use the default network's DNS servers. We cannot set the explicit bit
+ // because we need to be able to fall through a split tunnel to the default network.
VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid);
if (virtualNetwork && virtualNetwork->getHasDns()) {
*netId = virtualNetwork->getNetId();
@@ -331,6 +347,10 @@ unsigned NetworkController::getNetworkForInterface(const char* interface) const
bool NetworkController::isVirtualNetwork(unsigned netId) const {
android::RWLock::AutoRLock lock(mRWLock);
+ return isVirtualNetworkLocked(netId);
+}
+
+bool NetworkController::isVirtualNetworkLocked(unsigned netId) const {
Network* network = getNetworkLocked(netId);
return network && network->getType() == Network::VIRTUAL;
}
@@ -452,6 +472,14 @@ int NetworkController::destroyNetwork(unsigned netId) {
delete network;
_resolv_delete_cache_for_net(netId);
+ for (auto iter = mIfindexToLastNetId.begin(); iter != mIfindexToLastNetId.end();) {
+ if (iter->second == netId) {
+ iter = mIfindexToLastNetId.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+
updateTcpSocketMonitorPolling();
return ret;
@@ -470,8 +498,18 @@ int NetworkController::addInterfaceToNetwork(unsigned netId, const char* interfa
ALOGE("interface %s already assigned to netId %u", interface, existingNetId);
return -EBUSY;
}
+ if (int ret = getNetworkLocked(netId)->addInterface(interface)) {
+ return ret;
+ }
- return getNetworkLocked(netId)->addInterface(interface);
+ int ifIndex = RouteController::getIfIndex(interface);
+ if (ifIndex) {
+ mIfindexToLastNetId[ifIndex] = netId;
+ } else {
+ // Cannot happen, since addInterface() above will have failed.
+ ALOGE("inconceivable! added interface %s with no index", interface);
+ }
+ return 0;
}
int NetworkController::removeInterfaceFromNetwork(unsigned netId, const char* interface) {
@@ -569,6 +607,53 @@ int NetworkController::removeRoute(unsigned netId, const char* interface, const
return modifyRoute(netId, interface, destination, nexthop, false, legacy, uid);
}
+void NetworkController::addInterfaceAddress(unsigned ifIndex, const char* address) {
+ android::RWLock::AutoWLock lock(mRWLock);
+
+ if (ifIndex == 0) {
+ ALOGE("Attempting to add address %s without ifindex", address);
+ return;
+ }
+ mAddressToIfindices[address].insert(ifIndex);
+}
+
+// Returns whether we should call SOCK_DESTROY on the removed address.
+bool NetworkController::removeInterfaceAddress(unsigned ifindex, const char* address) {
+ android::RWLock::AutoWLock lock(mRWLock);
+ // First, update mAddressToIfindices map
+ auto ifindicesIter = mAddressToIfindices.find(address);
+ if (ifindicesIter == mAddressToIfindices.end()) {
+ ALOGE("Removing unknown address %s from ifindex %u", address, ifindex);
+ return true;
+ }
+ std::unordered_set<unsigned>& ifindices = ifindicesIter->second;
+ if (ifindices.erase(ifindex) > 0) {
+ if (ifindices.size() == 0) {
+ mAddressToIfindices.erase(ifindicesIter);
+ }
+ } else {
+ ALOGE("No record of address %s on interface %u", address, ifindex);
+ return true;
+ }
+ // Then, check for VPN handover condition
+ if (mIfindexToLastNetId.find(ifindex) == mIfindexToLastNetId.end()) {
+ ALOGE("Interface index %u was never in a currently-connected netId", ifindex);
+ return true;
+ }
+ unsigned lastNetId = mIfindexToLastNetId[ifindex];
+ for (unsigned idx : ifindices) {
+ unsigned activeNetId = mIfindexToLastNetId[idx];
+ // If this IP address is still assigned to another interface in the same network,
+ // then we don't need to destroy sockets on it because they are likely still valid.
+ // For now we do this only on VPNs.
+ // TODO: evaluate extending this to all network types.
+ if (lastNetId == activeNetId && isVirtualNetworkLocked(activeNetId)) {
+ return false;
+ }
+ }
+ return true;
+}
+
bool NetworkController::canProtectLocked(uid_t uid) const {
return ((getPermissionForUserLocked(uid) & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) ||
mProtectableUsers.find(uid) != mProtectableUsers.end();
@@ -617,6 +702,23 @@ void NetworkController::dump(DumpWriter& dw) {
}
dw.decIndent();
+ dw.blankline();
+ dw.println("Interface <-> last network map:");
+ dw.incIndent();
+ for (const auto& i : mIfindexToLastNetId) {
+ dw.println("Ifindex: %u NetId: %u", i.first, i.second);
+ }
+ dw.decIndent();
+
+ dw.blankline();
+ dw.println("Interface addresses:");
+ dw.incIndent();
+ for (const auto& i : mAddressToIfindices) {
+ dw.println("address: %s ifindices: [%s]", i.first.c_str(),
+ android::base::Join(i.second, ", ").c_str());
+ }
+ dw.decIndent();
+
dw.decIndent();
dw.decIndent();
diff --git a/server/NetworkController.h b/server/NetworkController.h
index 627e44da..5e7af809 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -27,6 +27,8 @@
#include <map>
#include <set>
#include <sys/types.h>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
struct android_net_context;
@@ -123,6 +125,12 @@ public:
int removeRoute(unsigned netId, const char* interface, const char* destination,
const char* nexthop, bool legacy, uid_t uid) WARN_UNUSED_RESULT;
+ // Notes that the specified address has appeared on the specified interface.
+ void addInterfaceAddress(unsigned ifIndex, const char* address);
+ // Notes that the specified address has been removed from the specified interface.
+ // Returns true if we should destroy sockets on this address.
+ bool removeInterfaceAddress(unsigned ifIndex, const char* address);
+
bool canProtect(uid_t uid) const;
void allowProtect(const std::vector<uid_t>& uids);
void denyProtect(const std::vector<uid_t>& uids);
@@ -137,6 +145,7 @@ private:
unsigned getNetworkForConnectLocked(uid_t uid) const;
unsigned getNetworkForInterfaceLocked(const char* interface) const;
bool canProtectLocked(uid_t uid) const;
+ bool isVirtualNetworkLocked(unsigned netId) const;
VirtualNetwork* getVirtualNetworkForUserLocked(uid_t uid) const;
Permission getPermissionForUserLocked(uid_t uid) const;
@@ -151,12 +160,27 @@ private:
class DelegateImpl;
DelegateImpl* const mDelegateImpl;
- // mRWLock guards all accesses to mDefaultNetId, mNetworks, mUsers and mProtectableUsers.
+ // mRWLock guards all accesses to mDefaultNetId, mNetworks, mUsers, mProtectableUsers,
+ // mIfindexToLastNetId and mAddressToIfindices.
mutable android::RWLock mRWLock;
unsigned mDefaultNetId;
std::map<unsigned, Network*> mNetworks; // Map keys are NetIds.
std::map<uid_t, Permission> mUsers;
std::set<uid_t> mProtectableUsers;
+ // Map interface (ifIndex) to its current NetId, or the last NetId if the interface was removed
+ // from the network and not added to another network. This state facilitates the interface to
+ // NetId lookup during RTM_DELADDR (NetworkController::removeInterfaceAddress), when the
+ // interface in question might already have been removed from the network.
+ // An interface is added to this map when it is added to a network and removed from this map
+ // when its network is destroyed.
+ std::unordered_map<unsigned, unsigned> mIfindexToLastNetId;
+ // Map IP address to the list of active interfaces (ifIndex) that have that address.
+ // Also contains IP addresses configured on interfaces that have not been added to any network.
+ // TODO: Does not track IP addresses present when netd is started or restarts after a crash.
+ // This is not a problem for its intended use (tracking IP addresses on VPN interfaces), but
+ // we should fix it.
+ std::unordered_map<std::string, std::unordered_set<unsigned>> mAddressToIfindices;
+
};
} // namespace net
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index b1aa5aca..c78854d8 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -154,6 +154,18 @@ uint32_t RouteController::getRouteTableForInterfaceLocked(const char* interface)
return iter->second;
}
+uint32_t RouteController::getIfIndex(const char* interface) {
+ android::RWLock::AutoRLock lock(sInterfaceToTableLock);
+
+ auto iter = sInterfaceToTable.find(interface);
+ if (iter == sInterfaceToTable.end()) {
+ ALOGE("getIfIndex: cannot find interface %s", interface);
+ return 0;
+ }
+
+ return iter->second - ROUTE_TABLE_OFFSET_FROM_INDEX;
+}
+
uint32_t RouteController::getRouteTableForInterface(const char* interface) {
android::RWLock::AutoRLock lock(sInterfaceToTableLock);
return getRouteTableForInterfaceLocked(interface);
diff --git a/server/RouteController.h b/server/RouteController.h
index de79b617..6e10ccea 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -45,6 +45,15 @@ public:
static int Init(unsigned localNetId) WARN_UNUSED_RESULT;
+ // Returns an ifindex given the interface name, by looking up in sInterfaceToTable.
+ // This is currently only used by NetworkController::addInterfaceToNetwork
+ // and should probabaly be changed to passing the ifindex into RouteController instead.
+ // We do this instead of calling if_nametoindex because the same interface name can
+ // correspond to different interface indices over time. This way, even if the interface
+ // index has changed, we can still free any map entries indexed by the ifindex that was
+ // used to add them.
+ static uint32_t getIfIndex(const char* interface);
+
static int addInterfaceToLocalNetwork(unsigned netId, const char* interface) WARN_UNUSED_RESULT;
static int removeInterfaceFromLocalNetwork(unsigned netId,
const char* interface) WARN_UNUSED_RESULT;
diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp
index 8a891eb7..b9a5a415 100644
--- a/server/XfrmController.cpp
+++ b/server/XfrmController.cpp
@@ -44,11 +44,6 @@
#include <linux/xfrm.h>
#define LOG_TAG "XfrmController"
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
-#include "android-base/unique_fd.h"
-#include <android/net/INetd.h>
-#include <log/log_properties.h>
#include "InterfaceController.h"
#include "NetdConstants.h"
#include "NetlinkCommands.h"
@@ -57,6 +52,11 @@
#include "netdutils/Fd.h"
#include "netdutils/Slice.h"
#include "netdutils/Syscalls.h"
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <android/net/INetd.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <logwrap/logwrap.h>
@@ -87,6 +87,11 @@ constexpr uint32_t RAND_SPI_MAX = 0xFFFFFFFE;
constexpr uint32_t INVALID_SPI = 0;
+static inline bool isEngBuild() {
+ static const std::string sBuildType = android::base::GetProperty("ro.build.type", "user");
+ return sBuildType == "eng";
+}
+
#define XFRM_MSG_TRANS(x) \
case x: \
return #x;
@@ -126,18 +131,18 @@ uint8_t kPadBytesArray[] = {0, 0, 0};
void* kPadBytes = static_cast<void*>(kPadBytesArray);
#define LOG_HEX(__desc16__, __buf__, __len__) \
- if (__android_log_is_debuggable()) { \
- do { \
+ do { \
+ if (isEngBuild()) { \
logHex(__desc16__, __buf__, __len__); \
- } while (0); \
- }
+ } \
+ } while (0)
#define LOG_IOV(__iov__) \
- if (__android_log_is_debuggable()) { \
- do { \
+ do { \
+ if (isEngBuild()) { \
logIov(__iov__); \
- } while (0); \
- }
+ } \
+ } while (0)
void logHex(const char* desc16, const char* buf, size_t len) {
char* printBuf = new char[len * 2 + 1 + 26]; // len->ascii, +newline, +prefix strlen