1 /* <lambda>null2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.net.ip 17 18 import android.content.Context 19 import android.net.INetd 20 import android.net.InetAddresses.parseNumericAddress 21 import android.net.IpPrefix 22 import android.net.LinkAddress 23 import android.net.LinkProperties 24 import android.net.RouteInfo 25 import android.net.metrics.IpConnectivityLog 26 import android.net.netlink.StructNdMsg.NUD_FAILED 27 import android.net.netlink.StructNdMsg.NUD_STALE 28 import android.net.netlink.makeNewNeighMessage 29 import android.net.util.InterfaceParams 30 import android.net.util.SharedLog 31 import android.os.Handler 32 import android.os.HandlerThread 33 import android.os.MessageQueue 34 import android.os.MessageQueue.OnFileDescriptorEventListener 35 import android.system.ErrnoException 36 import android.system.OsConstants.EAGAIN 37 import androidx.test.filters.SmallTest 38 import androidx.test.runner.AndroidJUnit4 39 import com.android.testutils.waitForIdle 40 import org.junit.After 41 import org.junit.Before 42 import org.junit.Test 43 import org.junit.runner.RunWith 44 import org.mockito.ArgumentCaptor 45 import org.mockito.ArgumentMatchers.any 46 import org.mockito.ArgumentMatchers.anyInt 47 import org.mockito.ArgumentMatchers.anyString 48 import org.mockito.ArgumentMatchers.eq 49 import org.mockito.Mockito.doAnswer 50 import org.mockito.Mockito.doReturn 51 import org.mockito.Mockito.mock 52 import org.mockito.Mockito.timeout 53 import org.mockito.Mockito.verify 54 import java.io.FileDescriptor 55 import java.net.Inet4Address 56 import java.net.Inet6Address 57 import java.net.InetAddress 58 import java.util.concurrent.CompletableFuture 59 import java.util.concurrent.ConcurrentLinkedQueue 60 import java.util.concurrent.TimeUnit 61 import kotlin.test.assertTrue 62 import kotlin.test.fail 63 64 private const val TEST_TIMEOUT_MS = 10_000L 65 66 private val TEST_IPV4_GATEWAY = parseNumericAddress("192.168.222.3") as Inet4Address 67 private val TEST_IPV6_GATEWAY = parseNumericAddress("2001:db8::1") as Inet6Address 68 69 private val TEST_IPV4_LINKADDR = LinkAddress("192.168.222.123/24") 70 private val TEST_IPV6_LINKADDR = LinkAddress("2001:db8::123/64") 71 72 // DNSes inside IP prefix 73 private val TEST_IPV4_DNS = parseNumericAddress("192.168.222.1") as Inet4Address 74 private val TEST_IPV6_DNS = parseNumericAddress("2001:db8::321") as Inet6Address 75 76 private val TEST_IFACE = InterfaceParams("fake0", 21, null) 77 private val TEST_LINK_PROPERTIES = LinkProperties().apply { 78 interfaceName = TEST_IFACE.name 79 addLinkAddress(TEST_IPV4_LINKADDR) 80 addLinkAddress(TEST_IPV6_LINKADDR) 81 82 // Add on link routes 83 addRoute(RouteInfo(TEST_IPV4_LINKADDR, null /* gateway */, TEST_IFACE.name)) 84 addRoute(RouteInfo(TEST_IPV6_LINKADDR, null /* gateway */, TEST_IFACE.name)) 85 86 // Add default routes 87 addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY)) 88 addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_GATEWAY)) 89 90 addDnsServer(TEST_IPV4_DNS) 91 addDnsServer(TEST_IPV6_DNS) 92 } 93 94 /** 95 * Tests for IpReachabilityMonitor. 96 */ 97 @RunWith(AndroidJUnit4::class) 98 @SmallTest 99 class IpReachabilityMonitorTest { 100 private val callback = mock(IpReachabilityMonitor.Callback::class.java) 101 private val dependencies = mock(IpReachabilityMonitor.Dependencies::class.java) 102 private val log = mock(SharedLog::class.java) 103 private val context = mock(Context::class.java) 104 private val netd = mock(INetd::class.java) 105 private val fd = mock(FileDescriptor::class.java) 106 private val metricsLog = mock(IpConnectivityLog::class.java) 107 108 private val handlerThread = HandlerThread(IpReachabilityMonitorTest::class.simpleName) <lambda>null109 private val handler by lazy { Handler(handlerThread.looper) } 110 111 private lateinit var reachabilityMonitor: IpReachabilityMonitor 112 private lateinit var neighborMonitor: TestIpNeighborMonitor 113 114 /** 115 * A version of [IpNeighborMonitor] that overrides packet reading from a socket, and instead 116 * allows the test to enqueue test packets via [enqueuePacket]. 117 */ 118 private class TestIpNeighborMonitor( 119 handler: Handler, 120 log: SharedLog, 121 cb: NeighborEventConsumer, 122 private val fd: FileDescriptor 123 ) : IpNeighborMonitor(handler, log, cb) { 124 125 private val pendingPackets = ConcurrentLinkedQueue<ByteArray>() 126 val msgQueue = mock(MessageQueue::class.java) 127 128 private var eventListener: OnFileDescriptorEventListener? = null 129 createFdnull130 override fun createFd() = fd 131 override fun getMessageQueue() = msgQueue 132 133 fun enqueuePacket(packet: ByteArray) { 134 val listener = eventListener ?: fail("IpNeighborMonitor was not yet started") 135 pendingPackets.add(packet) 136 handler.post { 137 listener.onFileDescriptorEvents(fd, OnFileDescriptorEventListener.EVENT_INPUT) 138 } 139 } 140 readPacketnull141 override fun readPacket(fd: FileDescriptor, packetBuffer: ByteArray): Int { 142 val packet = pendingPackets.poll() ?: throw ErrnoException("No pending packet", EAGAIN) 143 if (packet.size > packetBuffer.size) { 144 fail("Buffer (${packetBuffer.size}) is too small for packet (${packet.size})") 145 } 146 System.arraycopy(packet, 0, packetBuffer, 0, packet.size) 147 return packet.size 148 } 149 onStartnull150 override fun onStart() { 151 super.onStart() 152 153 // Find the file descriptor listener that was registered on the instrumented queue 154 val captor = ArgumentCaptor.forClass(OnFileDescriptorEventListener::class.java) 155 verify(msgQueue).addOnFileDescriptorEventListener( 156 eq(fd), anyInt(), captor.capture()) 157 eventListener = captor.value 158 } 159 } 160 161 @Before setUpnull162 fun setUp() { 163 doReturn(log).`when`(log).forSubComponent(anyString()) 164 doReturn(true).`when`(fd).valid() 165 handlerThread.start() 166 167 doAnswer { inv -> 168 val handler = inv.getArgument<Handler>(0) 169 val log = inv.getArgument<SharedLog>(1) 170 val cb = inv.getArgument<IpNeighborMonitor.NeighborEventConsumer>(2) 171 neighborMonitor = TestIpNeighborMonitor(handler, log, cb, fd) 172 neighborMonitor 173 }.`when`(dependencies).makeIpNeighborMonitor(any(), any(), any()) 174 175 val monitorFuture = CompletableFuture<IpReachabilityMonitor>() 176 // IpReachabilityMonitor needs to be started from the handler thread 177 handler.post { 178 monitorFuture.complete(IpReachabilityMonitor( 179 context, 180 TEST_IFACE, 181 handler, 182 log, 183 callback, 184 false /* useMultinetworkPolicyTracker */, 185 dependencies, 186 metricsLog, 187 netd)) 188 } 189 reachabilityMonitor = monitorFuture.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS) 190 assertTrue(::neighborMonitor.isInitialized, 191 "IpReachabilityMonitor did not call makeIpNeighborMonitor") 192 } 193 194 @After tearDownnull195 fun tearDown() { 196 // Ensure the handler thread is not accessing the fd while changing its mock 197 handlerThread.waitForIdle(TEST_TIMEOUT_MS) 198 doReturn(false).`when`(fd).valid() 199 handlerThread.quitSafely() 200 } 201 202 @Test testLoseProvisioning_FirstProbeIsFailednull203 fun testLoseProvisioning_FirstProbeIsFailed() { 204 reachabilityMonitor.updateLinkProperties(TEST_LINK_PROPERTIES) 205 206 neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_FAILED)) 207 verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(eq(TEST_IPV4_DNS), anyString()) 208 } 209 runLoseProvisioningTestnull210 private fun runLoseProvisioningTest(lostNeighbor: InetAddress) { 211 reachabilityMonitor.updateLinkProperties(TEST_LINK_PROPERTIES) 212 213 neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_GATEWAY, NUD_STALE)) 214 neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_GATEWAY, NUD_STALE)) 215 neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV4_DNS, NUD_STALE)) 216 neighborMonitor.enqueuePacket(makeNewNeighMessage(TEST_IPV6_DNS, NUD_STALE)) 217 218 neighborMonitor.enqueuePacket(makeNewNeighMessage(lostNeighbor, NUD_FAILED)) 219 verify(callback, timeout(TEST_TIMEOUT_MS)).notifyLost(eq(lostNeighbor), anyString()) 220 } 221 222 @Test testLoseProvisioning_Ipv4DnsLostnull223 fun testLoseProvisioning_Ipv4DnsLost() { 224 runLoseProvisioningTest(TEST_IPV4_DNS) 225 } 226 227 @Test testLoseProvisioning_Ipv6DnsLostnull228 fun testLoseProvisioning_Ipv6DnsLost() { 229 runLoseProvisioningTest(TEST_IPV6_DNS) 230 } 231 232 @Test testLoseProvisioning_Ipv4GatewayLostnull233 fun testLoseProvisioning_Ipv4GatewayLost() { 234 runLoseProvisioningTest(TEST_IPV4_GATEWAY) 235 } 236 237 @Test testLoseProvisioning_Ipv6GatewayLostnull238 fun testLoseProvisioning_Ipv6GatewayLost() { 239 runLoseProvisioningTest(TEST_IPV6_GATEWAY) 240 } 241 }