Loading src/android/net/ip/IpClient.java +9 −1 Original line number Diff line number Diff line Loading @@ -458,7 +458,7 @@ public class IpClient extends StateMachine { private final SharedLog mLog; private final LocalLog mConnectivityPacketLog; private final MessageHandlingLogger mMsgStateLogger; private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); private final IpConnectivityLog mMetricsLog; private final InterfaceController mInterfaceCtrl; // Ignore nonzero RDNSS option lifetimes below this value. 0 = disabled. Loading Loading @@ -537,6 +537,13 @@ public class IpClient extends StateMachine { return NetworkStackUtils.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, name, defaultValue); } /** * Get a IpConnectivityLog instance. */ public IpConnectivityLog getIpConnectivityLog() { return new IpConnectivityLog(); } } public IpClient(Context context, String ifName, IIpClientCallbacks callback, Loading @@ -558,6 +565,7 @@ public class IpClient extends StateMachine { mInterfaceName = ifName; mClatInterfaceName = CLAT_PREFIX + ifName; mDependencies = deps; mMetricsLog = deps.getIpConnectivityLog(); mShutdownLatch = new CountDownLatch(1); mCm = mContext.getSystemService(ConnectivityManager.class); mObserverRegistry = observerRegistry; Loading tests/integration/src/android/net/netlink/InetDiagSocketIntegrationTest.java 0 → 100644 +223 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.netlink; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; import static android.system.OsConstants.SOCK_STREAM; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assume.assumeTrue; import android.app.Instrumentation; import android.content.Context; import android.net.ConnectivityManager; import android.os.Process; import android.system.Os; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.networkstack.apishim.common.ShimUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.io.FileDescriptor; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; @RunWith(AndroidJUnit4.class) @SmallTest public class InetDiagSocketIntegrationTest { private ConnectivityManager mCm; private Context mContext; @Before public void setUp() throws Exception { Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); mContext = instrumentation.getTargetContext(); mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); } private class Connection { public int socketDomain; public int socketType; public InetAddress localAddress; public InetAddress remoteAddress; public InetAddress localhostAddress; public InetSocketAddress local; public InetSocketAddress remote; public int protocol; public FileDescriptor localFd; public FileDescriptor remoteFd; public FileDescriptor createSocket() throws Exception { return Os.socket(socketDomain, socketType, protocol); } Connection(String to, String from) throws Exception { remoteAddress = InetAddress.getByName(to); if (from != null) { localAddress = InetAddress.getByName(from); } else { localAddress = (remoteAddress instanceof Inet4Address) ? Inet4Address.getByName("localhost") : Inet6Address.getByName("::"); } if ((localAddress instanceof Inet4Address) && (remoteAddress instanceof Inet4Address)) { socketDomain = AF_INET; localhostAddress = Inet4Address.getByName("localhost"); } else { socketDomain = AF_INET6; localhostAddress = Inet6Address.getByName("::"); } } public void close() throws Exception { Os.close(localFd); } } private class TcpConnection extends Connection { TcpConnection(String to, String from) throws Exception { super(to, from); protocol = IPPROTO_TCP; socketType = SOCK_STREAM; remoteFd = createSocket(); Os.bind(remoteFd, remoteAddress, 0); Os.listen(remoteFd, 10); int remotePort = ((InetSocketAddress) Os.getsockname(remoteFd)).getPort(); localFd = createSocket(); Os.bind(localFd, localAddress, 0); Os.connect(localFd, remoteAddress, remotePort); local = (InetSocketAddress) Os.getsockname(localFd); remote = (InetSocketAddress) Os.getpeername(localFd); } public void close() throws Exception { super.close(); Os.close(remoteFd); } } private class UdpConnection extends Connection { UdpConnection(String to, String from) throws Exception { super(to, from); protocol = IPPROTO_UDP; socketType = SOCK_DGRAM; remoteFd = null; localFd = createSocket(); Os.bind(localFd, localAddress, 0); Os.connect(localFd, remoteAddress, 7); local = (InetSocketAddress) Os.getsockname(localFd); remote = new InetSocketAddress(remoteAddress, 7); } } private void checkConnectionOwnerUid(int protocol, InetSocketAddress local, InetSocketAddress remote, boolean expectSuccess) { final int uid = mCm.getConnectionOwnerUid(protocol, local, remote); if (expectSuccess) { assertEquals(Process.myUid(), uid); } else { assertNotEquals(Process.myUid(), uid); } } private int findLikelyFreeUdpPort(UdpConnection conn) throws Exception { UdpConnection udp = new UdpConnection(conn.remoteAddress.getHostAddress(), conn.localAddress.getHostAddress()); final int localPort = udp.local.getPort(); udp.close(); return localPort; } /** * Create a test connection for UDP and TCP sockets and verify that this * {protocol, local, remote} socket result in receiving a valid UID. */ public void checkGetConnectionOwnerUid(String to, String from) throws Exception { TcpConnection tcp = new TcpConnection(to, from); checkConnectionOwnerUid(tcp.protocol, tcp.local, tcp.remote, true); checkConnectionOwnerUid(IPPROTO_UDP, tcp.local, tcp.remote, false); checkConnectionOwnerUid(tcp.protocol, new InetSocketAddress(0), tcp.remote, false); checkConnectionOwnerUid(tcp.protocol, tcp.local, new InetSocketAddress(0), false); tcp.close(); UdpConnection udp = new UdpConnection(to, from); checkConnectionOwnerUid(udp.protocol, udp.local, udp.remote, true); checkConnectionOwnerUid(IPPROTO_TCP, udp.local, udp.remote, false); checkConnectionOwnerUid(udp.protocol, new InetSocketAddress(findLikelyFreeUdpPort(udp)), udp.remote, false); udp.close(); } @Test public void testGetConnectionOwnerUid() throws Exception { // Skip the test for API <= Q, as b/141603906 this was only fixed in Q-QPR2 assumeTrue(ShimUtils.isAtLeastR()); checkGetConnectionOwnerUid("::", null); checkGetConnectionOwnerUid("::", "::"); checkGetConnectionOwnerUid("0.0.0.0", null); checkGetConnectionOwnerUid("0.0.0.0", "0.0.0.0"); checkGetConnectionOwnerUid("127.0.0.1", null); checkGetConnectionOwnerUid("127.0.0.1", "127.0.0.2"); checkGetConnectionOwnerUid("::1", null); checkGetConnectionOwnerUid("::1", "::1"); } /* Verify fix for b/141603906 */ @Test public void testB141603906() throws Exception { // Skip the test for API <= Q, as b/141603906 this was only fixed in Q-QPR2 assumeTrue(ShimUtils.isAtLeastR()); final InetSocketAddress src = new InetSocketAddress(0); final InetSocketAddress dst = new InetSocketAddress(0); final int numThreads = 8; final int numSockets = 5000; final Thread[] threads = new Thread[numThreads]; for (int i = 0; i < numThreads; i++) { threads[i] = new Thread(() -> { for (int j = 0; j < numSockets; j++) { mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst); } }); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { thread.join(); } } } tests/unit/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ java_defaults { name: "NetworkStackTestsDefaults", certificate: "platform", platform_apis: true, srcs: ["src/**/*.java", "src/**/*.kt"], resource_dirs: ["res"], static_libs: [ Loading tests/unit/AndroidManifest.xml +0 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.NETWORK_STACK" /> <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> Loading tests/unit/src/android/net/ip/IpClientTest.java +3 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import android.net.MacAddress; import android.net.NetworkStackIpMemoryStore; import android.net.RouteInfo; import android.net.ipmemorystore.NetworkAttributes; import android.net.metrics.IpConnectivityLog; import android.net.shared.InitialConfiguration; import android.net.shared.ProvisioningConfiguration; import android.net.util.InterfaceParams; Loading Loading @@ -120,6 +121,7 @@ public class IpClientTest { @Mock private NetworkStackIpMemoryStore mIpMemoryStore; @Mock private IpMemoryStoreService mIpMemoryStoreService; @Mock private InterfaceParams mInterfaceParams; @Mock private IpConnectivityLog mMetricsLog; private NetworkObserver mObserver; private InterfaceParams mIfParams; Loading @@ -139,6 +141,7 @@ public class IpClientTest { when(mDependencies.getInterfaceParams(any())).thenReturn(mInterfaceParams); when(mDependencies.getIpMemoryStore(mContext, mNetworkStackServiceManager)) .thenReturn(mIpMemoryStore); when(mDependencies.getIpConnectivityLog()).thenReturn(mMetricsLog); mIfParams = null; } Loading Loading
src/android/net/ip/IpClient.java +9 −1 Original line number Diff line number Diff line Loading @@ -458,7 +458,7 @@ public class IpClient extends StateMachine { private final SharedLog mLog; private final LocalLog mConnectivityPacketLog; private final MessageHandlingLogger mMsgStateLogger; private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); private final IpConnectivityLog mMetricsLog; private final InterfaceController mInterfaceCtrl; // Ignore nonzero RDNSS option lifetimes below this value. 0 = disabled. Loading Loading @@ -537,6 +537,13 @@ public class IpClient extends StateMachine { return NetworkStackUtils.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, name, defaultValue); } /** * Get a IpConnectivityLog instance. */ public IpConnectivityLog getIpConnectivityLog() { return new IpConnectivityLog(); } } public IpClient(Context context, String ifName, IIpClientCallbacks callback, Loading @@ -558,6 +565,7 @@ public class IpClient extends StateMachine { mInterfaceName = ifName; mClatInterfaceName = CLAT_PREFIX + ifName; mDependencies = deps; mMetricsLog = deps.getIpConnectivityLog(); mShutdownLatch = new CountDownLatch(1); mCm = mContext.getSystemService(ConnectivityManager.class); mObserverRegistry = observerRegistry; Loading
tests/integration/src/android/net/netlink/InetDiagSocketIntegrationTest.java 0 → 100644 +223 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.netlink; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; import static android.system.OsConstants.SOCK_STREAM; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assume.assumeTrue; import android.app.Instrumentation; import android.content.Context; import android.net.ConnectivityManager; import android.os.Process; import android.system.Os; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.networkstack.apishim.common.ShimUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.io.FileDescriptor; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; @RunWith(AndroidJUnit4.class) @SmallTest public class InetDiagSocketIntegrationTest { private ConnectivityManager mCm; private Context mContext; @Before public void setUp() throws Exception { Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); mContext = instrumentation.getTargetContext(); mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); } private class Connection { public int socketDomain; public int socketType; public InetAddress localAddress; public InetAddress remoteAddress; public InetAddress localhostAddress; public InetSocketAddress local; public InetSocketAddress remote; public int protocol; public FileDescriptor localFd; public FileDescriptor remoteFd; public FileDescriptor createSocket() throws Exception { return Os.socket(socketDomain, socketType, protocol); } Connection(String to, String from) throws Exception { remoteAddress = InetAddress.getByName(to); if (from != null) { localAddress = InetAddress.getByName(from); } else { localAddress = (remoteAddress instanceof Inet4Address) ? Inet4Address.getByName("localhost") : Inet6Address.getByName("::"); } if ((localAddress instanceof Inet4Address) && (remoteAddress instanceof Inet4Address)) { socketDomain = AF_INET; localhostAddress = Inet4Address.getByName("localhost"); } else { socketDomain = AF_INET6; localhostAddress = Inet6Address.getByName("::"); } } public void close() throws Exception { Os.close(localFd); } } private class TcpConnection extends Connection { TcpConnection(String to, String from) throws Exception { super(to, from); protocol = IPPROTO_TCP; socketType = SOCK_STREAM; remoteFd = createSocket(); Os.bind(remoteFd, remoteAddress, 0); Os.listen(remoteFd, 10); int remotePort = ((InetSocketAddress) Os.getsockname(remoteFd)).getPort(); localFd = createSocket(); Os.bind(localFd, localAddress, 0); Os.connect(localFd, remoteAddress, remotePort); local = (InetSocketAddress) Os.getsockname(localFd); remote = (InetSocketAddress) Os.getpeername(localFd); } public void close() throws Exception { super.close(); Os.close(remoteFd); } } private class UdpConnection extends Connection { UdpConnection(String to, String from) throws Exception { super(to, from); protocol = IPPROTO_UDP; socketType = SOCK_DGRAM; remoteFd = null; localFd = createSocket(); Os.bind(localFd, localAddress, 0); Os.connect(localFd, remoteAddress, 7); local = (InetSocketAddress) Os.getsockname(localFd); remote = new InetSocketAddress(remoteAddress, 7); } } private void checkConnectionOwnerUid(int protocol, InetSocketAddress local, InetSocketAddress remote, boolean expectSuccess) { final int uid = mCm.getConnectionOwnerUid(protocol, local, remote); if (expectSuccess) { assertEquals(Process.myUid(), uid); } else { assertNotEquals(Process.myUid(), uid); } } private int findLikelyFreeUdpPort(UdpConnection conn) throws Exception { UdpConnection udp = new UdpConnection(conn.remoteAddress.getHostAddress(), conn.localAddress.getHostAddress()); final int localPort = udp.local.getPort(); udp.close(); return localPort; } /** * Create a test connection for UDP and TCP sockets and verify that this * {protocol, local, remote} socket result in receiving a valid UID. */ public void checkGetConnectionOwnerUid(String to, String from) throws Exception { TcpConnection tcp = new TcpConnection(to, from); checkConnectionOwnerUid(tcp.protocol, tcp.local, tcp.remote, true); checkConnectionOwnerUid(IPPROTO_UDP, tcp.local, tcp.remote, false); checkConnectionOwnerUid(tcp.protocol, new InetSocketAddress(0), tcp.remote, false); checkConnectionOwnerUid(tcp.protocol, tcp.local, new InetSocketAddress(0), false); tcp.close(); UdpConnection udp = new UdpConnection(to, from); checkConnectionOwnerUid(udp.protocol, udp.local, udp.remote, true); checkConnectionOwnerUid(IPPROTO_TCP, udp.local, udp.remote, false); checkConnectionOwnerUid(udp.protocol, new InetSocketAddress(findLikelyFreeUdpPort(udp)), udp.remote, false); udp.close(); } @Test public void testGetConnectionOwnerUid() throws Exception { // Skip the test for API <= Q, as b/141603906 this was only fixed in Q-QPR2 assumeTrue(ShimUtils.isAtLeastR()); checkGetConnectionOwnerUid("::", null); checkGetConnectionOwnerUid("::", "::"); checkGetConnectionOwnerUid("0.0.0.0", null); checkGetConnectionOwnerUid("0.0.0.0", "0.0.0.0"); checkGetConnectionOwnerUid("127.0.0.1", null); checkGetConnectionOwnerUid("127.0.0.1", "127.0.0.2"); checkGetConnectionOwnerUid("::1", null); checkGetConnectionOwnerUid("::1", "::1"); } /* Verify fix for b/141603906 */ @Test public void testB141603906() throws Exception { // Skip the test for API <= Q, as b/141603906 this was only fixed in Q-QPR2 assumeTrue(ShimUtils.isAtLeastR()); final InetSocketAddress src = new InetSocketAddress(0); final InetSocketAddress dst = new InetSocketAddress(0); final int numThreads = 8; final int numSockets = 5000; final Thread[] threads = new Thread[numThreads]; for (int i = 0; i < numThreads; i++) { threads[i] = new Thread(() -> { for (int j = 0; j < numSockets; j++) { mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst); } }); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { thread.join(); } } }
tests/unit/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ java_defaults { name: "NetworkStackTestsDefaults", certificate: "platform", platform_apis: true, srcs: ["src/**/*.java", "src/**/*.kt"], resource_dirs: ["res"], static_libs: [ Loading
tests/unit/AndroidManifest.xml +0 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.NETWORK_STACK" /> <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> Loading
tests/unit/src/android/net/ip/IpClientTest.java +3 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import android.net.MacAddress; import android.net.NetworkStackIpMemoryStore; import android.net.RouteInfo; import android.net.ipmemorystore.NetworkAttributes; import android.net.metrics.IpConnectivityLog; import android.net.shared.InitialConfiguration; import android.net.shared.ProvisioningConfiguration; import android.net.util.InterfaceParams; Loading Loading @@ -120,6 +121,7 @@ public class IpClientTest { @Mock private NetworkStackIpMemoryStore mIpMemoryStore; @Mock private IpMemoryStoreService mIpMemoryStoreService; @Mock private InterfaceParams mInterfaceParams; @Mock private IpConnectivityLog mMetricsLog; private NetworkObserver mObserver; private InterfaceParams mIfParams; Loading @@ -139,6 +141,7 @@ public class IpClientTest { when(mDependencies.getInterfaceParams(any())).thenReturn(mInterfaceParams); when(mDependencies.getIpMemoryStore(mContext, mNetworkStackServiceManager)) .thenReturn(mIpMemoryStore); when(mDependencies.getIpConnectivityLog()).thenReturn(mMetricsLog); mIfParams = null; } Loading