1 /* <lambda>null2 * Copyright (C) 2024 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.apf 17 18 import android.content.Context 19 import android.net.LinkAddress 20 import android.net.LinkProperties 21 import android.net.MacAddress 22 import android.net.NattKeepalivePacketDataParcelable 23 import android.net.TcpKeepalivePacketDataParcelable 24 import android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_NON_IPV4 25 import android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_OTHER_HOST 26 import android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_REPLY_SPA_NO_HOST 27 import android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_REQUEST_REPLIED 28 import android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_UNKNOWN 29 import android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_V6_ONLY 30 import android.net.apf.ApfCounterTracker.Counter.DROPPED_ETHERTYPE_NOT_ALLOWED 31 import android.net.apf.ApfCounterTracker.Counter.DROPPED_GARP_REPLY 32 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_BROADCAST_ADDR 33 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_BROADCAST_NET 34 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_KEEPALIVE_ACK 35 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_L2_BROADCAST 36 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_MULTICAST 37 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_NATT_KEEPALIVE 38 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_NON_DHCP4 39 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_TCP_PORT7_UNICAST 40 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MULTICAST_NA 41 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NON_ICMP_MULTICAST 42 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_INVALID 43 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_OTHER_HOST 44 import android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_REPLIED_NON_DAD 45 import android.net.apf.ApfCounterTracker.Counter.PASSED_ETHER_OUR_SRC_MAC 46 import android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_BROADCAST_REPLY 47 import android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_REQUEST 48 import android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_UNICAST_REPLY 49 import android.net.apf.ApfCounterTracker.Counter.PASSED_DHCP 50 import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV4 51 import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV4_FROM_DHCPV4_SERVER 52 import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV4_UNICAST 53 import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_ICMP 54 import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NON_ICMP 55 import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_DAD 56 import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_NO_ADDRESS 57 import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_NO_SLLA_OPTION 58 import android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_TENTATIVE 59 import android.net.apf.ApfCounterTracker.Counter.PASSED_MLD 60 import android.net.apf.ApfFilter.Dependencies 61 import android.net.apf.ApfTestHelpers.Companion.TIMEOUT_MS 62 import android.net.apf.ApfTestHelpers.Companion.consumeInstalledProgram 63 import android.net.apf.ApfTestHelpers.Companion.consumeTransmittedPackets 64 import android.net.apf.ApfTestHelpers.Companion.verifyProgramRun 65 import android.net.apf.BaseApfGenerator.APF_VERSION_3 66 import android.net.apf.BaseApfGenerator.APF_VERSION_6 67 import android.net.ip.IpClient.IpClientCallbacksWrapper 68 import android.net.nsd.NsdManager 69 import android.net.nsd.OffloadEngine 70 import android.net.nsd.OffloadServiceInfo 71 import android.os.Build 72 import android.os.Handler 73 import android.os.HandlerThread 74 import android.os.SystemClock 75 import android.system.Os 76 import android.system.OsConstants.AF_UNIX 77 import android.system.OsConstants.IFA_F_TENTATIVE 78 import android.system.OsConstants.SOCK_STREAM 79 import androidx.test.filters.SmallTest 80 import com.android.internal.annotations.GuardedBy 81 import com.android.net.module.util.HexDump 82 import com.android.net.module.util.InterfaceParams 83 import com.android.net.module.util.NetworkStackConstants.ARP_ETHER_IPV4_LEN 84 import com.android.net.module.util.NetworkStackConstants.ARP_REPLY 85 import com.android.net.module.util.NetworkStackConstants.ARP_REQUEST 86 import com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN 87 import com.android.net.module.util.NetworkStackConstants.ICMPV6_NA_HEADER_LEN 88 import com.android.net.module.util.NetworkStackConstants.ICMPV6_NS_HEADER_LEN 89 import com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN 90 import com.android.net.module.util.arp.ArpPacket 91 import com.android.networkstack.metrics.NetworkQuirkMetrics 92 import com.android.networkstack.packets.NeighborAdvertisement 93 import com.android.networkstack.packets.NeighborSolicitation 94 import com.android.networkstack.util.NetworkStackUtils 95 import com.android.testutils.DevSdkIgnoreRule 96 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo 97 import com.android.testutils.DevSdkIgnoreRunner 98 import com.android.testutils.quitResources 99 import com.android.testutils.waitForIdle 100 import java.io.FileDescriptor 101 import java.net.Inet4Address 102 import java.net.Inet6Address 103 import java.net.InetAddress 104 import kotlin.test.assertContentEquals 105 import kotlin.test.assertEquals 106 import libcore.io.IoUtils 107 import org.junit.After 108 import org.junit.Before 109 import org.junit.Rule 110 import org.junit.Test 111 import org.junit.runner.RunWith 112 import org.mockito.ArgumentCaptor 113 import org.mockito.ArgumentMatchers.any 114 import org.mockito.ArgumentMatchers.anyInt 115 import org.mockito.ArgumentMatchers.anyLong 116 import org.mockito.ArgumentMatchers.eq 117 import org.mockito.Mock 118 import org.mockito.Mockito 119 import org.mockito.Mockito.doAnswer 120 import org.mockito.Mockito.doReturn 121 import org.mockito.Mockito.never 122 import org.mockito.Mockito.times 123 import org.mockito.Mockito.verify 124 import org.mockito.MockitoAnnotations 125 import org.mockito.invocation.InvocationOnMock 126 127 /** 128 * Test for APF filter. 129 */ 130 @DevSdkIgnoreRunner.MonitorThreadLeak 131 @RunWith(DevSdkIgnoreRunner::class) 132 @SmallTest 133 class ApfFilterTest { 134 companion object { 135 private const val THREAD_QUIT_MAX_RETRY_COUNT = 3 136 private const val TAG = "ApfFilterTest" 137 } 138 139 @get:Rule 140 val ignoreRule = DevSdkIgnoreRule() 141 142 @Mock 143 private lateinit var context: Context 144 145 @Mock private lateinit var metrics: NetworkQuirkMetrics 146 147 @Mock private lateinit var dependencies: Dependencies 148 149 @Mock private lateinit var ipClientCallback: IpClientCallbacksWrapper 150 @Mock private lateinit var nsdManager: NsdManager 151 152 @GuardedBy("mApfFilterCreated") 153 private val mApfFilterCreated = ArrayList<AndroidPacketFilter>() 154 private val loInterfaceParams = InterfaceParams.getByName("lo") 155 private val ifParams = 156 InterfaceParams( 157 "lo", 158 loInterfaceParams.index, 159 MacAddress.fromBytes(byteArrayOf(2, 3, 4, 5, 6, 7)), 160 loInterfaceParams.defaultMtu 161 ) 162 private val hostIpv4Address = byteArrayOf(10, 0, 0, 1) 163 private val senderIpv4Address = byteArrayOf(10, 0, 0, 2) 164 private val arpBroadcastMacAddress = intArrayOf(0xff, 0xff, 0xff, 0xff, 0xff, 0xff) 165 .map { it.toByte() }.toByteArray() 166 private val senderMacAddress = intArrayOf(0x02, 0x22, 0x33, 0x44, 0x55, 0x66) 167 .map { it.toByte() }.toByteArray() 168 private val senderIpv6Address = 169 // 2001::200:1a:1122:3344 170 intArrayOf(0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x02, 0, 0, 0x1a, 0x11, 0x22, 0x33, 0x44) 171 .map{ it.toByte() }.toByteArray() 172 private val hostIpv6Addresses = listOf( 173 // 2001::200:1a:3344:1122 174 intArrayOf(0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x02, 0, 0, 0x1a, 0x33, 0x44, 0x11, 0x22) 175 .map{ it.toByte() }.toByteArray(), 176 // 2001::100:1b:4455:6677 177 intArrayOf(0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0x1b, 0x44, 0x55, 0x66, 0x77) 178 .map{ it.toByte() }.toByteArray() 179 ) 180 private val hostIpv6TentativeAddresses = listOf( 181 // 2001::200:1a:1234:5678 182 intArrayOf(0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x02, 0, 0, 0x1a, 0x12, 0x34, 0x56, 0x78) 183 .map{ it.toByte() }.toByteArray(), 184 // 2001::100:1b:1234:5678 185 intArrayOf(0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0x1b, 0x12, 0x34, 0x56, 0x78) 186 .map{ it.toByte() }.toByteArray() 187 ) 188 private val hostAnycast6Addresses = listOf( 189 // 2001::100:1b:aabb:ccdd 190 intArrayOf(0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0x1b, 0xaa, 0xbb, 0xcc, 0xdd) 191 .map{ it.toByte() }.toByteArray() 192 ) 193 private val hostMulticastMacAddresses = listOf( 194 // 33:33:00:00:00:01 195 intArrayOf(0x33, 0x33, 0, 0, 0, 1).map { it.toByte() }.toByteArray(), 196 // 33:33:ff:44:11:22 197 intArrayOf(0x33, 0x33, 0xff, 0x44, 0x11, 0x22).map { it.toByte() }.toByteArray(), 198 // 33:33:ff:55:66:77 199 intArrayOf(0x33, 0x33, 0xff, 0x55, 0x66, 0x77).map { it.toByte() }.toByteArray(), 200 // 33:33:ff:bb:cc:dd 201 intArrayOf(0x33, 0x33, 0xff, 0xbb, 0xcc, 0xdd).map { it.toByte() }.toByteArray(), 202 ) 203 204 private val handlerThread by lazy { 205 HandlerThread("$TAG handler thread").apply { start() } 206 } 207 private val handler by lazy { Handler(handlerThread.looper) } 208 private var writerSocket = FileDescriptor() 209 210 @Before 211 fun setUp() { 212 MockitoAnnotations.initMocks(this) 213 // mock anycast6 address from /proc/net/anycast6 214 doReturn(hostAnycast6Addresses).`when`(dependencies).getAnycast6Addresses(any()) 215 216 // mock ether multicast mac address from /proc/net/dev_mcast 217 doReturn(hostMulticastMacAddresses).`when`(dependencies).getEtherMulticastAddresses(any()) 218 219 // mock nd traffic class from /proc/sys/net/ipv6/conf/{ifname}/ndisc_tclass 220 doReturn(0).`when`(dependencies).getNdTrafficClass(any()) 221 doAnswer { invocation: InvocationOnMock -> 222 synchronized(mApfFilterCreated) { 223 mApfFilterCreated.add(invocation.getArgument(0)) 224 } 225 }.`when`(dependencies).onApfFilterCreated(any()) 226 doReturn(SystemClock.elapsedRealtime()).`when`(dependencies).elapsedRealtime() 227 val readSocket = FileDescriptor() 228 Os.socketpair(AF_UNIX, SOCK_STREAM, 0, writerSocket, readSocket) 229 doReturn(readSocket).`when`(dependencies).createPacketReaderSocket(anyInt()) 230 doReturn(nsdManager).`when`(context).getSystemService(NsdManager::class.java) 231 } 232 233 private fun shutdownApfFilters() { 234 quitResources(THREAD_QUIT_MAX_RETRY_COUNT, { 235 synchronized(mApfFilterCreated) { 236 val ret = ArrayList(mApfFilterCreated) 237 mApfFilterCreated.clear() 238 return@quitResources ret 239 } 240 }, { apf: AndroidPacketFilter -> 241 handler.post { apf.shutdown() } 242 }) 243 244 synchronized(mApfFilterCreated) { 245 assertEquals( 246 0, 247 mApfFilterCreated.size.toLong(), 248 "ApfFilters did not fully shutdown." 249 ) 250 } 251 } 252 253 @After 254 fun tearDown() { 255 IoUtils.closeQuietly(writerSocket) 256 shutdownApfFilters() 257 handler.waitForIdle(TIMEOUT_MS) 258 Mockito.framework().clearInlineMocks() 259 ApfJniUtils.resetTransmittedPacketMemory() 260 handlerThread.quitSafely() 261 handlerThread.join() 262 } 263 264 private fun getDefaultConfig(apfVersion: Int = APF_VERSION_6): ApfFilter.ApfConfiguration { 265 val config = ApfFilter.ApfConfiguration() 266 config.apfVersionSupported = apfVersion 267 // 4K is the highly recommended value in APFv6 for vendor 268 config.apfRamSize = 4096 269 config.multicastFilter = false 270 config.ieee802_3Filter = false 271 config.ethTypeBlackList = IntArray(0) 272 config.shouldHandleArpOffload = true 273 config.shouldHandleNdOffload = true 274 return config 275 } 276 277 private fun getApfFilter( 278 apfCfg: ApfFilter.ApfConfiguration = getDefaultConfig(APF_VERSION_6) 279 ): ApfFilter { 280 lateinit var apfFilter: ApfFilter 281 handler.post { 282 apfFilter = ApfFilter( 283 handler, 284 context, 285 apfCfg, 286 ifParams, 287 ipClientCallback, 288 metrics, 289 dependencies 290 ) 291 } 292 handlerThread.waitForIdle(TIMEOUT_MS) 293 return apfFilter 294 } 295 296 private fun doTestEtherTypeAllowListFilter(apfFilter: ApfFilter) { 297 val program = consumeInstalledProgram(ipClientCallback, installCnt = 2) 298 299 // Using scapy to generate IPv4 mDNS packet: 300 // eth = Ether(src="E8:9F:80:66:60:BB", dst="01:00:5E:00:00:FB") 301 // ip = IP(src="192.168.1.1") 302 // udp = UDP(sport=5353, dport=5353) 303 // dns = DNS(qd=DNSQR(qtype="PTR", qname="a.local")) 304 // p = eth/ip/udp/dns 305 val mdnsPkt = """ 306 01005e0000fbe89f806660bb080045000035000100004011d812c0a80101e00000f 307 b14e914e900214d970000010000010000000000000161056c6f63616c00000c0001 308 """.replace("\\s+".toRegex(), "").trim() 309 verifyProgramRun( 310 apfFilter.mApfVersionSupported, 311 program, 312 HexDump.hexStringToByteArray(mdnsPkt), 313 PASSED_IPV4 314 ) 315 316 // Using scapy to generate RA packet: 317 // eth = Ether(src="E8:9F:80:66:60:BB", dst="33:33:00:00:00:01") 318 // ip6 = IPv6(src="fe80::1", dst="ff02::1") 319 // icmp6 = ICMPv6ND_RA(routerlifetime=3600, retranstimer=3600) 320 // p = eth/ip6/icmp6 321 val raPkt = """ 322 333300000001e89f806660bb86dd6000000000103afffe800000000000000000000000 323 000001ff0200000000000000000000000000018600600700080e100000000000000e10 324 """.replace("\\s+".toRegex(), "").trim() 325 verifyProgramRun( 326 apfFilter.mApfVersionSupported, 327 program, 328 HexDump.hexStringToByteArray(raPkt), 329 PASSED_IPV6_ICMP 330 ) 331 332 // Using scapy to generate ethernet packet with type 0x88A2: 333 // p = Ether(type=0x88A2)/Raw(load="01") 334 val ethPkt = "ffffffffffff047bcb463fb588a23031" 335 verifyProgramRun( 336 apfFilter.mApfVersionSupported, 337 program, 338 HexDump.hexStringToByteArray(ethPkt), 339 DROPPED_ETHERTYPE_NOT_ALLOWED 340 ) 341 } 342 343 private fun generateNsPacket( 344 srcMac: ByteArray, 345 dstMac: ByteArray, 346 srcIp: ByteArray, 347 dstIp: ByteArray, 348 target: ByteArray, 349 ): ByteArray { 350 val nsPacketBuf = NeighborSolicitation.build( 351 MacAddress.fromBytes(srcMac), 352 MacAddress.fromBytes(dstMac), 353 InetAddress.getByAddress(srcIp) as Inet6Address, 354 InetAddress.getByAddress(dstIp) as Inet6Address, 355 InetAddress.getByAddress(target) as Inet6Address 356 ) 357 358 val nsPacket = ByteArray( 359 ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_NS_HEADER_LEN + 8 // option length 360 ) 361 nsPacketBuf.get(nsPacket) 362 return nsPacket 363 } 364 365 private fun generateNaPacket( 366 srcMac: ByteArray, 367 dstMac: ByteArray, 368 srcIp: ByteArray, 369 dstIp: ByteArray, 370 flags: Int, 371 target: ByteArray, 372 ): ByteArray { 373 val naPacketBuf = NeighborAdvertisement.build( 374 MacAddress.fromBytes(srcMac), 375 MacAddress.fromBytes(dstMac), 376 InetAddress.getByAddress(srcIp) as Inet6Address, 377 InetAddress.getByAddress(dstIp) as Inet6Address, 378 flags, 379 InetAddress.getByAddress(target) as Inet6Address 380 ) 381 val naPacket = ByteArray( 382 ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_NA_HEADER_LEN + 8 // lla option length 383 ) 384 385 naPacketBuf.get(naPacket) 386 return naPacket 387 } 388 389 @Test 390 @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 391 fun testV4EtherTypeAllowListFilter() { 392 val apfFilter = getApfFilter(getDefaultConfig(APF_VERSION_3)) 393 doTestEtherTypeAllowListFilter(apfFilter) 394 } 395 396 @Test 397 @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 398 fun testV6EtherTypeAllowListFilter() { 399 val apfFilter = getApfFilter(getDefaultConfig(APF_VERSION_6)) 400 doTestEtherTypeAllowListFilter(apfFilter) 401 } 402 403 @Test 404 fun testIPv4PacketFilterOnV6OnlyNetwork() { 405 val apfFilter = getApfFilter() 406 apfFilter.updateClatInterfaceState(true) 407 val program = consumeInstalledProgram(ipClientCallback, installCnt = 3) 408 409 // Using scapy to generate IPv4 mDNS packet: 410 // eth = Ether(src="E8:9F:80:66:60:BB", dst="01:00:5E:00:00:FB") 411 // ip = IP(src="192.168.1.1") 412 // udp = UDP(sport=5353, dport=5353) 413 // dns = DNS(qd=DNSQR(qtype="PTR", qname="a.local")) 414 // p = eth/ip/udp/dns 415 val mdnsPkt = """ 416 01005e0000fbe89f806660bb080045000035000100004011d812c0a80101e00000f 417 b14e914e900214d970000010000010000000000000161056c6f63616c00000c0001 418 """.replace("\\s+".toRegex(), "").trim() 419 verifyProgramRun( 420 apfFilter.mApfVersionSupported, 421 program, 422 HexDump.hexStringToByteArray(mdnsPkt), 423 DROPPED_IPV4_NON_DHCP4 424 ) 425 426 // Using scapy to generate non UDP protocol packet: 427 // ether = Ether(src='00:11:22:33:44:55', dst='ff:ff:ff:ff:ff:ff') 428 // ip = IP(src='192.168.1.1', dst='255.255.255.255', proto=12) 429 // pkt = ether/ip 430 val nonUdpPkt = """ 431 ffffffffffff00112233445508004500001400010000400cb934c0a80101ffffffff 432 """.replace("\\s+".toRegex(), "").trim() 433 verifyProgramRun( 434 apfFilter.mApfVersionSupported, 435 program, 436 HexDump.hexStringToByteArray(nonUdpPkt), 437 DROPPED_IPV4_NON_DHCP4 438 ) 439 440 // Using scapy to generate fragmented UDP protocol packet: 441 // ether = Ether(src='00:11:22:33:44:55', dst='ff:ff:ff:ff:ff:ff') 442 // ip = IP(src='192.168.1.1', dst='255.255.255.255', flags=1, frag=10, proto=17) 443 // pkt = ether/ip 444 val fragmentUdpPkt = """ 445 ffffffffffff0011223344550800450000140001200a40119925c0a80101ffffffff 446 """.replace("\\s+".toRegex(), "").trim() 447 verifyProgramRun( 448 apfFilter.mApfVersionSupported, 449 program, 450 HexDump.hexStringToByteArray(fragmentUdpPkt), 451 DROPPED_IPV4_NON_DHCP4 452 ) 453 454 // Using scapy to generate destination port is not DHCP client port packet: 455 // ether = Ether(src='00:11:22:33:44:55', dst='ff:ff:ff:ff:ff:ff') 456 // ip = IP(src='192.168.1.1', dst='255.255.255.255') 457 // udp = UDP(dport=70) 458 // pkt = ether/ip/udp 459 val nonDhcpServerPkt = """ 460 ffffffffffff00112233445508004500001c000100004011b927c0a80101ffffffff0035004600083dba 461 """.replace("\\s+".toRegex(), "").trim() 462 verifyProgramRun( 463 apfFilter.mApfVersionSupported, 464 program, 465 HexDump.hexStringToByteArray(nonDhcpServerPkt), 466 DROPPED_IPV4_NON_DHCP4 467 ) 468 469 // Using scapy to generate DHCP4 offer packet: 470 // ether = Ether(src='00:11:22:33:44:55', dst='ff:ff:ff:ff:ff:ff') 471 // ip = IP(src='192.168.1.1', dst='255.255.255.255') 472 // udp = UDP(sport=67, dport=68) 473 // bootp = BOOTP(op=2, 474 // yiaddr='192.168.1.100', 475 // siaddr='192.168.1.1', 476 // chaddr=b'\x00\x11\x22\x33\x44\x55') 477 // dhcp_options = [('message-type', 'offer'), 478 // ('server_id', '192.168.1.1'), 479 // ('subnet_mask', '255.255.255.0'), 480 // ('router', '192.168.1.1'), 481 // ('lease_time', 86400), 482 // ('name_server', '8.8.8.8'), 483 // 'end'] 484 // dhcp = DHCP(options=dhcp_options) 485 // dhcp_offer_packet = ether/ip/udp/bootp/dhcp 486 val dhcp4Pkt = """ 487 ffffffffffff00112233445508004500012e000100004011b815c0a80101ffffffff0043 488 0044011a5ffc02010600000000000000000000000000c0a80164c0a80101000000000011 489 223344550000000000000000000000000000000000000000000000000000000000000000 490 000000000000000000000000000000000000000000000000000000000000000000000000 491 000000000000000000000000000000000000000000000000000000000000000000000000 492 000000000000000000000000000000000000000000000000000000000000000000000000 493 000000000000000000000000000000000000000000000000000000000000000000000000 494 0000000000000000000000000000000000000000000000000000638253633501023604c0 495 a801010104ffffff000304c0a80101330400015180060408080808ff 496 """.replace("\\s+".toRegex(), "").trim() 497 verifyProgramRun( 498 apfFilter.mApfVersionSupported, 499 program, 500 HexDump.hexStringToByteArray(dhcp4Pkt), 501 PASSED_IPV4_FROM_DHCPV4_SERVER 502 ) 503 504 // Duplicate of dhcp4Pkt with DF flag set. 505 val dhcp4PktDf = """ 506 ffffffffffff00112233445508004500012e000140004011b815c0a80101ffffffff0043 507 0044011a5ffc02010600000000000000000000000000c0a80164c0a80101000000000011 508 223344550000000000000000000000000000000000000000000000000000000000000000 509 000000000000000000000000000000000000000000000000000000000000000000000000 510 000000000000000000000000000000000000000000000000000000000000000000000000 511 000000000000000000000000000000000000000000000000000000000000000000000000 512 000000000000000000000000000000000000000000000000000000000000000000000000 513 0000000000000000000000000000000000000000000000000000638253633501023604c0 514 a801010104ffffff000304c0a80101330400015180060408080808ff 515 """.replace("\\s+".toRegex(), "").trim() 516 verifyProgramRun( 517 apfFilter.mApfVersionSupported, 518 program, 519 HexDump.hexStringToByteArray(dhcp4PktDf), 520 PASSED_IPV4_FROM_DHCPV4_SERVER 521 ) 522 523 // Using scapy to generate DHCP4 offer packet: 524 // eth = Ether(src="E8:9F:80:66:60:BB", dst="01:00:5E:00:00:FB") 525 // ip = IP(src="192.168.1.10", dst="192.168.1.20") # IPv4 526 // udp = UDP(sport=12345, dport=53) 527 // dns = DNS(qd=DNSQR(qtype="PTR", qname="a.local")) 528 // pkt = eth / ip / udp / dns 529 // fragments = fragment(pkt, fragsize=30) 530 // fragments[1] 531 val fragmentedUdpPkt = """ 532 01005e0000fbe89f806660bb08004500001d000100034011f75dc0a8010ac0a8 533 01146f63616c00000c0001 534 """.replace("\\s+".toRegex(), "").trim() 535 verifyProgramRun( 536 apfFilter.mApfVersionSupported, 537 program, 538 HexDump.hexStringToByteArray(fragmentedUdpPkt), 539 DROPPED_IPV4_NON_DHCP4 540 ) 541 } 542 543 @Test 544 fun testLoopbackFilter() { 545 val apfConfig = getDefaultConfig() 546 val apfFilter = getApfFilter(apfConfig) 547 val program = consumeInstalledProgram(ipClientCallback, installCnt = 2) 548 // Using scapy to generate echo-ed broadcast packet: 549 // ether = Ether(src=${ifParams.macAddr}, dst='ff:ff:ff:ff:ff:ff') 550 // ip = IP(src='192.168.1.1', dst='255.255.255.255', proto=21) 551 // pkt = ether/ip 552 val nonDhcpBcastPkt = """ 553 ffffffffffff020304050607080045000014000100004015b92bc0a80101ffffffff 554 """.replace("\\s+".toRegex(), "").trim() 555 verifyProgramRun( 556 apfFilter.mApfVersionSupported, 557 program, 558 HexDump.hexStringToByteArray(nonDhcpBcastPkt), 559 PASSED_ETHER_OUR_SRC_MAC 560 ) 561 } 562 563 @Test 564 fun testIPv4MulticastPacketFilter() { 565 val apfConfig = getDefaultConfig() 566 apfConfig.multicastFilter = true 567 val apfFilter = getApfFilter(apfConfig) 568 consumeInstalledProgram(ipClientCallback, installCnt = 2) 569 val linkAddress = LinkAddress(InetAddress.getByAddress(hostIpv4Address), 24) 570 val lp = LinkProperties() 571 lp.addLinkAddress(linkAddress) 572 apfFilter.setLinkProperties(lp) 573 val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 574 575 // Using scapy to generate DHCP4 offer packet: 576 // ether = Ether(src='00:11:22:33:44:55', dst='ff:ff:ff:ff:ff:ff') 577 // ip = IP(src='192.168.1.1', dst='255.255.255.255') 578 // udp = UDP(sport=67, dport=68) 579 // bootp = BOOTP(op=2, 580 // yiaddr='192.168.1.100', 581 // siaddr='192.168.1.1', 582 // chaddr=b'\x02\x03\x04\x05\x06\x07') 583 // dhcp_options = [('message-type', 'offer'), 584 // ('server_id', '192.168.1.1'), 585 // ('subnet_mask', '255.255.255.0'), 586 // ('router', '192.168.1.1'), 587 // ('lease_time', 86400), 588 // ('name_server', '8.8.8.8'), 589 // 'end'] 590 // dhcp = DHCP(options=dhcp_options) 591 // dhcp_offer_packet = ether/ip/udp/bootp/dhcp 592 val dhcp4Pkt = """ 593 ffffffffffff00112233445508004500012e000100004011b815c0a80101ffffffff0043 594 0044011a5ffc02010600000000000000000000000000c0a80164c0a80101000000000203 595 040506070000000000000000000000000000000000000000000000000000000000000000 596 000000000000000000000000000000000000000000000000000000000000000000000000 597 000000000000000000000000000000000000000000000000000000000000000000000000 598 000000000000000000000000000000000000000000000000000000000000000000000000 599 000000000000000000000000000000000000000000000000000000000000000000000000 600 0000000000000000000000000000000000000000000000000000638253633501023604c0 601 a801010104ffffff000304c0a80101330400015180060408080808ff 602 """.replace("\\s+".toRegex(), "").trim() 603 verifyProgramRun( 604 apfFilter.mApfVersionSupported, 605 program, 606 HexDump.hexStringToByteArray(dhcp4Pkt), 607 PASSED_DHCP 608 ) 609 610 // Using scapy to generate non DHCP multicast packet: 611 // ether = Ether(src='00:11:22:33:44:55', dst='ff:ff:ff:ff:ff:ff') 612 // ip = IP(src='192.168.1.1', dst='224.0.0.1', proto=21) 613 // pkt = ether/ip 614 val nonDhcpMcastPkt = """ 615 ffffffffffff001122334455080045000014000100004015d929c0a80101e0000001 616 """.replace("\\s+".toRegex(), "").trim() 617 verifyProgramRun( 618 apfFilter.mApfVersionSupported, 619 program, 620 HexDump.hexStringToByteArray(nonDhcpMcastPkt), 621 DROPPED_IPV4_MULTICAST 622 ) 623 624 // Using scapy to generate non DHCP broadcast packet: 625 // ether = Ether(src='00:11:22:33:44:55', dst='ff:ff:ff:ff:ff:ff') 626 // ip = IP(src='192.168.1.1', dst='255.255.255.255', proto=21) 627 // pkt = ether/ip 628 val nonDhcpBcastPkt = """ 629 ffffffffffff001122334455080045000014000100004015b92bc0a80101ffffffff 630 """.replace("\\s+".toRegex(), "").trim() 631 verifyProgramRun( 632 apfFilter.mApfVersionSupported, 633 program, 634 HexDump.hexStringToByteArray(nonDhcpBcastPkt), 635 DROPPED_IPV4_BROADCAST_ADDR 636 ) 637 638 // Using scapy to generate non DHCP subnet broadcast packet: 639 // ether = Ether(src='00:11:22:33:44:55', dst='ff:ff:ff:ff:ff:ff') 640 // ip = IP(src='192.168.1.1', dst='10.0.0.255', proto=21) 641 // pkt = ether/ip 642 val nonDhcpNetBcastPkt = """ 643 ffffffffffff001122334455080045000014000100004015ae2cc0a801010a0000ff 644 """.replace("\\s+".toRegex(), "").trim() 645 verifyProgramRun( 646 apfFilter.mApfVersionSupported, 647 program, 648 HexDump.hexStringToByteArray(nonDhcpNetBcastPkt), 649 DROPPED_IPV4_BROADCAST_NET 650 ) 651 652 // Using scapy to generate non DHCP unicast packet: 653 // ether = Ether(src='00:11:22:33:44:55', dst='02:03:04:05:06:07') 654 // ip = IP(src='192.168.1.1', dst='192.168.1.2', proto=21) 655 // pkt = ether/ip 656 val nonDhcpUcastPkt = """ 657 020304050607001122334455080045000014000100004015f780c0a80101c0a80102 658 """.replace("\\s+".toRegex(), "").trim() 659 verifyProgramRun( 660 apfFilter.mApfVersionSupported, 661 program, 662 HexDump.hexStringToByteArray(nonDhcpUcastPkt), 663 PASSED_IPV4_UNICAST 664 ) 665 666 // Using scapy to generate non DHCP unicast packet with broadcast ether destination: 667 // ether = Ether(src='00:11:22:33:44:55', dst='ff:ff:ff:ff:ff:ff') 668 // ip = IP(src='192.168.1.1', dst='192.168.1.2', proto=21) 669 // pkt = ether/ip 670 val nonDhcpUcastL2BcastPkt = """ 671 ffffffffffff001122334455080045000014000100004015f780c0a80101c0a80102 672 """.replace("\\s+".toRegex(), "").trim() 673 verifyProgramRun( 674 apfFilter.mApfVersionSupported, 675 program, 676 HexDump.hexStringToByteArray(nonDhcpUcastL2BcastPkt), 677 DROPPED_IPV4_L2_BROADCAST 678 ) 679 } 680 681 @Test 682 fun testArpFilterDropPktsOnV6OnlyNetwork() { 683 val apfFilter = getApfFilter() 684 consumeInstalledProgram(ipClientCallback, installCnt = 2) 685 apfFilter.updateClatInterfaceState(true) 686 val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 687 688 // Drop ARP request packet when clat is enabled 689 // Using scapy to generate ARP request packet: 690 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 691 // arp = ARP() 692 // pkt = eth/arp 693 val arpPkt = """ 694 010203040506000102030405080600010800060400015c857e3c74e1c0a8012200000000000000000000 695 """.replace("\\s+".toRegex(), "").trim() 696 verifyProgramRun( 697 APF_VERSION_6, 698 program, 699 HexDump.hexStringToByteArray(arpPkt), 700 DROPPED_ARP_V6_ONLY 701 ) 702 } 703 704 @Test 705 fun testIPv4TcpKeepaliveFilter() { 706 val srcAddr = byteArrayOf(10, 0, 0, 5) 707 val dstAddr = byteArrayOf(10, 0, 0, 6) 708 val srcPort = 12345 709 val dstPort = 54321 710 val seqNum = 2123456789 711 val ackNum = 1234567890 712 713 // src: 10.0.0.5:12345 714 // dst: 10.0.0.6:54321 715 val parcel = TcpKeepalivePacketDataParcelable() 716 parcel.srcAddress = InetAddress.getByAddress(srcAddr).address 717 parcel.srcPort = srcPort 718 parcel.dstAddress = InetAddress.getByAddress(dstAddr).address 719 parcel.dstPort = dstPort 720 parcel.seq = seqNum 721 parcel.ack = ackNum 722 723 val apfConfig = getDefaultConfig() 724 apfConfig.multicastFilter = true 725 apfConfig.ieee802_3Filter = true 726 val apfFilter = getApfFilter(apfConfig) 727 consumeInstalledProgram(ipClientCallback, installCnt = 2) 728 apfFilter.addTcpKeepalivePacketFilter(1, parcel) 729 var program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 730 731 // Drop IPv4 keepalive ack 732 // Using scapy to generate IPv4 TCP keepalive ack packet with seq + 1: 733 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 734 // ip = IP(src='10.0.0.6', dst='10.0.0.5') 735 // tcp = TCP(sport=54321, dport=12345, flags="A", seq=1234567890, ack=2123456790) 736 // pkt = eth/ip/tcp 737 val keepaliveAckPkt = """ 738 01020304050600010203040508004500002800010000400666c50a0000060a000005d4313039499602d2 739 7e916116501020004b4f0000 740 """.replace("\\s+".toRegex(), "").trim() 741 verifyProgramRun( 742 APF_VERSION_6, 743 program, 744 HexDump.hexStringToByteArray(keepaliveAckPkt), 745 DROPPED_IPV4_KEEPALIVE_ACK 746 ) 747 748 // Pass IPv4 non-keepalive ack from the same source address 749 // Using scapy to generate IPv4 TCP non-keepalive ack from the same source address: 750 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 751 // ip = IP(src='10.0.0.6', dst='10.0.0.5') 752 // tcp = TCP(sport=54321, dport=12345, flags="A", seq=1234567990, ack=2123456789) 753 // pkt = eth/ip/tcp 754 val nonKeepaliveAckPkt1 = """ 755 01020304050600010203040508004500002800010000400666c50a0000060a000005d431303949960336 756 7e916115501020004aec0000 757 """.replace("\\s+".toRegex(), "").trim() 758 verifyProgramRun( 759 APF_VERSION_6, 760 program, 761 HexDump.hexStringToByteArray(nonKeepaliveAckPkt1), 762 PASSED_IPV4_UNICAST 763 ) 764 765 // Pass IPv4 non-keepalive ack from the same source address 766 // Using scapy to generate IPv4 TCP non-keepalive ack from the same source address: 767 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 768 // ip = IP(src='10.0.0.6', dst='10.0.0.5') 769 // tcp = TCP(sport=54321, dport=12345, flags="A", seq=1234567890, ack=2123456790) 770 // payload = Raw(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09') 771 // pkt = eth/ip/tcp/payload 772 val nonKeepaliveAckPkt2 = """ 773 01020304050600010203040508004500003200010000400666bb0a0000060a000005d4313039499602d27 774 e91611650102000372c000000010203040506070809 775 """.replace("\\s+".toRegex(), "").trim() 776 verifyProgramRun( 777 APF_VERSION_6, 778 program, 779 HexDump.hexStringToByteArray(nonKeepaliveAckPkt2), 780 PASSED_IPV4_UNICAST 781 ) 782 783 // Pass IPv4 keepalive ack from another address 784 // Using scapy to generate IPv4 TCP keepalive ack from another address: 785 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 786 // ip = IP(src='10.0.0.7', dst='10.0.0.5') 787 // tcp = TCP(sport=23456, dport=65432, flags="A", seq=2123456780, ack=1123456789) 788 // pkt = eth/ip/tcp 789 val otherSrcKeepaliveAck = """ 790 01020304050600010203040508004500002800010000400666c40a0000070a0000055ba0ff987e91610c4 791 2f697155010200066e60000 792 """.replace("\\s+".toRegex(), "").trim() 793 verifyProgramRun( 794 APF_VERSION_6, 795 program, 796 HexDump.hexStringToByteArray(otherSrcKeepaliveAck), 797 PASSED_IPV4_UNICAST 798 ) 799 800 // test IPv4 packets when TCP keepalive filter is removed 801 apfFilter.removeKeepalivePacketFilter(1) 802 program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 803 verifyProgramRun( 804 APF_VERSION_6, 805 program, 806 HexDump.hexStringToByteArray(keepaliveAckPkt), 807 PASSED_IPV4_UNICAST 808 ) 809 810 verifyProgramRun( 811 APF_VERSION_6, 812 program, 813 HexDump.hexStringToByteArray(otherSrcKeepaliveAck), 814 PASSED_IPV4_UNICAST 815 ) 816 } 817 818 @Test 819 fun testIPv4NattKeepaliveFilter() { 820 val srcAddr = byteArrayOf(10, 0, 0, 5) 821 val dstAddr = byteArrayOf(10, 0, 0, 6) 822 val srcPort = 1024 823 val dstPort = 4500 824 825 // src: 10.0.0.5:1024 826 // dst: 10.0.0.6:4500 827 val parcel = NattKeepalivePacketDataParcelable() 828 parcel.srcAddress = InetAddress.getByAddress(srcAddr).address 829 parcel.srcPort = srcPort 830 parcel.dstAddress = InetAddress.getByAddress(dstAddr).address 831 parcel.dstPort = dstPort 832 833 val apfConfig = getDefaultConfig() 834 apfConfig.multicastFilter = true 835 apfConfig.ieee802_3Filter = true 836 val apfFilter = getApfFilter(apfConfig) 837 consumeInstalledProgram(ipClientCallback, installCnt = 2) 838 apfFilter.addNattKeepalivePacketFilter(1, parcel) 839 val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 840 841 // Drop IPv4 keepalive response packet 842 // Using scapy to generate IPv4 NAT-T keepalive ack packet with payload 0xff: 843 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 844 // ip = IP(src='10.0.0.6', dst='10.0.0.5') 845 // udp = UDP(sport=4500, dport=1024) 846 // payload = NAT_KEEPALIVE(nat_keepalive=0xff) 847 // pkt = eth/ip/udp/payload 848 val validNattPkt = """ 849 01020304050600010203040508004500001d00010000401166c50a0000060a000005119404000009d73cff 850 """.replace("\\s+".toRegex(), "").trim() 851 verifyProgramRun( 852 APF_VERSION_6, 853 program, 854 HexDump.hexStringToByteArray(validNattPkt), 855 DROPPED_IPV4_NATT_KEEPALIVE 856 ) 857 858 // Pass IPv4 keepalive response packet with 0xfe payload 859 // Using scapy to generate IPv4 NAT-T keepalive ack packet with payload 0xfe: 860 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 861 // ip = IP(src='10.0.0.6', dst='10.0.0.5') 862 // udp = UDP(sport=4500, dport=1024) 863 // payload = NAT_KEEPALIVE(nat_keepalive=0xfe) 864 // pkt = eth/ip/udp/payload 865 val invalidNattPkt = """ 866 01020304050600010203040508004500001d00010000401166c50a0000060a000005119404000009d83cfe 867 """.replace("\\s+".toRegex(), "").trim() 868 verifyProgramRun( 869 APF_VERSION_6, 870 program, 871 HexDump.hexStringToByteArray(invalidNattPkt), 872 PASSED_IPV4_UNICAST 873 ) 874 875 // Pass IPv4 non-keepalive response packet from the same source address 876 // Using scapy to generate IPv4 NAT-T keepalive ack packet with payload 0xfe: 877 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 878 // ip = IP(src='10.0.0.6', dst='10.0.0.5') 879 // udp = UDP(sport=4500, dport=1024) 880 // payload = Raw(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09') 881 // pkt = eth/ip/udp/payload 882 val nonNattPkt = """ 883 01020304050600010203040508004500002600010000401166bc0a0000060a000005119404000012c2120 884 0010203040506070809 885 """.replace("\\s+".toRegex(), "").trim() 886 verifyProgramRun( 887 APF_VERSION_6, 888 program, 889 HexDump.hexStringToByteArray(nonNattPkt), 890 PASSED_IPV4_UNICAST 891 ) 892 893 // Pass IPv4 non-keepalive response packet from other source address 894 // Using scapy to generate IPv4 NAT-T keepalive ack packet with payload 0xfe: 895 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 896 // ip = IP(src='10.0.0.7', dst='10.0.0.5') 897 // udp = UDP(sport=4500, dport=1024) 898 // payload = Raw(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09') 899 // pkt = eth/ip/udp/payload 900 val otherSrcNonNattPkt = """ 901 01020304050600010203040508004500002600010000401166bb0a0000070a000005119404000012c2110 902 0010203040506070809 903 """.replace("\\s+".toRegex(), "").trim() 904 verifyProgramRun( 905 APF_VERSION_6, 906 program, 907 HexDump.hexStringToByteArray(otherSrcNonNattPkt), 908 PASSED_IPV4_UNICAST 909 ) 910 } 911 912 @Test 913 fun testIPv4TcpPort7Filter() { 914 val apfFilter = getApfFilter() 915 val program = consumeInstalledProgram(ipClientCallback, installCnt = 2) 916 917 // Drop IPv4 TCP port 7 packet 918 // Using scapy to generate IPv4 TCP port 7 packet: 919 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 920 // ip = IP(src='10.0.0.6', dst='10.0.0.5') 921 // tcp = TCP(dport=7) 922 // pkt = eth/ip/tcp 923 val tcpPort7Pkt = """ 924 01020304050600010203040508004500002800010000400666c50a0000060a00000500140007000000000 925 0000000500220007bbd0000 926 """.replace("\\s+".toRegex(), "").trim() 927 verifyProgramRun( 928 APF_VERSION_6, 929 program, 930 HexDump.hexStringToByteArray(tcpPort7Pkt), 931 DROPPED_IPV4_TCP_PORT7_UNICAST 932 ) 933 934 // Pass IPv4 TCP initial fragment packet 935 // Using scapy to generate IPv4 TCP initial fragment packet: 936 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 937 // ip = IP(src='10.0.0.6', dst='10.0.0.5', flags=1, frag=0) 938 // tcp = TCP() 939 // pkt = eth/ip/tcp 940 val initialFragmentTcpPkt = """ 941 01020304050600010203040508004500002800012000400646c50a0000060a00000500140050000000000 942 0000000500220007b740000 943 """.replace("\\s+".toRegex(), "").trim() 944 verifyProgramRun( 945 APF_VERSION_6, 946 program, 947 HexDump.hexStringToByteArray(initialFragmentTcpPkt), 948 PASSED_IPV4 949 ) 950 951 // Pass IPv4 TCP fragment packet 952 // Using scapy to generate IPv4 TCP fragment packet: 953 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 954 // ip = IP(src='10.0.0.6', dst='10.0.0.5', flags=1, frag=100) 955 // tcp = TCP() 956 // pkt = eth/ip/tcp 957 val fragmentTcpPkt = """ 958 01020304050600010203040508004500002800012064400646610a0000060a00000500140050000000000 959 0000000500220007b740000 960 """.replace("\\s+".toRegex(), "").trim() 961 verifyProgramRun( 962 APF_VERSION_6, 963 program, 964 HexDump.hexStringToByteArray(fragmentTcpPkt), 965 PASSED_IPV4 966 ) 967 } 968 969 @Test 970 fun testIPv6MulticastPacketFilterInDozeMode() { 971 val apfConfig = getDefaultConfig() 972 apfConfig.multicastFilter = true 973 val apfFilter = getApfFilter(apfConfig) 974 consumeInstalledProgram(ipClientCallback, installCnt = 2) 975 val lp = LinkProperties() 976 for (addr in hostIpv6Addresses) { 977 lp.addLinkAddress(LinkAddress(InetAddress.getByAddress(addr), 64)) 978 } 979 apfFilter.setLinkProperties(lp) 980 apfFilter.setDozeMode(true) 981 val program = consumeInstalledProgram(ipClientCallback, installCnt = 2) 982 // Using scapy to generate non ICMPv6 sent to ff00::/8 (multicast prefix) packet: 983 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 984 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="ff00::1", nh=59) 985 // pkt = eth/ip6 986 val nonIcmpv6McastPkt = """ 987 ffffffffffff00112233445586dd6000000000003b4020010000000000000200001a11223344ff00000 988 0000000000000000000000000 989 """.replace("\\s+".toRegex(), "").trim() 990 verifyProgramRun( 991 APF_VERSION_6, 992 program, 993 HexDump.hexStringToByteArray(nonIcmpv6McastPkt), 994 DROPPED_IPV6_NON_ICMP_MULTICAST 995 ) 996 997 // Using scapy to generate ICMPv6 echo sent to ff00::/8 (multicast prefix) packet: 998 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 999 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="ff00::1", hlim=255) 1000 // icmp6 = ICMPv6EchoRequest() 1001 // pkt = eth/ip6/icmp6 1002 val icmpv6EchoPkt = """ 1003 02030405060700010203040586dd6000000000083aff20010000000000000200001a11223344ff00000 1004 000000000000000000000000180001a3a00000000 1005 """.replace("\\s+".toRegex(), "").trim() 1006 verifyProgramRun( 1007 APF_VERSION_6, 1008 program, 1009 HexDump.hexStringToByteArray(icmpv6EchoPkt), 1010 DROPPED_IPV6_NON_ICMP_MULTICAST 1011 ) 1012 } 1013 1014 @Test 1015 fun testIPv6PacketFilter() { 1016 val apfFilter = getApfFilter() 1017 consumeInstalledProgram(ipClientCallback, installCnt = 2) 1018 val lp = LinkProperties() 1019 for (addr in hostIpv6Addresses) { 1020 lp.addLinkAddress(LinkAddress(InetAddress.getByAddress(addr), 64)) 1021 } 1022 apfFilter.setLinkProperties(lp) 1023 val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 1024 // Using scapy to generate non ICMPv6 packet: 1025 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 1026 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", nh=59) 1027 // pkt = eth/ip6 1028 val nonIcmpv6Pkt = """ 1029 ffffffffffff00112233445586dd6000000000003b4020010000000000000200001a112233442001000 1030 0000000000200001a33441122 1031 """.replace("\\s+".toRegex(), "").trim() 1032 verifyProgramRun( 1033 APF_VERSION_6, 1034 program, 1035 HexDump.hexStringToByteArray(nonIcmpv6Pkt), 1036 PASSED_IPV6_NON_ICMP 1037 ) 1038 1039 // Using scapy to generate ICMPv6 NA sent to ff02::/120 packet: 1040 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 1041 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="ff02::1") 1042 // icmp6 = ICMPv6ND_NA() 1043 // pkt = eth/ip6/icmp6 1044 val icmpv6McastNaPkt = """ 1045 01020304050600010203040586dd6000000000183aff20010000000000000200001a11223344ff02000 1046 000000000000000000000000188007227a000000000000000000000000000000000000000 1047 """.replace("\\s+".toRegex(), "").trim() 1048 verifyProgramRun( 1049 APF_VERSION_6, 1050 program, 1051 HexDump.hexStringToByteArray(icmpv6McastNaPkt), 1052 DROPPED_IPV6_MULTICAST_NA 1053 ) 1054 1055 // Using scapy to generate IPv6 packet with hop-by-hop option: 1056 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 1057 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", nh=0) 1058 // pkt = eth/ip6 1059 val ipv6WithHopByHopOptionPkt = """ 1060 01020304050600010203040586dd600000000000004020010000000000000200001a112233442001000 1061 0000000000200001a33441122 1062 """.replace("\\s+".toRegex(), "").trim() 1063 verifyProgramRun( 1064 APF_VERSION_6, 1065 program, 1066 HexDump.hexStringToByteArray(ipv6WithHopByHopOptionPkt), 1067 PASSED_MLD 1068 ) 1069 } 1070 1071 @Test 1072 fun testArpFilterDropPktsNoIPv4() { 1073 val apfFilter = getApfFilter() 1074 val program = consumeInstalledProgram(ipClientCallback, installCnt = 2) 1075 1076 // Drop ARP request packet with invalid hw type 1077 // Using scapy to generate ARP request packet with invalid hw type : 1078 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 1079 // arp = ARP(hwtype=3) 1080 // pkt = eth/arp 1081 val invalidHwTypePkt = """ 1082 01020304050600010203040508060003080000040001c0a8012200000000 1083 """.replace("\\s+".toRegex(), "").trim() 1084 verifyProgramRun( 1085 APF_VERSION_6, 1086 program, 1087 HexDump.hexStringToByteArray(invalidHwTypePkt), 1088 DROPPED_ARP_NON_IPV4 1089 ) 1090 1091 // Drop ARP request packet with invalid proto type 1092 // Using scapy to generate ARP request packet with invalid proto type: 1093 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 1094 // arp = ARP(ptype=20) 1095 // pkt = eth/arp 1096 val invalidProtoTypePkt = """ 1097 010203040506000102030405080600010014060000015c857e3c74e1000000000000 1098 """.replace("\\s+".toRegex(), "").trim() 1099 verifyProgramRun( 1100 APF_VERSION_6, 1101 program, 1102 HexDump.hexStringToByteArray(invalidProtoTypePkt), 1103 DROPPED_ARP_NON_IPV4 1104 ) 1105 1106 // Drop ARP request packet with invalid hw len 1107 // Using scapy to generate ARP request packet with invalid hw len: 1108 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 1109 // arp = ARP(hwlen=20) 1110 // pkt = eth/arp 1111 val invalidHwLenPkt = """ 1112 01020304050600010203040508060001080014040001000000000000000000000000 1113 0000000000000000c0a8012200000000000000000000000000000000000000000000 1114 0000 1115 """.replace("\\s+".toRegex(), "").trim() 1116 verifyProgramRun( 1117 APF_VERSION_6, 1118 program, 1119 HexDump.hexStringToByteArray(invalidHwLenPkt), 1120 DROPPED_ARP_NON_IPV4 1121 ) 1122 1123 // Drop ARP request packet with invalid proto len 1124 // Using scapy to generate ARP request packet with invalid proto len: 1125 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 1126 // arp = ARP(plen=20) 1127 // pkt = eth/arp 1128 val invalidProtoLenPkt = """ 1129 010203040506000102030405080600010800061400015c857e3c74e1000000000000 1130 00000000000000000000000000000000000000000000000000000000000000000000 1131 000000000000 1132 """.replace("\\s+".toRegex(), "").trim() 1133 verifyProgramRun( 1134 APF_VERSION_6, 1135 program, 1136 HexDump.hexStringToByteArray(invalidProtoLenPkt), 1137 DROPPED_ARP_NON_IPV4 1138 ) 1139 1140 // Drop ARP request packet with invalid opcode 1141 // Using scapy to generate ARP request packet with invalid opcode: 1142 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 1143 // arp = ARP(op=5) 1144 // pkt = eth/arp 1145 val invalidOpPkt = """ 1146 010203040506000102030405080600010800060400055c857e3c74e1c0a8012200000000000000000000 1147 """.replace("\\s+".toRegex(), "").trim() 1148 verifyProgramRun( 1149 APF_VERSION_6, 1150 program, 1151 HexDump.hexStringToByteArray(invalidOpPkt), 1152 DROPPED_ARP_UNKNOWN 1153 ) 1154 1155 // Drop ARP reply packet with zero source protocol address 1156 // Using scapy to generate ARP request packet with zero source protocol address: 1157 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 1158 // arp = ARP(op=2, psrc="0.0.0.0) 1159 // pkt = eth/arp 1160 val noHostArpReplyPkt = """ 1161 010203040506000102030405080600010800060400025c857e3c74e10000000000000000000000000000 1162 """.replace("\\s+".toRegex(), "").trim() 1163 verifyProgramRun( 1164 APF_VERSION_6, 1165 program, 1166 HexDump.hexStringToByteArray(noHostArpReplyPkt), 1167 DROPPED_ARP_REPLY_SPA_NO_HOST 1168 ) 1169 1170 // Drop ARP reply packet with ethernet broadcast destination 1171 // Using scapy to generate ARP reply packet with ethernet broadcast destination: 1172 // eth = Ether(src="00:01:02:03:04:05", dst="FF:FF:FF:FF:FF:FF") 1173 // arp = ARP(op=2, pdst="0.0.0.0") 1174 // pkt = eth/arp 1175 val garpReplyPkt = """ 1176 ffffffffffff000102030405080600010800060400025c857e3c74e1c0a8012200000000000000000000 1177 """.replace("\\s+".toRegex(), "").trim() 1178 verifyProgramRun( 1179 APF_VERSION_6, 1180 program, 1181 HexDump.hexStringToByteArray(garpReplyPkt), 1182 DROPPED_GARP_REPLY 1183 ) 1184 } 1185 1186 @Test 1187 fun testArpFilterPassPktsNoIPv4() { 1188 val apfFilter = getApfFilter() 1189 val program = consumeInstalledProgram(ipClientCallback, installCnt = 2) 1190 // Pass non-broadcast ARP reply packet 1191 // Using scapy to generate unicast ARP reply packet: 1192 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 1193 // arp = ARP(op=2, psrc="1.2.3.4") 1194 // pkt = eth/arp 1195 val nonBcastArpReplyPkt = """ 1196 010203040506000102030405080600010800060400025c857e3c74e10102030400000000000000000000 1197 """.replace("\\s+".toRegex(), "").trim() 1198 verifyProgramRun( 1199 APF_VERSION_6, 1200 program, 1201 HexDump.hexStringToByteArray(nonBcastArpReplyPkt), 1202 PASSED_ARP_UNICAST_REPLY 1203 ) 1204 1205 // Pass ARP request packet if device doesn't have any IPv4 address 1206 // Using scapy to generate ARP request packet: 1207 // eth = Ether(src="00:01:02:03:04:05", dst="FF:FF:FF:FF:FF:FF") 1208 // arp = ARP(op=1, pdst="1.2.3.4") 1209 // pkt = eth/arp 1210 val arpRequestPkt = """ 1211 ffffffffffff000102030405080600010800060400015c857e3c74e1c0a8012200000000000001020304 1212 """.replace("\\s+".toRegex(), "").trim() 1213 verifyProgramRun( 1214 APF_VERSION_6, 1215 program, 1216 HexDump.hexStringToByteArray(arpRequestPkt), 1217 PASSED_ARP_REQUEST 1218 ) 1219 } 1220 1221 @Test 1222 fun testArpFilterDropPktsWithIPv4() { 1223 val apfFilter = getApfFilter() 1224 consumeInstalledProgram(ipClientCallback, installCnt = 2) 1225 val linkAddress = LinkAddress(InetAddress.getByAddress(hostIpv4Address), 24) 1226 val lp = LinkProperties() 1227 lp.addLinkAddress(linkAddress) 1228 apfFilter.setLinkProperties(lp) 1229 val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 1230 // Drop ARP reply packet is not for the device 1231 // Using scapy to generate ARP reply packet not for the device: 1232 // eth = Ether(src="00:01:02:03:04:05", dst="FF:FF:FF:FF:FF:FF") 1233 // arp = ARP(op=2, pdst="1.2.3.4") 1234 // pkt = eth/arp 1235 val otherHostArpReplyPkt = """ 1236 ffffffffffff000102030405080600010800060400025c857e3c74e1c0a8012200000000000001020304 1237 """.replace("\\s+".toRegex(), "").trim() 1238 verifyProgramRun( 1239 APF_VERSION_6, 1240 program, 1241 HexDump.hexStringToByteArray(otherHostArpReplyPkt), 1242 DROPPED_ARP_OTHER_HOST 1243 ) 1244 1245 // Drop broadcast ARP request packet not for the device 1246 // Using scapy to generate ARP broadcast request packet not for the device: 1247 // eth = Ether(src="00:01:02:03:04:05", dst="FF:FF:FF:FF:FF:FF") 1248 // arp = ARP(op=1, pdst="1.2.3.4") 1249 // pkt = eth/arp 1250 val otherHostArpRequestPkt = """ 1251 ffffffffffff000102030405080600010800060400015c857e3c74e1c0a8012200000000000001020304 1252 """.replace("\\s+".toRegex(), "").trim() 1253 verifyProgramRun( 1254 APF_VERSION_6, 1255 program, 1256 HexDump.hexStringToByteArray(otherHostArpRequestPkt), 1257 DROPPED_ARP_OTHER_HOST 1258 ) 1259 } 1260 1261 @Test 1262 fun testArpFilterPassPktsWithIPv4() { 1263 val apfFilter = getApfFilter() 1264 consumeInstalledProgram(ipClientCallback, installCnt = 2) 1265 val linkAddress = LinkAddress(InetAddress.getByAddress(hostIpv4Address), 24) 1266 val lp = LinkProperties() 1267 lp.addLinkAddress(linkAddress) 1268 apfFilter.setLinkProperties(lp) 1269 val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 1270 1271 // Using scapy to generate ARP broadcast reply packet: 1272 // eth = Ether(src="00:01:02:03:04:05", dst="FF:FF:FF:FF:FF:FF") 1273 // arp = ARP(op=2, pdst="10.0.0.1") 1274 // pkt = eth/arp 1275 val bcastArpReplyPkt = """ 1276 ffffffffffff000102030405080600010800060400025c857e3c74e1c0a801220000000000000a000001 1277 """.replace("\\s+".toRegex(), "").trim() 1278 verifyProgramRun( 1279 APF_VERSION_6, 1280 program, 1281 HexDump.hexStringToByteArray(bcastArpReplyPkt), 1282 PASSED_ARP_BROADCAST_REPLY 1283 ) 1284 } 1285 1286 // The APFv6 code path is only turned on in V+ 1287 @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 1288 @Test 1289 fun testArpTransmit() { 1290 val apfFilter = getApfFilter() 1291 consumeInstalledProgram(ipClientCallback, installCnt = 2) 1292 val linkAddress = LinkAddress(InetAddress.getByAddress(hostIpv4Address), 24) 1293 val lp = LinkProperties() 1294 lp.addLinkAddress(linkAddress) 1295 apfFilter.setLinkProperties(lp) 1296 val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 1297 val receivedArpPacketBuf = ArpPacket.buildArpPacket( 1298 arpBroadcastMacAddress, 1299 senderMacAddress, 1300 hostIpv4Address, 1301 HexDump.hexStringToByteArray("000000000000"), 1302 senderIpv4Address, 1303 ARP_REQUEST.toShort() 1304 ) 1305 val receivedArpPacket = ByteArray(ARP_ETHER_IPV4_LEN) 1306 receivedArpPacketBuf.get(receivedArpPacket) 1307 verifyProgramRun( 1308 apfFilter.mApfVersionSupported, 1309 program, 1310 receivedArpPacket, 1311 DROPPED_ARP_REQUEST_REPLIED 1312 ) 1313 1314 val transmittedPackets = consumeTransmittedPackets(1) 1315 val expectedArpReplyBuf = ArpPacket.buildArpPacket( 1316 senderMacAddress, 1317 apfFilter.mHardwareAddress, 1318 senderIpv4Address, 1319 senderMacAddress, 1320 hostIpv4Address, 1321 ARP_REPLY.toShort() 1322 ) 1323 val expectedArpReplyPacket = ByteArray(ARP_ETHER_IPV4_LEN) 1324 expectedArpReplyBuf.get(expectedArpReplyPacket) 1325 assertContentEquals( 1326 expectedArpReplyPacket + ByteArray(18) { 0 }, 1327 transmittedPackets[0] 1328 ) 1329 } 1330 1331 @Test 1332 fun testArpOffloadDisabled() { 1333 val apfConfig = getDefaultConfig() 1334 apfConfig.shouldHandleArpOffload = false 1335 val apfFilter = getApfFilter(apfConfig) 1336 consumeInstalledProgram(ipClientCallback, installCnt = 2) 1337 val linkAddress = LinkAddress(InetAddress.getByAddress(hostIpv4Address), 24) 1338 val lp = LinkProperties() 1339 lp.addLinkAddress(linkAddress) 1340 apfFilter.setLinkProperties(lp) 1341 val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 1342 val receivedArpPacketBuf = ArpPacket.buildArpPacket( 1343 arpBroadcastMacAddress, 1344 senderMacAddress, 1345 hostIpv4Address, 1346 HexDump.hexStringToByteArray("000000000000"), 1347 senderIpv4Address, 1348 ARP_REQUEST.toShort() 1349 ) 1350 val receivedArpPacket = ByteArray(ARP_ETHER_IPV4_LEN) 1351 receivedArpPacketBuf.get(receivedArpPacket) 1352 verifyProgramRun( 1353 apfFilter.mApfVersionSupported, 1354 program, 1355 receivedArpPacket, 1356 PASSED_ARP_REQUEST 1357 ) 1358 } 1359 1360 @Test 1361 @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 1362 fun testNsFilterNoIPv6() { 1363 doReturn(listOf<ByteArray>()).`when`(dependencies).getAnycast6Addresses(any()) 1364 val apfFilter = getApfFilter() 1365 // validate NS packet check when there is no IPv6 address 1366 val program = consumeInstalledProgram(ipClientCallback, installCnt = 2) 1367 // Using scapy to generate IPv6 NS packet: 1368 // eth = Ether(src="00:01:02:03:04:05", dst="01:02:03:04:05:06") 1369 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1370 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1371 // pkt = eth/ip6/icmp6 1372 val nsPkt = """ 1373 01020304050600010203040586DD6000000000183AFF200100000000000 1374 00200001A1122334420010000000000000200001A334411228700452900 1375 00000020010000000000000200001A33441122 1376 """.replace("\\s+".toRegex(), "").trim() 1377 // when there is no IPv6 addresses -> pass NS packet 1378 verifyProgramRun( 1379 apfFilter.mApfVersionSupported, 1380 program, 1381 HexDump.hexStringToByteArray(nsPkt), 1382 PASSED_IPV6_NS_NO_ADDRESS 1383 ) 1384 } 1385 1386 @Test 1387 @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 1388 fun testNsFilter() { 1389 val apfFilter = getApfFilter() 1390 consumeInstalledProgram(ipClientCallback, installCnt = 2) 1391 val lp = LinkProperties() 1392 for (addr in hostIpv6Addresses) { 1393 lp.addLinkAddress(LinkAddress(InetAddress.getByAddress(addr), 64)) 1394 } 1395 1396 for (addr in hostIpv6TentativeAddresses) { 1397 lp.addLinkAddress( 1398 LinkAddress( 1399 InetAddress.getByAddress(addr), 1400 64, 1401 IFA_F_TENTATIVE, 1402 0 1403 ) 1404 ) 1405 } 1406 1407 apfFilter.setLinkProperties(lp) 1408 consumeInstalledProgram(ipClientCallback, installCnt = 1) 1409 apfFilter.updateClatInterfaceState(true) 1410 val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 1411 1412 // validate Ethernet dst address check 1413 // Using scapy to generate IPv6 NS packet: 1414 // eth = Ether(src="00:01:02:03:04:05", dst="00:05:04:03:02:01") 1415 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1416 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1417 // icmp6_opt = ICMPv6NDOptDstLLAddr(lladdr="00:01:02:03:04:05") 1418 // pkt = eth/ip6/icmp6/icmp6_opt 1419 val nonHostDstMacNsPkt = """ 1420 00050403020100010203040586DD6000000000203AFF2001000000000000 1421 0200001A1122334420010000000000000200001A3344112287003D170000 1422 000020010000000000000200001A334411220201000102030405 1423 """.replace("\\s+".toRegex(), "").trim() 1424 // invalid unicast ether dst -> pass 1425 verifyProgramRun( 1426 apfFilter.mApfVersionSupported, 1427 program, 1428 HexDump.hexStringToByteArray(nonHostDstMacNsPkt), 1429 DROPPED_IPV6_NS_OTHER_HOST 1430 ) 1431 1432 // Using scapy to generate IPv6 NS packet: 1433 // eth = Ether(src="00:01:02:03:04:05", dst="33:33:ff:03:02:01") 1434 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1435 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1436 // icmp6_opt = ICMPv6NDOptDstLLAddr(lladdr="00:01:02:03:04:05") 1437 // pkt = eth/ip6/icmp6/icmp6_opt 1438 val nonMcastDstMacNsPkt = """ 1439 3333FF03020100010203040586DD6000000000203AFF20010000000000 1440 000200001A1122334420010000000000000200001A3344112287003D17 1441 0000000020010000000000000200001A334411220201000102030405 1442 """.replace("\\s+".toRegex(), "").trim() 1443 // mcast dst mac is not one of solicited mcast mac derived from one of device's ip -> pass 1444 verifyProgramRun( 1445 apfFilter.mApfVersionSupported, 1446 program, 1447 HexDump.hexStringToByteArray(nonMcastDstMacNsPkt), 1448 DROPPED_IPV6_NS_OTHER_HOST 1449 ) 1450 1451 // Using scapy to generate IPv6 NS packet: 1452 // eth = Ether(src="00:01:02:03:04:05", dst="33:33:ff:44:11:22") 1453 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1454 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1455 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="00:01:02:03:04:05") 1456 // pkt = eth/ip6/icmp6/icmp6_opt 1457 val hostMcastDstMacNsPkt = """ 1458 3333FF44112200010203040586DD6000000000203AFF20010000000000 1459 000200001A1122334420010000000000000200001A3344112287003E17 1460 0000000020010000000000000200001A334411220101000102030405 1461 """.replace("\\s+".toRegex(), "").trim() 1462 // mcast dst mac is one of solicited mcast mac derived from one of device's ip 1463 // -> drop and replied 1464 verifyProgramRun( 1465 apfFilter.mApfVersionSupported, 1466 program, 1467 HexDump.hexStringToByteArray(hostMcastDstMacNsPkt), 1468 DROPPED_IPV6_NS_REPLIED_NON_DAD 1469 ) 1470 1471 // Using scapy to generate IPv6 NS packet: 1472 // eth = Ether(src="00:01:02:03:04:05", dst="FF:FF:FF:FF:FF:FF") 1473 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1474 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1475 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="00:01:02:03:04:05") 1476 // pkt = eth/ip6/icmp6/icmp6_opt 1477 val broadcastNsPkt = """ 1478 FFFFFFFFFFFF00010203040586DD6000000000203AFF200100000000000002000 1479 01A1122334420010000000000000200001A3344112287003E1700000000200100 1480 00000000000200001A334411220101000102030405 1481 """.replace("\\s+".toRegex(), "").trim() 1482 // mcast dst mac is broadcast address -> drop and replied 1483 verifyProgramRun( 1484 apfFilter.mApfVersionSupported, 1485 program, 1486 HexDump.hexStringToByteArray(broadcastNsPkt), 1487 DROPPED_IPV6_NS_REPLIED_NON_DAD 1488 ) 1489 1490 // validate IPv6 dst address check 1491 1492 // Using scapy to generate IPv6 NS packet: 1493 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1494 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1495 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1496 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="00:01:02:03:04:05") 1497 // pkt = eth/ip6/icmp6/icmp6_opt 1498 val validHostDstIpNsPkt = """ 1499 02030405060700010203040586DD6000000000203AFF200100000000000 1500 00200001A1122334420010000000000000200001A3344112287003E1700 1501 00000020010000000000000200001A334411220101000102030405 1502 """.replace("\\s+".toRegex(), "").trim() 1503 // dst ip is one of device's ip -> drop and replied 1504 verifyProgramRun( 1505 apfFilter.mApfVersionSupported, 1506 program, 1507 HexDump.hexStringToByteArray(validHostDstIpNsPkt), 1508 DROPPED_IPV6_NS_REPLIED_NON_DAD 1509 ) 1510 1511 // Using scapy to generate IPv6 NS packet: 1512 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1513 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::100:1b:aabb:ccdd", hlim=255) 1514 // icmp6 = ICMPv6ND_NS(tgt="2001::100:1b:aabb:ccdd") 1515 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="00:01:02:03:04:05") 1516 // pkt = eth/ip6/icmp6/icmp6_opt 1517 val validHostAnycastDstIpNsPkt = """ 1518 02030405060700010203040586DD6000000000203AFF20010000 1519 000000000200001A1122334420010000000000000100001BAABB 1520 CCDD8700D9AE0000000020010000000000000100001BAABBCCDD 1521 0101000102030405 1522 """.replace("\\s+".toRegex(), "").trim() 1523 // dst ip is device's anycast address -> drop and replied 1524 verifyProgramRun( 1525 apfFilter.mApfVersionSupported, 1526 program, 1527 HexDump.hexStringToByteArray(validHostAnycastDstIpNsPkt), 1528 DROPPED_IPV6_NS_REPLIED_NON_DAD 1529 ) 1530 1531 // Using scapy to generate IPv6 NS packet: 1532 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1533 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:4444:5555", hlim=255) 1534 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1535 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="00:01:02:03:04:05") 1536 // pkt = eth/ip6/icmp6/icmp6_opt 1537 val nonHostUcastDstIpNsPkt = """ 1538 02030405060700010203040586DD6000000000203AFF2001000000000 1539 0000200001A1122334420010000000000000200001A444455558700E8 1540 E30000000020010000000000000200001A334411220101000102030405 1541 """.replace("\\s+".toRegex(), "").trim() 1542 // unicast dst ip is not one of device's ip -> pass 1543 verifyProgramRun( 1544 apfFilter.mApfVersionSupported, 1545 program, 1546 HexDump.hexStringToByteArray(nonHostUcastDstIpNsPkt), 1547 DROPPED_IPV6_NS_OTHER_HOST 1548 ) 1549 1550 // Using scapy to generate IPv6 NS packet: 1551 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1552 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="ff02::1:ff44:1133", hlim=255) 1553 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1554 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="00:01:02:03:04:05") 1555 // pkt = eth/ip6/icmp6/icmp6_opt 1556 val nonHostMcastDstIpNsPkt = """ 1557 02030405060700010203040586DD6000000000203AFF2001000000000 1558 0000200001A11223344FF0200000000000000000001FF441133870095 1559 1C0000000020010000000000000200001A334411220101000102030405 1560 """.replace("\\s+".toRegex(), "").trim() 1561 // mcast dst ip is not one of solicited mcast ip derived from one of device's ip -> pass 1562 verifyProgramRun( 1563 apfFilter.mApfVersionSupported, 1564 program, 1565 HexDump.hexStringToByteArray(nonHostMcastDstIpNsPkt), 1566 DROPPED_IPV6_NS_OTHER_HOST 1567 ) 1568 1569 // Using scapy to generate IPv6 NS packet: 1570 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1571 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="ff02::1:ff44:1122", hlim=255) 1572 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1573 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="00:01:02:03:04:05") 1574 // pkt = eth/ip6/icmp6/icmp6_opt 1575 val hostMcastDstIpNsPkt = 1576 "02030405060700010203040586DD6000000000203AFF2001000000000000" + 1577 "0200001A11223344FF0200000000000000000001FF4411228700952D0000" + 1578 "000020010000000000000200001A334411220101000102030405" 1579 // mcast dst ip is one of solicited mcast ip derived from one of device's ip 1580 // -> drop and replied 1581 verifyProgramRun( 1582 apfFilter.mApfVersionSupported, 1583 program, 1584 HexDump.hexStringToByteArray(hostMcastDstIpNsPkt), 1585 DROPPED_IPV6_NS_REPLIED_NON_DAD 1586 ) 1587 1588 // validate IPv6 NS payload check 1589 1590 // Using scapy to generate IPv6 NS packet: 1591 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1592 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255, plen=20) 1593 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1594 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="01:02:03:04:05:06") 1595 // pkt = eth/ip6/icmp6/icmp6_opt 1596 val shortNsPkt = """ 1597 02030405060700010203040586DD6000000000143AFF20010000000000000200001A1 1598 122334420010000000000000200001A3344112287003B140000000020010000000000 1599 000200001A334411220101010203040506 1600 """.replace("\\s+".toRegex(), "").trim() 1601 // payload len < 24 -> drop 1602 verifyProgramRun( 1603 apfFilter.mApfVersionSupported, 1604 program, 1605 HexDump.hexStringToByteArray(shortNsPkt), 1606 DROPPED_IPV6_NS_INVALID 1607 ) 1608 1609 // Using scapy to generate IPv6 NS packet: 1610 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1611 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1612 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:4444:5555") 1613 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="01:02:03:04:05:06") 1614 // pkt = eth/ip6/icmp6/icmp6_opt 1615 val otherHostNsPkt = """ 1616 02030405060700010203040586DD6000000000203AFF200100000000000002000 1617 01A1122334420010000000000000200001A334411228700E5E000000000200100 1618 00000000000200001A444455550101010203040506 1619 """.replace("\\s+".toRegex(), "").trim() 1620 // target ip is not one of device's ip -> drop 1621 verifyProgramRun( 1622 apfFilter.mApfVersionSupported, 1623 program, 1624 HexDump.hexStringToByteArray(otherHostNsPkt), 1625 DROPPED_IPV6_NS_OTHER_HOST 1626 ) 1627 1628 // Using scapy to generate IPv6 NS packet: 1629 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1630 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=20) 1631 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1632 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="01:02:03:04:05:06") 1633 // pkt = eth/ip6/icmp6/icmp6_opt 1634 val invalidHoplimitNsPkt = """ 1635 02030405060700010203040586DD6000000000203A14200100000000000 1636 00200001A1122334420010000000000000200001A3344112287003B1400 1637 00000020010000000000000200001A334411220101010203040506 1638 """.replace("\\s+".toRegex(), "").trim() 1639 // hoplimit is not 255 -> drop 1640 verifyProgramRun( 1641 apfFilter.mApfVersionSupported, 1642 program, 1643 HexDump.hexStringToByteArray(invalidHoplimitNsPkt), 1644 DROPPED_IPV6_NS_INVALID 1645 ) 1646 1647 // Using scapy to generate IPv6 NS packet: 1648 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1649 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1650 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122", code=5) 1651 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="01:02:03:04:05:06") 1652 // pkt = eth/ip6/icmp6/icmp6_opt 1653 val invalidIcmpCodeNsPkt = """ 1654 02030405060700010203040586DD6000000000203AFF200100000000000 1655 00200001A1122334420010000000000000200001A3344112287053B0F00 1656 00000020010000000000000200001A334411220101010203040506 1657 """.replace("\\s+".toRegex(), "").trim() 1658 // icmp6 code is not 0 -> drop 1659 verifyProgramRun( 1660 apfFilter.mApfVersionSupported, 1661 program, 1662 HexDump.hexStringToByteArray(invalidIcmpCodeNsPkt), 1663 DROPPED_IPV6_NS_INVALID 1664 ) 1665 1666 // Using scapy to generate IPv6 NS packet: 1667 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1668 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1669 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:1234:5678") 1670 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="01:02:03:04:05:06") 1671 // pkt = eth/ip6/icmp6/icmp6_opt 1672 val tentativeTargetIpNsPkt = """ 1673 02030405060700010203040586DD6000000000203AFF200100000000 1674 00000200001A1122334420010000000000000200001A334411228700 1675 16CE0000000020010000000000000200001A123456780101010203040506 1676 """.replace("\\s+".toRegex(), "").trim() 1677 // target ip is one of tentative address -> pass 1678 verifyProgramRun( 1679 apfFilter.mApfVersionSupported, 1680 program, 1681 HexDump.hexStringToByteArray(tentativeTargetIpNsPkt), 1682 PASSED_IPV6_NS_TENTATIVE 1683 ) 1684 1685 // Using scapy to generate IPv6 NS packet: 1686 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1687 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1688 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1c:2255:6666") 1689 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="01:02:03:04:05:06") 1690 // pkt = eth/ip6/icmp6/icmp6_opt 1691 val invalidTargetIpNsPkt = """ 1692 02030405060700010203040586DD6000000000203AFF200100000000000 1693 00200001A1122334420010000000000000200001A334411228700F6BC00 1694 00000020010000000000000200001C225566660101010203040506 1695 """.replace("\\s+".toRegex(), "").trim() 1696 // target ip is none of {non-tentative, anycast} -> drop 1697 verifyProgramRun( 1698 apfFilter.mApfVersionSupported, 1699 program, 1700 HexDump.hexStringToByteArray(invalidTargetIpNsPkt), 1701 DROPPED_IPV6_NS_OTHER_HOST 1702 ) 1703 1704 // Using scapy to generate IPv6 NS packet: 1705 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1706 // ip6 = IPv6(src="::", dst="ff02::1:ff44:1122", hlim=255) 1707 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1708 // icmp6_opt = ICMPv6NDOptDstLLAddr(lladdr="02:03:04:05:06:07") 1709 // pkt = eth/ip6/icmp6/icmp6_opt 1710 val dadNsPkt = """ 1711 02030405060700010203040586DD6000000000203AFF000000000000000000000000000 1712 00000FF0200000000000000000001FF4411228700F4A800000000200100000000000002 1713 00001A334411220201020304050607 1714 """.replace("\\s+".toRegex(), "").trim() 1715 // DAD NS request -> pass 1716 verifyProgramRun( 1717 apfFilter.mApfVersionSupported, 1718 program, 1719 HexDump.hexStringToByteArray(dadNsPkt), 1720 PASSED_IPV6_NS_DAD 1721 ) 1722 1723 // Using scapy to generate IPv6 NS packet: 1724 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1725 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1726 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1727 // pkt = eth/ip6/icmp6 1728 val noOptionNsPkt = """ 1729 02030405060700010203040586DD6000000000183AFF2001000000000000020000 1730 1A1122334420010000000000000200001A33441122870045290000000020010000 1731 000000000200001A33441122 1732 """.replace("\\s+".toRegex(), "").trim() 1733 // payload len < 32 -> pass 1734 verifyProgramRun( 1735 apfFilter.mApfVersionSupported, 1736 program, 1737 HexDump.hexStringToByteArray(noOptionNsPkt), 1738 PASSED_IPV6_NS_NO_SLLA_OPTION 1739 ) 1740 1741 // Using scapy to generate IPv6 NS packet: 1742 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1743 // ip6 = IPv6(src="ff01::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1744 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1745 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="01:02:03:04:05:06") 1746 // pkt = eth/ip6/icmp6/icmp6_opt 1747 val nonDadMcastSrcIpPkt = """ 1748 02030405060700010203040586DD6000000000203AFFFF01000000000000 1749 0200001A1122334420010000000000000200001A3344112287005C130000 1750 000020010000000000000200001A334411220101010203040506 1751 """.replace("\\s+".toRegex(), "").trim() 1752 // non-DAD src IPv6 is FF::/8 -> drop 1753 verifyProgramRun( 1754 apfFilter.mApfVersionSupported, 1755 program, 1756 HexDump.hexStringToByteArray(nonDadMcastSrcIpPkt), 1757 DROPPED_IPV6_NS_INVALID 1758 ) 1759 1760 // Using scapy to generate IPv6 NS packet: 1761 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1762 // ip6 = IPv6(src="0001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1763 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1764 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="01:02:03:04:05:06") 1765 // pkt = eth/ip6/icmp6/icmp6_opt 1766 val nonDadLoopbackSrcIpPkt = """ 1767 02030405060700010203040586DD6000000000203AFF0001000000000 1768 0000200001A1122334420010000000000000200001A3344112287005B 1769 140000000020010000000000000200001A334411220101010203040506 1770 """.replace("\\s+".toRegex(), "").trim() 1771 // non-DAD src IPv6 is 00::/8 -> drop 1772 verifyProgramRun( 1773 apfFilter.mApfVersionSupported, 1774 program, 1775 HexDump.hexStringToByteArray(nonDadLoopbackSrcIpPkt), 1776 DROPPED_IPV6_NS_INVALID 1777 ) 1778 1779 // Using scapy to generate IPv6 NS packet: 1780 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1781 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1782 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1783 // icmp6_opt1 = ICMPv6NDOptDstLLAddr(lladdr="01:02:03:04:05:06") 1784 // icmp6_opt2 = ICMPv6NDOptSrcLLAddr(lladdr="01:02:03:04:05:06") 1785 // pkt = eth/ip6/icmp6/icmp6_opt1/icmp6_opt2 1786 val sllaNotFirstOptionNsPkt = """ 1787 02030405060700010203040586DD6000000000283AFF200100000000 1788 00000200001A1122334420010000000000000200001A334411228700 1789 2FFF0000000020010000000000000200001A33441122020101020304 1790 05060101010203040506 1791 """.replace("\\s+".toRegex(), "").trim() 1792 // non-DAD with multiple options, SLLA in 2nd option -> pass 1793 verifyProgramRun( 1794 apfFilter.mApfVersionSupported, 1795 program, 1796 HexDump.hexStringToByteArray(sllaNotFirstOptionNsPkt), 1797 PASSED_IPV6_NS_NO_SLLA_OPTION 1798 ) 1799 1800 // Using scapy to generate IPv6 NS packet: 1801 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1802 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1803 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1804 // icmp6_opt = ICMPv6NDOptDstLLAddr(lladdr="01:02:03:04:05:06") 1805 // pkt = eth/ip6/icmp6/icmp6_opt 1806 val noSllaOptionNsPkt = """ 1807 02030405060700010203040586DD6000000000203AFF200100000000000002 1808 00001A1122334420010000000000000200001A3344112287003A1400000000 1809 20010000000000000200001A334411220201010203040506 1810 """.replace("\\s+".toRegex(), "").trim() 1811 // non-DAD with one option but not SLLA -> pass 1812 verifyProgramRun( 1813 apfFilter.mApfVersionSupported, 1814 program, 1815 HexDump.hexStringToByteArray(noSllaOptionNsPkt), 1816 PASSED_IPV6_NS_NO_SLLA_OPTION 1817 ) 1818 1819 // Using scapy to generate IPv6 NS packet: 1820 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1821 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="2001::200:1a:3344:1122", hlim=255) 1822 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1823 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="01:02:03:04:05:06") 1824 // pkt = eth/ip6/icmp6/icmp6_opt 1825 val mcastMacSllaOptionNsPkt = """ 1826 02030405060700010203040586DD6000000000203AFF200100000000 1827 00000200001A1122334420010000000000000200001A334411228700 1828 3B140000000020010000000000000200001A33441122010101020304 1829 0506 1830 """.replace("\\s+".toRegex(), "").trim() 1831 // non-DAD, SLLA is multicast MAC -> drop 1832 verifyProgramRun( 1833 apfFilter.mApfVersionSupported, 1834 program, 1835 HexDump.hexStringToByteArray(mcastMacSllaOptionNsPkt), 1836 DROPPED_IPV6_NS_INVALID 1837 ) 1838 } 1839 1840 // The APFv6 code path is only turned on in V+ 1841 @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 1842 @Test 1843 fun testNaTransmit() { 1844 val apfFilter = getApfFilter() 1845 val lp = LinkProperties() 1846 for (addr in hostIpv6Addresses) { 1847 lp.addLinkAddress(LinkAddress(InetAddress.getByAddress(addr), 64)) 1848 } 1849 1850 apfFilter.setLinkProperties(lp) 1851 val program = consumeInstalledProgram(ipClientCallback, installCnt = 3) 1852 val validIpv6Addresses = hostIpv6Addresses + hostAnycast6Addresses 1853 val expectPackets = mutableListOf<ByteArray>() 1854 for (addr in validIpv6Addresses) { 1855 // unicast solicited NS request 1856 val receivedUcastNsPacket = generateNsPacket( 1857 senderMacAddress, 1858 apfFilter.mHardwareAddress, 1859 senderIpv6Address, 1860 addr, 1861 addr 1862 ) 1863 1864 verifyProgramRun( 1865 apfFilter.mApfVersionSupported, 1866 program, 1867 receivedUcastNsPacket, 1868 DROPPED_IPV6_NS_REPLIED_NON_DAD 1869 ) 1870 1871 val expectedUcastNaPacket = generateNaPacket( 1872 apfFilter.mHardwareAddress, 1873 senderMacAddress, 1874 addr, 1875 senderIpv6Address, 1876 0xe0000000.toInt(), // R=1, S=1, O=1 1877 addr 1878 ) 1879 expectPackets.add(expectedUcastNaPacket) 1880 1881 val solicitedMcastAddr = NetworkStackUtils.ipv6AddressToSolicitedNodeMulticast( 1882 InetAddress.getByAddress(addr) as Inet6Address 1883 )!! 1884 val mcastDa = NetworkStackUtils.ipv6MulticastToEthernetMulticast(solicitedMcastAddr) 1885 .toByteArray() 1886 1887 // multicast solicited NS request 1888 var receivedMcastNsPacket = generateNsPacket( 1889 senderMacAddress, 1890 mcastDa, 1891 senderIpv6Address, 1892 solicitedMcastAddr.address, 1893 addr 1894 ) 1895 1896 verifyProgramRun( 1897 apfFilter.mApfVersionSupported, 1898 program, 1899 receivedMcastNsPacket, 1900 DROPPED_IPV6_NS_REPLIED_NON_DAD 1901 ) 1902 1903 val expectedMcastNaPacket = generateNaPacket( 1904 apfFilter.mHardwareAddress, 1905 senderMacAddress, 1906 addr, 1907 senderIpv6Address, 1908 0xe0000000.toInt(), // R=1, S=1, O=1 1909 addr 1910 ) 1911 expectPackets.add(expectedMcastNaPacket) 1912 } 1913 1914 val transmitPackets = consumeTransmittedPackets(expectPackets.size) 1915 for (i in transmitPackets.indices) { 1916 assertContentEquals(expectPackets[i], transmitPackets[i]) 1917 } 1918 } 1919 1920 // The APFv6 code path is only turned on in V+ 1921 @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 1922 @Test 1923 fun testNaTransmitWithTclass() { 1924 // mock nd traffic class from /proc/sys/net/ipv6/conf/{ifname}/ndisc_tclass to 20 1925 doReturn(20).`when`(dependencies).getNdTrafficClass(any()) 1926 val apfFilter = getApfFilter() 1927 val lp = LinkProperties() 1928 for (addr in hostIpv6Addresses) { 1929 lp.addLinkAddress(LinkAddress(InetAddress.getByAddress(addr), 64)) 1930 } 1931 apfFilter.setLinkProperties(lp) 1932 val program = consumeInstalledProgram(ipClientCallback, installCnt = 3) 1933 // Using scapy to generate IPv6 NS packet: 1934 // eth = Ether(src="00:01:02:03:04:05", dst="02:03:04:05:06:07") 1935 // ip6 = IPv6(src="2001::200:1a:1122:3344", dst="ff02::1:ff44:1122", hlim=255, tc=20) 1936 // icmp6 = ICMPv6ND_NS(tgt="2001::200:1a:3344:1122") 1937 // icmp6_opt = ICMPv6NDOptSrcLLAddr(lladdr="00:01:02:03:04:05") 1938 // pkt = eth/ip6/icmp6/icmp6_opt 1939 val hostMcastDstIpNsPkt = """ 1940 02030405060700010203040586DD6140000000203AFF2001000000000000 1941 0200001A11223344FF0200000000000000000001FF4411228700952D0000 1942 000020010000000000000200001A334411220101000102030405 1943 """.replace("\\s+".toRegex(), "").trim() 1944 verifyProgramRun( 1945 apfFilter.mApfVersionSupported, 1946 program, 1947 HexDump.hexStringToByteArray(hostMcastDstIpNsPkt), 1948 DROPPED_IPV6_NS_REPLIED_NON_DAD 1949 ) 1950 1951 val transmitPkts = consumeTransmittedPackets(1) 1952 // Using scapy to generate IPv6 NA packet: 1953 // eth = Ether(src="02:03:04:05:06:07", dst="00:01:02:03:04:05") 1954 // ip6 = IPv6(src="2001::200:1a:3344:1122", dst="2001::200:1a:1122:3344", hlim=255, tc=20) 1955 // icmp6 = ICMPv6ND_NA(tgt="2001::200:1a:3344:1122", R=1, S=1, O=1) 1956 // icmp6_opt = ICMPv6NDOptDstLLAddr(lladdr="02:03:04:05:06:07") 1957 // pkt = eth/ip6/icmp6/icmp6_opt 1958 val expectedNaPacket = """ 1959 00010203040502030405060786DD6140000000203AFF2001000000000000020 1960 0001A3344112220010000000000000200001A1122334488005610E000000020 1961 010000000000000200001A334411220201020304050607 1962 """.replace("\\s+".toRegex(), "").trim() 1963 assertContentEquals( 1964 HexDump.hexStringToByteArray(expectedNaPacket), 1965 transmitPkts[0] 1966 ) 1967 } 1968 1969 @Test 1970 fun testNdOffloadDisabled() { 1971 val apfConfig = getDefaultConfig() 1972 apfConfig.shouldHandleNdOffload = false 1973 val apfFilter = getApfFilter(apfConfig) 1974 val lp = LinkProperties() 1975 for (addr in hostIpv6Addresses) { 1976 lp.addLinkAddress(LinkAddress(InetAddress.getByAddress(addr), 64)) 1977 } 1978 1979 apfFilter.setLinkProperties(lp) 1980 val program = consumeInstalledProgram(ipClientCallback, installCnt = 3) 1981 val validIpv6Addresses = hostIpv6Addresses + hostAnycast6Addresses 1982 for (addr in validIpv6Addresses) { 1983 // unicast solicited NS request 1984 val receivedUcastNsPacket = generateNsPacket( 1985 senderMacAddress, 1986 apfFilter.mHardwareAddress, 1987 senderIpv6Address, 1988 addr, 1989 addr 1990 ) 1991 1992 verifyProgramRun( 1993 apfFilter.mApfVersionSupported, 1994 program, 1995 receivedUcastNsPacket, 1996 PASSED_IPV6_ICMP 1997 ) 1998 1999 val solicitedMcastAddr = NetworkStackUtils.ipv6AddressToSolicitedNodeMulticast( 2000 InetAddress.getByAddress(addr) as Inet6Address 2001 )!! 2002 val mcastDa = NetworkStackUtils.ipv6MulticastToEthernetMulticast(solicitedMcastAddr) 2003 .toByteArray() 2004 2005 // multicast solicited NS request 2006 var receivedMcastNsPacket = generateNsPacket( 2007 senderMacAddress, 2008 mcastDa, 2009 senderIpv6Address, 2010 solicitedMcastAddr.address, 2011 addr 2012 ) 2013 2014 verifyProgramRun( 2015 apfFilter.mApfVersionSupported, 2016 program, 2017 receivedMcastNsPacket, 2018 PASSED_IPV6_ICMP 2019 ) 2020 } 2021 } 2022 2023 @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 2024 @Test 2025 fun testRegisterOffloadEngine() { 2026 val apfConfig = getDefaultConfig() 2027 apfConfig.shouldHandleMdnsOffload = true 2028 val apfFilter = getApfFilter(apfConfig) 2029 val captor = ArgumentCaptor.forClass(OffloadEngine::class.java) 2030 verify(nsdManager).registerOffloadEngine( 2031 eq(ifParams.name), 2032 anyLong(), 2033 anyLong(), 2034 any(), 2035 captor.capture() 2036 ) 2037 val offloadEngine = captor.value 2038 val info1 = OffloadServiceInfo( 2039 OffloadServiceInfo.Key("TestServiceName", "_advertisertest._tcp"), 2040 listOf(), 2041 "Android_test.local", 2042 byteArrayOf(0x01, 0x02, 0x03, 0x04), 2043 0, 2044 OffloadEngine.OFFLOAD_TYPE_REPLY.toLong() 2045 ) 2046 val info2 = OffloadServiceInfo( 2047 OffloadServiceInfo.Key("TestServiceName2", "_advertisertest._tcp"), 2048 listOf(), 2049 "Android_test.local", 2050 byteArrayOf(0x01, 0x02, 0x03, 0x04), 2051 0, 2052 OffloadEngine.OFFLOAD_TYPE_REPLY.toLong() 2053 ) 2054 val updatedInfo1 = OffloadServiceInfo( 2055 OffloadServiceInfo.Key("TestServiceName", "_advertisertest._tcp"), 2056 listOf(), 2057 "Android_test.local", 2058 byteArrayOf(), 2059 0, 2060 OffloadEngine.OFFLOAD_TYPE_REPLY.toLong() 2061 ) 2062 handler.post { offloadEngine.onOffloadServiceUpdated(info1) } 2063 handlerThread.waitForIdle(TIMEOUT_MS) 2064 assertContentEquals(listOf(info1), apfFilter.mOffloadServiceInfos) 2065 handler.post { offloadEngine.onOffloadServiceUpdated(info2) } 2066 handlerThread.waitForIdle(TIMEOUT_MS) 2067 assertContentEquals(listOf(info1, info2), apfFilter.mOffloadServiceInfos) 2068 handler.post { offloadEngine.onOffloadServiceUpdated(updatedInfo1) } 2069 handlerThread.waitForIdle(TIMEOUT_MS) 2070 assertContentEquals(listOf(info2, updatedInfo1), apfFilter.mOffloadServiceInfos) 2071 handler.post { offloadEngine.onOffloadServiceRemoved(updatedInfo1) } 2072 handlerThread.waitForIdle(TIMEOUT_MS) 2073 assertContentEquals(listOf(info2), apfFilter.mOffloadServiceInfos) 2074 2075 handler.post { apfFilter.shutdown() } 2076 handlerThread.waitForIdle(TIMEOUT_MS) 2077 verify(nsdManager).unregisterOffloadEngine(any()) 2078 } 2079 2080 @Test 2081 fun testApfProgramUpdate() { 2082 val apfFilter = getApfFilter() 2083 consumeInstalledProgram(ipClientCallback, installCnt = 2) 2084 // add IPv4 address, expect to have apf program update 2085 val lp = LinkProperties() 2086 val linkAddress = LinkAddress(InetAddress.getByAddress(hostIpv4Address), 24) 2087 lp.addLinkAddress(linkAddress) 2088 apfFilter.setLinkProperties(lp) 2089 consumeInstalledProgram(ipClientCallback, installCnt = 1) 2090 2091 // add the same IPv4 address, expect to have no apf program update 2092 apfFilter.setLinkProperties(lp) 2093 verify(ipClientCallback, never()).installPacketFilter(any()) 2094 2095 // add IPv6 addresses, expect to have apf program update 2096 for (addr in hostIpv6Addresses) { 2097 lp.addLinkAddress(LinkAddress(InetAddress.getByAddress(addr), 64)) 2098 } 2099 2100 apfFilter.setLinkProperties(lp) 2101 consumeInstalledProgram(ipClientCallback, installCnt = 1) 2102 2103 // add the same IPv6 addresses, expect to have no apf program update 2104 apfFilter.setLinkProperties(lp) 2105 verify(ipClientCallback, never()).installPacketFilter(any()) 2106 2107 // add more tentative IPv6 addresses, expect to have apf program update 2108 for (addr in hostIpv6TentativeAddresses) { 2109 lp.addLinkAddress( 2110 LinkAddress( 2111 InetAddress.getByAddress(addr), 2112 64, 2113 IFA_F_TENTATIVE, 2114 0 2115 ) 2116 ) 2117 } 2118 2119 apfFilter.setLinkProperties(lp) 2120 consumeInstalledProgram(ipClientCallback, installCnt = 1) 2121 2122 // add the same IPv6 addresses, expect to have no apf program update 2123 apfFilter.setLinkProperties(lp) 2124 verify(ipClientCallback, never()).installPacketFilter(any()) 2125 } 2126 2127 @Test 2128 fun testApfFilterInitializationCleanUpTheApfMemoryRegion() { 2129 val apfFilter = getApfFilter() 2130 val programCaptor = ArgumentCaptor.forClass(ByteArray::class.java) 2131 verify(ipClientCallback, times(2)).installPacketFilter(programCaptor.capture()) 2132 val program = programCaptor.allValues.first() 2133 assertContentEquals(ByteArray(4096) { 0 }, program) 2134 } 2135 2136 @Test 2137 fun testApfFilterResumeWillCleanUpTheApfMemoryRegion() { 2138 val apfFilter = getApfFilter() 2139 consumeInstalledProgram(ipClientCallback, installCnt = 2) 2140 apfFilter.resume() 2141 val program = consumeInstalledProgram(ipClientCallback, installCnt = 1) 2142 assertContentEquals(ByteArray(4096) { 0 }, program) 2143 } 2144 2145 @Test 2146 fun testApfIPv4MulticastAddrsUpdate() { 2147 val apfFilter = getApfFilter() 2148 // mock IPv4 multicast address from /proc/net/igmp 2149 val mcastAddrs = mutableListOf( 2150 InetAddress.getByName("224.0.0.1") as Inet4Address 2151 ) 2152 consumeInstalledProgram(ipClientCallback, installCnt = 2) 2153 2154 doReturn(mcastAddrs).`when`(dependencies).getIPv4MulticastAddresses(any()) 2155 apfFilter.updateIPv4MulticastAddrs() 2156 consumeInstalledProgram(ipClientCallback, installCnt = 1) 2157 assertEquals(mcastAddrs.toSet(), apfFilter.mIPv4MulticastAddresses) 2158 2159 val addr = InetAddress.getByName("239.0.0.1") as Inet4Address 2160 mcastAddrs.add(addr) 2161 doReturn(mcastAddrs).`when`(dependencies).getIPv4MulticastAddresses(any()) 2162 apfFilter.updateIPv4MulticastAddrs() 2163 consumeInstalledProgram(ipClientCallback, installCnt = 1) 2164 assertEquals(mcastAddrs.toSet(), apfFilter.mIPv4MulticastAddresses) 2165 2166 apfFilter.updateIPv4MulticastAddrs() 2167 verify(ipClientCallback, never()).installPacketFilter(any()) 2168 } 2169 } 2170