Add a binder IPC to close socket connections.

Bug: 27824851
Bug: 27867653
Change-Id: I2e63ccfb268db763ec732594a73c2908838468b8
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 388b6b5..a8f5c3b 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -31,6 +31,7 @@
 #include "NetdConstants.h"
 #include "NetdNativeService.h"
 #include "RouteController.h"
+#include "SockDiag.h"
 #include "UidRanges.h"
 
 using android::base::StringPrintf;
@@ -67,7 +68,6 @@
     android::RWLock::AutoWLock _lock(lock);
 
 #define NETD_BIG_LOCK_RPC(permission) NETD_LOCKING_RPC((permission), gBigNetdLock)
-
 }  // namespace
 
 
@@ -135,8 +135,7 @@
     // look at routes, but it's not enough here).
     NETD_BIG_LOCK_RPC(CONNECTIVITY_INTERNAL);
 
-    UidRanges uidRanges;
-    uidRanges.createFrom(uidRangeArray);
+    UidRanges uidRanges(uidRangeArray);
 
     int err;
     if (add) {
@@ -152,5 +151,27 @@
     return binder::Status::ok();
 }
 
+binder::Status NetdNativeService::socketDestroy(const std::vector<UidRange>& uids,
+        const std::vector<int32_t>& skipUids) {
+
+    ENFORCE_PERMISSION(CONNECTIVITY_INTERNAL);
+
+    SockDiag sd;
+    if (!sd.open()) {
+        return binder::Status::fromServiceSpecificError(EIO,
+                String8("Could not open SOCK_DIAG socket"));
+    }
+
+    UidRanges uidRanges(uids);
+    int err = sd.destroySockets(uidRanges, std::set<uid_t>(skipUids.begin(), skipUids.end()));
+
+    if (err) {
+        return binder::Status::fromServiceSpecificError(-err,
+                String8::format("destroySockets: %s", strerror(-err)));
+    }
+
+    return binder::Status::ok();
+}
+
 }  // namespace net
 }  // namespace android
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index 96759e1..22c81fc 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -40,6 +40,8 @@
     binder::Status bandwidthEnableDataSaver(bool enable, bool *ret) override;
     binder::Status networkRejectNonSecureVpn(bool enable, const std::vector<UidRange>& uids)
             override;
+    binder::Status socketDestroy(const std::vector<UidRange>& uids,
+            const std::vector<int32_t>& skipUids) override;
 };
 
 }  // namespace net
diff --git a/server/UidRanges.cpp b/server/UidRanges.cpp
index a2b8dde..b7db616 100644
--- a/server/UidRanges.cpp
+++ b/server/UidRanges.cpp
@@ -75,7 +75,7 @@
     return true;
 }
 
-void UidRanges::createFrom(const std::vector<android::net::UidRange>& ranges) {
+UidRanges::UidRanges(const std::vector<android::net::UidRange>& ranges) {
     mRanges.resize(ranges.size());
     std::transform(ranges.begin(), ranges.end(), mRanges.begin(),
             [](const android::net::UidRange& range) {
diff --git a/server/UidRanges.h b/server/UidRanges.h
index 3cbbe80..293f53f 100644
--- a/server/UidRanges.h
+++ b/server/UidRanges.h
@@ -30,11 +30,13 @@
     // a larger type first.
     typedef std::pair<uid_t, uid_t> Range;
 
+    UidRanges() {}
+    UidRanges(const std::vector<android::net::UidRange>& ranges);
+
     bool hasUid(uid_t uid) const;
     const std::vector<Range>& getRanges() const;
 
     bool parseFrom(int argc, char* argv[]);
-    void createFrom(const std::vector<android::net::UidRange>& ranges);
     std::string toString() const;
 
     void add(const UidRanges& other);
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index 63054f8..616842b 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -80,4 +80,9 @@
      *         unix errno.
      */
     void networkRejectNonSecureVpn(boolean add, in UidRange[] uidRanges);
+
+    /**
+     * Administratively closes sockets belonging to the specified UIDs.
+     */
+    void socketDestroy(in UidRange[] uidRanges, in int[] exemptUids);
 }