summaryrefslogtreecommitdiff
path: root/server/NetworkController.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'server/NetworkController.cpp')
-rw-r--r--server/NetworkController.cpp90
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();