1 /* 2 * Copyright (C) 2012 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 17 package android.net.apf; 18 19 import static android.net.apf.ApfGenerator.Register.R0; 20 import static android.net.apf.ApfGenerator.Register.R1; 21 import static android.system.OsConstants.AF_UNIX; 22 import static android.system.OsConstants.ARPHRD_ETHER; 23 import static android.system.OsConstants.ETH_P_ARP; 24 import static android.system.OsConstants.ETH_P_IP; 25 import static android.system.OsConstants.ETH_P_IPV6; 26 import static android.system.OsConstants.IPPROTO_ICMPV6; 27 import static android.system.OsConstants.IPPROTO_IPV6; 28 import static android.system.OsConstants.IPPROTO_TCP; 29 import static android.system.OsConstants.IPPROTO_UDP; 30 import static android.system.OsConstants.SOCK_STREAM; 31 32 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE; 33 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN; 34 import static com.android.networkstack.util.NetworkStackUtils.APF_USE_RA_LIFETIME_CALCULATION_FIX_VERSION; 35 36 import static org.junit.Assert.assertEquals; 37 import static org.junit.Assert.assertFalse; 38 import static org.junit.Assert.assertTrue; 39 import static org.junit.Assert.fail; 40 import static org.mockito.Mockito.anyBoolean; 41 import static org.mockito.Mockito.atLeastOnce; 42 import static org.mockito.Mockito.eq; 43 import static org.mockito.Mockito.mock; 44 import static org.mockito.Mockito.verify; 45 import static org.mockito.Mockito.when; 46 47 import android.content.Context; 48 import android.net.InetAddresses; 49 import android.net.IpPrefix; 50 import android.net.LinkAddress; 51 import android.net.LinkProperties; 52 import android.net.MacAddress; 53 import android.net.NattKeepalivePacketDataParcelable; 54 import android.net.TcpKeepalivePacketDataParcelable; 55 import android.net.apf.ApfFilter.ApfConfiguration; 56 import android.net.apf.ApfGenerator.IllegalInstructionException; 57 import android.net.ip.IIpClientCallbacks; 58 import android.net.ip.IpClient.IpClientCallbacksWrapper; 59 import android.net.metrics.IpConnectivityLog; 60 import android.net.metrics.RaEvent; 61 import android.os.ConditionVariable; 62 import android.os.Parcelable; 63 import android.os.SystemClock; 64 import android.system.ErrnoException; 65 import android.system.Os; 66 import android.text.TextUtils; 67 import android.text.format.DateUtils; 68 import android.util.Log; 69 import android.util.Pair; 70 71 import androidx.test.InstrumentationRegistry; 72 import androidx.test.filters.SmallTest; 73 import androidx.test.runner.AndroidJUnit4; 74 75 import com.android.internal.util.HexDump; 76 import com.android.net.module.util.DnsPacket; 77 import com.android.net.module.util.Inet4AddressUtils; 78 import com.android.net.module.util.InterfaceParams; 79 import com.android.net.module.util.NetworkStackConstants; 80 import com.android.net.module.util.PacketBuilder; 81 import com.android.net.module.util.SharedLog; 82 import com.android.networkstack.apishim.NetworkInformationShimImpl; 83 import com.android.server.networkstack.tests.R; 84 85 import libcore.io.IoUtils; 86 import libcore.io.Streams; 87 88 import org.junit.Assert; 89 import org.junit.Before; 90 import org.junit.Test; 91 import org.junit.runner.RunWith; 92 import org.mockito.ArgumentCaptor; 93 import org.mockito.Mock; 94 import org.mockito.MockitoAnnotations; 95 96 import java.io.File; 97 import java.io.FileDescriptor; 98 import java.io.FileOutputStream; 99 import java.io.IOException; 100 import java.io.InputStream; 101 import java.io.OutputStream; 102 import java.net.Inet4Address; 103 import java.net.Inet6Address; 104 import java.net.InetAddress; 105 import java.nio.ByteBuffer; 106 import java.nio.charset.StandardCharsets; 107 import java.util.ArrayList; 108 import java.util.Arrays; 109 import java.util.HashMap; 110 import java.util.List; 111 import java.util.Random; 112 113 /** 114 * Tests for APF program generator and interpreter. 115 * 116 * Build, install and run with: 117 * runtest frameworks-net -c android.net.apf.ApfTest 118 */ 119 @RunWith(AndroidJUnit4.class) 120 @SmallTest 121 public class ApfTest { 122 private static final int TIMEOUT_MS = 500; 123 private static final int MIN_APF_VERSION = 2; 124 125 @Mock IpConnectivityLog mLog; 126 @Mock ApfFilter.Dependencies mDependencies; 127 @Mock Context mContext; 128 129 @Before setUp()130 public void setUp() throws Exception { 131 MockitoAnnotations.initMocks(this); 132 when(mDependencies.isFeatureEnabled(eq(mContext), 133 eq(APF_USE_RA_LIFETIME_CALCULATION_FIX_VERSION), anyBoolean())).thenReturn(true); 134 // Load up native shared library containing APF interpreter exposed via JNI. 135 System.loadLibrary("networkstacktestsjni"); 136 } 137 138 private static final String TAG = "ApfTest"; 139 // Expected return codes from APF interpreter. 140 private static final int PASS = 1; 141 private static final int DROP = 0; 142 // Interpreter will just accept packets without link layer headers, so pad fake packet to at 143 // least the minimum packet size. 144 private static final int MIN_PKT_SIZE = 15; 145 146 private static final ApfCapabilities MOCK_APF_CAPABILITIES = 147 new ApfCapabilities(2, 4096, ARPHRD_ETHER); 148 149 private static final boolean DROP_MULTICAST = true; 150 private static final boolean ALLOW_MULTICAST = false; 151 152 private static final boolean DROP_802_3_FRAMES = true; 153 private static final boolean ALLOW_802_3_FRAMES = false; 154 155 private static final int MIN_RDNSS_LIFETIME_SEC = 0; 156 157 // Constants for opcode encoding 158 private static final byte LI_OP = (byte)(13 << 3); 159 private static final byte LDDW_OP = (byte)(22 << 3); 160 private static final byte STDW_OP = (byte)(23 << 3); 161 private static final byte SIZE0 = (byte)(0 << 1); 162 private static final byte SIZE8 = (byte)(1 << 1); 163 private static final byte SIZE16 = (byte)(2 << 1); 164 private static final byte SIZE32 = (byte)(3 << 1); 165 private static final byte R1_REG = 1; 166 getDefaultConfig()167 private static ApfConfiguration getDefaultConfig() { 168 ApfFilter.ApfConfiguration config = new ApfConfiguration(); 169 config.apfCapabilities = MOCK_APF_CAPABILITIES; 170 config.multicastFilter = ALLOW_MULTICAST; 171 config.ieee802_3Filter = ALLOW_802_3_FRAMES; 172 config.ethTypeBlackList = new int[0]; 173 config.minRdnssLifetimeSec = MIN_RDNSS_LIFETIME_SEC; 174 config.minRdnssLifetimeSec = 67; 175 return config; 176 } 177 label(int code)178 private static String label(int code) { 179 switch (code) { 180 case PASS: return "PASS"; 181 case DROP: return "DROP"; 182 default: return "UNKNOWN"; 183 } 184 } 185 assertReturnCodesEqual(String msg, int expected, int got)186 private static void assertReturnCodesEqual(String msg, int expected, int got) { 187 assertEquals(msg, label(expected), label(got)); 188 } 189 assertReturnCodesEqual(int expected, int got)190 private static void assertReturnCodesEqual(int expected, int got) { 191 assertEquals(label(expected), label(got)); 192 } 193 assertVerdict(int expected, byte[] program, byte[] packet, int filterAge)194 private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) { 195 final String msg = "Unexpected APF verdict. To debug:\n" 196 + " apf_run --program " + HexDump.toHexString(program) 197 + " --packet " + HexDump.toHexString(packet) + " --trace | less\n "; 198 assertReturnCodesEqual(msg, expected, apfSimulate(program, packet, null, filterAge)); 199 } 200 assertVerdict(String msg, int expected, byte[] program, byte[] packet, int filterAge)201 private void assertVerdict(String msg, int expected, byte[] program, byte[] packet, 202 int filterAge) { 203 assertReturnCodesEqual(msg, expected, apfSimulate(program, packet, null, filterAge)); 204 } 205 assertVerdict(int expected, byte[] program, byte[] packet)206 private void assertVerdict(int expected, byte[] program, byte[] packet) { 207 assertVerdict(expected, program, packet, 0); 208 } 209 assertPass(byte[] program, byte[] packet, int filterAge)210 private void assertPass(byte[] program, byte[] packet, int filterAge) { 211 assertVerdict(PASS, program, packet, filterAge); 212 } 213 assertPass(byte[] program, byte[] packet)214 private void assertPass(byte[] program, byte[] packet) { 215 assertVerdict(PASS, program, packet); 216 } 217 assertDrop(byte[] program, byte[] packet, int filterAge)218 private void assertDrop(byte[] program, byte[] packet, int filterAge) { 219 assertVerdict(DROP, program, packet, filterAge); 220 } 221 assertDrop(byte[] program, byte[] packet)222 private void assertDrop(byte[] program, byte[] packet) { 223 assertVerdict(DROP, program, packet); 224 } 225 assertProgramEquals(byte[] expected, byte[] program)226 private void assertProgramEquals(byte[] expected, byte[] program) throws AssertionError { 227 // assertArrayEquals() would only print one byte, making debugging difficult. 228 if (!Arrays.equals(expected, program)) { 229 throw new AssertionError( 230 "\nexpected: " + HexDump.toHexString(expected) + 231 "\nactual: " + HexDump.toHexString(program)); 232 } 233 } 234 assertDataMemoryContents( int expected, byte[] program, byte[] packet, byte[] data, byte[] expected_data)235 private void assertDataMemoryContents( 236 int expected, byte[] program, byte[] packet, byte[] data, byte[] expected_data) 237 throws IllegalInstructionException, Exception { 238 assertReturnCodesEqual(expected, apfSimulate(program, packet, data, 0 /* filterAge */)); 239 240 // assertArrayEquals() would only print one byte, making debugging difficult. 241 if (!Arrays.equals(expected_data, data)) { 242 throw new Exception( 243 "\nprogram: " + HexDump.toHexString(program) + 244 "\ndata memory: " + HexDump.toHexString(data) + 245 "\nexpected: " + HexDump.toHexString(expected_data)); 246 } 247 } 248 assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)249 private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge) 250 throws IllegalInstructionException { 251 assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, null, 252 filterAge)); 253 } 254 assertPass(ApfGenerator gen, byte[] packet, int filterAge)255 private void assertPass(ApfGenerator gen, byte[] packet, int filterAge) 256 throws IllegalInstructionException { 257 assertVerdict(PASS, gen, packet, filterAge); 258 } 259 assertDrop(ApfGenerator gen, byte[] packet, int filterAge)260 private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge) 261 throws IllegalInstructionException { 262 assertVerdict(DROP, gen, packet, filterAge); 263 } 264 assertPass(ApfGenerator gen)265 private void assertPass(ApfGenerator gen) 266 throws IllegalInstructionException { 267 assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0); 268 } 269 assertDrop(ApfGenerator gen)270 private void assertDrop(ApfGenerator gen) 271 throws IllegalInstructionException { 272 assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0); 273 } 274 275 /** 276 * Test each instruction by generating a program containing the instruction, 277 * generating bytecode for that program and running it through the 278 * interpreter to verify it functions correctly. 279 */ 280 @Test testApfInstructions()281 public void testApfInstructions() throws IllegalInstructionException { 282 // Empty program should pass because having the program counter reach the 283 // location immediately after the program indicates the packet should be 284 // passed to the AP. 285 ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION); 286 assertPass(gen); 287 288 // Test jumping to pass label. 289 gen = new ApfGenerator(MIN_APF_VERSION); 290 gen.addJump(gen.PASS_LABEL); 291 byte[] program = gen.generate(); 292 assertEquals(1, program.length); 293 assertEquals((14 << 3) | (0 << 1) | 0, program[0]); 294 assertPass(program, new byte[MIN_PKT_SIZE], 0); 295 296 // Test jumping to drop label. 297 gen = new ApfGenerator(MIN_APF_VERSION); 298 gen.addJump(gen.DROP_LABEL); 299 program = gen.generate(); 300 assertEquals(2, program.length); 301 assertEquals((14 << 3) | (1 << 1) | 0, program[0]); 302 assertEquals(1, program[1]); 303 assertDrop(program, new byte[15], 15); 304 305 // Test jumping if equal to 0. 306 gen = new ApfGenerator(MIN_APF_VERSION); 307 gen.addJumpIfR0Equals(0, gen.DROP_LABEL); 308 assertDrop(gen); 309 310 // Test jumping if not equal to 0. 311 gen = new ApfGenerator(MIN_APF_VERSION); 312 gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL); 313 assertPass(gen); 314 gen = new ApfGenerator(MIN_APF_VERSION); 315 gen.addLoadImmediate(R0, 1); 316 gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL); 317 assertDrop(gen); 318 319 // Test jumping if registers equal. 320 gen = new ApfGenerator(MIN_APF_VERSION); 321 gen.addJumpIfR0EqualsR1(gen.DROP_LABEL); 322 assertDrop(gen); 323 324 // Test jumping if registers not equal. 325 gen = new ApfGenerator(MIN_APF_VERSION); 326 gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL); 327 assertPass(gen); 328 gen = new ApfGenerator(MIN_APF_VERSION); 329 gen.addLoadImmediate(R0, 1); 330 gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL); 331 assertDrop(gen); 332 333 // Test load immediate. 334 gen = new ApfGenerator(MIN_APF_VERSION); 335 gen.addLoadImmediate(R0, 1234567890); 336 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 337 assertDrop(gen); 338 339 // Test add. 340 gen = new ApfGenerator(MIN_APF_VERSION); 341 gen.addAdd(1234567890); 342 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 343 assertDrop(gen); 344 345 // Test subtract. 346 gen = new ApfGenerator(MIN_APF_VERSION); 347 gen.addAdd(-1234567890); 348 gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); 349 assertDrop(gen); 350 351 // Test or. 352 gen = new ApfGenerator(MIN_APF_VERSION); 353 gen.addOr(1234567890); 354 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 355 assertDrop(gen); 356 357 // Test and. 358 gen = new ApfGenerator(MIN_APF_VERSION); 359 gen.addLoadImmediate(R0, 1234567890); 360 gen.addAnd(123456789); 361 gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL); 362 assertDrop(gen); 363 364 // Test left shift. 365 gen = new ApfGenerator(MIN_APF_VERSION); 366 gen.addLoadImmediate(R0, 1234567890); 367 gen.addLeftShift(1); 368 gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL); 369 assertDrop(gen); 370 371 // Test right shift. 372 gen = new ApfGenerator(MIN_APF_VERSION); 373 gen.addLoadImmediate(R0, 1234567890); 374 gen.addRightShift(1); 375 gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL); 376 assertDrop(gen); 377 378 // Test multiply. 379 gen = new ApfGenerator(MIN_APF_VERSION); 380 gen.addLoadImmediate(R0, 123456789); 381 gen.addMul(2); 382 gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL); 383 assertDrop(gen); 384 385 // Test divide. 386 gen = new ApfGenerator(MIN_APF_VERSION); 387 gen.addLoadImmediate(R0, 1234567890); 388 gen.addDiv(2); 389 gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL); 390 assertDrop(gen); 391 392 // Test divide by zero. 393 gen = new ApfGenerator(MIN_APF_VERSION); 394 gen.addDiv(0); 395 gen.addJump(gen.DROP_LABEL); 396 assertPass(gen); 397 398 // Test add. 399 gen = new ApfGenerator(MIN_APF_VERSION); 400 gen.addLoadImmediate(R1, 1234567890); 401 gen.addAddR1(); 402 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 403 assertDrop(gen); 404 405 // Test subtract. 406 gen = new ApfGenerator(MIN_APF_VERSION); 407 gen.addLoadImmediate(R1, -1234567890); 408 gen.addAddR1(); 409 gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); 410 assertDrop(gen); 411 412 // Test or. 413 gen = new ApfGenerator(MIN_APF_VERSION); 414 gen.addLoadImmediate(R1, 1234567890); 415 gen.addOrR1(); 416 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 417 assertDrop(gen); 418 419 // Test and. 420 gen = new ApfGenerator(MIN_APF_VERSION); 421 gen.addLoadImmediate(R0, 1234567890); 422 gen.addLoadImmediate(R1, 123456789); 423 gen.addAndR1(); 424 gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL); 425 assertDrop(gen); 426 427 // Test left shift. 428 gen = new ApfGenerator(MIN_APF_VERSION); 429 gen.addLoadImmediate(R0, 1234567890); 430 gen.addLoadImmediate(R1, 1); 431 gen.addLeftShiftR1(); 432 gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL); 433 assertDrop(gen); 434 435 // Test right shift. 436 gen = new ApfGenerator(MIN_APF_VERSION); 437 gen.addLoadImmediate(R0, 1234567890); 438 gen.addLoadImmediate(R1, -1); 439 gen.addLeftShiftR1(); 440 gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL); 441 assertDrop(gen); 442 443 // Test multiply. 444 gen = new ApfGenerator(MIN_APF_VERSION); 445 gen.addLoadImmediate(R0, 123456789); 446 gen.addLoadImmediate(R1, 2); 447 gen.addMulR1(); 448 gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL); 449 assertDrop(gen); 450 451 // Test divide. 452 gen = new ApfGenerator(MIN_APF_VERSION); 453 gen.addLoadImmediate(R0, 1234567890); 454 gen.addLoadImmediate(R1, 2); 455 gen.addDivR1(); 456 gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL); 457 assertDrop(gen); 458 459 // Test divide by zero. 460 gen = new ApfGenerator(MIN_APF_VERSION); 461 gen.addDivR1(); 462 gen.addJump(gen.DROP_LABEL); 463 assertPass(gen); 464 465 // Test byte load. 466 gen = new ApfGenerator(MIN_APF_VERSION); 467 gen.addLoad8(R0, 1); 468 gen.addJumpIfR0Equals(45, gen.DROP_LABEL); 469 assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 470 471 // Test out of bounds load. 472 gen = new ApfGenerator(MIN_APF_VERSION); 473 gen.addLoad8(R0, 16); 474 gen.addJumpIfR0Equals(0, gen.DROP_LABEL); 475 assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 476 477 // Test half-word load. 478 gen = new ApfGenerator(MIN_APF_VERSION); 479 gen.addLoad16(R0, 1); 480 gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL); 481 assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 482 483 // Test word load. 484 gen = new ApfGenerator(MIN_APF_VERSION); 485 gen.addLoad32(R0, 1); 486 gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL); 487 assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0); 488 489 // Test byte indexed load. 490 gen = new ApfGenerator(MIN_APF_VERSION); 491 gen.addLoadImmediate(R1, 1); 492 gen.addLoad8Indexed(R0, 0); 493 gen.addJumpIfR0Equals(45, gen.DROP_LABEL); 494 assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 495 496 // Test out of bounds indexed load. 497 gen = new ApfGenerator(MIN_APF_VERSION); 498 gen.addLoadImmediate(R1, 8); 499 gen.addLoad8Indexed(R0, 8); 500 gen.addJumpIfR0Equals(0, gen.DROP_LABEL); 501 assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 502 503 // Test half-word indexed load. 504 gen = new ApfGenerator(MIN_APF_VERSION); 505 gen.addLoadImmediate(R1, 1); 506 gen.addLoad16Indexed(R0, 0); 507 gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL); 508 assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 509 510 // Test word indexed load. 511 gen = new ApfGenerator(MIN_APF_VERSION); 512 gen.addLoadImmediate(R1, 1); 513 gen.addLoad32Indexed(R0, 0); 514 gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL); 515 assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0); 516 517 // Test jumping if greater than. 518 gen = new ApfGenerator(MIN_APF_VERSION); 519 gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL); 520 assertPass(gen); 521 gen = new ApfGenerator(MIN_APF_VERSION); 522 gen.addLoadImmediate(R0, 1); 523 gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL); 524 assertDrop(gen); 525 526 // Test jumping if less than. 527 gen = new ApfGenerator(MIN_APF_VERSION); 528 gen.addJumpIfR0LessThan(0, gen.DROP_LABEL); 529 assertPass(gen); 530 gen = new ApfGenerator(MIN_APF_VERSION); 531 gen.addJumpIfR0LessThan(1, gen.DROP_LABEL); 532 assertDrop(gen); 533 534 // Test jumping if any bits set. 535 gen = new ApfGenerator(MIN_APF_VERSION); 536 gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); 537 assertPass(gen); 538 gen = new ApfGenerator(MIN_APF_VERSION); 539 gen.addLoadImmediate(R0, 1); 540 gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); 541 assertDrop(gen); 542 gen = new ApfGenerator(MIN_APF_VERSION); 543 gen.addLoadImmediate(R0, 3); 544 gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); 545 assertDrop(gen); 546 547 // Test jumping if register greater than. 548 gen = new ApfGenerator(MIN_APF_VERSION); 549 gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL); 550 assertPass(gen); 551 gen = new ApfGenerator(MIN_APF_VERSION); 552 gen.addLoadImmediate(R0, 2); 553 gen.addLoadImmediate(R1, 1); 554 gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL); 555 assertDrop(gen); 556 557 // Test jumping if register less than. 558 gen = new ApfGenerator(MIN_APF_VERSION); 559 gen.addJumpIfR0LessThanR1(gen.DROP_LABEL); 560 assertPass(gen); 561 gen = new ApfGenerator(MIN_APF_VERSION); 562 gen.addLoadImmediate(R1, 1); 563 gen.addJumpIfR0LessThanR1(gen.DROP_LABEL); 564 assertDrop(gen); 565 566 // Test jumping if any bits set in register. 567 gen = new ApfGenerator(MIN_APF_VERSION); 568 gen.addLoadImmediate(R1, 3); 569 gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); 570 assertPass(gen); 571 gen = new ApfGenerator(MIN_APF_VERSION); 572 gen.addLoadImmediate(R1, 3); 573 gen.addLoadImmediate(R0, 1); 574 gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); 575 assertDrop(gen); 576 gen = new ApfGenerator(MIN_APF_VERSION); 577 gen.addLoadImmediate(R1, 3); 578 gen.addLoadImmediate(R0, 3); 579 gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); 580 assertDrop(gen); 581 582 // Test load from memory. 583 gen = new ApfGenerator(MIN_APF_VERSION); 584 gen.addLoadFromMemory(R0, 0); 585 gen.addJumpIfR0Equals(0, gen.DROP_LABEL); 586 assertDrop(gen); 587 588 // Test store to memory. 589 gen = new ApfGenerator(MIN_APF_VERSION); 590 gen.addLoadImmediate(R1, 1234567890); 591 gen.addStoreToMemory(R1, 12); 592 gen.addLoadFromMemory(R0, 12); 593 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 594 assertDrop(gen); 595 596 // Test filter age pre-filled memory. 597 gen = new ApfGenerator(MIN_APF_VERSION); 598 gen.addLoadFromMemory(R0, gen.FILTER_AGE_MEMORY_SLOT); 599 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 600 assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890); 601 602 // Test packet size pre-filled memory. 603 gen = new ApfGenerator(MIN_APF_VERSION); 604 gen.addLoadFromMemory(R0, gen.PACKET_SIZE_MEMORY_SLOT); 605 gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL); 606 assertDrop(gen); 607 608 // Test IPv4 header size pre-filled memory. 609 gen = new ApfGenerator(MIN_APF_VERSION); 610 gen.addLoadFromMemory(R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); 611 gen.addJumpIfR0Equals(20, gen.DROP_LABEL); 612 assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0); 613 614 // Test not. 615 gen = new ApfGenerator(MIN_APF_VERSION); 616 gen.addLoadImmediate(R0, 1234567890); 617 gen.addNot(R0); 618 gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL); 619 assertDrop(gen); 620 621 // Test negate. 622 gen = new ApfGenerator(MIN_APF_VERSION); 623 gen.addLoadImmediate(R0, 1234567890); 624 gen.addNeg(R0); 625 gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); 626 assertDrop(gen); 627 628 // Test move. 629 gen = new ApfGenerator(MIN_APF_VERSION); 630 gen.addLoadImmediate(R1, 1234567890); 631 gen.addMove(R0); 632 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 633 assertDrop(gen); 634 gen = new ApfGenerator(MIN_APF_VERSION); 635 gen.addLoadImmediate(R0, 1234567890); 636 gen.addMove(R1); 637 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 638 assertDrop(gen); 639 640 // Test swap. 641 gen = new ApfGenerator(MIN_APF_VERSION); 642 gen.addLoadImmediate(R1, 1234567890); 643 gen.addSwap(); 644 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 645 assertDrop(gen); 646 gen = new ApfGenerator(MIN_APF_VERSION); 647 gen.addLoadImmediate(R0, 1234567890); 648 gen.addSwap(); 649 gen.addJumpIfR0Equals(0, gen.DROP_LABEL); 650 assertDrop(gen); 651 652 // Test jump if bytes not equal. 653 gen = new ApfGenerator(MIN_APF_VERSION); 654 gen.addLoadImmediate(R0, 1); 655 gen.addJumpIfBytesNotEqual(R0, new byte[]{123}, gen.DROP_LABEL); 656 program = gen.generate(); 657 assertEquals(6, program.length); 658 assertEquals((13 << 3) | (1 << 1) | 0, program[0]); 659 assertEquals(1, program[1]); 660 assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]); 661 assertEquals(1, program[3]); 662 assertEquals(1, program[4]); 663 assertEquals(123, program[5]); 664 assertDrop(program, new byte[MIN_PKT_SIZE], 0); 665 gen = new ApfGenerator(MIN_APF_VERSION); 666 gen.addLoadImmediate(R0, 1); 667 gen.addJumpIfBytesNotEqual(R0, new byte[]{123}, gen.DROP_LABEL); 668 byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0}; 669 assertPass(gen, packet123, 0); 670 gen = new ApfGenerator(MIN_APF_VERSION); 671 gen.addJumpIfBytesNotEqual(R0, new byte[]{123}, gen.DROP_LABEL); 672 assertDrop(gen, packet123, 0); 673 gen = new ApfGenerator(MIN_APF_VERSION); 674 gen.addLoadImmediate(R0, 1); 675 gen.addJumpIfBytesNotEqual(R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL); 676 byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0}; 677 assertDrop(gen, packet12345, 0); 678 gen = new ApfGenerator(MIN_APF_VERSION); 679 gen.addLoadImmediate(R0, 1); 680 gen.addJumpIfBytesNotEqual(R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL); 681 assertPass(gen, packet12345, 0); 682 } 683 684 @Test(expected = ApfGenerator.IllegalInstructionException.class) testApfGeneratorWantsV2OrGreater()685 public void testApfGeneratorWantsV2OrGreater() throws Exception { 686 // The minimum supported APF version is 2. 687 new ApfGenerator(1); 688 } 689 690 @Test testApfDataOpcodesWantApfV3()691 public void testApfDataOpcodesWantApfV3() throws IllegalInstructionException, Exception { 692 ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION); 693 try { 694 gen.addStoreData(R0, 0); 695 fail(); 696 } catch (IllegalInstructionException expected) { 697 /* pass */ 698 } 699 try { 700 gen.addLoadData(R0, 0); 701 fail(); 702 } catch (IllegalInstructionException expected) { 703 /* pass */ 704 } 705 } 706 707 /** 708 * Test that the generator emits immediates using the shortest possible encoding. 709 */ 710 @Test testImmediateEncoding()711 public void testImmediateEncoding() throws IllegalInstructionException { 712 ApfGenerator gen; 713 714 // 0-byte immediate: li R0, 0 715 gen = new ApfGenerator(4); 716 gen.addLoadImmediate(R0, 0); 717 assertProgramEquals(new byte[]{LI_OP | SIZE0}, gen.generate()); 718 719 // 1-byte immediate: li R0, 42 720 gen = new ApfGenerator(4); 721 gen.addLoadImmediate(R0, 42); 722 assertProgramEquals(new byte[]{LI_OP | SIZE8, 42}, gen.generate()); 723 724 // 2-byte immediate: li R1, 0x1234 725 gen = new ApfGenerator(4); 726 gen.addLoadImmediate(R1, 0x1234); 727 assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1_REG, 0x12, 0x34}, gen.generate()); 728 729 // 4-byte immediate: li R0, 0x12345678 730 gen = new ApfGenerator(3); 731 gen.addLoadImmediate(R0, 0x12345678); 732 assertProgramEquals( 733 new byte[]{LI_OP | SIZE32, 0x12, 0x34, 0x56, 0x78}, 734 gen.generate()); 735 } 736 737 /** 738 * Test that the generator emits negative immediates using the shortest possible encoding. 739 */ 740 @Test testNegativeImmediateEncoding()741 public void testNegativeImmediateEncoding() throws IllegalInstructionException { 742 ApfGenerator gen; 743 744 // 1-byte negative immediate: li R0, -42 745 gen = new ApfGenerator(3); 746 gen.addLoadImmediate(R0, -42); 747 assertProgramEquals(new byte[]{LI_OP | SIZE8, -42}, gen.generate()); 748 749 // 2-byte negative immediate: li R1, -0x1122 750 gen = new ApfGenerator(3); 751 gen.addLoadImmediate(R1, -0x1122); 752 assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1_REG, (byte)0xEE, (byte)0xDE}, 753 gen.generate()); 754 755 // 4-byte negative immediate: li R0, -0x11223344 756 gen = new ApfGenerator(3); 757 gen.addLoadImmediate(R0, -0x11223344); 758 assertProgramEquals( 759 new byte[]{LI_OP | SIZE32, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC}, 760 gen.generate()); 761 } 762 763 /** 764 * Test that the generator correctly emits positive and negative immediates for LDDW/STDW. 765 */ 766 @Test testLoadStoreDataEncoding()767 public void testLoadStoreDataEncoding() throws IllegalInstructionException { 768 ApfGenerator gen; 769 770 // Load data with no offset: lddw R0, [0 + r1] 771 gen = new ApfGenerator(3); 772 gen.addLoadData(R0, 0); 773 assertProgramEquals(new byte[]{LDDW_OP | SIZE0}, gen.generate()); 774 775 // Store data with 8bit negative offset: lddw r0, [-42 + r1] 776 gen = new ApfGenerator(3); 777 gen.addStoreData(R0, -42); 778 assertProgramEquals(new byte[]{STDW_OP | SIZE8, -42}, gen.generate()); 779 780 // Store data to R1 with 16bit negative offset: stdw r1, [-0x1122 + r0] 781 gen = new ApfGenerator(3); 782 gen.addStoreData(R1, -0x1122); 783 assertProgramEquals(new byte[]{STDW_OP | SIZE16 | R1_REG, (byte)0xEE, (byte)0xDE}, 784 gen.generate()); 785 786 // Load data to R1 with 32bit negative offset: lddw r1, [0xDEADBEEF + r0] 787 gen = new ApfGenerator(3); 788 gen.addLoadData(R1, 0xDEADBEEF); 789 assertProgramEquals( 790 new byte[]{LDDW_OP | SIZE32 | R1_REG, 791 (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF}, 792 gen.generate()); 793 } 794 795 /** 796 * Test that the interpreter correctly executes STDW with a negative 8bit offset 797 */ 798 @Test testApfDataWrite()799 public void testApfDataWrite() throws IllegalInstructionException, Exception { 800 byte[] packet = new byte[MIN_PKT_SIZE]; 801 byte[] data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; 802 byte[] expected_data = data.clone(); 803 804 // No memory access instructions: should leave the data segment untouched. 805 ApfGenerator gen = new ApfGenerator(3); 806 assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data); 807 808 // Expect value 0x87654321 to be stored starting from address -11 from the end of the 809 // data buffer, in big-endian order. 810 gen = new ApfGenerator(3); 811 gen.addLoadImmediate(R0, 0x87654321); 812 gen.addLoadImmediate(R1, -5); 813 gen.addStoreData(R0, -6); // -5 + -6 = -11 (offset +5 with data_len=16) 814 expected_data[5] = (byte)0x87; 815 expected_data[6] = (byte)0x65; 816 expected_data[7] = (byte)0x43; 817 expected_data[8] = (byte)0x21; 818 assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data); 819 } 820 821 /** 822 * Test that the interpreter correctly executes LDDW with a negative 16bit offset 823 */ 824 @Test testApfDataRead()825 public void testApfDataRead() throws IllegalInstructionException, Exception { 826 // Program that DROPs if address 10 (-6) contains 0x87654321. 827 ApfGenerator gen = new ApfGenerator(3); 828 gen.addLoadImmediate(R1, 1000); 829 gen.addLoadData(R0, -1006); // 1000 + -1006 = -6 (offset +10 with data_len=16) 830 gen.addJumpIfR0Equals(0x87654321, gen.DROP_LABEL); 831 byte[] program = gen.generate(); 832 byte[] packet = new byte[MIN_PKT_SIZE]; 833 834 // Content is incorrect (last byte does not match) -> PASS 835 byte[] data = new byte[16]; 836 data[10] = (byte)0x87; 837 data[11] = (byte)0x65; 838 data[12] = (byte)0x43; 839 data[13] = (byte)0x00; // != 0x21 840 byte[] expected_data = data.clone(); 841 assertDataMemoryContents(PASS, program, packet, data, expected_data); 842 843 // Fix the last byte -> conditional jump taken -> DROP 844 data[13] = (byte)0x21; 845 expected_data = data; 846 assertDataMemoryContents(DROP, program, packet, data, expected_data); 847 } 848 849 /** 850 * Test that the interpreter correctly executes LDDW followed by a STDW. 851 * To cover a few more edge cases, LDDW has a 0bit offset, while STDW has a positive 8bit 852 * offset. 853 */ 854 @Test testApfDataReadModifyWrite()855 public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception { 856 ApfGenerator gen = new ApfGenerator(3); 857 gen.addLoadImmediate(R1, -22); 858 gen.addLoadData(R0, 0); // Load from address 32 -22 + 0 = 10 859 gen.addAdd(0x78453412); // 87654321 + 78453412 = FFAA7733 860 gen.addStoreData(R0, 4); // Write back to address 32 -22 + 4 = 14 861 862 byte[] packet = new byte[MIN_PKT_SIZE]; 863 byte[] data = new byte[32]; 864 data[10] = (byte)0x87; 865 data[11] = (byte)0x65; 866 data[12] = (byte)0x43; 867 data[13] = (byte)0x21; 868 byte[] expected_data = data.clone(); 869 expected_data[14] = (byte)0xFF; 870 expected_data[15] = (byte)0xAA; 871 expected_data[16] = (byte)0x77; 872 expected_data[17] = (byte)0x33; 873 assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data); 874 } 875 876 @Test testApfDataBoundChecking()877 public void testApfDataBoundChecking() throws IllegalInstructionException, Exception { 878 byte[] packet = new byte[MIN_PKT_SIZE]; 879 byte[] data = new byte[32]; 880 byte[] expected_data = data; 881 882 // Program that DROPs unconditionally. This is our the baseline. 883 ApfGenerator gen = new ApfGenerator(3); 884 gen.addLoadImmediate(R0, 3); 885 gen.addLoadData(R1, 7); 886 gen.addJump(gen.DROP_LABEL); 887 assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data); 888 889 // Same program as before, but this time we're trying to load past the end of the data. 890 gen = new ApfGenerator(3); 891 gen.addLoadImmediate(R0, 20); 892 gen.addLoadData(R1, 15); // 20 + 15 > 32 893 gen.addJump(gen.DROP_LABEL); // Not reached. 894 assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data); 895 896 // Subtracting an immediate should work... 897 gen = new ApfGenerator(3); 898 gen.addLoadImmediate(R0, 20); 899 gen.addLoadData(R1, -4); 900 gen.addJump(gen.DROP_LABEL); 901 assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data); 902 903 // ...and underflowing simply wraps around to the end of the buffer... 904 gen = new ApfGenerator(3); 905 gen.addLoadImmediate(R0, 20); 906 gen.addLoadData(R1, -30); 907 gen.addJump(gen.DROP_LABEL); 908 assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data); 909 910 // ...but doesn't allow accesses before the start of the buffer 911 gen = new ApfGenerator(3); 912 gen.addLoadImmediate(R0, 20); 913 gen.addLoadData(R1, -1000); 914 gen.addJump(gen.DROP_LABEL); // Not reached. 915 assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data); 916 } 917 918 /** 919 * Generate some BPF programs, translate them to APF, then run APF and BPF programs 920 * over packet traces and verify both programs filter out the same packets. 921 */ 922 @Test testApfAgainstBpf()923 public void testApfAgainstBpf() throws Exception { 924 String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53", 925 "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24", 926 "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000", 927 "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" }; 928 String pcap_filename = stageFile(R.raw.apf); 929 for (String tcpdump_filter : tcpdump_filters) { 930 byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter)); 931 assertTrue("Failed to match for filter: " + tcpdump_filter, 932 compareBpfApf(tcpdump_filter, pcap_filename, apf_program)); 933 } 934 } 935 936 /** 937 * Generate APF program, run pcap file though APF filter, then check all the packets in the file 938 * should be dropped. 939 */ 940 @Test testApfFilterPcapFile()941 public void testApfFilterPcapFile() throws Exception { 942 final byte[] MOCK_PCAP_IPV4_ADDR = {(byte) 172, 16, 7, (byte) 151}; 943 String pcapFilename = stageFile(R.raw.apfPcap); 944 MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 945 LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_PCAP_IPV4_ADDR), 16); 946 LinkProperties lp = new LinkProperties(); 947 lp.addLinkAddress(link); 948 949 ApfConfiguration config = getDefaultConfig(); 950 ApfCapabilities MOCK_APF_PCAP_CAPABILITIES = new ApfCapabilities(4, 1700, ARPHRD_ETHER); 951 config.apfCapabilities = MOCK_APF_PCAP_CAPABILITIES; 952 config.multicastFilter = DROP_MULTICAST; 953 config.ieee802_3Filter = DROP_802_3_FRAMES; 954 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, 955 mDependencies); 956 apfFilter.setLinkProperties(lp); 957 byte[] program = ipClientCallback.getApfProgram(); 958 byte[] data = new byte[ApfFilter.Counter.totalSize()]; 959 final boolean result; 960 961 result = dropsAllPackets(program, data, pcapFilename); 962 Log.i(TAG, "testApfFilterPcapFile(): Data counters: " + HexDump.toHexString(data, false)); 963 964 assertTrue("Failed to drop all packets by filter. \nAPF counters:" + 965 HexDump.toHexString(data, false), result); 966 } 967 968 private class MockIpClientCallback extends IpClientCallbacksWrapper { 969 private final ConditionVariable mGotApfProgram = new ConditionVariable(); 970 private byte[] mLastApfProgram; 971 MockIpClientCallback()972 MockIpClientCallback() { 973 super(mock(IIpClientCallbacks.class), mock(SharedLog.class), 974 NetworkInformationShimImpl.newInstance()); 975 } 976 977 @Override installPacketFilter(byte[] filter)978 public void installPacketFilter(byte[] filter) { 979 mLastApfProgram = filter; 980 mGotApfProgram.open(); 981 } 982 resetApfProgramWait()983 public void resetApfProgramWait() { 984 mGotApfProgram.close(); 985 } 986 getApfProgram()987 public byte[] getApfProgram() { 988 assertTrue(mGotApfProgram.block(TIMEOUT_MS)); 989 return mLastApfProgram; 990 } 991 assertNoProgramUpdate()992 public void assertNoProgramUpdate() { 993 assertFalse(mGotApfProgram.block(TIMEOUT_MS)); 994 } 995 } 996 997 private static class TestApfFilter extends ApfFilter { 998 public static final byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6}; 999 1000 private FileDescriptor mWriteSocket; 1001 private long mCurrentTimeMs = SystemClock.elapsedRealtime(); 1002 TestApfFilter(Context context, ApfConfiguration config, IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log, ApfFilter.Dependencies deps)1003 public TestApfFilter(Context context, ApfConfiguration config, 1004 IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log, 1005 ApfFilter.Dependencies deps) throws Exception { 1006 super(context, config, InterfaceParams.getByName("lo"), ipClientCallback, log, deps); 1007 } 1008 1009 // Pretend an RA packet has been received and show it to ApfFilter. pretendPacketReceived(byte[] packet)1010 public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException { 1011 // ApfFilter's ReceiveThread will be waiting to read this. 1012 Os.write(mWriteSocket, packet, 0, packet.length); 1013 } 1014 1015 // Simulate current time changes increaseCurrentTimeSeconds(int delta)1016 public void increaseCurrentTimeSeconds(int delta) { 1017 mCurrentTimeMs += delta * DateUtils.SECOND_IN_MILLIS; 1018 } 1019 1020 @Override currentTimeSeconds()1021 protected long currentTimeSeconds() { 1022 return mCurrentTimeMs / DateUtils.SECOND_IN_MILLIS; 1023 } 1024 1025 @Override maybeStartFilter()1026 public synchronized void maybeStartFilter() { 1027 mHardwareAddress = MOCK_MAC_ADDR; 1028 installNewProgramLocked(); 1029 1030 // Create two sockets, "readSocket" and "mWriteSocket" and connect them together. 1031 FileDescriptor readSocket = new FileDescriptor(); 1032 mWriteSocket = new FileDescriptor(); 1033 try { 1034 Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket); 1035 } catch (ErrnoException e) { 1036 fail(); 1037 return; 1038 } 1039 // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs. 1040 // This allows us to pretend RA packets have been recieved via pretendPacketReceived(). 1041 mReceiveThread = new ReceiveThread(readSocket); 1042 mReceiveThread.start(); 1043 } 1044 1045 @Override shutdown()1046 public void shutdown() { 1047 super.shutdown(); 1048 IoUtils.closeQuietly(mWriteSocket); 1049 } 1050 } 1051 1052 private static final int ETH_HEADER_LEN = 14; 1053 private static final int ETH_DEST_ADDR_OFFSET = 0; 1054 private static final int ETH_ETHERTYPE_OFFSET = 12; 1055 private static final byte[] ETH_BROADCAST_MAC_ADDRESS = 1056 {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; 1057 private static final byte[] ETH_MULTICAST_MDNS_v4_MAC_ADDRESS = 1058 {(byte) 0x01, (byte) 0x00, (byte) 0x5e, (byte) 0x00, (byte) 0x00, (byte) 0xfb}; 1059 private static final byte[] ETH_MULTICAST_MDNS_V6_MAC_ADDRESS = 1060 {(byte) 0x33, (byte) 0x33, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xfb}; 1061 1062 private static final int IP_HEADER_OFFSET = ETH_HEADER_LEN; 1063 1064 private static final int IPV4_HEADER_LEN = 20; 1065 private static final int IPV4_TOTAL_LENGTH_OFFSET = IP_HEADER_OFFSET + 2; 1066 private static final int IPV4_PROTOCOL_OFFSET = IP_HEADER_OFFSET + 9; 1067 private static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12; 1068 private static final int IPV4_DEST_ADDR_OFFSET = IP_HEADER_OFFSET + 16; 1069 1070 private static final int IPV4_TCP_HEADER_LEN = 20; 1071 private static final int IPV4_TCP_HEADER_OFFSET = IP_HEADER_OFFSET + IPV4_HEADER_LEN; 1072 private static final int IPV4_TCP_SRC_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 0; 1073 private static final int IPV4_TCP_DEST_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 2; 1074 private static final int IPV4_TCP_SEQ_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 4; 1075 private static final int IPV4_TCP_ACK_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 8; 1076 private static final int IPV4_TCP_HEADER_LENGTH_OFFSET = IPV4_TCP_HEADER_OFFSET + 12; 1077 private static final int IPV4_TCP_HEADER_FLAG_OFFSET = IPV4_TCP_HEADER_OFFSET + 13; 1078 1079 private static final int IPV4_UDP_HEADER_OFFSET = IP_HEADER_OFFSET + IPV4_HEADER_LEN; 1080 private static final int IPV4_UDP_SRC_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 0; 1081 private static final int IPV4_UDP_DEST_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 2; 1082 private static final int IPV4_UDP_LENGTH_OFFSET = IPV4_UDP_HEADER_OFFSET + 4; 1083 private static final int IPV4_UDP_PAYLOAD_OFFSET = IPV4_UDP_HEADER_OFFSET + 8; 1084 private static final byte[] IPV4_BROADCAST_ADDRESS = 1085 {(byte) 255, (byte) 255, (byte) 255, (byte) 255}; 1086 1087 private static final int IPV6_HEADER_LEN = 40; 1088 private static final int IPV6_PAYLOAD_LENGTH_OFFSET = IP_HEADER_OFFSET + 4; 1089 private static final int IPV6_NEXT_HEADER_OFFSET = IP_HEADER_OFFSET + 6; 1090 private static final int IPV6_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 8; 1091 private static final int IPV6_DEST_ADDR_OFFSET = IP_HEADER_OFFSET + 24; 1092 private static final int IPV6_PAYLOAD_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN; 1093 private static final int IPV6_TCP_SRC_PORT_OFFSET = IPV6_PAYLOAD_OFFSET + 0; 1094 private static final int IPV6_TCP_DEST_PORT_OFFSET = IPV6_PAYLOAD_OFFSET + 2; 1095 private static final int IPV6_TCP_SEQ_NUM_OFFSET = IPV6_PAYLOAD_OFFSET + 4; 1096 private static final int IPV6_TCP_ACK_NUM_OFFSET = IPV6_PAYLOAD_OFFSET + 8; 1097 // The IPv6 all nodes address ff02::1 1098 private static final byte[] IPV6_ALL_NODES_ADDRESS = 1099 { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; 1100 private static final byte[] IPV6_ALL_ROUTERS_ADDRESS = 1101 { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }; 1102 private static final byte[] IPV6_SOLICITED_NODE_MULTICAST_ADDRESS = { 1103 (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1104 (byte) 0xff, (byte) 0xab, (byte) 0xcd, (byte) 0xef, 1105 }; 1106 1107 private static final int ICMP6_TYPE_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN; 1108 private static final int ICMP6_ROUTER_SOLICITATION = 133; 1109 private static final int ICMP6_ROUTER_ADVERTISEMENT = 134; 1110 private static final int ICMP6_NEIGHBOR_SOLICITATION = 135; 1111 private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136; 1112 1113 private static final int ICMP6_RA_HEADER_LEN = 16; 1114 private static final int ICMP6_RA_CHECKSUM_OFFSET = 1115 IP_HEADER_OFFSET + IPV6_HEADER_LEN + 2; 1116 private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET = 1117 IP_HEADER_OFFSET + IPV6_HEADER_LEN + 6; 1118 private static final int ICMP6_RA_REACHABLE_TIME_OFFSET = 1119 IP_HEADER_OFFSET + IPV6_HEADER_LEN + 8; 1120 private static final int ICMP6_RA_RETRANSMISSION_TIMER_OFFSET = 1121 IP_HEADER_OFFSET + IPV6_HEADER_LEN + 12; 1122 private static final int ICMP6_RA_OPTION_OFFSET = 1123 IP_HEADER_OFFSET + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN; 1124 1125 private static final int ICMP6_PREFIX_OPTION_TYPE = 3; 1126 private static final int ICMP6_PREFIX_OPTION_LEN = 32; 1127 private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4; 1128 private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8; 1129 1130 // From RFC6106: Recursive DNS Server option 1131 private static final int ICMP6_RDNSS_OPTION_TYPE = 25; 1132 // From RFC6106: DNS Search List option 1133 private static final int ICMP6_DNSSL_OPTION_TYPE = 31; 1134 1135 // From RFC4191: Route Information option 1136 private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24; 1137 // Above three options all have the same format: 1138 private static final int ICMP6_4_BYTE_OPTION_LEN = 8; 1139 private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4; 1140 private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4; 1141 1142 private static final int UDP_HEADER_LEN = 8; 1143 private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22; 1144 1145 private static final int DHCP_CLIENT_PORT = 68; 1146 private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48; 1147 1148 private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN; 1149 private static final byte[] ARP_IPV4_REQUEST_HEADER = { 1150 0, 1, // Hardware type: Ethernet (1) 1151 8, 0, // Protocol type: IP (0x0800) 1152 6, // Hardware size: 6 1153 4, // Protocol size: 4 1154 0, 1 // Opcode: request (1) 1155 }; 1156 private static final byte[] ARP_IPV4_REPLY_HEADER = { 1157 0, 1, // Hardware type: Ethernet (1) 1158 8, 0, // Protocol type: IP (0x0800) 1159 6, // Hardware size: 6 1160 4, // Protocol size: 4 1161 0, 2 // Opcode: reply (2) 1162 }; 1163 private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14; 1164 private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24; 1165 1166 private static final byte[] MOCK_IPV4_ADDR = {10, 0, 0, 1}; 1167 private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19 1168 private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1}; 1169 private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2}; 1170 private static final byte[] IPV4_SOURCE_ADDR = {10, 0, 0, 3}; 1171 private static final byte[] ANOTHER_IPV4_SOURCE_ADDR = {(byte) 192, 0, 2, 1}; 1172 private static final byte[] BUG_PROBE_SOURCE_ADDR1 = {0, 0, 1, 2}; 1173 private static final byte[] BUG_PROBE_SOURCE_ADDR2 = {3, 4, 0, 0}; 1174 private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0}; 1175 private static final byte[] IPV4_MDNS_MULTICAST_ADDR = {(byte) 224, 0, 0, (byte) 251}; 1176 private static final byte[] IPV6_MDNS_MULTICAST_ADDR = 1177 {(byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfb}; 1178 private static final int IPV6_UDP_DEST_PORT_OFFSET = IPV6_PAYLOAD_OFFSET + 2; 1179 private static final int MDNS_UDP_PORT = 5353; 1180 1181 // Helper to initialize a default apfFilter. setupApfFilter( IpClientCallbacksWrapper ipClientCallback, ApfConfiguration config)1182 private ApfFilter setupApfFilter( 1183 IpClientCallbacksWrapper ipClientCallback, ApfConfiguration config) throws Exception { 1184 LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19); 1185 LinkProperties lp = new LinkProperties(); 1186 lp.addLinkAddress(link); 1187 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, 1188 mDependencies); 1189 apfFilter.setLinkProperties(lp); 1190 return apfFilter; 1191 } 1192 setIpv4VersionFields(ByteBuffer packet)1193 private static void setIpv4VersionFields(ByteBuffer packet) { 1194 packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP); 1195 packet.put(IP_HEADER_OFFSET, (byte) 0x45); 1196 } 1197 setIpv6VersionFields(ByteBuffer packet)1198 private static void setIpv6VersionFields(ByteBuffer packet) { 1199 packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6); 1200 packet.put(IP_HEADER_OFFSET, (byte) 0x60); 1201 } 1202 makeIpv4Packet(int proto)1203 private static ByteBuffer makeIpv4Packet(int proto) { 1204 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 1205 setIpv4VersionFields(packet); 1206 packet.put(IPV4_PROTOCOL_OFFSET, (byte) proto); 1207 return packet; 1208 } 1209 makeIpv6Packet(int nextHeader)1210 private static ByteBuffer makeIpv6Packet(int nextHeader) { 1211 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 1212 setIpv6VersionFields(packet); 1213 packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) nextHeader); 1214 return packet; 1215 } 1216 1217 @Test testApfFilterIPv4()1218 public void testApfFilterIPv4() throws Exception { 1219 MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 1220 LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19); 1221 LinkProperties lp = new LinkProperties(); 1222 lp.addLinkAddress(link); 1223 1224 ApfConfiguration config = getDefaultConfig(); 1225 config.multicastFilter = DROP_MULTICAST; 1226 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, 1227 mDependencies); 1228 apfFilter.setLinkProperties(lp); 1229 1230 byte[] program = ipClientCallback.getApfProgram(); 1231 1232 // Verify empty packet of 100 zero bytes is passed 1233 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 1234 assertPass(program, packet.array()); 1235 1236 // Verify unicast IPv4 packet is passed 1237 put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR); 1238 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); 1239 put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR); 1240 assertPass(program, packet.array()); 1241 1242 // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088) 1243 put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS); 1244 assertDrop(program, packet.array()); 1245 put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR); 1246 assertDrop(program, packet.array()); 1247 1248 // Verify multicast/broadcast IPv4, not DHCP to us, is dropped 1249 put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS); 1250 assertDrop(program, packet.array()); 1251 packet.put(IP_HEADER_OFFSET, (byte) 0x45); 1252 assertDrop(program, packet.array()); 1253 packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP); 1254 assertDrop(program, packet.array()); 1255 packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT); 1256 assertDrop(program, packet.array()); 1257 put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR); 1258 assertDrop(program, packet.array()); 1259 put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR); 1260 assertDrop(program, packet.array()); 1261 put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS); 1262 assertDrop(program, packet.array()); 1263 1264 // Verify broadcast IPv4 DHCP to us is passed 1265 put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR); 1266 assertPass(program, packet.array()); 1267 1268 // Verify unicast IPv4 DHCP to us is passed 1269 put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR); 1270 assertPass(program, packet.array()); 1271 1272 apfFilter.shutdown(); 1273 } 1274 1275 @Test testApfFilterIPv6()1276 public void testApfFilterIPv6() throws Exception { 1277 MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 1278 ApfConfiguration config = getDefaultConfig(); 1279 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, 1280 mDependencies); 1281 byte[] program = ipClientCallback.getApfProgram(); 1282 1283 // Verify empty IPv6 packet is passed 1284 ByteBuffer packet = makeIpv6Packet(IPPROTO_UDP); 1285 assertPass(program, packet.array()); 1286 1287 // Verify empty ICMPv6 packet is passed 1288 packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); 1289 assertPass(program, packet.array()); 1290 1291 // Verify empty ICMPv6 NA packet is passed 1292 packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT); 1293 assertPass(program, packet.array()); 1294 1295 // Verify ICMPv6 NA to ff02::1 is dropped 1296 put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS); 1297 assertDrop(program, packet.array()); 1298 1299 // Verify ICMPv6 NA to ff02::2 is dropped 1300 put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS); 1301 assertDrop(program, packet.array()); 1302 1303 // Verify ICMPv6 NA to Solicited-Node Multicast is passed 1304 put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_SOLICITED_NODE_MULTICAST_ADDRESS); 1305 assertPass(program, packet.array()); 1306 1307 // Verify ICMPv6 RS to any is dropped 1308 packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION); 1309 assertDrop(program, packet.array()); 1310 put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS); 1311 assertDrop(program, packet.array()); 1312 1313 apfFilter.shutdown(); 1314 } 1315 fillQuestionSection(ByteBuffer buf, String... qnames)1316 private static void fillQuestionSection(ByteBuffer buf, String... qnames) throws IOException { 1317 buf.put(new DnsPacket.DnsHeader(0 /* id */, 0 /* flags */, qnames.length, 0 /* ancount */) 1318 .getBytes()); 1319 for (String qname : qnames) { 1320 buf.put(DnsPacket.DnsRecord.makeQuestion(qname, 0 /* nsType */, 0 /* nsClass */) 1321 .getBytes()); 1322 } 1323 } 1324 makeMdnsV4Packet(String... qnames)1325 private static byte[] makeMdnsV4Packet(String... qnames) throws IOException { 1326 final ByteBuffer buf = ByteBuffer.wrap(new byte[256]); 1327 final PacketBuilder builder = new PacketBuilder(buf); 1328 builder.writeL2Header(MacAddress.fromString("11:22:33:44:55:66"), 1329 MacAddress.fromBytes(ETH_MULTICAST_MDNS_v4_MAC_ADDRESS), 1330 (short) ETH_P_IP); 1331 builder.writeIpv4Header((byte) 0 /* tos */, (short) 0 /* id */, 1332 (short) 0 /* flagsAndFragmentOffset */, (byte) 0 /* ttl */, (byte) IPPROTO_UDP, 1333 (Inet4Address) Inet4Address.getByAddress(IPV4_SOURCE_ADDR), 1334 (Inet4Address) Inet4Address.getByAddress(IPV4_MDNS_MULTICAST_ADDR)); 1335 builder.writeUdpHeader((short) MDNS_UDP_PORT, (short) MDNS_UDP_PORT); 1336 fillQuestionSection(buf, qnames); 1337 return builder.finalizePacket().array(); 1338 } 1339 makeMdnsV6Packet(String... qnames)1340 private static byte[] makeMdnsV6Packet(String... qnames) throws IOException { 1341 ByteBuffer buf = ByteBuffer.wrap(new byte[256]); 1342 final PacketBuilder builder = new PacketBuilder(buf); 1343 builder.writeL2Header(MacAddress.fromString("11:22:33:44:55:66"), 1344 MacAddress.fromBytes(ETH_MULTICAST_MDNS_V6_MAC_ADDRESS), 1345 (short) ETH_P_IPV6); 1346 builder.writeIpv6Header(0x680515ca /* vtf */, (byte) IPPROTO_UDP, (short) 0 /* hopLimit */, 1347 (Inet6Address) InetAddress.getByAddress(IPV6_ANOTHER_ADDR), 1348 (Inet6Address) Inet6Address.getByAddress(IPV6_MDNS_MULTICAST_ADDR)); 1349 builder.writeUdpHeader((short) MDNS_UDP_PORT, (short) MDNS_UDP_PORT); 1350 fillQuestionSection(buf, qnames); 1351 return builder.finalizePacket().array(); 1352 } 1353 putLabel(ByteBuffer buf, String label)1354 private static void putLabel(ByteBuffer buf, String label) { 1355 final byte[] bytes = label.getBytes(StandardCharsets.UTF_8); 1356 buf.put((byte) bytes.length); 1357 buf.put(bytes); 1358 } 1359 putPointer(ByteBuffer buf, int offset)1360 private static void putPointer(ByteBuffer buf, int offset) { 1361 short pointer = (short) (offset | 0xc000); 1362 buf.putShort(pointer); 1363 } 1364 1365 1366 // Simplistic DNS compression code that intentionally does not depend on production code. getDnsLabels(int startOffset, String... names)1367 private static List<Pair<Integer, String>> getDnsLabels(int startOffset, String... names) { 1368 // Maps all possible name suffixes to packet offsets. 1369 final HashMap<String, Integer> mPointerOffsets = new HashMap<>(); 1370 final List<Pair<Integer, String>> out = new ArrayList<>(); 1371 int offset = startOffset; 1372 for (int i = 0; i < names.length; i++) { 1373 String name = names[i]; 1374 while (true) { 1375 if (name.length() == 0) { 1376 out.add(label("")); 1377 offset += 1 + 4; // 1-byte label, DNS query 1378 break; 1379 } 1380 1381 final int pointerOffset = mPointerOffsets.getOrDefault(name, -1); 1382 if (pointerOffset != -1) { 1383 out.add(pointer(pointerOffset)); 1384 offset += 2 + 4; // 2-byte pointer, DNS query 1385 break; 1386 } 1387 1388 mPointerOffsets.put(name, offset); 1389 1390 final int indexOfDot = name.indexOf("."); 1391 final String label; 1392 if (indexOfDot == -1) { 1393 label = name; 1394 name = ""; 1395 } else { 1396 label = name.substring(0, indexOfDot); 1397 name = name.substring(indexOfDot + 1); 1398 } 1399 out.add(label(label)); 1400 offset += 1 + label.length(); 1401 } 1402 } 1403 return out; 1404 } 1405 label(String label)1406 static Pair<Integer, String> label(String label) { 1407 return Pair.create(label.length(), label); 1408 } 1409 pointer(int offset)1410 static Pair<Integer, String> pointer(int offset) { 1411 return Pair.create(0xc000 | offset, null); 1412 } 1413 1414 @Test testGetDnsLabels()1415 public void testGetDnsLabels() throws Exception { 1416 int startOffset = 12; 1417 List<Pair<Integer, String>> actual = getDnsLabels(startOffset, "myservice.tcp.local"); 1418 assertEquals(4, actual.size()); 1419 assertEquals(label("myservice"), actual.get(0)); 1420 assertEquals(label("tcp"), actual.get(1)); 1421 assertEquals(label("local"), actual.get(2)); 1422 assertEquals(label(""), actual.get(3)); 1423 1424 startOffset = 30; 1425 actual = getDnsLabels(startOffset, 1426 "myservice.tcp.local", "foo.tcp.local", "myhostname.local", "bar.udp.local", 1427 "foo.myhostname.local"); 1428 final int tcpLocalOffset = startOffset + 1 + "myservice".length(); 1429 final int localOffset = startOffset + 1 + "myservice".length() + 1 + "tcp".length(); 1430 final int myhostnameLocalOffset = 30 1431 + 1 + "myservice".length() + 1 + "tcp".length() + 1 + "local".length() + 1 + 4 1432 + 1 + "foo".length() + 2 + 4; 1433 1434 assertEquals(13, actual.size()); 1435 assertEquals(label("myservice"), actual.get(0)); 1436 assertEquals(label("tcp"), actual.get(1)); 1437 assertEquals(label("local"), actual.get(2)); 1438 assertEquals(label(""), actual.get(3)); 1439 assertEquals(label("foo"), actual.get(4)); 1440 assertEquals(pointer(tcpLocalOffset), actual.get(5)); 1441 assertEquals(label("myhostname"), actual.get(6)); 1442 assertEquals(pointer(localOffset), actual.get(7)); 1443 assertEquals(label("bar"), actual.get(8)); 1444 assertEquals(label("udp"), actual.get(9)); 1445 assertEquals(pointer(localOffset), actual.get(10)); 1446 assertEquals(label("foo"), actual.get(11)); 1447 assertEquals(pointer(myhostnameLocalOffset), actual.get(12)); 1448 1449 } 1450 makeMdnsCompressedV6Packet(String... names)1451 private static byte[] makeMdnsCompressedV6Packet(String... names) throws IOException { 1452 ByteBuffer questions = ByteBuffer.allocate(1500); 1453 questions.put(new DnsPacket.DnsHeader(123, 0, names.length, 0).getBytes()); 1454 final List<Pair<Integer, String>> labels = getDnsLabels(questions.position(), names); 1455 for (Pair<Integer, String> label : labels) { 1456 final String name = label.second; 1457 if (name == null) { 1458 putPointer(questions, label.first); 1459 } else { 1460 putLabel(questions, name); 1461 } 1462 if (TextUtils.isEmpty(name)) { 1463 questions.put(new byte[4]); 1464 } 1465 } 1466 questions.flip(); 1467 1468 ByteBuffer buf = PacketBuilder.allocate(/*hasEther=*/ true, IPPROTO_IPV6, IPPROTO_UDP, 1469 questions.limit()); 1470 final PacketBuilder builder = new PacketBuilder(buf); 1471 builder.writeL2Header(MacAddress.fromString("11:22:33:44:55:66"), 1472 MacAddress.fromBytes(ETH_MULTICAST_MDNS_V6_MAC_ADDRESS), 1473 (short) ETH_P_IPV6); 1474 builder.writeIpv6Header(0x680515ca /* vtf */, (byte) IPPROTO_UDP, (short) 0 /* hopLimit */, 1475 (Inet6Address) InetAddress.getByAddress(IPV6_ANOTHER_ADDR), 1476 (Inet6Address) Inet6Address.getByAddress(IPV6_MDNS_MULTICAST_ADDR)); 1477 builder.writeUdpHeader((short) MDNS_UDP_PORT, (short) MDNS_UDP_PORT); 1478 1479 buf.put(questions); 1480 1481 return builder.finalizePacket().array(); 1482 } 1483 makeMdnsCompressedV6Packet()1484 private static byte[] makeMdnsCompressedV6Packet() throws IOException { 1485 return makeMdnsCompressedV6Packet("myservice.tcp.local", "googlecast.tcp.local", 1486 "matter.tcp.local", "myhostname.local"); 1487 } 1488 makeMdnsCompressedV6PacketWithManyNames()1489 private static byte[] makeMdnsCompressedV6PacketWithManyNames() throws IOException { 1490 return makeMdnsCompressedV6Packet("myservice.tcp.local", "googlecast.tcp.local", 1491 "matter.tcp.local", "myhostname.local", "myhostname2.local", "myhostname3.local", 1492 "myhostname4.local", "myhostname5.local", "myhostname6.local", "myhostname7.local"); 1493 1494 } 1495 1496 /** Adds to the program a no-op instruction that is one byte long. */ addOneByteNoop(ApfGenerator gen)1497 private void addOneByteNoop(ApfGenerator gen) { 1498 gen.addOr(0); 1499 } 1500 1501 @Test testAddOneByteNoopAddsOneByte()1502 public void testAddOneByteNoopAddsOneByte() throws Exception { 1503 ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION); 1504 addOneByteNoop(gen); 1505 assertEquals(1, gen.generate().length); 1506 1507 final int count = 42; 1508 gen = new ApfGenerator(MIN_APF_VERSION); 1509 for (int i = 0; i < count; i++) { 1510 addOneByteNoop(gen); 1511 } 1512 assertEquals(count, gen.generate().length); 1513 } 1514 1515 @Test testQnameEncoding()1516 public void testQnameEncoding() { 1517 String[] qname = new String[]{"abcd", "ef", "日本"}; 1518 byte[] encodedQname = ApfFilter.encodeQname(qname); 1519 Assert.assertArrayEquals( 1520 new byte[]{0x04, 0x61, 0x62, 0x63, 0x64, 0x02, 0x65, 0x66, 0x06, (byte) 0xe6, 1521 (byte) 0x97, (byte) 0xa5, (byte) 0xe6, (byte) 0x9c, (byte) 0xac, 0x00}, 1522 encodedQname); 1523 } 1524 1525 @Test testApfFilterMdns()1526 public void testApfFilterMdns() throws Exception { 1527 final byte[] unicastIpv4Addr = {(byte) 192, 0, 2, 63}; 1528 1529 MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 1530 LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24); 1531 LinkProperties lp = new LinkProperties(); 1532 lp.addLinkAddress(link); 1533 1534 ApfConfiguration config = getDefaultConfig(); 1535 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, 1536 mDependencies); 1537 apfFilter.setLinkProperties(lp); 1538 1539 // Construct IPv4 mDNS packet 1540 byte[] mdnsv4packet = makeMdnsV4Packet("test.local"); 1541 byte[] mdnsv6packet = makeMdnsV6Packet("test.local"); 1542 byte[] program = ipClientCallback.getApfProgram(); 1543 // mDNSv4 packet is passed if no mDns filter is turned on 1544 assertPass(program, mdnsv4packet); 1545 // mDNSv6 packet is passed if no mDNS filter is turned on 1546 assertPass(program, mdnsv6packet); 1547 1548 // mDNSv4 packet with qname in the allowlist is passed 1549 apfFilter.addToMdnsAllowList(new String[]{"test", "local"}); 1550 apfFilter.addToMdnsAllowList(new String[]{"abcd", "local"}); 1551 apfFilter.setMulticastFilter(true); 1552 program = ipClientCallback.getApfProgram(); 1553 assertPass(program, mdnsv4packet); 1554 assertPass(program, mdnsv6packet); 1555 1556 mdnsv4packet = makeMdnsV4Packet("abcd.local"); 1557 mdnsv6packet = makeMdnsV6Packet("abcd.local"); 1558 assertPass(program, mdnsv4packet); 1559 assertPass(program, mdnsv6packet); 1560 1561 // mDNSv4 packet with qname not in the allowlist is dropped 1562 mdnsv4packet = makeMdnsV4Packet("ffff.local"); 1563 mdnsv6packet = makeMdnsV6Packet("ffff.local"); 1564 assertDrop(program, mdnsv4packet); 1565 assertDrop(program, mdnsv6packet); 1566 1567 apfFilter.removeFromAllowList(new String[]{"abcd", "local"}); 1568 program = ipClientCallback.getApfProgram(); 1569 mdnsv4packet = makeMdnsV4Packet("abcd.local"); 1570 mdnsv6packet = makeMdnsV6Packet("abcd.local"); 1571 assertDrop(program, mdnsv4packet); 1572 assertDrop(program, mdnsv6packet); 1573 1574 apfFilter.shutdown(); 1575 } 1576 generateDnsFilter(boolean ipv6, String... labels)1577 private ApfGenerator generateDnsFilter(boolean ipv6, String... labels) throws Exception { 1578 ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION); 1579 gen.addLoadImmediate(R1, ipv6 ? IPV6_HEADER_LEN : IPV4_HEADER_LEN); 1580 DnsUtils.generateFilter(gen, labels); 1581 return gen; 1582 } 1583 doTestDnsParsing(boolean expectPass, boolean ipv6, String filterName, byte[] pkt)1584 private void doTestDnsParsing(boolean expectPass, boolean ipv6, String filterName, 1585 byte[] pkt) throws Exception { 1586 final String[] labels = filterName.split(/*regex=*/ "[.]"); 1587 ApfGenerator gen = generateDnsFilter(ipv6, labels); 1588 1589 // Hack to prevent the APF instruction limit triggering. 1590 for (int i = 0; i < 500; i++) { 1591 addOneByteNoop(gen); 1592 } 1593 1594 byte[] program = gen.generate(); 1595 Log.d(TAG, "prog_len=" + program.length); 1596 if (expectPass) { 1597 assertPass(program, pkt, 0); 1598 } else { 1599 assertDrop(program, pkt, 0); 1600 } 1601 } 1602 doTestDnsParsing(boolean expectPass, boolean ipv6, String filterName, String... packetNames)1603 private void doTestDnsParsing(boolean expectPass, boolean ipv6, String filterName, 1604 String... packetNames) throws Exception { 1605 final byte[] pkt = ipv6 ? makeMdnsV6Packet(packetNames) : makeMdnsV4Packet(packetNames); 1606 doTestDnsParsing(expectPass, ipv6, filterName, pkt); 1607 } 1608 1609 @Test testDnsParsing()1610 public void testDnsParsing() throws Exception { 1611 final boolean ipv4 = false, ipv6 = true; 1612 1613 // Packets with one question. 1614 // Names don't start with _ because DnsPacket thinks such names are invalid. 1615 doTestDnsParsing(true, ipv6, "googlecast.tcp.local", "googlecast.tcp.local"); 1616 doTestDnsParsing(true, ipv4, "googlecast.tcp.local", "googlecast.tcp.local"); 1617 doTestDnsParsing(false, ipv6, "googlecast.tcp.lozal", "googlecast.tcp.local"); 1618 doTestDnsParsing(false, ipv4, "googlecast.tcp.lozal", "googlecast.tcp.local"); 1619 doTestDnsParsing(false, ipv6, "googlecast.udp.local", "googlecast.tcp.local"); 1620 doTestDnsParsing(false, ipv4, "googlecast.udp.local", "googlecast.tcp.local"); 1621 1622 // Packets with multiple questions that can't be compressed. Not realistic for MDNS since 1623 // everything ends in .local, but useful to ensure only the non-compression code is tested. 1624 doTestDnsParsing(true, ipv6, "googlecast.tcp.local", 1625 "googlecast.tcp.local", "developer.android.com"); 1626 doTestDnsParsing(true, ipv4, "googlecast.tcp.local", 1627 "developer.android.com", "googlecast.tcp.local"); 1628 doTestDnsParsing(false, ipv4, "googlecast.tcp.local", 1629 "developer.android.com", "googlecast.tcp.invalid"); 1630 doTestDnsParsing(true, ipv6, "googlecast.tcp.local", 1631 "developer.android.com", "www.google.co.jp", "googlecast.tcp.local"); 1632 doTestDnsParsing(false, ipv4, "veryverylongservicename.tcp.local", 1633 "www.google.co.jp", "veryverylongservicename.tcp.invalid"); 1634 doTestDnsParsing(true, ipv6, "googlecast.tcp.local", 1635 "www.google.co.jp", "googlecast.tcp.local", "developer.android.com"); 1636 1637 // Name with duplicate labels. 1638 doTestDnsParsing(true, ipv6, "local.tcp.local", "local.tcp.local"); 1639 1640 final byte[] pkt = makeMdnsCompressedV6Packet(); 1641 doTestDnsParsing(true, ipv6, "googlecast.tcp.local", pkt); 1642 doTestDnsParsing(true, ipv6, "matter.tcp.local", pkt); 1643 doTestDnsParsing(true, ipv6, "myservice.tcp.local", pkt); 1644 doTestDnsParsing(false, ipv6, "otherservice.tcp.local", pkt); 1645 } 1646 doTestDnsParsingProgramLength(int expectedLength, String filterName)1647 private void doTestDnsParsingProgramLength(int expectedLength, 1648 String filterName) throws Exception { 1649 final String[] labels = filterName.split(/*regex=*/ "[.]"); 1650 1651 ApfGenerator gen = generateDnsFilter(/*ipv6=*/ true, labels); 1652 assertEquals("Program for " + filterName + " had unexpected length:", 1653 expectedLength, gen.generate().length); 1654 } 1655 1656 /** 1657 * Rough metric of code size. Checks how large the generated filter is in various scenarios. 1658 * Helps ensure any changes to the code do not substantially increase APF code size. 1659 */ 1660 @Test testDnsParsingProgramLength()1661 public void testDnsParsingProgramLength() throws Exception { 1662 doTestDnsParsingProgramLength(237, "MyDevice.local"); 1663 doTestDnsParsingProgramLength(285, "_googlecast.tcp.local"); 1664 doTestDnsParsingProgramLength(291, "_googlecast12345.tcp.local"); 1665 doTestDnsParsingProgramLength(244, "_googlecastZtcp.local"); 1666 doTestDnsParsingProgramLength(249, "_googlecastZtcp12345.local"); 1667 } 1668 doTestDnsParsingNecessaryOverhead(int expectedNecessaryOverhead, String filterName, byte[] pkt, String description)1669 private void doTestDnsParsingNecessaryOverhead(int expectedNecessaryOverhead, 1670 String filterName, byte[] pkt, String description) throws Exception { 1671 final String[] labels = filterName.split(/*regex=*/ "[.]"); 1672 1673 // Check that the generated code, when the program contains the specified number of extra 1674 // bytes, is capable of dropping the packet. 1675 ApfGenerator gen = generateDnsFilter(/*ipv6=*/ true, labels); 1676 for (int i = 0; i < expectedNecessaryOverhead; i++) { 1677 addOneByteNoop(gen); 1678 } 1679 final byte[] programWithJustEnoughOverhead = gen.generate(); 1680 assertVerdict( 1681 "Overhead too low: filter for " + filterName + " with " + expectedNecessaryOverhead 1682 + " extra instructions unexpectedly passed " + description, 1683 DROP, programWithJustEnoughOverhead, pkt, 0); 1684 1685 if (expectedNecessaryOverhead == 0) return; 1686 1687 // Check that the generated code, without the specified number of extra program bytes, 1688 // cannot correctly drop the packet because it hits the interpreter instruction limit. 1689 gen = generateDnsFilter(/*ipv6=*/ true, labels); 1690 for (int i = 0; i < expectedNecessaryOverhead - 1; i++) { 1691 addOneByteNoop(gen); 1692 } 1693 final byte[] programWithNotEnoughOverhead = gen.generate(); 1694 1695 assertVerdict( 1696 "Overhead too high: filter for " + filterName + " with " + expectedNecessaryOverhead 1697 + " extra instructions unexpectedly dropped " + description, 1698 PASS, programWithNotEnoughOverhead, pkt, 0); 1699 } 1700 doTestDnsParsingNecessaryOverhead(int expectedNecessaryOverhead, String filterName, String... packetNames)1701 private void doTestDnsParsingNecessaryOverhead(int expectedNecessaryOverhead, 1702 String filterName, String... packetNames) throws Exception { 1703 doTestDnsParsingNecessaryOverhead(expectedNecessaryOverhead, filterName, 1704 makeMdnsV6Packet(packetNames), 1705 "IPv6 MDNS packet containing: " + Arrays.toString(packetNames)); 1706 } 1707 1708 /** 1709 * Rough metric of filter efficiency. Because the filter uses backwards jumps, on complex 1710 * packets it will not finish running before the interpreter hits the maximum number of allowed 1711 * instructions (== number of bytes in the program) and unconditionally accepts the packet. 1712 * This test checks much extra code the program must contain in order for the generated filter 1713 * to successfully drop the packet. It helps ensure any changes to the code do not reduce the 1714 * complexity of packets that the APF code can drop. 1715 */ 1716 @Test testDnsParsingNecessaryOverhead()1717 public void testDnsParsingNecessaryOverhead() throws Exception { 1718 // Simple packets can be parsed with zero extra code. 1719 doTestDnsParsingNecessaryOverhead(0, "googlecast.tcp.local", 1720 "matter.tcp.local", "developer.android.com"); 1721 1722 doTestDnsParsingNecessaryOverhead(0, "googlecast.tcp.local", 1723 "developer.android.com", "matter.tcp.local"); 1724 1725 doTestDnsParsingNecessaryOverhead(0, "googlecast.tcp.local", 1726 "developer.android.com", "matter.tcp.local", "www.google.co.jp"); 1727 1728 doTestDnsParsingNecessaryOverhead(0, "googlecast.tcp.local", 1729 "developer.android.com", "matter.tcp.local", "www.google.co.jp", 1730 "example.org"); 1731 1732 // More complicated packets cause more instructions to be run and can only be dropped if 1733 // the program contains lots of extra code. 1734 doTestDnsParsingNecessaryOverhead(57, "googlecast.tcp.local", 1735 "developer.android.com", "matter.tcp.local", "www.google.co.jp", 1736 "example.org", "otherexample.net"); 1737 1738 doTestDnsParsingNecessaryOverhead(115, "googlecast.tcp.local", 1739 "developer.android.com", "matter.tcp.local", "www.google.co.jp", 1740 "example.org", "otherexample.net", "docs.new"); 1741 1742 doTestDnsParsingNecessaryOverhead(0, "foo.tcp.local", 1743 makeMdnsCompressedV6Packet(), "compressed packet"); 1744 1745 doTestDnsParsingNecessaryOverhead(235, "foo.tcp.local", 1746 makeMdnsCompressedV6PacketWithManyNames(), "compressed packet with many names"); 1747 } 1748 1749 @Test testApfFilterMulticast()1750 public void testApfFilterMulticast() throws Exception { 1751 final byte[] unicastIpv4Addr = {(byte)192,0,2,63}; 1752 final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255}; 1753 final byte[] multicastIpv4Addr = {(byte)224,0,0,1}; 1754 final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb}; 1755 1756 MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 1757 LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24); 1758 LinkProperties lp = new LinkProperties(); 1759 lp.addLinkAddress(link); 1760 1761 ApfConfiguration config = getDefaultConfig(); 1762 config.ieee802_3Filter = DROP_802_3_FRAMES; 1763 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, 1764 mDependencies); 1765 apfFilter.setLinkProperties(lp); 1766 1767 byte[] program = ipClientCallback.getApfProgram(); 1768 1769 // Construct IPv4 and IPv6 multicast packets. 1770 ByteBuffer mcastv4packet = makeIpv4Packet(IPPROTO_UDP); 1771 put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr); 1772 1773 ByteBuffer mcastv6packet = makeIpv6Packet(IPPROTO_UDP); 1774 put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr); 1775 1776 // Construct IPv4 broadcast packet. 1777 ByteBuffer bcastv4packet1 = makeIpv4Packet(IPPROTO_UDP); 1778 bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS); 1779 bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); 1780 put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr); 1781 1782 ByteBuffer bcastv4packet2 = makeIpv4Packet(IPPROTO_UDP); 1783 bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS); 1784 bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); 1785 put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS); 1786 1787 // Construct IPv4 broadcast with L2 unicast address packet (b/30231088). 1788 ByteBuffer bcastv4unicastl2packet = makeIpv4Packet(IPPROTO_UDP); 1789 bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR); 1790 bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); 1791 put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr); 1792 1793 // Verify initially disabled multicast filter is off 1794 assertPass(program, mcastv4packet.array()); 1795 assertPass(program, mcastv6packet.array()); 1796 assertPass(program, bcastv4packet1.array()); 1797 assertPass(program, bcastv4packet2.array()); 1798 assertPass(program, bcastv4unicastl2packet.array()); 1799 1800 // Turn on multicast filter and verify it works 1801 ipClientCallback.resetApfProgramWait(); 1802 apfFilter.setMulticastFilter(true); 1803 program = ipClientCallback.getApfProgram(); 1804 assertDrop(program, mcastv4packet.array()); 1805 assertDrop(program, mcastv6packet.array()); 1806 assertDrop(program, bcastv4packet1.array()); 1807 assertDrop(program, bcastv4packet2.array()); 1808 assertDrop(program, bcastv4unicastl2packet.array()); 1809 1810 // Turn off multicast filter and verify it's off 1811 ipClientCallback.resetApfProgramWait(); 1812 apfFilter.setMulticastFilter(false); 1813 program = ipClientCallback.getApfProgram(); 1814 assertPass(program, mcastv4packet.array()); 1815 assertPass(program, mcastv6packet.array()); 1816 assertPass(program, bcastv4packet1.array()); 1817 assertPass(program, bcastv4packet2.array()); 1818 assertPass(program, bcastv4unicastl2packet.array()); 1819 1820 // Verify it can be initialized to on 1821 ipClientCallback.resetApfProgramWait(); 1822 apfFilter.shutdown(); 1823 config.multicastFilter = DROP_MULTICAST; 1824 config.ieee802_3Filter = DROP_802_3_FRAMES; 1825 apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, mDependencies); 1826 apfFilter.setLinkProperties(lp); 1827 program = ipClientCallback.getApfProgram(); 1828 assertDrop(program, mcastv4packet.array()); 1829 assertDrop(program, mcastv6packet.array()); 1830 assertDrop(program, bcastv4packet1.array()); 1831 assertDrop(program, bcastv4unicastl2packet.array()); 1832 1833 // Verify that ICMPv6 multicast is not dropped. 1834 mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); 1835 assertPass(program, mcastv6packet.array()); 1836 1837 apfFilter.shutdown(); 1838 } 1839 1840 @Test testApfFilterMulticastPingWhileDozing()1841 public void testApfFilterMulticastPingWhileDozing() throws Exception { 1842 MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 1843 ApfFilter apfFilter = setupApfFilter(ipClientCallback, getDefaultConfig()); 1844 1845 // Construct a multicast ICMPv6 ECHO request. 1846 final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb}; 1847 ByteBuffer packet = makeIpv6Packet(IPPROTO_ICMPV6); 1848 packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE); 1849 put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr); 1850 1851 // Normally, we let multicast pings alone... 1852 assertPass(ipClientCallback.getApfProgram(), packet.array()); 1853 1854 // ...and even while dozing... 1855 apfFilter.setDozeMode(true); 1856 assertPass(ipClientCallback.getApfProgram(), packet.array()); 1857 1858 // ...but when the multicast filter is also enabled, drop the multicast pings to save power. 1859 apfFilter.setMulticastFilter(true); 1860 assertDrop(ipClientCallback.getApfProgram(), packet.array()); 1861 1862 // However, we should still let through all other ICMPv6 types. 1863 ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone()); 1864 setIpv6VersionFields(packet); 1865 packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_ICMPV6); 1866 raPacket.put(ICMP6_TYPE_OFFSET, (byte) NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT); 1867 assertPass(ipClientCallback.getApfProgram(), raPacket.array()); 1868 1869 // Now wake up from doze mode to ensure that we no longer drop the packets. 1870 // (The multicast filter is still enabled at this point). 1871 apfFilter.setDozeMode(false); 1872 assertPass(ipClientCallback.getApfProgram(), packet.array()); 1873 1874 apfFilter.shutdown(); 1875 } 1876 1877 @Test testApfFilter802_3()1878 public void testApfFilter802_3() throws Exception { 1879 MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 1880 ApfConfiguration config = getDefaultConfig(); 1881 ApfFilter apfFilter = setupApfFilter(ipClientCallback, config); 1882 byte[] program = ipClientCallback.getApfProgram(); 1883 1884 // Verify empty packet of 100 zero bytes is passed 1885 // Note that eth-type = 0 makes it an IEEE802.3 frame 1886 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 1887 assertPass(program, packet.array()); 1888 1889 // Verify empty packet with IPv4 is passed 1890 setIpv4VersionFields(packet); 1891 assertPass(program, packet.array()); 1892 1893 // Verify empty IPv6 packet is passed 1894 setIpv6VersionFields(packet); 1895 assertPass(program, packet.array()); 1896 1897 // Now turn on the filter 1898 ipClientCallback.resetApfProgramWait(); 1899 apfFilter.shutdown(); 1900 config.ieee802_3Filter = DROP_802_3_FRAMES; 1901 apfFilter = setupApfFilter(ipClientCallback, config); 1902 program = ipClientCallback.getApfProgram(); 1903 1904 // Verify that IEEE802.3 frame is dropped 1905 // In this case ethtype is used for payload length 1906 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)(100 - 14)); 1907 assertDrop(program, packet.array()); 1908 1909 // Verify that IPv4 (as example of Ethernet II) frame will pass 1910 setIpv4VersionFields(packet); 1911 assertPass(program, packet.array()); 1912 1913 // Verify that IPv6 (as example of Ethernet II) frame will pass 1914 setIpv6VersionFields(packet); 1915 assertPass(program, packet.array()); 1916 1917 apfFilter.shutdown(); 1918 } 1919 1920 @Test testApfFilterEthTypeBL()1921 public void testApfFilterEthTypeBL() throws Exception { 1922 final int[] emptyBlackList = {}; 1923 final int[] ipv4BlackList = {ETH_P_IP}; 1924 final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6}; 1925 1926 MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 1927 ApfConfiguration config = getDefaultConfig(); 1928 ApfFilter apfFilter = setupApfFilter(ipClientCallback, config); 1929 byte[] program = ipClientCallback.getApfProgram(); 1930 1931 // Verify empty packet of 100 zero bytes is passed 1932 // Note that eth-type = 0 makes it an IEEE802.3 frame 1933 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 1934 assertPass(program, packet.array()); 1935 1936 // Verify empty packet with IPv4 is passed 1937 setIpv4VersionFields(packet); 1938 assertPass(program, packet.array()); 1939 1940 // Verify empty IPv6 packet is passed 1941 setIpv6VersionFields(packet); 1942 assertPass(program, packet.array()); 1943 1944 // Now add IPv4 to the black list 1945 ipClientCallback.resetApfProgramWait(); 1946 apfFilter.shutdown(); 1947 config.ethTypeBlackList = ipv4BlackList; 1948 apfFilter = setupApfFilter(ipClientCallback, config); 1949 program = ipClientCallback.getApfProgram(); 1950 1951 // Verify that IPv4 frame will be dropped 1952 setIpv4VersionFields(packet); 1953 assertDrop(program, packet.array()); 1954 1955 // Verify that IPv6 frame will pass 1956 setIpv6VersionFields(packet); 1957 assertPass(program, packet.array()); 1958 1959 // Now let us have both IPv4 and IPv6 in the black list 1960 ipClientCallback.resetApfProgramWait(); 1961 apfFilter.shutdown(); 1962 config.ethTypeBlackList = ipv4Ipv6BlackList; 1963 apfFilter = setupApfFilter(ipClientCallback, config); 1964 program = ipClientCallback.getApfProgram(); 1965 1966 // Verify that IPv4 frame will be dropped 1967 setIpv4VersionFields(packet); 1968 assertDrop(program, packet.array()); 1969 1970 // Verify that IPv6 frame will be dropped 1971 setIpv6VersionFields(packet); 1972 assertDrop(program, packet.array()); 1973 1974 apfFilter.shutdown(); 1975 } 1976 getProgram(MockIpClientCallback cb, ApfFilter filter, LinkProperties lp)1977 private byte[] getProgram(MockIpClientCallback cb, ApfFilter filter, LinkProperties lp) { 1978 cb.resetApfProgramWait(); 1979 filter.setLinkProperties(lp); 1980 return cb.getApfProgram(); 1981 } 1982 verifyArpFilter(byte[] program, int filterResult)1983 private void verifyArpFilter(byte[] program, int filterResult) { 1984 // Verify ARP request packet 1985 assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR)); 1986 assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR)); 1987 assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR)); 1988 1989 // Verify ARP reply packets from different source ip 1990 assertDrop(program, arpReply(IPV4_ANY_HOST_ADDR, IPV4_ANY_HOST_ADDR)); 1991 assertPass(program, arpReply(ANOTHER_IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR)); 1992 assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR1, IPV4_ANY_HOST_ADDR)); 1993 assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR2, IPV4_ANY_HOST_ADDR)); 1994 1995 // Verify unicast ARP reply packet is always accepted. 1996 assertPass(program, arpReply(IPV4_SOURCE_ADDR, MOCK_IPV4_ADDR)); 1997 assertPass(program, arpReply(IPV4_SOURCE_ADDR, ANOTHER_IPV4_ADDR)); 1998 assertPass(program, arpReply(IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR)); 1999 2000 // Verify GARP reply packets are always filtered 2001 assertDrop(program, garpReply()); 2002 } 2003 2004 @Test testApfFilterArp()2005 public void testApfFilterArp() throws Exception { 2006 MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 2007 ApfConfiguration config = getDefaultConfig(); 2008 config.multicastFilter = DROP_MULTICAST; 2009 config.ieee802_3Filter = DROP_802_3_FRAMES; 2010 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, 2011 mDependencies); 2012 2013 // Verify initially ARP request filter is off, and GARP filter is on. 2014 verifyArpFilter(ipClientCallback.getApfProgram(), PASS); 2015 2016 // Inform ApfFilter of our address and verify ARP filtering is on 2017 LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24); 2018 LinkProperties lp = new LinkProperties(); 2019 assertTrue(lp.addLinkAddress(linkAddress)); 2020 verifyArpFilter(getProgram(ipClientCallback, apfFilter, lp), DROP); 2021 2022 // Inform ApfFilter of loss of IP and verify ARP filtering is off 2023 verifyArpFilter(getProgram(ipClientCallback, apfFilter, new LinkProperties()), PASS); 2024 2025 apfFilter.shutdown(); 2026 } 2027 arpReply(byte[] sip, byte[] tip)2028 private static byte[] arpReply(byte[] sip, byte[] tip) { 2029 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 2030 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); 2031 put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER); 2032 put(packet, ARP_SOURCE_IP_ADDRESS_OFFSET, sip); 2033 put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip); 2034 return packet.array(); 2035 } 2036 arpRequestBroadcast(byte[] tip)2037 private static byte[] arpRequestBroadcast(byte[] tip) { 2038 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 2039 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); 2040 put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS); 2041 put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REQUEST_HEADER); 2042 put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip); 2043 return packet.array(); 2044 } 2045 garpReply()2046 private static byte[] garpReply() { 2047 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 2048 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); 2049 put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS); 2050 put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER); 2051 put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR); 2052 return packet.array(); 2053 } 2054 2055 private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 5}; 2056 private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 6}; 2057 private static final byte[] IPV4_ANOTHER_ADDR = {10, 0 , 0, 7}; 2058 private static final byte[] IPV6_KEEPALIVE_SRC_ADDR = 2059 {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf1}; 2060 private static final byte[] IPV6_KEEPALIVE_DST_ADDR = 2061 {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf2}; 2062 private static final byte[] IPV6_ANOTHER_ADDR = 2063 {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf5}; 2064 2065 @Test testApfFilterKeepaliveAck()2066 public void testApfFilterKeepaliveAck() throws Exception { 2067 final MockIpClientCallback cb = new MockIpClientCallback(); 2068 final ApfConfiguration config = getDefaultConfig(); 2069 config.multicastFilter = DROP_MULTICAST; 2070 config.ieee802_3Filter = DROP_802_3_FRAMES; 2071 final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog, 2072 mDependencies); 2073 byte[] program; 2074 final int srcPort = 12345; 2075 final int dstPort = 54321; 2076 final int seqNum = 2123456789; 2077 final int ackNum = 1234567890; 2078 final int anotherSrcPort = 23456; 2079 final int anotherDstPort = 65432; 2080 final int anotherSeqNum = 2123456780; 2081 final int anotherAckNum = 1123456789; 2082 final int slot1 = 1; 2083 final int slot2 = 2; 2084 final int window = 14480; 2085 final int windowScale = 4; 2086 2087 // src: 10.0.0.5, port: 12345 2088 // dst: 10.0.0.6, port: 54321 2089 InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR); 2090 InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR); 2091 2092 final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable(); 2093 parcel.srcAddress = srcAddr.getAddress(); 2094 parcel.srcPort = srcPort; 2095 parcel.dstAddress = dstAddr.getAddress(); 2096 parcel.dstPort = dstPort; 2097 parcel.seq = seqNum; 2098 parcel.ack = ackNum; 2099 2100 apfFilter.addTcpKeepalivePacketFilter(slot1, parcel); 2101 program = cb.getApfProgram(); 2102 2103 // Verify IPv4 keepalive ack packet is dropped 2104 // src: 10.0.0.6, port: 54321 2105 // dst: 10.0.0.5, port: 12345 2106 assertDrop(program, 2107 ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, 2108 dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */)); 2109 // Verify IPv4 non-keepalive ack packet from the same source address is passed 2110 assertPass(program, 2111 ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, 2112 dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */)); 2113 assertPass(program, 2114 ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, 2115 dstPort, srcPort, ackNum, seqNum + 1, 10 /* dataLength */)); 2116 // Verify IPv4 packet from another address is passed 2117 assertPass(program, 2118 ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort, 2119 anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */)); 2120 2121 // Remove IPv4 keepalive filter 2122 apfFilter.removeKeepalivePacketFilter(slot1); 2123 2124 try { 2125 // src: 2404:0:0:0:0:0:faf1, port: 12345 2126 // dst: 2404:0:0:0:0:0:faf2, port: 54321 2127 srcAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_SRC_ADDR); 2128 dstAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_DST_ADDR); 2129 2130 final TcpKeepalivePacketDataParcelable ipv6Parcel = 2131 new TcpKeepalivePacketDataParcelable(); 2132 ipv6Parcel.srcAddress = srcAddr.getAddress(); 2133 ipv6Parcel.srcPort = srcPort; 2134 ipv6Parcel.dstAddress = dstAddr.getAddress(); 2135 ipv6Parcel.dstPort = dstPort; 2136 ipv6Parcel.seq = seqNum; 2137 ipv6Parcel.ack = ackNum; 2138 2139 apfFilter.addTcpKeepalivePacketFilter(slot1, ipv6Parcel); 2140 program = cb.getApfProgram(); 2141 2142 // Verify IPv6 keepalive ack packet is dropped 2143 // src: 2404:0:0:0:0:0:faf2, port: 54321 2144 // dst: 2404:0:0:0:0:0:faf1, port: 12345 2145 assertDrop(program, 2146 ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR, 2147 dstPort, srcPort, ackNum, seqNum + 1)); 2148 // Verify IPv6 non-keepalive ack packet from the same source address is passed 2149 assertPass(program, 2150 ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR, 2151 dstPort, srcPort, ackNum + 100, seqNum)); 2152 // Verify IPv6 packet from another address is passed 2153 assertPass(program, 2154 ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort, 2155 anotherDstPort, anotherSeqNum, anotherAckNum)); 2156 2157 // Remove IPv6 keepalive filter 2158 apfFilter.removeKeepalivePacketFilter(slot1); 2159 2160 // Verify multiple filters 2161 apfFilter.addTcpKeepalivePacketFilter(slot1, parcel); 2162 apfFilter.addTcpKeepalivePacketFilter(slot2, ipv6Parcel); 2163 program = cb.getApfProgram(); 2164 2165 // Verify IPv4 keepalive ack packet is dropped 2166 // src: 10.0.0.6, port: 54321 2167 // dst: 10.0.0.5, port: 12345 2168 assertDrop(program, 2169 ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, 2170 dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */)); 2171 // Verify IPv4 non-keepalive ack packet from the same source address is passed 2172 assertPass(program, 2173 ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, 2174 dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */)); 2175 // Verify IPv4 packet from another address is passed 2176 assertPass(program, 2177 ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort, 2178 anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */)); 2179 2180 // Verify IPv6 keepalive ack packet is dropped 2181 // src: 2404:0:0:0:0:0:faf2, port: 54321 2182 // dst: 2404:0:0:0:0:0:faf1, port: 12345 2183 assertDrop(program, 2184 ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR, 2185 dstPort, srcPort, ackNum, seqNum + 1)); 2186 // Verify IPv6 non-keepalive ack packet from the same source address is passed 2187 assertPass(program, 2188 ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR, 2189 dstPort, srcPort, ackNum + 100, seqNum)); 2190 // Verify IPv6 packet from another address is passed 2191 assertPass(program, 2192 ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort, 2193 anotherDstPort, anotherSeqNum, anotherAckNum)); 2194 2195 // Remove keepalive filters 2196 apfFilter.removeKeepalivePacketFilter(slot1); 2197 apfFilter.removeKeepalivePacketFilter(slot2); 2198 } catch (UnsupportedOperationException e) { 2199 // TODO: support V6 packets 2200 } 2201 2202 program = cb.getApfProgram(); 2203 2204 // Verify IPv4, IPv6 packets are passed 2205 assertPass(program, 2206 ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, 2207 dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */)); 2208 assertPass(program, 2209 ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR, 2210 dstPort, srcPort, ackNum, seqNum + 1)); 2211 assertPass(program, 2212 ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, srcPort, 2213 dstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */)); 2214 assertPass(program, 2215 ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, srcPort, 2216 dstPort, anotherSeqNum, anotherAckNum)); 2217 2218 apfFilter.shutdown(); 2219 } 2220 ipv4TcpPacket(byte[] sip, byte[] dip, int sport, int dport, int seq, int ack, int dataLength)2221 private static byte[] ipv4TcpPacket(byte[] sip, byte[] dip, int sport, 2222 int dport, int seq, int ack, int dataLength) { 2223 final int totalLength = dataLength + IPV4_HEADER_LEN + IPV4_TCP_HEADER_LEN; 2224 2225 ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]); 2226 2227 // Ethertype and IPv4 header 2228 setIpv4VersionFields(packet); 2229 packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength); 2230 packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_TCP); 2231 put(packet, IPV4_SRC_ADDR_OFFSET, sip); 2232 put(packet, IPV4_DEST_ADDR_OFFSET, dip); 2233 packet.putShort(IPV4_TCP_SRC_PORT_OFFSET, (short) sport); 2234 packet.putShort(IPV4_TCP_DEST_PORT_OFFSET, (short) dport); 2235 packet.putInt(IPV4_TCP_SEQ_NUM_OFFSET, seq); 2236 packet.putInt(IPV4_TCP_ACK_NUM_OFFSET, ack); 2237 2238 // TCP header length 5(20 bytes), reserved 3 bits, NS=0 2239 packet.put(IPV4_TCP_HEADER_LENGTH_OFFSET, (byte) 0x50); 2240 // TCP flags: ACK set 2241 packet.put(IPV4_TCP_HEADER_FLAG_OFFSET, (byte) 0x10); 2242 return packet.array(); 2243 } 2244 ipv6TcpPacket(byte[] sip, byte[] tip, int sport, int dport, int seq, int ack)2245 private static byte[] ipv6TcpPacket(byte[] sip, byte[] tip, int sport, 2246 int dport, int seq, int ack) { 2247 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 2248 setIpv6VersionFields(packet); 2249 packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_TCP); 2250 put(packet, IPV6_SRC_ADDR_OFFSET, sip); 2251 put(packet, IPV6_DEST_ADDR_OFFSET, tip); 2252 packet.putShort(IPV6_TCP_SRC_PORT_OFFSET, (short) sport); 2253 packet.putShort(IPV6_TCP_DEST_PORT_OFFSET, (short) dport); 2254 packet.putInt(IPV6_TCP_SEQ_NUM_OFFSET, seq); 2255 packet.putInt(IPV6_TCP_ACK_NUM_OFFSET, ack); 2256 return packet.array(); 2257 } 2258 2259 @Test testApfFilterNattKeepalivePacket()2260 public void testApfFilterNattKeepalivePacket() throws Exception { 2261 final MockIpClientCallback cb = new MockIpClientCallback(); 2262 final ApfConfiguration config = getDefaultConfig(); 2263 config.multicastFilter = DROP_MULTICAST; 2264 config.ieee802_3Filter = DROP_802_3_FRAMES; 2265 final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog, 2266 mDependencies); 2267 byte[] program; 2268 final int srcPort = 1024; 2269 final int dstPort = 4500; 2270 final int slot1 = 1; 2271 // NAT-T keepalive 2272 final byte[] kaPayload = {(byte) 0xff}; 2273 final byte[] nonKaPayload = {(byte) 0xfe}; 2274 2275 // src: 10.0.0.5, port: 1024 2276 // dst: 10.0.0.6, port: 4500 2277 InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR); 2278 InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR); 2279 2280 final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable(); 2281 parcel.srcAddress = srcAddr.getAddress(); 2282 parcel.srcPort = srcPort; 2283 parcel.dstAddress = dstAddr.getAddress(); 2284 parcel.dstPort = dstPort; 2285 2286 apfFilter.addNattKeepalivePacketFilter(slot1, parcel); 2287 program = cb.getApfProgram(); 2288 2289 // Verify IPv4 keepalive packet is dropped 2290 // src: 10.0.0.6, port: 4500 2291 // dst: 10.0.0.5, port: 1024 2292 byte[] pkt = ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR, 2293 IPV4_KEEPALIVE_SRC_ADDR, dstPort, srcPort, 1 /* dataLength */); 2294 System.arraycopy(kaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, kaPayload.length); 2295 assertDrop(program, pkt); 2296 2297 // Verify a packet with payload length 1 byte but it is not 0xff will pass the filter. 2298 System.arraycopy(nonKaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, nonKaPayload.length); 2299 assertPass(program, pkt); 2300 2301 // Verify IPv4 non-keepalive response packet from the same source address is passed 2302 assertPass(program, 2303 ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR, 2304 dstPort, srcPort, 10 /* dataLength */)); 2305 2306 // Verify IPv4 non-keepalive response packet from other source address is passed 2307 assertPass(program, 2308 ipv4UdpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, 2309 dstPort, srcPort, 10 /* dataLength */)); 2310 2311 apfFilter.removeKeepalivePacketFilter(slot1); 2312 apfFilter.shutdown(); 2313 } 2314 ipv4UdpPacket(byte[] sip, byte[] dip, int sport, int dport, int dataLength)2315 private static byte[] ipv4UdpPacket(byte[] sip, byte[] dip, int sport, 2316 int dport, int dataLength) { 2317 final int totalLength = dataLength + IPV4_HEADER_LEN + UDP_HEADER_LEN; 2318 final int udpLength = UDP_HEADER_LEN + dataLength; 2319 ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]); 2320 2321 // Ethertype and IPv4 header 2322 setIpv4VersionFields(packet); 2323 packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength); 2324 packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_UDP); 2325 put(packet, IPV4_SRC_ADDR_OFFSET, sip); 2326 put(packet, IPV4_DEST_ADDR_OFFSET, dip); 2327 packet.putShort(IPV4_UDP_SRC_PORT_OFFSET, (short) sport); 2328 packet.putShort(IPV4_UDP_DEST_PORT_OFFSET, (short) dport); 2329 packet.putShort(IPV4_UDP_LENGTH_OFFSET, (short) udpLength); 2330 2331 return packet.array(); 2332 } 2333 addRdnssOption(ByteBuffer packet, int lifetime, String... servers)2334 private void addRdnssOption(ByteBuffer packet, int lifetime, String... servers) 2335 throws Exception { 2336 int optionLength = 1 + 2 * servers.length; // In 8-byte units 2337 packet.put((byte) ICMP6_RDNSS_OPTION_TYPE); // Type 2338 packet.put((byte) optionLength); // Length 2339 packet.putShort((short) 0); // Reserved 2340 packet.putInt(lifetime); // Lifetime 2341 for (String server : servers) { 2342 packet.put(InetAddress.getByName(server).getAddress()); 2343 } 2344 } 2345 addRioOption(ByteBuffer packet, int lifetime, String prefixString)2346 private void addRioOption(ByteBuffer packet, int lifetime, String prefixString) 2347 throws Exception { 2348 IpPrefix prefix = new IpPrefix(prefixString); 2349 2350 int optionLength; 2351 if (prefix.getPrefixLength() == 0) { 2352 optionLength = 1; 2353 } else if (prefix.getPrefixLength() <= 64) { 2354 optionLength = 2; 2355 } else { 2356 optionLength = 3; 2357 } 2358 2359 packet.put((byte) ICMP6_ROUTE_INFO_OPTION_TYPE); // Type 2360 packet.put((byte) optionLength); // Length in 8-byte units 2361 packet.put((byte) prefix.getPrefixLength()); // Prefix length 2362 packet.put((byte) 0b00011000); // Pref = high 2363 packet.putInt(lifetime); // Lifetime 2364 2365 byte[] prefixBytes = prefix.getRawAddress(); 2366 packet.put(prefixBytes, 0, (optionLength - 1) * 8); 2367 } 2368 addPioOption(ByteBuffer packet, int valid, int preferred, String prefixString)2369 private void addPioOption(ByteBuffer packet, int valid, int preferred, String prefixString) { 2370 IpPrefix prefix = new IpPrefix(prefixString); 2371 packet.put((byte) ICMP6_PREFIX_OPTION_TYPE); // Type 2372 packet.put((byte) 4); // Length in 8-byte units 2373 packet.put((byte) prefix.getPrefixLength()); // Prefix length 2374 packet.put((byte) 0b11000000); // L = 1, A = 1 2375 packet.putInt(valid); 2376 packet.putInt(preferred); 2377 packet.putInt(0); // Reserved 2378 packet.put(prefix.getRawAddress()); 2379 } 2380 buildLargeRa()2381 private byte[] buildLargeRa() throws Exception { 2382 InetAddress src = InetAddress.getByName("fe80::1234:abcd"); 2383 2384 ByteBuffer packet = ByteBuffer.wrap(new byte[1514]); 2385 packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6); 2386 packet.position(ETH_HEADER_LEN); 2387 2388 packet.putInt(0x60012345); // Version, tclass, flowlabel 2389 packet.putShort((short) 0); // Payload length; updated later 2390 packet.put((byte) IPPROTO_ICMPV6); // Next header 2391 packet.put((byte) 0xff); // Hop limit 2392 packet.put(src.getAddress()); // Source address 2393 packet.put(IPV6_ALL_NODES_ADDRESS); // Destination address 2394 2395 packet.put((byte) ICMP6_ROUTER_ADVERTISEMENT); // Type 2396 packet.put((byte) 0); // Code (0) 2397 packet.putShort((short) 0); // Checksum (ignored) 2398 packet.put((byte) 64); // Hop limit 2399 packet.put((byte) 0); // M/O, reserved 2400 packet.putShort((short) 1800); // Router lifetime 2401 packet.putInt(30_000); // Reachable time 2402 packet.putInt(1000); // Retrans timer 2403 2404 addRioOption(packet, 1200, "64:ff9b::/96"); 2405 addRdnssOption(packet, 7200, "2001:db8:1::1", "2001:db8:1::2"); 2406 addRioOption(packet, 2100, "2000::/3"); 2407 addRioOption(packet, 2400, "::/0"); 2408 addPioOption(packet, 600, 300, "2001:db8:a::/64"); 2409 addRioOption(packet, 1500, "2001:db8:c:d::/64"); 2410 addPioOption(packet, 86400, 43200, "fd95:d1e:12::/64"); 2411 2412 int length = packet.position(); 2413 packet.putShort(IPV6_PAYLOAD_LENGTH_OFFSET, (short) length); 2414 2415 // Don't pass the Ra constructor a packet that is longer than the actual RA. 2416 // This relies on the fact that all the relative writes to the byte buffer are at the end. 2417 byte[] packetArray = new byte[length]; 2418 packet.rewind(); 2419 packet.get(packetArray); 2420 return packetArray; 2421 } 2422 2423 @Test testRaToString()2424 public void testRaToString() throws Exception { 2425 MockIpClientCallback cb = new MockIpClientCallback(); 2426 ApfConfiguration config = getDefaultConfig(); 2427 TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog, mDependencies); 2428 2429 byte[] packet = buildLargeRa(); 2430 ApfFilter.Ra ra = apfFilter.new Ra(packet, packet.length); 2431 String expected = "RA fe80::1234:abcd -> ff02::1 1800s " 2432 + "2001:db8:a::/64 600s/300s fd95:d1e:12::/64 86400s/43200s " 2433 + "DNS 7200s 2001:db8:1::1 2001:db8:1::2 " 2434 + "RIO 1200s 64:ff9b::/96 RIO 2100s 2000::/3 " 2435 + "RIO 2400s ::/0 RIO 1500s 2001:db8:c:d::/64 "; 2436 assertEquals(expected, ra.toString()); 2437 } 2438 2439 // Verify that the last program pushed to the IpClient.Callback properly filters the 2440 // given packet for the given lifetime. verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime)2441 private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) { 2442 verifyRaLifetime(program, packet, lifetime, 0); 2443 } 2444 2445 // Verify that the last program pushed to the IpClient.Callback properly filters the 2446 // given packet for the given lifetime and programInstallTime. programInstallTime is 2447 // the time difference between when RA is last seen and the program is installed. verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime, int programInstallTime)2448 private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime, 2449 int programInstallTime) { 2450 final int FRACTION_OF_LIFETIME = 6; 2451 final int ageLimit = lifetime / FRACTION_OF_LIFETIME - programInstallTime; 2452 2453 // Verify new program should drop RA for 1/6th its lifetime and pass afterwards. 2454 assertDrop(program, packet.array()); 2455 assertDrop(program, packet.array(), ageLimit); 2456 assertPass(program, packet.array(), ageLimit + 1); 2457 assertPass(program, packet.array(), lifetime); 2458 // Verify RA checksum is ignored 2459 final short originalChecksum = packet.getShort(ICMP6_RA_CHECKSUM_OFFSET); 2460 packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345); 2461 assertDrop(program, packet.array()); 2462 packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345); 2463 assertDrop(program, packet.array()); 2464 packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum); 2465 2466 // Verify other changes to RA (e.g., a change in the source address) make it not match. 2467 final int offset = IPV6_SRC_ADDR_OFFSET + 5; 2468 final byte originalByte = packet.get(offset); 2469 packet.put(offset, (byte) (~originalByte)); 2470 assertPass(program, packet.array()); 2471 packet.put(offset, originalByte); 2472 assertDrop(program, packet.array()); 2473 } 2474 2475 // Test that when ApfFilter is shown the given packet, it generates a program to filter it 2476 // for the given lifetime. verifyRaLifetime(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback, ByteBuffer packet, int lifetime)2477 private void verifyRaLifetime(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback, 2478 ByteBuffer packet, int lifetime) throws IOException, ErrnoException { 2479 // Verify new program generated if ApfFilter witnesses RA 2480 ipClientCallback.resetApfProgramWait(); 2481 apfFilter.pretendPacketReceived(packet.array()); 2482 byte[] program = ipClientCallback.getApfProgram(); 2483 verifyRaLifetime(program, packet, lifetime); 2484 } 2485 verifyRaEvent(RaEvent expected)2486 private void verifyRaEvent(RaEvent expected) { 2487 ArgumentCaptor<IpConnectivityLog.Event> captor = 2488 ArgumentCaptor.forClass(IpConnectivityLog.Event.class); 2489 verify(mLog, atLeastOnce()).log(captor.capture()); 2490 RaEvent got = lastRaEvent(captor.getAllValues()); 2491 if (!raEventEquals(expected, got)) { 2492 assertEquals(expected, got); // fail for printing an assertion error message. 2493 } 2494 } 2495 lastRaEvent(List<IpConnectivityLog.Event> events)2496 private RaEvent lastRaEvent(List<IpConnectivityLog.Event> events) { 2497 RaEvent got = null; 2498 for (Parcelable ev : events) { 2499 if (ev instanceof RaEvent) { 2500 got = (RaEvent) ev; 2501 } 2502 } 2503 return got; 2504 } 2505 raEventEquals(RaEvent ev1, RaEvent ev2)2506 private boolean raEventEquals(RaEvent ev1, RaEvent ev2) { 2507 return (ev1 != null) && (ev2 != null) 2508 && (ev1.routerLifetime == ev2.routerLifetime) 2509 && (ev1.prefixValidLifetime == ev2.prefixValidLifetime) 2510 && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime) 2511 && (ev1.routeInfoLifetime == ev2.routeInfoLifetime) 2512 && (ev1.rdnssLifetime == ev2.rdnssLifetime) 2513 && (ev1.dnsslLifetime == ev2.dnsslLifetime); 2514 } 2515 assertInvalidRa(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback, ByteBuffer packet)2516 private void assertInvalidRa(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback, 2517 ByteBuffer packet) throws IOException, ErrnoException { 2518 ipClientCallback.resetApfProgramWait(); 2519 apfFilter.pretendPacketReceived(packet.array()); 2520 ipClientCallback.assertNoProgramUpdate(); 2521 } 2522 makeBaseRaPacket()2523 private ByteBuffer makeBaseRaPacket() { 2524 ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]); 2525 final int ROUTER_LIFETIME = 1000; 2526 final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN; 2527 // IPv6, traffic class = 0, flow label = 0x12345 2528 final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345; 2529 2530 basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6); 2531 basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET, 2532 VERSION_TRAFFIC_CLASS_FLOW_LABEL); 2533 basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_ICMPV6); 2534 basePacket.put(ICMP6_TYPE_OFFSET, (byte) ICMP6_ROUTER_ADVERTISEMENT); 2535 basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short) ROUTER_LIFETIME); 2536 basePacket.position(IPV6_DEST_ADDR_OFFSET); 2537 basePacket.put(IPV6_ALL_NODES_ADDRESS); 2538 2539 return basePacket; 2540 } 2541 2542 @Test testApfFilterRa()2543 public void testApfFilterRa() throws Exception { 2544 MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 2545 ApfConfiguration config = getDefaultConfig(); 2546 config.multicastFilter = DROP_MULTICAST; 2547 config.ieee802_3Filter = DROP_802_3_FRAMES; 2548 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, 2549 mDependencies); 2550 byte[] program = ipClientCallback.getApfProgram(); 2551 2552 final int ROUTER_LIFETIME = 1000; 2553 final int PREFIX_VALID_LIFETIME = 200; 2554 final int PREFIX_PREFERRED_LIFETIME = 100; 2555 final int RDNSS_LIFETIME = 300; 2556 final int ROUTE_LIFETIME = 400; 2557 // Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000. 2558 final int DNSSL_LIFETIME = 2000; 2559 final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN; 2560 // IPv6, traffic class = 0, flow label = 0x12345 2561 final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345; 2562 2563 // Verify RA is passed the first time 2564 ByteBuffer basePacket = makeBaseRaPacket(); 2565 assertPass(program, basePacket.array()); 2566 2567 verifyRaLifetime(apfFilter, ipClientCallback, basePacket, ROUTER_LIFETIME); 2568 verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1)); 2569 2570 ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]); 2571 basePacket.clear(); 2572 newFlowLabelPacket.put(basePacket); 2573 // Check that changes are ignored in every byte of the flow label. 2574 newFlowLabelPacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET, 2575 VERSION_TRAFFIC_CLASS_FLOW_LABEL + 0x11111); 2576 2577 // Ensure zero-length options cause the packet to be silently skipped. 2578 // Do this before we test other packets. http://b/29586253 2579 ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap( 2580 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); 2581 basePacket.clear(); 2582 zeroLengthOptionPacket.put(basePacket); 2583 zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE); 2584 zeroLengthOptionPacket.put((byte)0); 2585 assertInvalidRa(apfFilter, ipClientCallback, zeroLengthOptionPacket); 2586 2587 // Generate several RAs with different options and lifetimes, and verify when 2588 // ApfFilter is shown these packets, it generates programs to filter them for the 2589 // appropriate lifetime. 2590 ByteBuffer prefixOptionPacket = ByteBuffer.wrap( 2591 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]); 2592 basePacket.clear(); 2593 prefixOptionPacket.put(basePacket); 2594 addPioOption(prefixOptionPacket, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, 2595 "2001:db8::/64"); 2596 verifyRaLifetime( 2597 apfFilter, ipClientCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME); 2598 verifyRaEvent(new RaEvent( 2599 ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1)); 2600 2601 ByteBuffer rdnssOptionPacket = ByteBuffer.wrap( 2602 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + 2 * IPV6_ADDR_LEN]); 2603 basePacket.clear(); 2604 rdnssOptionPacket.put(basePacket); 2605 addRdnssOption(rdnssOptionPacket, RDNSS_LIFETIME, 2606 "2001:4860:4860::8888", "2001:4860:4860::8844"); 2607 verifyRaLifetime(apfFilter, ipClientCallback, rdnssOptionPacket, RDNSS_LIFETIME); 2608 verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1)); 2609 2610 final int lowLifetime = 60; 2611 ByteBuffer lowLifetimeRdnssOptionPacket = ByteBuffer.wrap( 2612 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]); 2613 basePacket.clear(); 2614 lowLifetimeRdnssOptionPacket.put(basePacket); 2615 addRdnssOption(lowLifetimeRdnssOptionPacket, lowLifetime, "2620:fe::9"); 2616 verifyRaLifetime(apfFilter, ipClientCallback, lowLifetimeRdnssOptionPacket, 2617 ROUTER_LIFETIME); 2618 verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, lowLifetime, -1)); 2619 2620 ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap( 2621 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]); 2622 basePacket.clear(); 2623 routeInfoOptionPacket.put(basePacket); 2624 addRioOption(routeInfoOptionPacket, ROUTE_LIFETIME, "64:ff9b::/96"); 2625 verifyRaLifetime(apfFilter, ipClientCallback, routeInfoOptionPacket, ROUTE_LIFETIME); 2626 verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1)); 2627 2628 // Check that RIOs differing only in the first 4 bytes are different. 2629 ByteBuffer similarRouteInfoOptionPacket = ByteBuffer.wrap( 2630 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]); 2631 basePacket.clear(); 2632 similarRouteInfoOptionPacket.put(basePacket); 2633 addRioOption(similarRouteInfoOptionPacket, ROUTE_LIFETIME, "64:ff9b::/64"); 2634 // Packet should be passed because it is different. 2635 program = ipClientCallback.getApfProgram(); 2636 assertPass(program, similarRouteInfoOptionPacket.array()); 2637 2638 ByteBuffer dnsslOptionPacket = ByteBuffer.wrap( 2639 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); 2640 basePacket.clear(); 2641 dnsslOptionPacket.put(basePacket); 2642 dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE); 2643 dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); 2644 dnsslOptionPacket.putInt( 2645 ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME); 2646 verifyRaLifetime(apfFilter, ipClientCallback, dnsslOptionPacket, ROUTER_LIFETIME); 2647 verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME)); 2648 2649 ByteBuffer largeRaPacket = ByteBuffer.wrap(buildLargeRa()); 2650 verifyRaLifetime(apfFilter, ipClientCallback, largeRaPacket, 300); 2651 verifyRaEvent(new RaEvent(1800, 600, 300, 1200, 7200, -1)); 2652 2653 // Verify that current program filters all the RAs (note: ApfFilter.MAX_RAS == 10). 2654 program = ipClientCallback.getApfProgram(); 2655 verifyRaLifetime(program, basePacket, ROUTER_LIFETIME); 2656 verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME); 2657 verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME); 2658 verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME); 2659 verifyRaLifetime(program, lowLifetimeRdnssOptionPacket, ROUTER_LIFETIME); 2660 verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME); 2661 verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME); 2662 verifyRaLifetime(program, largeRaPacket, 300); 2663 2664 apfFilter.shutdown(); 2665 } 2666 2667 @Test testRaWithDifferentReachableTimeAndRetransTimer()2668 public void testRaWithDifferentReachableTimeAndRetransTimer() throws Exception { 2669 final MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 2670 final ApfConfiguration config = getDefaultConfig(); 2671 config.multicastFilter = DROP_MULTICAST; 2672 config.ieee802_3Filter = DROP_802_3_FRAMES; 2673 final TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, 2674 mDependencies); 2675 byte[] program = ipClientCallback.getApfProgram(); 2676 final int RA_REACHABLE_TIME = 1800; 2677 final int RA_RETRANSMISSION_TIMER = 1234; 2678 2679 // Create an Ra packet without options 2680 // Reachable time = 1800, retransmission timer = 1234 2681 ByteBuffer raPacket = makeBaseRaPacket(); 2682 raPacket.position(ICMP6_RA_REACHABLE_TIME_OFFSET); 2683 raPacket.putInt(RA_REACHABLE_TIME); 2684 raPacket.putInt(RA_RETRANSMISSION_TIMER); 2685 // First RA passes filter 2686 assertPass(program, raPacket.array()); 2687 2688 // Assume apf is shown the given RA, it generates program to filter it. 2689 ipClientCallback.resetApfProgramWait(); 2690 apfFilter.pretendPacketReceived(raPacket.array()); 2691 program = ipClientCallback.getApfProgram(); 2692 assertDrop(program, raPacket.array()); 2693 2694 // A packet with different reachable time should be passed. 2695 // Reachable time = 2300, retransmission timer = 1234 2696 raPacket.clear(); 2697 raPacket.putInt(ICMP6_RA_REACHABLE_TIME_OFFSET, RA_REACHABLE_TIME + 500); 2698 assertPass(program, raPacket.array()); 2699 2700 // A packet with different retransmission timer should be passed. 2701 // Reachable time = 1800, retransmission timer = 2234 2702 raPacket.clear(); 2703 raPacket.putInt(ICMP6_RA_REACHABLE_TIME_OFFSET, RA_REACHABLE_TIME); 2704 raPacket.putInt(ICMP6_RA_RETRANSMISSION_TIMER_OFFSET, RA_RETRANSMISSION_TIMER + 1000); 2705 assertPass(program, raPacket.array()); 2706 } 2707 2708 // The ByteBuffer is always created by ByteBuffer#wrap in the helper functions 2709 @SuppressWarnings("ByteBufferBackingArray") 2710 @Test testRaWithProgramInstalledSomeTimeAfterLastSeen()2711 public void testRaWithProgramInstalledSomeTimeAfterLastSeen() throws Exception { 2712 final MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 2713 final ApfConfiguration config = getDefaultConfig(); 2714 config.multicastFilter = DROP_MULTICAST; 2715 config.ieee802_3Filter = DROP_802_3_FRAMES; 2716 final TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, 2717 mDependencies); 2718 byte[] program = ipClientCallback.getApfProgram(); 2719 2720 final int routerLifetime = 1000; 2721 final int timePassedSeconds = 12; 2722 2723 // Verify that when the program is generated and installed some time after RA is last seen 2724 // it should be installed with the correct remaining lifetime. 2725 ByteBuffer basePacket = makeBaseRaPacket(); 2726 verifyRaLifetime(apfFilter, ipClientCallback, basePacket, routerLifetime); 2727 apfFilter.increaseCurrentTimeSeconds(timePassedSeconds); 2728 synchronized (apfFilter) { 2729 apfFilter.installNewProgramLocked(); 2730 } 2731 program = ipClientCallback.getApfProgram(); 2732 verifyRaLifetime(program, basePacket, routerLifetime, timePassedSeconds); 2733 2734 // Packet should be passed if the program is installed after 1/6 * lifetime from last seen 2735 apfFilter.increaseCurrentTimeSeconds((int) (routerLifetime / 6) - timePassedSeconds - 1); 2736 synchronized (apfFilter) { 2737 apfFilter.installNewProgramLocked(); 2738 } 2739 program = ipClientCallback.getApfProgram(); 2740 assertDrop(program, basePacket.array()); 2741 apfFilter.increaseCurrentTimeSeconds(1); 2742 synchronized (apfFilter) { 2743 apfFilter.installNewProgramLocked(); 2744 } 2745 program = ipClientCallback.getApfProgram(); 2746 assertPass(program, basePacket.array()); 2747 2748 apfFilter.shutdown(); 2749 } 2750 2751 // The ByteBuffer is always created by ByteBuffer#wrap in the helper functions 2752 @SuppressWarnings("ByteBufferBackingArray") 2753 @Test testRaWithoutLifetimeCalculationFix()2754 public void testRaWithoutLifetimeCalculationFix() throws Exception { 2755 final MockIpClientCallback ipClientCallback = new MockIpClientCallback(); 2756 final ApfConfiguration config = getDefaultConfig(); 2757 config.multicastFilter = DROP_MULTICAST; 2758 config.ieee802_3Filter = DROP_802_3_FRAMES; 2759 // Disable the RA lifetime calculation fix in aosp/2276160 2760 when(mDependencies.isFeatureEnabled(eq(mContext), 2761 eq(APF_USE_RA_LIFETIME_CALCULATION_FIX_VERSION), anyBoolean())).thenReturn(false); 2762 final TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, 2763 mDependencies); 2764 byte[] program = ipClientCallback.getApfProgram(); 2765 2766 final int routerLifetime = 1000; 2767 final int timePassedSeconds = 12; 2768 2769 // Verify that when the program is generated and installed without the RA lifetime 2770 // calculation fix, it should be installed with the old buggy behavior. 2771 ByteBuffer basePacket = makeBaseRaPacket(); 2772 verifyRaLifetime(apfFilter, ipClientCallback, basePacket, routerLifetime); 2773 apfFilter.increaseCurrentTimeSeconds(timePassedSeconds); 2774 synchronized (apfFilter) { 2775 apfFilter.installNewProgramLocked(); 2776 } 2777 program = ipClientCallback.getApfProgram(); 2778 final int ageLimit = (routerLifetime - timePassedSeconds) / 6; 2779 assertDrop(program, basePacket.array()); 2780 assertDrop(program, basePacket.array(), ageLimit); 2781 assertPass(program, basePacket.array(), ageLimit + 1); 2782 assertPass(program, basePacket.array(), routerLifetime); 2783 2784 apfFilter.shutdown(); 2785 } 2786 2787 /** 2788 * Stage a file for testing, i.e. make it native accessible. Given a resource ID, 2789 * copy that resource into the app's data directory and return the path to it. 2790 */ stageFile(int rawId)2791 private String stageFile(int rawId) throws Exception { 2792 File file = new File(InstrumentationRegistry.getContext().getFilesDir(), "staged_file"); 2793 new File(file.getParent()).mkdirs(); 2794 InputStream in = null; 2795 OutputStream out = null; 2796 try { 2797 in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId); 2798 out = new FileOutputStream(file); 2799 Streams.copy(in, out); 2800 } finally { 2801 if (in != null) in.close(); 2802 if (out != null) out.close(); 2803 } 2804 return file.getAbsolutePath(); 2805 } 2806 put(ByteBuffer buffer, int position, byte[] bytes)2807 private static void put(ByteBuffer buffer, int position, byte[] bytes) { 2808 final int original = buffer.position(); 2809 buffer.position(position); 2810 buffer.put(bytes); 2811 buffer.position(original); 2812 } 2813 2814 @Test testRaParsing()2815 public void testRaParsing() throws Exception { 2816 final int maxRandomPacketSize = 512; 2817 final Random r = new Random(); 2818 MockIpClientCallback cb = new MockIpClientCallback(); 2819 ApfConfiguration config = getDefaultConfig(); 2820 config.multicastFilter = DROP_MULTICAST; 2821 config.ieee802_3Filter = DROP_802_3_FRAMES; 2822 TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog, mDependencies); 2823 for (int i = 0; i < 1000; i++) { 2824 byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)]; 2825 r.nextBytes(packet); 2826 try { 2827 apfFilter.new Ra(packet, packet.length); 2828 } catch (ApfFilter.InvalidRaException e) { 2829 } catch (Exception e) { 2830 throw new Exception("bad packet: " + HexDump.toHexString(packet), e); 2831 } 2832 } 2833 } 2834 2835 @Test testRaProcessing()2836 public void testRaProcessing() throws Exception { 2837 final int maxRandomPacketSize = 512; 2838 final Random r = new Random(); 2839 MockIpClientCallback cb = new MockIpClientCallback(); 2840 ApfConfiguration config = getDefaultConfig(); 2841 config.multicastFilter = DROP_MULTICAST; 2842 config.ieee802_3Filter = DROP_802_3_FRAMES; 2843 TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog, mDependencies); 2844 for (int i = 0; i < 1000; i++) { 2845 byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)]; 2846 r.nextBytes(packet); 2847 try { 2848 apfFilter.processRa(packet, packet.length); 2849 } catch (Exception e) { 2850 throw new Exception("bad packet: " + HexDump.toHexString(packet), e); 2851 } 2852 } 2853 } 2854 2855 /** 2856 * Call the APF interpreter to run {@code program} on {@code packet} with persistent memory 2857 * segment {@data} pretending the filter was installed {@code filter_age} seconds ago. 2858 */ apfSimulate(byte[] program, byte[] packet, byte[] data, int filter_age)2859 private native static int apfSimulate(byte[] program, byte[] packet, byte[] data, 2860 int filter_age); 2861 2862 /** 2863 * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF 2864 * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d". 2865 */ compileToBpf(String filter)2866 private native static String compileToBpf(String filter); 2867 2868 /** 2869 * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump 2870 * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and 2871 * at the same time using APF program {@code apf_program}. Return {@code true} if 2872 * both APF and BPF programs filter out exactly the same packets. 2873 */ compareBpfApf(String filter, String pcap_filename, byte[] apf_program)2874 private native static boolean compareBpfApf(String filter, String pcap_filename, 2875 byte[] apf_program); 2876 2877 2878 /** 2879 * Open packet capture file {@code pcapFilename} and run it through APF filter. Then 2880 * checks whether all the packets are dropped and populates data[] {@code data} with 2881 * the APF counters. 2882 */ dropsAllPackets(byte[] program, byte[] data, String pcapFilename)2883 private native static boolean dropsAllPackets(byte[] program, byte[] data, String pcapFilename); 2884 2885 @Test testBroadcastAddress()2886 public void testBroadcastAddress() throws Exception { 2887 assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0)); 2888 assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32)); 2889 assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22)); 2890 assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8)); 2891 2892 assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0)); 2893 assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32)); 2894 assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24)); 2895 assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16)); 2896 } 2897 assertEqualsIp(String expected, int got)2898 public void assertEqualsIp(String expected, int got) throws Exception { 2899 int want = Inet4AddressUtils.inet4AddressToIntHTH( 2900 (Inet4Address) InetAddresses.parseNumericAddress(expected)); 2901 assertEquals(want, got); 2902 } 2903 } 2904