Merge "Add ICMP header length constant"
diff --git a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
index 0a2f50d..d462c53 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/InetDiagMessage.java
@@ -19,32 +19,48 @@
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.ENOENT;
 import static android.system.OsConstants.IPPROTO_TCP;
 import static android.system.OsConstants.IPPROTO_UDP;
 import static android.system.OsConstants.NETLINK_INET_DIAG;
 
+import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE;
+import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DESTROY;
 import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
+import static com.android.net.module.util.netlink.NetlinkConstants.hexify;
+import static com.android.net.module.util.netlink.NetlinkConstants.stringForAddressFamily;
+import static com.android.net.module.util.netlink.NetlinkConstants.stringForProtocol;
 import static com.android.net.module.util.netlink.NetlinkUtils.DEFAULT_RECV_BUFSIZE;
+import static com.android.net.module.util.netlink.NetlinkUtils.IO_TIMEOUT_MS;
+import static com.android.net.module.util.netlink.NetlinkUtils.TCP_ALIVE_STATE_FILTER;
+import static com.android.net.module.util.netlink.NetlinkUtils.connectSocketToNetlink;
 import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP;
 import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
 
 import android.net.util.SocketUtils;
+import android.os.Process;
 import android.system.ErrnoException;
 import android.util.Log;
+import android.util.Range;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InterruptedIOException;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
+import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
 
 /**
  * A NetlinkMessage subclass for netlink inet_diag messages.
@@ -138,7 +154,8 @@
 
     public StructInetDiagMsg inetDiagMsg;
 
-    private InetDiagMessage(@NonNull StructNlMsgHdr header) {
+    @VisibleForTesting
+    public InetDiagMessage(@NonNull StructNlMsgHdr header) {
         super(header);
         inetDiagMsg = new StructInetDiagMsg();
     }
@@ -157,6 +174,13 @@
         return msg;
     }
 
+    private static void closeSocketQuietly(final FileDescriptor fd) {
+        try {
+            SocketUtils.closeSocket(fd);
+        } catch (IOException ignored) {
+        }
+    }
+
     private static int lookupUidByFamily(int protocol, InetSocketAddress local,
                                          InetSocketAddress remote, int family, short flags,
                                          FileDescriptor fd)
@@ -247,13 +271,7 @@
                 | InterruptedIOException e) {
             Log.e(TAG, e.toString());
         } finally {
-            if (fd != null) {
-                try {
-                    SocketUtils.closeSocket(fd);
-                } catch (IOException e) {
-                    Log.e(TAG, e.toString());
-                }
-            }
+            closeSocketQuietly(fd);
         }
         return uid;
     }
@@ -269,7 +287,185 @@
                 (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP) /* flag */,
                 0 /* pad */,
                 1 << NetlinkConstants.INET_DIAG_MEMINFO /* idiagExt */,
