Close sockets when changing network permissions.

Bug: 23113288
Change-Id: I8dcb02c79c81244e5b7288cb50770ac6a5867fcc
diff --git a/server/PhysicalNetwork.cpp b/server/PhysicalNetwork.cpp
index 495a93a..ee0e7c7 100644
--- a/server/PhysicalNetwork.cpp
+++ b/server/PhysicalNetwork.cpp
@@ -17,6 +17,7 @@
 #include "PhysicalNetwork.h"
 
 #include "RouteController.h"
+#include "SockDiag.h"
 
 #define LOG_TAG "Netd"
 #include "log/log.h"
@@ -65,10 +66,33 @@
     return mPermission;
 }
 
+int PhysicalNetwork::destroySocketsLackingPermission(Permission permission) {
+    if (permission == PERMISSION_NONE) return 0;
+
+    SockDiag sd;
+    if (!sd.open()) {
+       ALOGE("Error closing sockets for netId %d permission change", mNetId);
+       return -EBADFD;
+    }
+    if (int ret = sd.destroySocketsLackingPermission(mNetId, permission,
+                                                     true /* excludeLoopback */)) {
+        ALOGE("Failed to close sockets changing netId %d to permission %d: %s",
+              mNetId, permission, strerror(-ret));
+        return ret;
+    }
+    return 0;
+}
+
 int PhysicalNetwork::setPermission(Permission permission) {
     if (permission == mPermission) {
         return 0;
     }
+    if (mInterfaces.empty()) {
+        mPermission = permission;
+        return 0;
+    }
+
+    destroySocketsLackingPermission(permission);
     for (const std::string& interface : mInterfaces) {
         if (int ret = RouteController::modifyPhysicalNetworkPermission(mNetId, interface.c_str(),
                                                                        mPermission, permission)) {
@@ -87,6 +111,10 @@
             }
         }
     }
+    // Destroy sockets again in case any were opened after we called destroySocketsLackingPermission
+    // above and before we changed the permissions. These sockets won't be able to send any RST
+    // packets because they are now no longer routed, but at least the apps will get errors.
+    destroySocketsLackingPermission(permission);
     mPermission = permission;
     return 0;
 }