ApfTest.java revision 11e13e2175674389ed18c2b1e1af69c5ad931e8f
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 17package android.net.apf; 18 19import static android.system.OsConstants.*; 20 21import com.android.frameworks.servicestests.R; 22 23import android.net.apf.ApfCapabilities; 24import android.net.apf.ApfFilter; 25import android.net.apf.ApfGenerator; 26import android.net.apf.ApfGenerator.IllegalInstructionException; 27import android.net.apf.ApfGenerator.Register; 28import android.net.ip.IpManager; 29import android.net.LinkAddress; 30import android.net.LinkProperties; 31import android.os.ConditionVariable; 32import android.system.ErrnoException; 33import android.system.Os; 34import android.test.AndroidTestCase; 35import android.test.suitebuilder.annotation.LargeTest; 36 37import java.io.File; 38import java.io.FileDescriptor; 39import java.io.FileOutputStream; 40import java.io.IOException; 41import java.io.InputStream; 42import java.io.OutputStream; 43import java.net.InetAddress; 44import java.net.NetworkInterface; 45import java.nio.ByteBuffer; 46 47import libcore.io.IoUtils; 48import libcore.io.Streams; 49 50/** 51 * Tests for APF program generator and interpreter. 52 * 53 * Build, install and run with: 54 * runtest frameworks-services -c com.android.server.ApfTest 55 */ 56public class ApfTest extends AndroidTestCase { 57 private static final int TIMEOUT_MS = 500; 58 59 @Override 60 public void setUp() throws Exception { 61 super.setUp(); 62 // Load up native shared library containing APF interpreter exposed via JNI. 63 System.loadLibrary("servicestestsjni"); 64 } 65 66 // Expected return codes from APF interpreter. 67 private final static int PASS = 1; 68 private final static int DROP = 0; 69 // Interpreter will just accept packets without link layer headers, so pad fake packet to at 70 // least the minimum packet size. 71 private final static int MIN_PKT_SIZE = 15; 72 73 private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) { 74 assertEquals(expected, apfSimulate(program, packet, filterAge)); 75 } 76 77 private void assertPass(byte[] program, byte[] packet, int filterAge) { 78 assertVerdict(PASS, program, packet, filterAge); 79 } 80 81 private void assertDrop(byte[] program, byte[] packet, int filterAge) { 82 assertVerdict(DROP, program, packet, filterAge); 83 } 84 85 private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge) 86 throws IllegalInstructionException { 87 assertEquals(expected, apfSimulate(gen.generate(), packet, filterAge)); 88 } 89 90 private void assertPass(ApfGenerator gen, byte[] packet, int filterAge) 91 throws IllegalInstructionException { 92 assertVerdict(PASS, gen, packet, filterAge); 93 } 94 95 private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge) 96 throws IllegalInstructionException { 97 assertVerdict(DROP, gen, packet, filterAge); 98 } 99 100 private void assertPass(ApfGenerator gen) 101 throws IllegalInstructionException { 102 assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0); 103 } 104 105 private void assertDrop(ApfGenerator gen) 106 throws IllegalInstructionException { 107 assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0); 108 } 109 110 /** 111 * Test each instruction by generating a program containing the instruction, 112 * generating bytecode for that program and running it through the 113 * interpreter to verify it functions correctly. 114 */ 115 @LargeTest 116 public void testApfInstructions() throws IllegalInstructionException { 117 // Empty program should pass because having the program counter reach the 118 // location immediately after the program indicates the packet should be 119 // passed to the AP. 120 ApfGenerator gen = new ApfGenerator(); 121 assertPass(gen); 122 123 // Test jumping to pass label. 124 gen = new ApfGenerator(); 125 gen.addJump(gen.PASS_LABEL); 126 byte[] program = gen.generate(); 127 assertEquals(1, program.length); 128 assertEquals((14 << 3) | (0 << 1) | 0, program[0]); 129 assertPass(program, new byte[MIN_PKT_SIZE], 0); 130 131 // Test jumping to drop label. 132 gen = new ApfGenerator(); 133 gen.addJump(gen.DROP_LABEL); 134 program = gen.generate(); 135 assertEquals(2, program.length); 136 assertEquals((14 << 3) | (1 << 1) | 0, program[0]); 137 assertEquals(1, program[1]); 138 assertDrop(program, new byte[15], 15); 139 140 // Test jumping if equal to 0. 141 gen = new ApfGenerator(); 142 gen.addJumpIfR0Equals(0, gen.DROP_LABEL); 143 assertDrop(gen); 144 145 // Test jumping if not equal to 0. 146 gen = new ApfGenerator(); 147 gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL); 148 assertPass(gen); 149 gen = new ApfGenerator(); 150 gen.addLoadImmediate(Register.R0, 1); 151 gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL); 152 assertDrop(gen); 153 154 // Test jumping if registers equal. 155 gen = new ApfGenerator(); 156 gen.addJumpIfR0EqualsR1(gen.DROP_LABEL); 157 assertDrop(gen); 158 159 // Test jumping if registers not equal. 160 gen = new ApfGenerator(); 161 gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL); 162 assertPass(gen); 163 gen = new ApfGenerator(); 164 gen.addLoadImmediate(Register.R0, 1); 165 gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL); 166 assertDrop(gen); 167 168 // Test load immediate. 169 gen = new ApfGenerator(); 170 gen.addLoadImmediate(Register.R0, 1234567890); 171 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 172 assertDrop(gen); 173 174 // Test add. 175 gen = new ApfGenerator(); 176 gen.addAdd(1234567890); 177 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 178 assertDrop(gen); 179 180 // Test subtract. 181 gen = new ApfGenerator(); 182 gen.addAdd(-1234567890); 183 gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); 184 assertDrop(gen); 185 186 // Test or. 187 gen = new ApfGenerator(); 188 gen.addOr(1234567890); 189 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 190 assertDrop(gen); 191 192 // Test and. 193 gen = new ApfGenerator(); 194 gen.addLoadImmediate(Register.R0, 1234567890); 195 gen.addAnd(123456789); 196 gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL); 197 assertDrop(gen); 198 199 // Test left shift. 200 gen = new ApfGenerator(); 201 gen.addLoadImmediate(Register.R0, 1234567890); 202 gen.addLeftShift(1); 203 gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL); 204 assertDrop(gen); 205 206 // Test right shift. 207 gen = new ApfGenerator(); 208 gen.addLoadImmediate(Register.R0, 1234567890); 209 gen.addRightShift(1); 210 gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL); 211 assertDrop(gen); 212 213 // Test multiply. 214 gen = new ApfGenerator(); 215 gen.addLoadImmediate(Register.R0, 1234567890); 216 gen.addMul(2); 217 gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL); 218 assertDrop(gen); 219 220 // Test divide. 221 gen = new ApfGenerator(); 222 gen.addLoadImmediate(Register.R0, 1234567890); 223 gen.addDiv(2); 224 gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL); 225 assertDrop(gen); 226 227 // Test divide by zero. 228 gen = new ApfGenerator(); 229 gen.addDiv(0); 230 gen.addJump(gen.DROP_LABEL); 231 assertPass(gen); 232 233 // Test add. 234 gen = new ApfGenerator(); 235 gen.addLoadImmediate(Register.R1, 1234567890); 236 gen.addAddR1(); 237 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 238 assertDrop(gen); 239 240 // Test subtract. 241 gen = new ApfGenerator(); 242 gen.addLoadImmediate(Register.R1, -1234567890); 243 gen.addAddR1(); 244 gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); 245 assertDrop(gen); 246 247 // Test or. 248 gen = new ApfGenerator(); 249 gen.addLoadImmediate(Register.R1, 1234567890); 250 gen.addOrR1(); 251 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 252 assertDrop(gen); 253 254 // Test and. 255 gen = new ApfGenerator(); 256 gen.addLoadImmediate(Register.R0, 1234567890); 257 gen.addLoadImmediate(Register.R1, 123456789); 258 gen.addAndR1(); 259 gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL); 260 assertDrop(gen); 261 262 // Test left shift. 263 gen = new ApfGenerator(); 264 gen.addLoadImmediate(Register.R0, 1234567890); 265 gen.addLoadImmediate(Register.R1, 1); 266 gen.addLeftShiftR1(); 267 gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL); 268 assertDrop(gen); 269 270 // Test right shift. 271 gen = new ApfGenerator(); 272 gen.addLoadImmediate(Register.R0, 1234567890); 273 gen.addLoadImmediate(Register.R1, -1); 274 gen.addLeftShiftR1(); 275 gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL); 276 assertDrop(gen); 277 278 // Test multiply. 279 gen = new ApfGenerator(); 280 gen.addLoadImmediate(Register.R0, 1234567890); 281 gen.addLoadImmediate(Register.R1, 2); 282 gen.addMulR1(); 283 gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL); 284 assertDrop(gen); 285 286 // Test divide. 287 gen = new ApfGenerator(); 288 gen.addLoadImmediate(Register.R0, 1234567890); 289 gen.addLoadImmediate(Register.R1, 2); 290 gen.addDivR1(); 291 gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL); 292 assertDrop(gen); 293 294 // Test divide by zero. 295 gen = new ApfGenerator(); 296 gen.addDivR1(); 297 gen.addJump(gen.DROP_LABEL); 298 assertPass(gen); 299 300 // Test byte load. 301 gen = new ApfGenerator(); 302 gen.addLoad8(Register.R0, 1); 303 gen.addJumpIfR0Equals(45, gen.DROP_LABEL); 304 assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 305 306 // Test out of bounds load. 307 gen = new ApfGenerator(); 308 gen.addLoad8(Register.R0, 16); 309 gen.addJumpIfR0Equals(0, gen.DROP_LABEL); 310 assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 311 312 // Test half-word load. 313 gen = new ApfGenerator(); 314 gen.addLoad16(Register.R0, 1); 315 gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL); 316 assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 317 318 // Test word load. 319 gen = new ApfGenerator(); 320 gen.addLoad32(Register.R0, 1); 321 gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL); 322 assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0); 323 324 // Test byte indexed load. 325 gen = new ApfGenerator(); 326 gen.addLoadImmediate(Register.R1, 1); 327 gen.addLoad8Indexed(Register.R0, 0); 328 gen.addJumpIfR0Equals(45, gen.DROP_LABEL); 329 assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 330 331 // Test out of bounds indexed load. 332 gen = new ApfGenerator(); 333 gen.addLoadImmediate(Register.R1, 8); 334 gen.addLoad8Indexed(Register.R0, 8); 335 gen.addJumpIfR0Equals(0, gen.DROP_LABEL); 336 assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 337 338 // Test half-word indexed load. 339 gen = new ApfGenerator(); 340 gen.addLoadImmediate(Register.R1, 1); 341 gen.addLoad16Indexed(Register.R0, 0); 342 gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL); 343 assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0); 344 345 // Test word indexed load. 346 gen = new ApfGenerator(); 347 gen.addLoadImmediate(Register.R1, 1); 348 gen.addLoad32Indexed(Register.R0, 0); 349 gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL); 350 assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0); 351 352 // Test jumping if greater than. 353 gen = new ApfGenerator(); 354 gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL); 355 assertPass(gen); 356 gen = new ApfGenerator(); 357 gen.addLoadImmediate(Register.R0, 1); 358 gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL); 359 assertDrop(gen); 360 361 // Test jumping if less than. 362 gen = new ApfGenerator(); 363 gen.addJumpIfR0LessThan(0, gen.DROP_LABEL); 364 assertPass(gen); 365 gen = new ApfGenerator(); 366 gen.addJumpIfR0LessThan(1, gen.DROP_LABEL); 367 assertDrop(gen); 368 369 // Test jumping if any bits set. 370 gen = new ApfGenerator(); 371 gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); 372 assertPass(gen); 373 gen = new ApfGenerator(); 374 gen.addLoadImmediate(Register.R0, 1); 375 gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); 376 assertDrop(gen); 377 gen = new ApfGenerator(); 378 gen.addLoadImmediate(Register.R0, 3); 379 gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); 380 assertDrop(gen); 381 382 // Test jumping if register greater than. 383 gen = new ApfGenerator(); 384 gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL); 385 assertPass(gen); 386 gen = new ApfGenerator(); 387 gen.addLoadImmediate(Register.R0, 2); 388 gen.addLoadImmediate(Register.R1, 1); 389 gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL); 390 assertDrop(gen); 391 392 // Test jumping if register less than. 393 gen = new ApfGenerator(); 394 gen.addJumpIfR0LessThanR1(gen.DROP_LABEL); 395 assertPass(gen); 396 gen = new ApfGenerator(); 397 gen.addLoadImmediate(Register.R1, 1); 398 gen.addJumpIfR0LessThanR1(gen.DROP_LABEL); 399 assertDrop(gen); 400 401 // Test jumping if any bits set in register. 402 gen = new ApfGenerator(); 403 gen.addLoadImmediate(Register.R1, 3); 404 gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); 405 assertPass(gen); 406 gen = new ApfGenerator(); 407 gen.addLoadImmediate(Register.R1, 3); 408 gen.addLoadImmediate(Register.R0, 1); 409 gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); 410 assertDrop(gen); 411 gen = new ApfGenerator(); 412 gen.addLoadImmediate(Register.R1, 3); 413 gen.addLoadImmediate(Register.R0, 3); 414 gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); 415 assertDrop(gen); 416 417 // Test load from memory. 418 gen = new ApfGenerator(); 419 gen.addLoadFromMemory(Register.R0, 0); 420 gen.addJumpIfR0Equals(0, gen.DROP_LABEL); 421 assertDrop(gen); 422 423 // Test store to memory. 424 gen = new ApfGenerator(); 425 gen.addLoadImmediate(Register.R1, 1234567890); 426 gen.addStoreToMemory(Register.R1, 12); 427 gen.addLoadFromMemory(Register.R0, 12); 428 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 429 assertDrop(gen); 430 431 // Test filter age pre-filled memory. 432 gen = new ApfGenerator(); 433 gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT); 434 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 435 assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890); 436 437 // Test packet size pre-filled memory. 438 gen = new ApfGenerator(); 439 gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT); 440 gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL); 441 assertDrop(gen); 442 443 // Test IPv4 header size pre-filled memory. 444 gen = new ApfGenerator(); 445 gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); 446 gen.addJumpIfR0Equals(20, gen.DROP_LABEL); 447 assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0); 448 449 // Test not. 450 gen = new ApfGenerator(); 451 gen.addLoadImmediate(Register.R0, 1234567890); 452 gen.addNot(Register.R0); 453 gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL); 454 assertDrop(gen); 455 456 // Test negate. 457 gen = new ApfGenerator(); 458 gen.addLoadImmediate(Register.R0, 1234567890); 459 gen.addNeg(Register.R0); 460 gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); 461 assertDrop(gen); 462 463 // Test move. 464 gen = new ApfGenerator(); 465 gen.addLoadImmediate(Register.R1, 1234567890); 466 gen.addMove(Register.R0); 467 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 468 assertDrop(gen); 469 gen = new ApfGenerator(); 470 gen.addLoadImmediate(Register.R0, 1234567890); 471 gen.addMove(Register.R1); 472 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 473 assertDrop(gen); 474 475 // Test swap. 476 gen = new ApfGenerator(); 477 gen.addLoadImmediate(Register.R1, 1234567890); 478 gen.addSwap(); 479 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); 480 assertDrop(gen); 481 gen = new ApfGenerator(); 482 gen.addLoadImmediate(Register.R0, 1234567890); 483 gen.addSwap(); 484 gen.addJumpIfR0Equals(0, gen.DROP_LABEL); 485 assertDrop(gen); 486 487 // Test jump if bytes not equal. 488 gen = new ApfGenerator(); 489 gen.addLoadImmediate(Register.R0, 1); 490 gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL); 491 program = gen.generate(); 492 assertEquals(6, program.length); 493 assertEquals((13 << 3) | (1 << 1) | 0, program[0]); 494 assertEquals(1, program[1]); 495 assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]); 496 assertEquals(1, program[3]); 497 assertEquals(1, program[4]); 498 assertEquals(123, program[5]); 499 assertDrop(program, new byte[MIN_PKT_SIZE], 0); 500 gen = new ApfGenerator(); 501 gen.addLoadImmediate(Register.R0, 1); 502 gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL); 503 byte[] packet123 = new byte[]{0,123,0,0,0,0,0,0,0,0,0,0,0,0,0}; 504 assertPass(gen, packet123, 0); 505 gen = new ApfGenerator(); 506 gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL); 507 assertDrop(gen, packet123, 0); 508 gen = new ApfGenerator(); 509 gen.addLoadImmediate(Register.R0, 1); 510 gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL); 511 byte[] packet12345 = new byte[]{0,1,2,3,4,5,0,0,0,0,0,0,0,0,0}; 512 assertDrop(gen, packet12345, 0); 513 gen = new ApfGenerator(); 514 gen.addLoadImmediate(Register.R0, 1); 515 gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL); 516 assertPass(gen, packet12345, 0); 517 } 518 519 /** 520 * Generate some BPF programs, translate them to APF, then run APF and BPF programs 521 * over packet traces and verify both programs filter out the same packets. 522 */ 523 @LargeTest 524 public void testApfAgainstBpf() throws Exception { 525 String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53", 526 "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24", 527 "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000", 528 "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" }; 529 String pcap_filename = stageFile(R.raw.apf); 530 for (String tcpdump_filter : tcpdump_filters) { 531 byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter)); 532 assertTrue("Failed to match for filter: " + tcpdump_filter, 533 compareBpfApf(tcpdump_filter, pcap_filename, apf_program)); 534 } 535 } 536 537 private class MockIpManagerCallback extends IpManager.Callback { 538 private final ConditionVariable mGotApfProgram = new ConditionVariable(); 539 private byte[] mLastApfProgram; 540 541 @Override 542 public void installPacketFilter(byte[] filter) { 543 mLastApfProgram = filter; 544 mGotApfProgram.open(); 545 } 546 547 public void resetApfProgramWait() { 548 mGotApfProgram.close(); 549 } 550 551 public byte[] getApfProgram() { 552 assertTrue(mGotApfProgram.block(TIMEOUT_MS)); 553 return mLastApfProgram; 554 } 555 } 556 557 private static class TestApfFilter extends ApfFilter { 558 public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6}; 559 private FileDescriptor mWriteSocket; 560 561 public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter) throws 562 Exception { 563 super(new ApfCapabilities(2, 1000, ARPHRD_ETHER), NetworkInterface.getByName("lo"), 564 ipManagerCallback, multicastFilter); 565 } 566 567 // Pretend an RA packet has been received and show it to ApfFilter. 568 public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException { 569 // ApfFilter's ReceiveThread will be waiting to read this. 570 Os.write(mWriteSocket, packet, 0, packet.length); 571 } 572 573 @Override 574 void maybeStartFilter() { 575 mHardwareAddress = MOCK_MAC_ADDR; 576 installNewProgramLocked(); 577 578 // Create two sockets, "readSocket" and "mWriteSocket" and connect them together. 579 FileDescriptor readSocket = new FileDescriptor(); 580 mWriteSocket = new FileDescriptor(); 581 try { 582 Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket); 583 } catch (ErrnoException e) { 584 fail(); 585 return; 586 } 587 // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs. 588 // This allows us to pretend RA packets have been recieved via pretendPacketReceived(). 589 mReceiveThread = new ReceiveThread(readSocket); 590 mReceiveThread.start(); 591 } 592 593 @Override 594 public void shutdown() { 595 super.shutdown(); 596 IoUtils.closeQuietly(mWriteSocket); 597 } 598 } 599 600 private static final int ETH_HEADER_LEN = 14; 601 private static final int ETH_ETHERTYPE_OFFSET = 12; 602 private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{ 603 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; 604 605 private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0; 606 private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9; 607 private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16; 608 609 private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6; 610 private static final int IPV6_HEADER_LEN = 40; 611 private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24; 612 // The IPv6 all nodes address ff02::1 613 private static final byte[] IPV6_ALL_NODES_ADDRESS = 614 new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; 615 616 private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN; 617 private static final int ICMP6_ROUTER_ADVERTISEMENT = 134; 618 private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136; 619 620 private static final int ICMP6_RA_HEADER_LEN = 16; 621 private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET = 622 ETH_HEADER_LEN + IPV6_HEADER_LEN + 6; 623 private static final int ICMP6_RA_CHECKSUM_OFFSET = 624 ETH_HEADER_LEN + IPV6_HEADER_LEN + 2; 625 private static final int ICMP6_RA_OPTION_OFFSET = 626 ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN; 627 628 private static final int ICMP6_PREFIX_OPTION_TYPE = 3; 629 private static final int ICMP6_PREFIX_OPTION_LEN = 32; 630 private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4; 631 private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8; 632 633 // From RFC6106: Recursive DNS Server option 634 private static final int ICMP6_RDNSS_OPTION_TYPE = 25; 635 // From RFC6106: DNS Search List option 636 private static final int ICMP6_DNSSL_OPTION_TYPE = 31; 637 638 // From RFC4191: Route Information option 639 private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24; 640 // Above three options all have the same format: 641 private static final int ICMP6_4_BYTE_OPTION_LEN = 8; 642 private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4; 643 private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4; 644 645 private static final int UDP_HEADER_LEN = 8; 646 private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22; 647 648 private static final int DHCP_CLIENT_PORT = 68; 649 private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48; 650 651 private static int ARP_HEADER_OFFSET = ETH_HEADER_LEN; 652 private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{ 653 0, 1, // Hardware type: Ethernet (1) 654 8, 0, // Protocol type: IP (0x0800) 655 6, // Hardware size: 6 656 4, // Protocol size: 4 657 0, 1 // Opcode: request (1) 658 }; 659 private static int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24; 660 661 private static byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1}; 662 663 @LargeTest 664 public void testApfFilterIPv4() throws Exception { 665 MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); 666 ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */); 667 byte[] program = ipManagerCallback.getApfProgram(); 668 669 // Verify empty packet of 100 zero bytes is passed 670 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 671 assertPass(program, packet.array(), 0); 672 673 // Verify unicast IPv4 packet is passed 674 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); 675 assertPass(program, packet.array(), 0); 676 677 // Verify broadcast IPv4, not DHCP to us, is dropped 678 packet.put(ETH_BROADCAST_MAC_ADDRESS); 679 assertDrop(program, packet.array(), 0); 680 packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45); 681 assertDrop(program, packet.array(), 0); 682 packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP); 683 assertDrop(program, packet.array(), 0); 684 packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT); 685 assertDrop(program, packet.array(), 0); 686 687 // Verify broadcast IPv4 DHCP to us is passed 688 packet.position(DHCP_CLIENT_MAC_OFFSET); 689 packet.put(TestApfFilter.MOCK_MAC_ADDR); 690 assertPass(program, packet.array(), 0); 691 692 apfFilter.shutdown(); 693 } 694 695 @LargeTest 696 public void testApfFilterIPv6() throws Exception { 697 MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); 698 ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */); 699 byte[] program = ipManagerCallback.getApfProgram(); 700 701 // Verify empty IPv6 packet is passed 702 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 703 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6); 704 assertPass(program, packet.array(), 0); 705 706 // Verify empty ICMPv6 packet is passed 707 packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); 708 assertPass(program, packet.array(), 0); 709 710 // Verify empty ICMPv6 NA packet is passed 711 packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT); 712 assertPass(program, packet.array(), 0); 713 714 // Verify ICMPv6 NA to ff02::1 is dropped 715 packet.position(IPV6_DEST_ADDR_OFFSET); 716 packet.put(IPV6_ALL_NODES_ADDRESS); 717 assertDrop(program, packet.array(), 0); 718 719 apfFilter.shutdown(); 720 } 721 722 @LargeTest 723 public void testApfFilterMulticast() throws Exception { 724 MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); 725 ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */); 726 byte[] program = ipManagerCallback.getApfProgram(); 727 728 // Construct IPv4 and IPv6 multicast packets. 729 ByteBuffer v4packet = ByteBuffer.wrap(new byte[100]); 730 v4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); 731 v4packet.position(IPV4_DEST_ADDR_OFFSET); 732 v4packet.put(new byte[]{(byte)224,0,0,1}); 733 734 ByteBuffer v6packet = ByteBuffer.wrap(new byte[100]); 735 v6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6); 736 v6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP); 737 v6packet.position(IPV6_DEST_ADDR_OFFSET); 738 v6packet.put(new byte[]{(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb}); 739 740 // Verify initially disabled multicast filter is off 741 assertPass(program, v4packet.array(), 0); 742 assertPass(program, v6packet.array(), 0); 743 744 // Turn on multicast filter and verify it works 745 ipManagerCallback.resetApfProgramWait(); 746 apfFilter.setMulticastFilter(true); 747 program = ipManagerCallback.getApfProgram(); 748 assertDrop(program, v4packet.array(), 0); 749 assertDrop(program, v6packet.array(), 0); 750 751 // Turn off multicast filter and verify it's off 752 ipManagerCallback.resetApfProgramWait(); 753 apfFilter.setMulticastFilter(false); 754 program = ipManagerCallback.getApfProgram(); 755 assertPass(program, v4packet.array(), 0); 756 assertPass(program, v6packet.array(), 0); 757 758 // Verify it can be initialized to on 759 ipManagerCallback.resetApfProgramWait(); 760 apfFilter.shutdown(); 761 apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */); 762 program = ipManagerCallback.getApfProgram(); 763 assertDrop(program, v4packet.array(), 0); 764 assertDrop(program, v6packet.array(), 0); 765 766 // Verify that ICMPv6 multicast is not dropped. 767 v6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); 768 assertPass(program, v6packet.array(), 0); 769 770 apfFilter.shutdown(); 771 } 772 773 private void verifyArpFilter(MockIpManagerCallback ipManagerCallback, ApfFilter apfFilter, 774 LinkProperties linkProperties, int filterResult) { 775 ipManagerCallback.resetApfProgramWait(); 776 apfFilter.setLinkProperties(linkProperties); 777 byte[] program = ipManagerCallback.getApfProgram(); 778 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 779 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); 780 assertPass(program, packet.array(), 0); 781 packet.position(ARP_HEADER_OFFSET); 782 packet.put(ARP_IPV4_REQUEST_HEADER); 783 assertVerdict(filterResult, program, packet.array(), 0); 784 packet.position(ARP_TARGET_IP_ADDRESS_OFFSET); 785 packet.put(MOCK_IPV4_ADDR); 786 assertPass(program, packet.array(), 0); 787 } 788 789 @LargeTest 790 public void testApfFilterArp() throws Exception { 791 MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); 792 ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */); 793 byte[] program = ipManagerCallback.getApfProgram(); 794 795 // Verify initially ARP filter is off 796 ByteBuffer packet = ByteBuffer.wrap(new byte[100]); 797 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); 798 assertPass(program, packet.array(), 0); 799 packet.position(ARP_HEADER_OFFSET); 800 packet.put(ARP_IPV4_REQUEST_HEADER); 801 assertPass(program, packet.array(), 0); 802 packet.position(ARP_TARGET_IP_ADDRESS_OFFSET); 803 packet.put(MOCK_IPV4_ADDR); 804 assertPass(program, packet.array(), 0); 805 806 // Inform ApfFilter of our address and verify ARP filtering is on 807 LinkProperties lp = new LinkProperties(); 808 assertTrue(lp.addLinkAddress( 809 new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24))); 810 verifyArpFilter(ipManagerCallback, apfFilter, lp, DROP); 811 812 // Inform ApfFilter of loss of IP and verify ARP filtering is off 813 verifyArpFilter(ipManagerCallback, apfFilter, new LinkProperties(), PASS); 814 815 apfFilter.shutdown(); 816 } 817 818 // Verify that the last program pushed to the IpManager.Callback properly filters the 819 // given packet for the given lifetime. 820 private void verifyRaLifetime(MockIpManagerCallback ipManagerCallback, ByteBuffer packet, 821 int lifetime) { 822 byte[] program = ipManagerCallback.getApfProgram(); 823 824 // Verify new program should drop RA for 1/6th its lifetime 825 assertDrop(program, packet.array(), 0); 826 assertDrop(program, packet.array(), lifetime/6); 827 assertPass(program, packet.array(), lifetime/6 + 1); 828 assertPass(program, packet.array(), lifetime); 829 830 // Verify RA checksum is ignored 831 packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345); 832 assertDrop(program, packet.array(), 0); 833 packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345); 834 assertDrop(program, packet.array(), 0); 835 836 // Verify other changes to RA make it not match filter 837 packet.put(0, (byte)-1); 838 assertPass(program, packet.array(), 0); 839 packet.put(0, (byte)0); 840 assertDrop(program, packet.array(), 0); 841 } 842 843 // Test that when ApfFilter is shown the given packet, it generates a program to filter it 844 // for the given lifetime. 845 private void testRaLifetime(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback, 846 ByteBuffer packet, int lifetime) throws IOException, ErrnoException { 847 // Verify new program generated if ApfFilter witnesses RA 848 ipManagerCallback.resetApfProgramWait(); 849 apfFilter.pretendPacketReceived(packet.array()); 850 ipManagerCallback.getApfProgram(); 851 852 verifyRaLifetime(ipManagerCallback, packet, lifetime); 853 } 854 855 @LargeTest 856 public void testApfFilterRa() throws Exception { 857 MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); 858 TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */); 859 byte[] program = ipManagerCallback.getApfProgram(); 860 861 // Verify RA is passed the first time 862 ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]); 863 basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6); 864 basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); 865 basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT); 866 basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000); 867 basePacket.position(IPV6_DEST_ADDR_OFFSET); 868 basePacket.put(IPV6_ALL_NODES_ADDRESS); 869 assertPass(program, basePacket.array(), 0); 870 871 testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000); 872 873 // Generate several RAs with different options and lifetimes, and verify when 874 // ApfFilter is shown these packets, it generates programs to filter them for the 875 // appropriate lifetime. 876 ByteBuffer prefixOptionPacket = ByteBuffer.wrap( 877 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]); 878 basePacket.clear(); 879 prefixOptionPacket.put(basePacket); 880 prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE); 881 prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8)); 882 prefixOptionPacket.putInt( 883 ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, 100); 884 prefixOptionPacket.putInt( 885 ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 200); 886 testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, 100); 887 888 ByteBuffer rdnssOptionPacket = ByteBuffer.wrap( 889 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); 890 basePacket.clear(); 891 rdnssOptionPacket.put(basePacket); 892 rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE); 893 rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); 894 rdnssOptionPacket.putInt( 895 ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 300); 896 testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, 300); 897 898 ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap( 899 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); 900 basePacket.clear(); 901 routeInfoOptionPacket.put(basePacket); 902 routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE); 903 routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); 904 routeInfoOptionPacket.putInt( 905 ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 400); 906 testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, 400); 907 908 ByteBuffer dnsslOptionPacket = ByteBuffer.wrap( 909 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); 910 basePacket.clear(); 911 dnsslOptionPacket.put(basePacket); 912 dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE); 913 dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); 914 dnsslOptionPacket.putInt( 915 ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 2000); 916 // Note that lifetime of 2000 will be ignored in favor of shorter 917 // route lifetime of 1000. 918 testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, 1000); 919 920 // Verify that current program filters all five RAs: 921 verifyRaLifetime(ipManagerCallback, basePacket, 1000); 922 verifyRaLifetime(ipManagerCallback, prefixOptionPacket, 100); 923 verifyRaLifetime(ipManagerCallback, rdnssOptionPacket, 300); 924 verifyRaLifetime(ipManagerCallback, routeInfoOptionPacket, 400); 925 verifyRaLifetime(ipManagerCallback, dnsslOptionPacket, 1000); 926 927 apfFilter.shutdown(); 928 } 929 930 /** 931 * Stage a file for testing, i.e. make it native accessible. Given a resource ID, 932 * copy that resource into the app's data directory and return the path to it. 933 */ 934 private String stageFile(int rawId) throws Exception { 935 File file = new File(getContext().getFilesDir(), "staged_file"); 936 new File(file.getParent()).mkdirs(); 937 InputStream in = null; 938 OutputStream out = null; 939 try { 940 in = getContext().getResources().openRawResource(rawId); 941 out = new FileOutputStream(file); 942 Streams.copy(in, out); 943 } finally { 944 if (in != null) in.close(); 945 if (out != null) out.close(); 946 } 947 return file.getAbsolutePath(); 948 } 949 950 /** 951 * Call the APF interpreter the run {@code program} on {@code packet} pretending the 952 * filter was installed {@code filter_age} seconds ago. 953 */ 954 private native static int apfSimulate(byte[] program, byte[] packet, int filter_age); 955 956 /** 957 * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF 958 * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d". 959 */ 960 private native static String compileToBpf(String filter); 961 962 /** 963 * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump 964 * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and 965 * at the same time using APF program {@code apf_program}. Return {@code true} if 966 * both APF and BPF programs filter out exactly the same packets. 967 */ 968 private native static boolean compareBpfApf(String filter, String pcap_filename, 969 byte[] apf_program); 970} 971