diff options
Diffstat (limited to 'server/NetworkController.cpp')
| -rw-r--r-- | server/NetworkController.cpp | 90 |
1 files changed, 89 insertions, 1 deletions
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp index 87ad1bd0..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" @@ -345,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; } @@ -466,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; @@ -484,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) { @@ -583,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(); @@ -631,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(); |
