Do not destroy socket when VPN interface address is still in use

Normally when an IP address is removed, all sockets associated with the
addresses are destroyed. This patchset changes this behavior such that
if the address in question is still being used by another interface that
belongs to the same underlying virtual network, the destroy operation is
skipped. This change is needed to support VPN seamless handover where the
VPN app will establish a second TUN interface (with different config)
before tearing down the existing interface. The intention is that during
this handover existing socket connections should not be disturbed. There
is a companion change in the framework side to make sure during such
handover, the VPN netId remains unchanged so routing still works.

Bug: 64692591
Test: cts-tradefed run commandAndExit cts-dev -m CtsHostsideNetworkTests -t com.android.cts.net.HostsideVpnTests
Test: system/netd/tests/runtests.sh
Change-Id: I02c6b0db5f15cd1aef3e3fa6f0c36e86b4f427fd
Merged-In: I02c6b0db5f15cd1aef3e3fa6f0c36e86b4f427fd
(cherry picked from commit acbb6b7bbea17c5653929ee5224bd4f8e16c0f69)
diff --git a/server/NetworkController.h b/server/NetworkController.h
index 627e44d..5e7af80 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 @@
     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 @@
     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 @@
     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