Don't close loopback sockets when a VPN connects or entering doze.
Bug: 30186506
(cherry picked from commit 0726fec82842883a2332318aa675f7f04670db51)
Change-Id: I269d9d9dc2f036b7b65e14577c5525d9cab426ba
diff --git a/server/SockDiag.cpp b/server/SockDiag.cpp
index b37455a..6b93a97 100644
--- a/server/SockDiag.cpp
+++ b/server/SockDiag.cpp
@@ -236,6 +236,28 @@
return 0;
}
+// Determines whether a socket is a loopback socket. Does not check socket state.
+bool SockDiag::isLoopbackSocket(const inet_diag_msg *msg) {
+ switch (msg->idiag_family) {
+ case AF_INET:
+ // Old kernels only copy the IPv4 address and leave the other 12 bytes uninitialized.
+ return IN_LOOPBACK(htonl(msg->id.idiag_src[0])) ||
+ IN_LOOPBACK(htonl(msg->id.idiag_dst[0])) ||
+ msg->id.idiag_src[0] == msg->id.idiag_dst[0];
+
+ case AF_INET6: {
+ const struct in6_addr *src = (const struct in6_addr *) &msg->id.idiag_src;
+ const struct in6_addr *dst = (const struct in6_addr *) &msg->id.idiag_dst;
+ return (IN6_IS_ADDR_V4MAPPED(src) && IN_LOOPBACK(src->s6_addr32[3])) ||
+ (IN6_IS_ADDR_V4MAPPED(dst) && IN_LOOPBACK(dst->s6_addr32[3])) ||
+ IN6_IS_ADDR_LOOPBACK(src) || IN6_IS_ADDR_LOOPBACK(dst) ||
+ !memcmp(src, dst, sizeof(*src));
+ }
+ default:
+ return false;
+ }
+}
+
int SockDiag::sockDestroy(uint8_t proto, const inet_diag_msg *msg) {
if (msg == nullptr) {
return 0;
@@ -319,12 +341,14 @@
return 0;
}
-int SockDiag::destroySockets(uint8_t proto, const uid_t uid) {
+int SockDiag::destroySockets(uint8_t proto, const uid_t uid, bool excludeLoopback) {
mSocketsDestroyed = 0;
Stopwatch s;
- auto shouldDestroy = [uid] (uint8_t, const inet_diag_msg *msg) {
- return (msg != nullptr && msg->idiag_uid == uid);
+ auto shouldDestroy = [uid, excludeLoopback] (uint8_t, const inet_diag_msg *msg) {
+ return msg != nullptr &&
+ msg->idiag_uid == uid &&
+ !(excludeLoopback && isLoopbackSocket(msg));
};
for (const int family : {AF_INET, AF_INET6}) {
@@ -347,14 +371,16 @@
return 0;
}
-int SockDiag::destroySockets(const UidRanges& uidRanges, const std::set<uid_t>& skipUids) {
+int SockDiag::destroySockets(const UidRanges& uidRanges, const std::set<uid_t>& skipUids,
+ bool excludeLoopback) {
mSocketsDestroyed = 0;
Stopwatch s;
auto shouldDestroy = [&] (uint8_t, const inet_diag_msg *msg) {
return msg != nullptr &&
uidRanges.hasUid(msg->idiag_uid) &&
- skipUids.find(msg->idiag_uid) == skipUids.end();
+ skipUids.find(msg->idiag_uid) == skipUids.end() &&
+ !(excludeLoopback && isLoopbackSocket(msg));
};
if (int ret = destroyLiveSockets(shouldDestroy)) {