-                NetlinkUtils.TCP_MONITOR_STATE_FILTER);
+                TCP_ALIVE_STATE_FILTER);
+    }
+
+    private static void sendNetlinkDestroyRequest(FileDescriptor fd, int proto,
+            InetDiagMessage diagMsg) throws InterruptedIOException, ErrnoException {
+        final byte[] destroyMsg = InetDiagMessage.inetDiagReqV2(
+                proto,
+                diagMsg.inetDiagMsg.id,
+                diagMsg.inetDiagMsg.idiag_family,
+                SOCK_DESTROY,
+                (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_ACK),
+                0 /* pad */,
+                0 /* idiagExt */,
+                1 << diagMsg.inetDiagMsg.idiag_state
+        );
+        NetlinkUtils.sendMessage(fd, destroyMsg, 0, destroyMsg.length, IO_TIMEOUT_MS);
+        NetlinkUtils.receiveNetlinkAck(fd);
+    }
+
+    private static void sendNetlinkDumpRequest(FileDescriptor fd, int proto, int states, int family)
+            throws InterruptedIOException, ErrnoException {
+        final byte[] dumpMsg = InetDiagMessage.inetDiagReqV2(
+                proto,
+                null /* id */,
+                family,
+                SOCK_DIAG_BY_FAMILY,
+                (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP),
+                0 /* pad */,
+                0 /* idiagExt */,
+                states);
+        NetlinkUtils.sendMessage(fd, dumpMsg, 0, dumpMsg.length, IO_TIMEOUT_MS);
+    }
+
+    private static int processNetlinkDumpAndDestroySockets(FileDescriptor dumpFd,
+            FileDescriptor destroyFd, int proto, Predicate<InetDiagMessage> filter)
+            throws InterruptedIOException, ErrnoException {
+        int destroyedSockets = 0;
+
+        while (true) {
+            final ByteBuffer buf = NetlinkUtils.recvMessage(
+                    dumpFd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS);
+
+            while (buf.remaining() > 0) {
+                final int position = buf.position();
+                final NetlinkMessage nlMsg = NetlinkMessage.parse(buf, NETLINK_INET_DIAG);
+                if (nlMsg == null) {
+                    // Move to the position where parse started for error log.
+                    buf.position(position);
+                    Log.e(TAG, "Failed to parse netlink message: " + hexify(buf));
+                    break;
+                }
+
+                if (nlMsg.getHeader().nlmsg_type == NLMSG_DONE) {
+                    return destroyedSockets;
+                }
+
+                if (!(nlMsg instanceof InetDiagMessage)) {
+                    Log.wtf(TAG, "Received unexpected netlink message: " + nlMsg);
+                    continue;
+                }
+
+                final InetDiagMessage diagMsg = (InetDiagMessage) nlMsg;
+                if (filter.test(diagMsg)) {
+                    try {
+                        sendNetlinkDestroyRequest(destroyFd, proto, diagMsg);
+                        destroyedSockets++;
+                    } catch (InterruptedIOException | ErrnoException e) {
+                        if (!(e instanceof ErrnoException
+                                && ((ErrnoException) e).errno == ENOENT)) {
+                            Log.e(TAG, "Failed to destroy socket: diagMsg=" + diagMsg + ", " + e);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns whether the InetDiagMessage is for adb socket or not
+     */
+    @VisibleForTesting
+    public static boolean isAdbSocket(final InetDiagMessage msg) {
+        // This is inaccurate since adb could run with ROOT_UID or other services can run with
+        // SHELL_UID. But this check covers most cases and enough.
+        // Note that getting service.adb.tcp.port system property is prohibited by sepolicy
+        // TODO: skip the socket only if there is a listen socket owned by SHELL_UID with the same
+        // source port as this socket
+        return msg.inetDiagMsg.idiag_uid == Process.SHELL_UID;
+    }
+
+    /**
+     * Returns whether the range contains the uid in the InetDiagMessage or not
+     */
+    @VisibleForTesting
+    public static boolean containsUid(InetDiagMessage msg, Set<Range<Integer>> ranges) {
+        for (final Range<Integer> range: ranges) {
+            if (range.contains(msg.inetDiagMsg.idiag_uid)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isLoopbackAddress(InetAddress addr) {
+        if (addr.isLoopbackAddress()) return true;
+        if (!(addr instanceof Inet6Address)) return false;
+
+        // Following check is for v4-mapped v6 address. StructInetDiagSockId contains v4-mapped v6
+        // address as Inet6Address, See StructInetDiagSockId#parse
+        final byte[] addrBytes = addr.getAddress();
+        for (int i = 0; i < 10; i++) {
+            if (addrBytes[i] != 0) return false;
+        }
+        return addrBytes[10] == (byte) 0xff
+                && addrBytes[11] == (byte) 0xff
+                && addrBytes[12] == 127;
+    }
+
+    /**
+     * Returns whether the socket address in the InetDiagMessage is loopback or not
+     */
+    @VisibleForTesting
+    public static boolean isLoopback(InetDiagMessage msg) {
+        final InetAddress srcAddr = msg.inetDiagMsg.id.locSocketAddress.getAddress();
+        final InetAddress dstAddr = msg.inetDiagMsg.id.remSocketAddress.getAddress();
+        return isLoopbackAddress(srcAddr)
+                || isLoopbackAddress(dstAddr)
+                || srcAddr.equals(dstAddr);
+    }
+
+    private static void destroySockets(int proto, int states, Predicate<InetDiagMessage> filter)
+            throws ErrnoException, SocketException, InterruptedIOException {
+        FileDescriptor dumpFd = null;
+        FileDescriptor destroyFd = null;
+
+        try {
+            dumpFd = NetlinkUtils.createNetLinkInetDiagSocket();
+            destroyFd = NetlinkUtils.createNetLinkInetDiagSocket();
+            connectSocketToNetlink(dumpFd);
+            connectSocketToNetlink(destroyFd);
+
+            for (int family : List.of(AF_INET, AF_INET6)) {
+                try {
+                    sendNetlinkDumpRequest(dumpFd, proto, states, family);
+                } catch (InterruptedIOException | ErrnoException e) {
+                    Log.e(TAG, "Failed to send netlink dump request: " + e);
+                    continue;
+                }
+                final int destroyedSockets = processNetlinkDumpAndDestroySockets(
+                        dumpFd, destroyFd, proto, filter);
+                Log.d(TAG, "Destroyed " + destroyedSockets + " sockets"
+                        + ", proto=" + stringForProtocol(proto)
+                        + ", family=" + stringForAddressFamily(family)
+                        + ", states=" + states);
+            }
+        } finally {
+            closeSocketQuietly(dumpFd);
+            closeSocketQuietly(destroyFd);
+        }
+    }
+
+    /**
+     * Close tcp sockets that match the following condition
+     *  1. TCP status is one of TCP_ESTABLISHED, TCP_SYN_SENT, and TCP_SYN_RECV
+     *  2. Owner uid of socket is not in the exemptUids
+     *  3. Owner uid of socket is in the ranges
+     *  4. Socket is not loopback
+     *  5. Socket is not adb socket
+     *
+     * @param ranges target uid ranges
+     * @param exemptUids uids to skip close socket
+     */
+    public static void destroyLiveTcpSockets(Set<Range<Integer>> ranges, Set<Integer> exemptUids)
+            throws SocketException, InterruptedIOException, ErrnoException {
+        destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER,
+                (diagMsg) -> !exemptUids.contains(diagMsg.inetDiagMsg.idiag_uid)
+                        && containsUid(diagMsg, ranges)
+                        && !isLoopback(diagMsg)
+                        && !isAdbSocket(diagMsg));
     }
 
     @Override
diff --git a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
index d4bf14a..308ea24 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/NetlinkUtils.java
@@ -56,7 +56,7 @@
     private static final int TCP_SYN_SENT = 2;
     private static final int TCP_SYN_RECV = 3;
 
-    public static final int TCP_MONITOR_STATE_FILTER =
+    public static final int TCP_ALIVE_STATE_FILTER =
             (1 << TCP_ESTABLISHED) | (1 << TCP_SYN_SENT) | (1 << TCP_SYN_RECV);
 
     public static final int UNKNOWN_MARK = 0xffffffff;
diff --git a/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java b/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java
index 31d0729..40fc59f 100644
--- a/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/InetAddressUtils.java
@@ -16,7 +16,10 @@
 
 package com.android.net.module.util;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
+import android.util.Log;
+
 
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -28,6 +31,7 @@
  */
 public class InetAddressUtils {
 
+    private static final String TAG = InetAddressUtils.class.getSimpleName();
     private static final int INET6_ADDR_LENGTH = 16;
 
     /**
@@ -71,5 +75,23 @@
         }
     }
 
+    /**
+     * Create a Inet6Address with scope id if it is a link local address. Otherwise, returns the
+     * original address.
+     */
+    public static Inet6Address withScopeId(@NonNull final Inet6Address addr, int scopeid) {
+        if (!addr.isLinkLocalAddress()) {
+            return addr;
+        }
+        try {
+            return Inet6Address.getByAddress(null /* host */, addr.getAddress(),
+                    scopeid);
+        } catch (UnknownHostException impossible) {
+            Log.wtf(TAG, "Cannot construct scoped Inet6Address with Inet6Address.getAddress("
+                    + addr.getHostAddress() + "): ", impossible);
+            return null;
+        }
+    }
+
     private InetAddressUtils() {}
 }
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
index 4939483..70c0f89 100644
--- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
@@ -27,13 +27,6 @@
 // Android S / 12 (api level 31) - added 'tethering' mainline eBPF support
 #define BPFLOADER_S_VERSION 2u
 
-// Android T / 13 Beta 3 (api level 33) - added support for 'netd_shared'
-#define BPFLOADER_T_BETA3_VERSION 13u
-
-// v0.18 added support for shared and pindir, but still ignores selinux_content
-// v0.19 added support for selinux_content along with the required selinux changes
-// and should be available starting with Android T Beta 4
-//
 // Android T / 13 (api level 33) - support for shared/selinux_context/pindir
 #define BPFLOADER_T_VERSION 19u
 
@@ -43,6 +36,9 @@
 // Bpfloader v0.33+ supports {map,prog}.ignore_on_{eng,user,userdebug}
 #define BPFLOADER_IGNORED_ON_VERSION 33u
 
+// Android U / 14 (api level 34) - various new program types added
+#define BPFLOADER_U_VERSION 37u
+
 /* For mainline module use, you can #define BPFLOADER_{MIN/MAX}_VER
  * before #include "bpf_helpers.h" to change which bpfloaders will
  * process the resulting .o file.
@@ -225,7 +221,7 @@
 
 #ifdef THIS_BPF_PROGRAM_IS_FOR_TEST_PURPOSES_ONLY
 #define BPF_MAP_ASSERT_OK(type, entries, mode)
-#elif BPFLOADER_MIN_VER >= BPFLOADER_T_BETA3_VERSION
+#elif BPFLOADER_MIN_VER >= BPFLOADER_T_VERSION
 #define BPF_MAP_ASSERT_OK(type, entries, mode)
 #else
 #define BPF_MAP_ASSERT_OK(type, entries, mode) \
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
index d286eba..65540e0 100644
--- a/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_map_def.h
@@ -48,9 +48,8 @@
 #define DEFAULT_SIZEOF_BPF_MAP_DEF 32       // v0.0 struct: enum (uint sized) + 7 uint
 #define DEFAULT_SIZEOF_BPF_PROG_DEF 20      // v0.0 struct: 4 uint + bool + 3 byte alignment pad
 
-// By default, unless otherwise specified, allow the use of features only supported by v0.28,
-// which first added working support for map uid != root
-#define COMPILE_FOR_BPFLOADER_VERSION 28u
+// By default, unless otherwise specified, allow the use of features only supported by v0.37.
+#define COMPILE_FOR_BPFLOADER_VERSION 37u
 
 /*
  * The bpf_{map,prog}_def structures are compiled for different architectures.
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java
index 2736c53..bb2b933 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/InetAddressUtilsTest.java
@@ -18,6 +18,10 @@
 
 import static junit.framework.Assert.assertEquals;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.InetAddresses;
 import android.os.Parcel;
 
 import androidx.test.filters.SmallTest;
@@ -67,4 +71,25 @@
         assertEquals(ipv6, out);
         assertEquals(42, out.getScopeId());
     }
+
+    @Test
+    public void testWithScopeId() {
+        final int scopeId = 999;
+
+        final String globalAddrStr = "2401:fa00:49c:484:dc41:e6ff:fefd:f180";
+        final Inet6Address globalAddr = (Inet6Address) InetAddresses
+                .parseNumericAddress(globalAddrStr);
+        final Inet6Address updatedGlobalAddr = InetAddressUtils.withScopeId(globalAddr, scopeId);
+        assertFalse(updatedGlobalAddr.isLinkLocalAddress());
+        assertEquals(globalAddrStr, updatedGlobalAddr.getHostAddress());
+        assertEquals(0, updatedGlobalAddr.getScopeId());
+
+        final String localAddrStr = "fe80::4735:9628:d038:2087";
+        final Inet6Address localAddr = (Inet6Address) InetAddresses
+                .parseNumericAddress(localAddrStr);
+        final Inet6Address updatedLocalAddr = InetAddressUtils.withScopeId(localAddr, scopeId);
+        assertTrue(updatedLocalAddr.isLinkLocalAddress());
+        assertEquals(localAddrStr + "%" + scopeId, updatedLocalAddr.getHostAddress());
+        assertEquals(scopeId, updatedLocalAddr.getScopeId());
+    }
 }
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java
index 30796d2..65e99f8 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/InetDiagSocketTest.java
@@ -16,6 +16,8 @@
 
 package com.android.net.module.util.netlink;
 
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SHELL_UID;
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.AF_INET6;
 import static android.system.OsConstants.IPPROTO_TCP;
@@ -34,6 +36,8 @@
 import static org.junit.Assert.fail;
 
 import android.net.InetAddresses;
+import android.util.ArraySet;
+import android.util.Range;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -46,8 +50,11 @@
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.util.List;
+import java.util.Set;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -543,4 +550,143 @@
                 7  /* ifIndex */,
                 88 /* cookie */);
     }
+
+    private void doTestIsLoopback(InetAddress srcAddr, InetAddress dstAddr, boolean expected) {
+        final InetDiagMessage inetDiagMsg = new InetDiagMessage(new StructNlMsgHdr());
+        inetDiagMsg.inetDiagMsg.id = new StructInetDiagSockId(
+                new InetSocketAddress(srcAddr, 43031),
+                new InetSocketAddress(dstAddr, 38415)
+        );
+
+        assertEquals(expected, InetDiagMessage.isLoopback(inetDiagMsg));
+    }
+
+    @Test
+    public void testIsLoopback() {
+        doTestIsLoopback(
+                InetAddresses.parseNumericAddress("127.0.0.1"),
+                InetAddresses.parseNumericAddress("192.0.2.1"),
+                true
+        );
+        doTestIsLoopback(
+                InetAddresses.parseNumericAddress("192.0.2.1"),
+                InetAddresses.parseNumericAddress("127.7.7.7"),
+                true
+        );
+        doTestIsLoopback(
+                InetAddresses.parseNumericAddress("::1"),
+                InetAddresses.parseNumericAddress("::1"),
+                true
+        );
+        doTestIsLoopback(
+                InetAddresses.parseNumericAddress("::1"),
+                InetAddresses.parseNumericAddress("2001:db8::1"),
+                true
+        );
+    }
+
+    @Test
+    public void testIsLoopbackSameSrcDstAddress()  {
+        doTestIsLoopback(
+                InetAddresses.parseNumericAddress("192.0.2.1"),
+                InetAddresses.parseNumericAddress("192.0.2.1"),
+                true
+        );
+        doTestIsLoopback(
+                InetAddresses.parseNumericAddress("2001:db8::1"),
+                InetAddresses.parseNumericAddress("2001:db8::1"),
+                true
+        );
+    }
+
+    @Test
+    public void testIsLoopbackNonLoopbackSocket()  {
+        doTestIsLoopback(
+                InetAddresses.parseNumericAddress("192.0.2.1"),
+                InetAddresses.parseNumericAddress("192.0.2.2"),
+                false
+        );
+        doTestIsLoopback(
+                InetAddresses.parseNumericAddress("2001:db8::1"),
+                InetAddresses.parseNumericAddress("2001:db8::2"),
+                false
+        );
+    }
+
+    @Test
+    public void testIsLoopbackV4MappedV6() throws UnknownHostException {
+        // ::FFFF:127.1.2.3
+        final byte[] addrLoopbackByte = {
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff,
+                (byte) 0x7f, (byte) 0x01, (byte) 0x02, (byte) 0x03,
+        };
+        // ::FFFF:192.0.2.1
+        final byte[] addrNonLoopbackByte1 = {
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff,
+                (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01,
+        };
+        // ::FFFF:192.0.2.2
+        final byte[] addrNonLoopbackByte2 = {
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+                (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xff,
+                (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x02,
+        };
+
+        final Inet6Address addrLoopback = Inet6Address.getByAddress(null, addrLoopbackByte, -1);
+        final Inet6Address addrNonLoopback1 =
+                Inet6Address.getByAddress(null, addrNonLoopbackByte1, -1);
+        final Inet6Address addrNonLoopback2 =
+                Inet6Address.getByAddress(null, addrNonLoopbackByte2, -1);
+
+        doTestIsLoopback(addrLoopback, addrNonLoopback1, true);
+        doTestIsLoopback(addrNonLoopback1, addrNonLoopback2, false);
+        doTestIsLoopback(addrNonLoopback1, addrNonLoopback1, true);
+    }
+
+    private void doTestContainsUid(final int uid, final Set<Range<Integer>> ranges,
+            final boolean expected) {
+        final InetDiagMessage inetDiagMsg = new InetDiagMessage(new StructNlMsgHdr());
+        inetDiagMsg.inetDiagMsg.idiag_uid = uid;
+        assertEquals(expected, InetDiagMessage.containsUid(inetDiagMsg, ranges));
+    }
+
+    @Test
+    public void testContainsUid() {
+        doTestContainsUid(77 /* uid */,
+                new ArraySet<>(List.of(new Range<>(0, 100))),
+                true /* expected */);
+        doTestContainsUid(77 /* uid */,
+                new ArraySet<>(List.of(new Range<>(77, 77), new Range<>(100, 200))),
+                true /* expected */);
+
+        doTestContainsUid(77 /* uid */,
+                new ArraySet<>(List.of(new Range<>(100, 200))),
+                false /* expected */);
+        doTestContainsUid(77 /* uid */,
+                new ArraySet<>(List.of(new Range<>(0, 76), new Range<>(78, 100))),
+                false /* expected */);
+    }
+
+    private void doTestIsAdbSocket(final int uid, final boolean expected) {
+        final InetDiagMessage inetDiagMsg = new InetDiagMessage(new StructNlMsgHdr());
+        inetDiagMsg.inetDiagMsg.idiag_uid = uid;
+        inetDiagMsg.inetDiagMsg.id = new StructInetDiagSockId(
+                new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::1"), 38417),
+                new InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::2"), 38415)
+        );
+        assertEquals(expected, InetDiagMessage.isAdbSocket(inetDiagMsg));
+    }
+
+    @Test
+    public void testIsAdbSocket() {
+        final int appUid = 10108;
+        doTestIsAdbSocket(SHELL_UID,  true /* expected */);
+        doTestIsAdbSocket(ROOT_UID, false /* expected */);
+        doTestIsAdbSocket(appUid, false /* expected */);
+    }
 }
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java
index 7a1639a..6fbfbf9 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NetlinkUtilsTest.java
@@ -30,6 +30,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
 
 import android.content.Context;
 import android.system.ErrnoException;
@@ -51,11 +52,13 @@
 import java.io.FileDescriptor;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class NetlinkUtilsTest {
-    private static final String TAG = "NetlinkUitlsTest";
+    private static final String TAG = "NetlinkUtilsTest";
     private static final int TEST_SEQNO = 5;
     private static final int TEST_TIMEOUT_MS = 500;
 
@@ -82,6 +85,8 @@
 
         // Apps targeting an SDK version > S are not allowed to send RTM_GETNEIGH{TBL} messages
         if (SdkLevel.isAtLeastT() && targetSdk > 31) {
+            var ctxt = new String(Files.readAllBytes(Paths.get("/proc/thread-self/attr/current")));
+            assumeFalse("must not be platform app", ctxt.startsWith("u:r:platform_app:s0:"));
             try {
                 NetlinkUtils.sendMessage(fd, req, 0, req.length, TEST_TIMEOUT_MS);
                 fail("RTM_GETNEIGH is not allowed for apps targeting SDK > 31 on T+ platforms,"