Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 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.system.OsConstants.*; |
| 20 | |
| 21 | import com.android.frameworks.servicestests.R; |
| 22 | |
Hugo Benichi | 7d21eae | 2016-09-02 14:00:29 +0900 | [diff] [blame] | 23 | import android.net.LinkAddress; |
| 24 | import android.net.LinkProperties; |
| 25 | import android.net.NetworkUtils; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 26 | import android.net.apf.ApfCapabilities; |
| 27 | import android.net.apf.ApfFilter; |
| 28 | import android.net.apf.ApfGenerator; |
| 29 | import android.net.apf.ApfGenerator.IllegalInstructionException; |
| 30 | import android.net.apf.ApfGenerator.Register; |
| 31 | import android.net.ip.IpManager; |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 32 | import android.net.metrics.IpConnectivityLog; |
| 33 | import android.net.metrics.RaEvent; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 34 | import android.os.ConditionVariable; |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 35 | import android.os.Parcelable; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 36 | import android.system.ErrnoException; |
| 37 | import android.system.Os; |
| 38 | import android.test.AndroidTestCase; |
| 39 | import android.test.suitebuilder.annotation.LargeTest; |
| 40 | |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 41 | import org.mockito.ArgumentCaptor; |
| 42 | import org.mockito.Mock; |
| 43 | import org.mockito.MockitoAnnotations; |
| 44 | import static org.mockito.Mockito.atLeastOnce; |
| 45 | import static org.mockito.Mockito.verify; |
| 46 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 47 | import java.io.File; |
| 48 | import java.io.FileDescriptor; |
| 49 | import java.io.FileOutputStream; |
| 50 | import java.io.IOException; |
| 51 | import java.io.InputStream; |
| 52 | import java.io.OutputStream; |
| 53 | import java.net.InetAddress; |
| 54 | import java.net.NetworkInterface; |
| 55 | import java.nio.ByteBuffer; |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 56 | import java.util.List; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 57 | |
| 58 | import libcore.io.IoUtils; |
| 59 | import libcore.io.Streams; |
| 60 | |
| 61 | /** |
| 62 | * Tests for APF program generator and interpreter. |
| 63 | * |
| 64 | * Build, install and run with: |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 65 | * runtest frameworks-services -c android.net.apf.ApfTest |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 66 | */ |
| 67 | public class ApfTest extends AndroidTestCase { |
| 68 | private static final int TIMEOUT_MS = 500; |
| 69 | |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 70 | @Mock IpConnectivityLog mLog; |
| 71 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 72 | @Override |
| 73 | public void setUp() throws Exception { |
| 74 | super.setUp(); |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 75 | MockitoAnnotations.initMocks(this); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 76 | // Load up native shared library containing APF interpreter exposed via JNI. |
| 77 | System.loadLibrary("servicestestsjni"); |
| 78 | } |
| 79 | |
| 80 | // Expected return codes from APF interpreter. |
| 81 | private final static int PASS = 1; |
| 82 | private final static int DROP = 0; |
| 83 | // Interpreter will just accept packets without link layer headers, so pad fake packet to at |
| 84 | // least the minimum packet size. |
| 85 | private final static int MIN_PKT_SIZE = 15; |
| 86 | |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 87 | private final static boolean DROP_MULTICAST = true; |
| 88 | private final static boolean ALLOW_MULTICAST = false; |
| 89 | |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 90 | private static String label(int code) { |
| 91 | switch (code) { |
| 92 | case PASS: return "PASS"; |
| 93 | case DROP: return "DROP"; |
| 94 | default: return "UNKNOWN"; |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | private static void assertReturnCodesEqual(int expected, int got) { |
| 99 | assertEquals(label(expected), label(got)); |
| 100 | } |
| 101 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 102 | private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) { |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 103 | assertReturnCodesEqual(expected, apfSimulate(program, packet, filterAge)); |
| 104 | } |
| 105 | |
| 106 | private void assertVerdict(int expected, byte[] program, byte[] packet) { |
| 107 | assertReturnCodesEqual(expected, apfSimulate(program, packet, 0)); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | private void assertPass(byte[] program, byte[] packet, int filterAge) { |
| 111 | assertVerdict(PASS, program, packet, filterAge); |
| 112 | } |
| 113 | |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 114 | private void assertPass(byte[] program, byte[] packet) { |
| 115 | assertVerdict(PASS, program, packet); |
| 116 | } |
| 117 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 118 | private void assertDrop(byte[] program, byte[] packet, int filterAge) { |
| 119 | assertVerdict(DROP, program, packet, filterAge); |
| 120 | } |
| 121 | |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 122 | private void assertDrop(byte[] program, byte[] packet) { |
| 123 | assertVerdict(DROP, program, packet); |
| 124 | } |
| 125 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 126 | private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge) |
| 127 | throws IllegalInstructionException { |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 128 | assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, filterAge)); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 129 | } |
| 130 | |
| 131 | private void assertPass(ApfGenerator gen, byte[] packet, int filterAge) |
| 132 | throws IllegalInstructionException { |
| 133 | assertVerdict(PASS, gen, packet, filterAge); |
| 134 | } |
| 135 | |
| 136 | private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge) |
| 137 | throws IllegalInstructionException { |
| 138 | assertVerdict(DROP, gen, packet, filterAge); |
| 139 | } |
| 140 | |
| 141 | private void assertPass(ApfGenerator gen) |
| 142 | throws IllegalInstructionException { |
| 143 | assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0); |
| 144 | } |
| 145 | |
| 146 | private void assertDrop(ApfGenerator gen) |
| 147 | throws IllegalInstructionException { |
| 148 | assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0); |
| 149 | } |
| 150 | |
| 151 | /** |
| 152 | * Test each instruction by generating a program containing the instruction, |
| 153 | * generating bytecode for that program and running it through the |
| 154 | * interpreter to verify it functions correctly. |
| 155 | */ |
| 156 | @LargeTest |
| 157 | public void testApfInstructions() throws IllegalInstructionException { |
| 158 | // Empty program should pass because having the program counter reach the |
| 159 | // location immediately after the program indicates the packet should be |
| 160 | // passed to the AP. |
| 161 | ApfGenerator gen = new ApfGenerator(); |
| 162 | assertPass(gen); |
| 163 | |
| 164 | // Test jumping to pass label. |
| 165 | gen = new ApfGenerator(); |
| 166 | gen.addJump(gen.PASS_LABEL); |
| 167 | byte[] program = gen.generate(); |
| 168 | assertEquals(1, program.length); |
| 169 | assertEquals((14 << 3) | (0 << 1) | 0, program[0]); |
| 170 | assertPass(program, new byte[MIN_PKT_SIZE], 0); |
| 171 | |
| 172 | // Test jumping to drop label. |
| 173 | gen = new ApfGenerator(); |
| 174 | gen.addJump(gen.DROP_LABEL); |
| 175 | program = gen.generate(); |
| 176 | assertEquals(2, program.length); |
| 177 | assertEquals((14 << 3) | (1 << 1) | 0, program[0]); |
| 178 | assertEquals(1, program[1]); |
| 179 | assertDrop(program, new byte[15], 15); |
| 180 | |
| 181 | // Test jumping if equal to 0. |
| 182 | gen = new ApfGenerator(); |
| 183 | gen.addJumpIfR0Equals(0, gen.DROP_LABEL); |
| 184 | assertDrop(gen); |
| 185 | |
| 186 | // Test jumping if not equal to 0. |
| 187 | gen = new ApfGenerator(); |
| 188 | gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL); |
| 189 | assertPass(gen); |
| 190 | gen = new ApfGenerator(); |
| 191 | gen.addLoadImmediate(Register.R0, 1); |
| 192 | gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL); |
| 193 | assertDrop(gen); |
| 194 | |
| 195 | // Test jumping if registers equal. |
| 196 | gen = new ApfGenerator(); |
| 197 | gen.addJumpIfR0EqualsR1(gen.DROP_LABEL); |
| 198 | assertDrop(gen); |
| 199 | |
| 200 | // Test jumping if registers not equal. |
| 201 | gen = new ApfGenerator(); |
| 202 | gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL); |
| 203 | assertPass(gen); |
| 204 | gen = new ApfGenerator(); |
| 205 | gen.addLoadImmediate(Register.R0, 1); |
| 206 | gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL); |
| 207 | assertDrop(gen); |
| 208 | |
| 209 | // Test load immediate. |
| 210 | gen = new ApfGenerator(); |
| 211 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 212 | gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); |
| 213 | assertDrop(gen); |
| 214 | |
| 215 | // Test add. |
| 216 | gen = new ApfGenerator(); |
| 217 | gen.addAdd(1234567890); |
| 218 | gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); |
| 219 | assertDrop(gen); |
| 220 | |
| 221 | // Test subtract. |
| 222 | gen = new ApfGenerator(); |
| 223 | gen.addAdd(-1234567890); |
| 224 | gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); |
| 225 | assertDrop(gen); |
| 226 | |
| 227 | // Test or. |
| 228 | gen = new ApfGenerator(); |
| 229 | gen.addOr(1234567890); |
| 230 | gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); |
| 231 | assertDrop(gen); |
| 232 | |
| 233 | // Test and. |
| 234 | gen = new ApfGenerator(); |
| 235 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 236 | gen.addAnd(123456789); |
| 237 | gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL); |
| 238 | assertDrop(gen); |
| 239 | |
| 240 | // Test left shift. |
| 241 | gen = new ApfGenerator(); |
| 242 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 243 | gen.addLeftShift(1); |
| 244 | gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL); |
| 245 | assertDrop(gen); |
| 246 | |
| 247 | // Test right shift. |
| 248 | gen = new ApfGenerator(); |
| 249 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 250 | gen.addRightShift(1); |
| 251 | gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL); |
| 252 | assertDrop(gen); |
| 253 | |
| 254 | // Test multiply. |
| 255 | gen = new ApfGenerator(); |
| 256 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 257 | gen.addMul(2); |
| 258 | gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL); |
| 259 | assertDrop(gen); |
| 260 | |
| 261 | // Test divide. |
| 262 | gen = new ApfGenerator(); |
| 263 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 264 | gen.addDiv(2); |
| 265 | gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL); |
| 266 | assertDrop(gen); |
| 267 | |
| 268 | // Test divide by zero. |
| 269 | gen = new ApfGenerator(); |
| 270 | gen.addDiv(0); |
| 271 | gen.addJump(gen.DROP_LABEL); |
| 272 | assertPass(gen); |
| 273 | |
| 274 | // Test add. |
| 275 | gen = new ApfGenerator(); |
| 276 | gen.addLoadImmediate(Register.R1, 1234567890); |
| 277 | gen.addAddR1(); |
| 278 | gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); |
| 279 | assertDrop(gen); |
| 280 | |
| 281 | // Test subtract. |
| 282 | gen = new ApfGenerator(); |
| 283 | gen.addLoadImmediate(Register.R1, -1234567890); |
| 284 | gen.addAddR1(); |
| 285 | gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); |
| 286 | assertDrop(gen); |
| 287 | |
| 288 | // Test or. |
| 289 | gen = new ApfGenerator(); |
| 290 | gen.addLoadImmediate(Register.R1, 1234567890); |
| 291 | gen.addOrR1(); |
| 292 | gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); |
| 293 | assertDrop(gen); |
| 294 | |
| 295 | // Test and. |
| 296 | gen = new ApfGenerator(); |
| 297 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 298 | gen.addLoadImmediate(Register.R1, 123456789); |
| 299 | gen.addAndR1(); |
| 300 | gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL); |
| 301 | assertDrop(gen); |
| 302 | |
| 303 | // Test left shift. |
| 304 | gen = new ApfGenerator(); |
| 305 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 306 | gen.addLoadImmediate(Register.R1, 1); |
| 307 | gen.addLeftShiftR1(); |
| 308 | gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL); |
| 309 | assertDrop(gen); |
| 310 | |
| 311 | // Test right shift. |
| 312 | gen = new ApfGenerator(); |
| 313 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 314 | gen.addLoadImmediate(Register.R1, -1); |
| 315 | gen.addLeftShiftR1(); |
| 316 | gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL); |
| 317 | assertDrop(gen); |
| 318 | |
| 319 | // Test multiply. |
| 320 | gen = new ApfGenerator(); |
| 321 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 322 | gen.addLoadImmediate(Register.R1, 2); |
| 323 | gen.addMulR1(); |
| 324 | gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL); |
| 325 | assertDrop(gen); |
| 326 | |
| 327 | // Test divide. |
| 328 | gen = new ApfGenerator(); |
| 329 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 330 | gen.addLoadImmediate(Register.R1, 2); |
| 331 | gen.addDivR1(); |
| 332 | gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL); |
| 333 | assertDrop(gen); |
| 334 | |
| 335 | // Test divide by zero. |
| 336 | gen = new ApfGenerator(); |
| 337 | gen.addDivR1(); |
| 338 | gen.addJump(gen.DROP_LABEL); |
| 339 | assertPass(gen); |
| 340 | |
| 341 | // Test byte load. |
| 342 | gen = new ApfGenerator(); |
| 343 | gen.addLoad8(Register.R0, 1); |
| 344 | gen.addJumpIfR0Equals(45, gen.DROP_LABEL); |
| 345 | assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); |
| 346 | |
| 347 | // Test out of bounds load. |
| 348 | gen = new ApfGenerator(); |
| 349 | gen.addLoad8(Register.R0, 16); |
| 350 | gen.addJumpIfR0Equals(0, gen.DROP_LABEL); |
| 351 | assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); |
| 352 | |
| 353 | // Test half-word load. |
| 354 | gen = new ApfGenerator(); |
| 355 | gen.addLoad16(Register.R0, 1); |
| 356 | gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL); |
| 357 | assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0); |
| 358 | |
| 359 | // Test word load. |
| 360 | gen = new ApfGenerator(); |
| 361 | gen.addLoad32(Register.R0, 1); |
| 362 | gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL); |
| 363 | assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0); |
| 364 | |
| 365 | // Test byte indexed load. |
| 366 | gen = new ApfGenerator(); |
| 367 | gen.addLoadImmediate(Register.R1, 1); |
| 368 | gen.addLoad8Indexed(Register.R0, 0); |
| 369 | gen.addJumpIfR0Equals(45, gen.DROP_LABEL); |
| 370 | assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); |
| 371 | |
| 372 | // Test out of bounds indexed load. |
| 373 | gen = new ApfGenerator(); |
| 374 | gen.addLoadImmediate(Register.R1, 8); |
| 375 | gen.addLoad8Indexed(Register.R0, 8); |
| 376 | gen.addJumpIfR0Equals(0, gen.DROP_LABEL); |
| 377 | assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0); |
| 378 | |
| 379 | // Test half-word indexed load. |
| 380 | gen = new ApfGenerator(); |
| 381 | gen.addLoadImmediate(Register.R1, 1); |
| 382 | gen.addLoad16Indexed(Register.R0, 0); |
| 383 | gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL); |
| 384 | assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0); |
| 385 | |
| 386 | // Test word indexed load. |
| 387 | gen = new ApfGenerator(); |
| 388 | gen.addLoadImmediate(Register.R1, 1); |
| 389 | gen.addLoad32Indexed(Register.R0, 0); |
| 390 | gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL); |
| 391 | assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0); |
| 392 | |
| 393 | // Test jumping if greater than. |
| 394 | gen = new ApfGenerator(); |
| 395 | gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL); |
| 396 | assertPass(gen); |
| 397 | gen = new ApfGenerator(); |
| 398 | gen.addLoadImmediate(Register.R0, 1); |
| 399 | gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL); |
| 400 | assertDrop(gen); |
| 401 | |
| 402 | // Test jumping if less than. |
| 403 | gen = new ApfGenerator(); |
| 404 | gen.addJumpIfR0LessThan(0, gen.DROP_LABEL); |
| 405 | assertPass(gen); |
| 406 | gen = new ApfGenerator(); |
| 407 | gen.addJumpIfR0LessThan(1, gen.DROP_LABEL); |
| 408 | assertDrop(gen); |
| 409 | |
| 410 | // Test jumping if any bits set. |
| 411 | gen = new ApfGenerator(); |
| 412 | gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); |
| 413 | assertPass(gen); |
| 414 | gen = new ApfGenerator(); |
| 415 | gen.addLoadImmediate(Register.R0, 1); |
| 416 | gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); |
| 417 | assertDrop(gen); |
| 418 | gen = new ApfGenerator(); |
| 419 | gen.addLoadImmediate(Register.R0, 3); |
| 420 | gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL); |
| 421 | assertDrop(gen); |
| 422 | |
| 423 | // Test jumping if register greater than. |
| 424 | gen = new ApfGenerator(); |
| 425 | gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL); |
| 426 | assertPass(gen); |
| 427 | gen = new ApfGenerator(); |
| 428 | gen.addLoadImmediate(Register.R0, 2); |
| 429 | gen.addLoadImmediate(Register.R1, 1); |
| 430 | gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL); |
| 431 | assertDrop(gen); |
| 432 | |
| 433 | // Test jumping if register less than. |
| 434 | gen = new ApfGenerator(); |
| 435 | gen.addJumpIfR0LessThanR1(gen.DROP_LABEL); |
| 436 | assertPass(gen); |
| 437 | gen = new ApfGenerator(); |
| 438 | gen.addLoadImmediate(Register.R1, 1); |
| 439 | gen.addJumpIfR0LessThanR1(gen.DROP_LABEL); |
| 440 | assertDrop(gen); |
| 441 | |
| 442 | // Test jumping if any bits set in register. |
| 443 | gen = new ApfGenerator(); |
| 444 | gen.addLoadImmediate(Register.R1, 3); |
| 445 | gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); |
| 446 | assertPass(gen); |
| 447 | gen = new ApfGenerator(); |
| 448 | gen.addLoadImmediate(Register.R1, 3); |
| 449 | gen.addLoadImmediate(Register.R0, 1); |
| 450 | gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); |
| 451 | assertDrop(gen); |
| 452 | gen = new ApfGenerator(); |
| 453 | gen.addLoadImmediate(Register.R1, 3); |
| 454 | gen.addLoadImmediate(Register.R0, 3); |
| 455 | gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL); |
| 456 | assertDrop(gen); |
| 457 | |
| 458 | // Test load from memory. |
| 459 | gen = new ApfGenerator(); |
| 460 | gen.addLoadFromMemory(Register.R0, 0); |
| 461 | gen.addJumpIfR0Equals(0, gen.DROP_LABEL); |
| 462 | assertDrop(gen); |
| 463 | |
| 464 | // Test store to memory. |
| 465 | gen = new ApfGenerator(); |
| 466 | gen.addLoadImmediate(Register.R1, 1234567890); |
| 467 | gen.addStoreToMemory(Register.R1, 12); |
| 468 | gen.addLoadFromMemory(Register.R0, 12); |
| 469 | gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); |
| 470 | assertDrop(gen); |
| 471 | |
| 472 | // Test filter age pre-filled memory. |
| 473 | gen = new ApfGenerator(); |
| 474 | gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT); |
| 475 | gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); |
| 476 | assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890); |
| 477 | |
| 478 | // Test packet size pre-filled memory. |
| 479 | gen = new ApfGenerator(); |
| 480 | gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT); |
| 481 | gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL); |
| 482 | assertDrop(gen); |
| 483 | |
| 484 | // Test IPv4 header size pre-filled memory. |
| 485 | gen = new ApfGenerator(); |
| 486 | gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); |
| 487 | gen.addJumpIfR0Equals(20, gen.DROP_LABEL); |
| 488 | assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0); |
| 489 | |
| 490 | // Test not. |
| 491 | gen = new ApfGenerator(); |
| 492 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 493 | gen.addNot(Register.R0); |
| 494 | gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL); |
| 495 | assertDrop(gen); |
| 496 | |
| 497 | // Test negate. |
| 498 | gen = new ApfGenerator(); |
| 499 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 500 | gen.addNeg(Register.R0); |
| 501 | gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL); |
| 502 | assertDrop(gen); |
| 503 | |
| 504 | // Test move. |
| 505 | gen = new ApfGenerator(); |
| 506 | gen.addLoadImmediate(Register.R1, 1234567890); |
| 507 | gen.addMove(Register.R0); |
| 508 | gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); |
| 509 | assertDrop(gen); |
| 510 | gen = new ApfGenerator(); |
| 511 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 512 | gen.addMove(Register.R1); |
| 513 | gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); |
| 514 | assertDrop(gen); |
| 515 | |
| 516 | // Test swap. |
| 517 | gen = new ApfGenerator(); |
| 518 | gen.addLoadImmediate(Register.R1, 1234567890); |
| 519 | gen.addSwap(); |
| 520 | gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL); |
| 521 | assertDrop(gen); |
| 522 | gen = new ApfGenerator(); |
| 523 | gen.addLoadImmediate(Register.R0, 1234567890); |
| 524 | gen.addSwap(); |
| 525 | gen.addJumpIfR0Equals(0, gen.DROP_LABEL); |
| 526 | assertDrop(gen); |
| 527 | |
| 528 | // Test jump if bytes not equal. |
| 529 | gen = new ApfGenerator(); |
| 530 | gen.addLoadImmediate(Register.R0, 1); |
| 531 | gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL); |
| 532 | program = gen.generate(); |
| 533 | assertEquals(6, program.length); |
| 534 | assertEquals((13 << 3) | (1 << 1) | 0, program[0]); |
| 535 | assertEquals(1, program[1]); |
| 536 | assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]); |
| 537 | assertEquals(1, program[3]); |
| 538 | assertEquals(1, program[4]); |
| 539 | assertEquals(123, program[5]); |
| 540 | assertDrop(program, new byte[MIN_PKT_SIZE], 0); |
| 541 | gen = new ApfGenerator(); |
| 542 | gen.addLoadImmediate(Register.R0, 1); |
| 543 | gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 544 | byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0}; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 545 | assertPass(gen, packet123, 0); |
| 546 | gen = new ApfGenerator(); |
| 547 | gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL); |
| 548 | assertDrop(gen, packet123, 0); |
| 549 | gen = new ApfGenerator(); |
| 550 | gen.addLoadImmediate(Register.R0, 1); |
| 551 | gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 552 | byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0}; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 553 | assertDrop(gen, packet12345, 0); |
| 554 | gen = new ApfGenerator(); |
| 555 | gen.addLoadImmediate(Register.R0, 1); |
| 556 | gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL); |
| 557 | assertPass(gen, packet12345, 0); |
| 558 | } |
| 559 | |
| 560 | /** |
| 561 | * Generate some BPF programs, translate them to APF, then run APF and BPF programs |
| 562 | * over packet traces and verify both programs filter out the same packets. |
| 563 | */ |
| 564 | @LargeTest |
| 565 | public void testApfAgainstBpf() throws Exception { |
| 566 | String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53", |
| 567 | "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24", |
| 568 | "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000", |
| 569 | "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" }; |
| 570 | String pcap_filename = stageFile(R.raw.apf); |
| 571 | for (String tcpdump_filter : tcpdump_filters) { |
| 572 | byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter)); |
| 573 | assertTrue("Failed to match for filter: " + tcpdump_filter, |
| 574 | compareBpfApf(tcpdump_filter, pcap_filename, apf_program)); |
| 575 | } |
| 576 | } |
| 577 | |
| 578 | private class MockIpManagerCallback extends IpManager.Callback { |
| 579 | private final ConditionVariable mGotApfProgram = new ConditionVariable(); |
| 580 | private byte[] mLastApfProgram; |
| 581 | |
| 582 | @Override |
| 583 | public void installPacketFilter(byte[] filter) { |
| 584 | mLastApfProgram = filter; |
| 585 | mGotApfProgram.open(); |
| 586 | } |
| 587 | |
| 588 | public void resetApfProgramWait() { |
| 589 | mGotApfProgram.close(); |
| 590 | } |
| 591 | |
| 592 | public byte[] getApfProgram() { |
| 593 | assertTrue(mGotApfProgram.block(TIMEOUT_MS)); |
| 594 | return mLastApfProgram; |
| 595 | } |
Lorenzo Colitti | 8995d85 | 2016-06-23 15:24:46 +0900 | [diff] [blame] | 596 | |
| 597 | public void assertNoProgramUpdate() { |
| 598 | assertFalse(mGotApfProgram.block(TIMEOUT_MS)); |
| 599 | } |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 600 | } |
| 601 | |
| 602 | private static class TestApfFilter extends ApfFilter { |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 603 | public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6}; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 604 | private FileDescriptor mWriteSocket; |
| 605 | |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 606 | public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter, |
| 607 | IpConnectivityLog log) throws Exception { |
Hugo Benichi | 0dc1d31 | 2016-09-02 12:40:31 +0900 | [diff] [blame] | 608 | super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"), |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 609 | ipManagerCallback, multicastFilter, log); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 610 | } |
| 611 | |
| 612 | // Pretend an RA packet has been received and show it to ApfFilter. |
| 613 | public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException { |
| 614 | // ApfFilter's ReceiveThread will be waiting to read this. |
| 615 | Os.write(mWriteSocket, packet, 0, packet.length); |
| 616 | } |
| 617 | |
| 618 | @Override |
| 619 | void maybeStartFilter() { |
| 620 | mHardwareAddress = MOCK_MAC_ADDR; |
| 621 | installNewProgramLocked(); |
| 622 | |
| 623 | // Create two sockets, "readSocket" and "mWriteSocket" and connect them together. |
| 624 | FileDescriptor readSocket = new FileDescriptor(); |
| 625 | mWriteSocket = new FileDescriptor(); |
| 626 | try { |
| 627 | Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket); |
| 628 | } catch (ErrnoException e) { |
| 629 | fail(); |
| 630 | return; |
| 631 | } |
| 632 | // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs. |
| 633 | // This allows us to pretend RA packets have been recieved via pretendPacketReceived(). |
| 634 | mReceiveThread = new ReceiveThread(readSocket); |
| 635 | mReceiveThread.start(); |
| 636 | } |
| 637 | |
| 638 | @Override |
| 639 | public void shutdown() { |
| 640 | super.shutdown(); |
| 641 | IoUtils.closeQuietly(mWriteSocket); |
| 642 | } |
| 643 | } |
| 644 | |
| 645 | private static final int ETH_HEADER_LEN = 14; |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 646 | private static final int ETH_DEST_ADDR_OFFSET = 0; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 647 | private static final int ETH_ETHERTYPE_OFFSET = 12; |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 648 | private static final byte[] ETH_BROADCAST_MAC_ADDRESS = |
| 649 | {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 650 | |
| 651 | private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0; |
| 652 | private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9; |
| 653 | private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16; |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 654 | private static final byte[] IPV4_BROADCAST_ADDRESS = |
| 655 | {(byte) 255, (byte) 255, (byte) 255, (byte) 255}; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 656 | |
| 657 | private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6; |
| 658 | private static final int IPV6_HEADER_LEN = 40; |
| 659 | private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24; |
| 660 | // The IPv6 all nodes address ff02::1 |
| 661 | private static final byte[] IPV6_ALL_NODES_ADDRESS = |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 662 | { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; |
Hugo Benichi | 0cc49bb | 2016-12-08 16:34:46 +0900 | [diff] [blame] | 663 | private static final byte[] IPV6_ALL_ROUTERS_ADDRESS = |
| 664 | { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 665 | |
| 666 | private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN; |
Hugo Benichi | 0cc49bb | 2016-12-08 16:34:46 +0900 | [diff] [blame] | 667 | private static final int ICMP6_ROUTER_SOLICITATION = 133; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 668 | private static final int ICMP6_ROUTER_ADVERTISEMENT = 134; |
Hugo Benichi | 0cc49bb | 2016-12-08 16:34:46 +0900 | [diff] [blame] | 669 | private static final int ICMP6_NEIGHBOR_SOLICITATION = 135; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 670 | private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136; |
| 671 | |
| 672 | private static final int ICMP6_RA_HEADER_LEN = 16; |
| 673 | private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET = |
| 674 | ETH_HEADER_LEN + IPV6_HEADER_LEN + 6; |
| 675 | private static final int ICMP6_RA_CHECKSUM_OFFSET = |
| 676 | ETH_HEADER_LEN + IPV6_HEADER_LEN + 2; |
| 677 | private static final int ICMP6_RA_OPTION_OFFSET = |
| 678 | ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN; |
| 679 | |
| 680 | private static final int ICMP6_PREFIX_OPTION_TYPE = 3; |
| 681 | private static final int ICMP6_PREFIX_OPTION_LEN = 32; |
| 682 | private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4; |
| 683 | private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8; |
| 684 | |
| 685 | // From RFC6106: Recursive DNS Server option |
| 686 | private static final int ICMP6_RDNSS_OPTION_TYPE = 25; |
| 687 | // From RFC6106: DNS Search List option |
| 688 | private static final int ICMP6_DNSSL_OPTION_TYPE = 31; |
| 689 | |
| 690 | // From RFC4191: Route Information option |
| 691 | private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24; |
| 692 | // Above three options all have the same format: |
| 693 | private static final int ICMP6_4_BYTE_OPTION_LEN = 8; |
| 694 | private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4; |
| 695 | private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4; |
| 696 | |
| 697 | private static final int UDP_HEADER_LEN = 8; |
| 698 | private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22; |
| 699 | |
| 700 | private static final int DHCP_CLIENT_PORT = 68; |
| 701 | private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48; |
| 702 | |
Hugo Benichi | 4fc3ee5 | 2016-06-02 11:20:27 +0900 | [diff] [blame] | 703 | private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN; |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 704 | private static final byte[] ARP_IPV4_REQUEST_HEADER = { |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 705 | 0, 1, // Hardware type: Ethernet (1) |
| 706 | 8, 0, // Protocol type: IP (0x0800) |
| 707 | 6, // Hardware size: 6 |
| 708 | 4, // Protocol size: 4 |
| 709 | 0, 1 // Opcode: request (1) |
| 710 | }; |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 711 | private static final byte[] ARP_IPV4_REPLY_HEADER = { |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 712 | 0, 1, // Hardware type: Ethernet (1) |
| 713 | 8, 0, // Protocol type: IP (0x0800) |
| 714 | 6, // Hardware size: 6 |
| 715 | 4, // Protocol size: 4 |
| 716 | 0, 2 // Opcode: reply (2) |
| 717 | }; |
Hugo Benichi | 4fc3ee5 | 2016-06-02 11:20:27 +0900 | [diff] [blame] | 718 | private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 719 | |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 720 | private static final byte[] MOCK_IPV4_ADDR = {10, 0, 0, 1}; |
Hugo Benichi | 7d21eae | 2016-09-02 14:00:29 +0900 | [diff] [blame] | 721 | private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19 |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 722 | private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1}; |
| 723 | private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2}; |
| 724 | private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0}; |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 725 | |
| 726 | @LargeTest |
| 727 | public void testApfFilterIPv4() throws Exception { |
| 728 | MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); |
Hugo Benichi | 7d21eae | 2016-09-02 14:00:29 +0900 | [diff] [blame] | 729 | LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19); |
| 730 | LinkProperties lp = new LinkProperties(); |
| 731 | lp.addLinkAddress(link); |
Hugo Benichi | 0dc1d31 | 2016-09-02 12:40:31 +0900 | [diff] [blame] | 732 | |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 733 | ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); |
Hugo Benichi | 7d21eae | 2016-09-02 14:00:29 +0900 | [diff] [blame] | 734 | apfFilter.setLinkProperties(lp); |
Hugo Benichi | 0dc1d31 | 2016-09-02 12:40:31 +0900 | [diff] [blame] | 735 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 736 | byte[] program = ipManagerCallback.getApfProgram(); |
| 737 | |
| 738 | // Verify empty packet of 100 zero bytes is passed |
| 739 | ByteBuffer packet = ByteBuffer.wrap(new byte[100]); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 740 | assertPass(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 741 | |
| 742 | // Verify unicast IPv4 packet is passed |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 743 | put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 744 | packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 745 | put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR); |
| 746 | assertPass(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 747 | |
Hugo Benichi | 0dc1d31 | 2016-09-02 12:40:31 +0900 | [diff] [blame] | 748 | // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088) |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 749 | put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS); |
Hugo Benichi | 0dc1d31 | 2016-09-02 12:40:31 +0900 | [diff] [blame] | 750 | assertDrop(program, packet.array()); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 751 | put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR); |
Hugo Benichi | 7d21eae | 2016-09-02 14:00:29 +0900 | [diff] [blame] | 752 | assertDrop(program, packet.array()); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 753 | |
| 754 | // Verify multicast/broadcast IPv4, not DHCP to us, is dropped |
| 755 | put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS); |
| 756 | assertDrop(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 757 | packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 758 | assertDrop(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 759 | packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 760 | assertDrop(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 761 | packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 762 | assertDrop(program, packet.array()); |
| 763 | put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR); |
| 764 | assertDrop(program, packet.array()); |
| 765 | put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR); |
| 766 | assertDrop(program, packet.array()); |
| 767 | put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS); |
| 768 | assertDrop(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 769 | |
| 770 | // Verify broadcast IPv4 DHCP to us is passed |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 771 | put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR); |
| 772 | assertPass(program, packet.array()); |
| 773 | |
| 774 | // Verify unicast IPv4 DHCP to us is passed |
| 775 | put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR); |
| 776 | assertPass(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 777 | |
| 778 | apfFilter.shutdown(); |
| 779 | } |
| 780 | |
| 781 | @LargeTest |
| 782 | public void testApfFilterIPv6() throws Exception { |
| 783 | MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 784 | ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 785 | byte[] program = ipManagerCallback.getApfProgram(); |
| 786 | |
| 787 | // Verify empty IPv6 packet is passed |
| 788 | ByteBuffer packet = ByteBuffer.wrap(new byte[100]); |
| 789 | packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 790 | assertPass(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 791 | |
| 792 | // Verify empty ICMPv6 packet is passed |
| 793 | packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 794 | assertPass(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 795 | |
| 796 | // Verify empty ICMPv6 NA packet is passed |
| 797 | packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 798 | assertPass(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 799 | |
| 800 | // Verify ICMPv6 NA to ff02::1 is dropped |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 801 | put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS); |
| 802 | assertDrop(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 803 | |
Hugo Benichi | 0cc49bb | 2016-12-08 16:34:46 +0900 | [diff] [blame] | 804 | // Verify ICMPv6 RS to any is dropped |
| 805 | packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION); |
| 806 | assertDrop(program, packet.array()); |
| 807 | put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS); |
| 808 | assertDrop(program, packet.array()); |
| 809 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 810 | apfFilter.shutdown(); |
| 811 | } |
| 812 | |
| 813 | @LargeTest |
Lorenzo Colitti | 11e13e2 | 2016-05-20 00:04:43 +0900 | [diff] [blame] | 814 | public void testApfFilterMulticast() throws Exception { |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 815 | final byte[] unicastIpv4Addr = {(byte)192,0,2,63}; |
Hugo Benichi | 7d21eae | 2016-09-02 14:00:29 +0900 | [diff] [blame] | 816 | final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255}; |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 817 | final byte[] multicastIpv4Addr = {(byte)224,0,0,1}; |
| 818 | final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb}; |
| 819 | |
Hugo Benichi | 7d21eae | 2016-09-02 14:00:29 +0900 | [diff] [blame] | 820 | MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); |
| 821 | LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24); |
| 822 | LinkProperties lp = new LinkProperties(); |
| 823 | lp.addLinkAddress(link); |
| 824 | |
| 825 | ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); |
| 826 | apfFilter.setLinkProperties(lp); |
| 827 | |
| 828 | byte[] program = ipManagerCallback.getApfProgram(); |
| 829 | |
Lorenzo Colitti | 11e13e2 | 2016-05-20 00:04:43 +0900 | [diff] [blame] | 830 | // Construct IPv4 and IPv6 multicast packets. |
Paul Jensen | f8a01e8 | 2016-05-26 09:16:11 -0400 | [diff] [blame] | 831 | ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]); |
| 832 | mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 833 | put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr); |
Lorenzo Colitti | 11e13e2 | 2016-05-20 00:04:43 +0900 | [diff] [blame] | 834 | |
Paul Jensen | f8a01e8 | 2016-05-26 09:16:11 -0400 | [diff] [blame] | 835 | ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]); |
| 836 | mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6); |
| 837 | mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 838 | put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr); |
Paul Jensen | f8a01e8 | 2016-05-26 09:16:11 -0400 | [diff] [blame] | 839 | |
| 840 | // Construct IPv4 broadcast packet. |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 841 | ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]); |
| 842 | bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS); |
| 843 | bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); |
| 844 | put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr); |
| 845 | |
| 846 | ByteBuffer bcastv4packet2 = ByteBuffer.wrap(new byte[100]); |
| 847 | bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS); |
| 848 | bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); |
| 849 | put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS); |
| 850 | |
| 851 | // Construct IPv4 broadcast with L2 unicast address packet (b/30231088). |
| 852 | ByteBuffer bcastv4unicastl2packet = ByteBuffer.wrap(new byte[100]); |
| 853 | bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR); |
| 854 | bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); |
| 855 | put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr); |
Lorenzo Colitti | 11e13e2 | 2016-05-20 00:04:43 +0900 | [diff] [blame] | 856 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 857 | // Verify initially disabled multicast filter is off |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 858 | assertPass(program, mcastv4packet.array()); |
| 859 | assertPass(program, mcastv6packet.array()); |
| 860 | assertPass(program, bcastv4packet1.array()); |
| 861 | assertPass(program, bcastv4packet2.array()); |
| 862 | assertPass(program, bcastv4unicastl2packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 863 | |
| 864 | // Turn on multicast filter and verify it works |
| 865 | ipManagerCallback.resetApfProgramWait(); |
| 866 | apfFilter.setMulticastFilter(true); |
| 867 | program = ipManagerCallback.getApfProgram(); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 868 | assertDrop(program, mcastv4packet.array()); |
| 869 | assertDrop(program, mcastv6packet.array()); |
| 870 | assertDrop(program, bcastv4packet1.array()); |
| 871 | assertDrop(program, bcastv4packet2.array()); |
Hugo Benichi | 7d21eae | 2016-09-02 14:00:29 +0900 | [diff] [blame] | 872 | assertDrop(program, bcastv4unicastl2packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 873 | |
| 874 | // Turn off multicast filter and verify it's off |
| 875 | ipManagerCallback.resetApfProgramWait(); |
| 876 | apfFilter.setMulticastFilter(false); |
| 877 | program = ipManagerCallback.getApfProgram(); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 878 | assertPass(program, mcastv4packet.array()); |
| 879 | assertPass(program, mcastv6packet.array()); |
| 880 | assertPass(program, bcastv4packet1.array()); |
| 881 | assertPass(program, bcastv4packet2.array()); |
| 882 | assertPass(program, bcastv4unicastl2packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 883 | |
| 884 | // Verify it can be initialized to on |
| 885 | ipManagerCallback.resetApfProgramWait(); |
| 886 | apfFilter.shutdown(); |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 887 | apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); |
Hugo Benichi | 7d21eae | 2016-09-02 14:00:29 +0900 | [diff] [blame] | 888 | apfFilter.setLinkProperties(lp); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 889 | program = ipManagerCallback.getApfProgram(); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 890 | assertDrop(program, mcastv4packet.array()); |
| 891 | assertDrop(program, mcastv6packet.array()); |
| 892 | assertDrop(program, bcastv4packet1.array()); |
Hugo Benichi | 7d21eae | 2016-09-02 14:00:29 +0900 | [diff] [blame] | 893 | assertDrop(program, bcastv4unicastl2packet.array()); |
Lorenzo Colitti | 11e13e2 | 2016-05-20 00:04:43 +0900 | [diff] [blame] | 894 | |
| 895 | // Verify that ICMPv6 multicast is not dropped. |
Paul Jensen | f8a01e8 | 2016-05-26 09:16:11 -0400 | [diff] [blame] | 896 | mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 897 | assertPass(program, mcastv6packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 898 | |
| 899 | apfFilter.shutdown(); |
| 900 | } |
| 901 | |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 902 | private byte[] getProgram(MockIpManagerCallback cb, ApfFilter filter, LinkProperties lp) { |
| 903 | cb.resetApfProgramWait(); |
| 904 | filter.setLinkProperties(lp); |
| 905 | return cb.getApfProgram(); |
| 906 | } |
| 907 | |
| 908 | private void verifyArpFilter(byte[] program, int filterResult) { |
| 909 | // Verify ARP request packet |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 910 | assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR)); |
| 911 | assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR)); |
| 912 | assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR)); |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 913 | |
| 914 | // Verify unicast ARP reply packet is always accepted. |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 915 | assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR)); |
| 916 | assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR)); |
| 917 | assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR)); |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 918 | |
| 919 | // Verify GARP reply packets are always filtered |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 920 | assertDrop(program, garpReply()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 921 | } |
| 922 | |
| 923 | @LargeTest |
| 924 | public void testApfFilterArp() throws Exception { |
| 925 | MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 926 | ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 927 | |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 928 | // Verify initially ARP request filter is off, and GARP filter is on. |
| 929 | verifyArpFilter(ipManagerCallback.getApfProgram(), PASS); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 930 | |
| 931 | // Inform ApfFilter of our address and verify ARP filtering is on |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 932 | LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 933 | LinkProperties lp = new LinkProperties(); |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 934 | assertTrue(lp.addLinkAddress(linkAddress)); |
| 935 | verifyArpFilter(getProgram(ipManagerCallback, apfFilter, lp), DROP); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 936 | |
| 937 | // Inform ApfFilter of loss of IP and verify ARP filtering is off |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 938 | verifyArpFilter(getProgram(ipManagerCallback, apfFilter, new LinkProperties()), PASS); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 939 | |
| 940 | apfFilter.shutdown(); |
| 941 | } |
| 942 | |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 943 | private static byte[] arpRequestBroadcast(byte[] tip) { |
| 944 | ByteBuffer packet = ByteBuffer.wrap(new byte[100]); |
| 945 | packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 946 | put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS); |
| 947 | put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER); |
| 948 | put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip); |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 949 | return packet.array(); |
| 950 | } |
| 951 | |
| 952 | private static byte[] arpReplyUnicast(byte[] tip) { |
| 953 | ByteBuffer packet = ByteBuffer.wrap(new byte[100]); |
| 954 | packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 955 | put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER); |
| 956 | put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip); |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 957 | return packet.array(); |
| 958 | } |
| 959 | |
| 960 | private static byte[] garpReply() { |
| 961 | ByteBuffer packet = ByteBuffer.wrap(new byte[100]); |
| 962 | packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 963 | put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS); |
| 964 | put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER); |
| 965 | put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR); |
Hugo Benichi | 38db976 | 2016-07-12 15:08:50 +0900 | [diff] [blame] | 966 | return packet.array(); |
| 967 | } |
| 968 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 969 | // Verify that the last program pushed to the IpManager.Callback properly filters the |
| 970 | // given packet for the given lifetime. |
| 971 | private void verifyRaLifetime(MockIpManagerCallback ipManagerCallback, ByteBuffer packet, |
| 972 | int lifetime) { |
| 973 | byte[] program = ipManagerCallback.getApfProgram(); |
| 974 | |
| 975 | // Verify new program should drop RA for 1/6th its lifetime |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 976 | assertDrop(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 977 | assertDrop(program, packet.array(), lifetime/6); |
| 978 | assertPass(program, packet.array(), lifetime/6 + 1); |
| 979 | assertPass(program, packet.array(), lifetime); |
| 980 | |
| 981 | // Verify RA checksum is ignored |
| 982 | packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 983 | assertDrop(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 984 | packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 985 | assertDrop(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 986 | |
| 987 | // Verify other changes to RA make it not match filter |
| 988 | packet.put(0, (byte)-1); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 989 | assertPass(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 990 | packet.put(0, (byte)0); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 991 | assertDrop(program, packet.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 992 | } |
| 993 | |
| 994 | // Test that when ApfFilter is shown the given packet, it generates a program to filter it |
| 995 | // for the given lifetime. |
| 996 | private void testRaLifetime(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback, |
| 997 | ByteBuffer packet, int lifetime) throws IOException, ErrnoException { |
| 998 | // Verify new program generated if ApfFilter witnesses RA |
| 999 | ipManagerCallback.resetApfProgramWait(); |
| 1000 | apfFilter.pretendPacketReceived(packet.array()); |
| 1001 | ipManagerCallback.getApfProgram(); |
| 1002 | |
| 1003 | verifyRaLifetime(ipManagerCallback, packet, lifetime); |
| 1004 | } |
| 1005 | |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 1006 | private void verifyRaEvent(RaEvent expected) { |
| 1007 | ArgumentCaptor<Parcelable> captor = ArgumentCaptor.forClass(Parcelable.class); |
| 1008 | verify(mLog, atLeastOnce()).log(captor.capture()); |
| 1009 | RaEvent got = lastRaEvent(captor.getAllValues()); |
| 1010 | if (!raEventEquals(expected, got)) { |
| 1011 | assertEquals(expected, got); // fail for printing an assertion error message. |
| 1012 | } |
| 1013 | } |
| 1014 | |
| 1015 | private RaEvent lastRaEvent(List<Parcelable> events) { |
| 1016 | RaEvent got = null; |
| 1017 | for (Parcelable ev : events) { |
| 1018 | if (ev instanceof RaEvent) { |
| 1019 | got = (RaEvent) ev; |
| 1020 | } |
| 1021 | } |
| 1022 | return got; |
| 1023 | } |
| 1024 | |
| 1025 | private boolean raEventEquals(RaEvent ev1, RaEvent ev2) { |
| 1026 | return (ev1 != null) && (ev2 != null) |
| 1027 | && (ev1.routerLifetime == ev2.routerLifetime) |
| 1028 | && (ev1.prefixValidLifetime == ev2.prefixValidLifetime) |
| 1029 | && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime) |
| 1030 | && (ev1.routeInfoLifetime == ev2.routeInfoLifetime) |
| 1031 | && (ev1.rdnssLifetime == ev2.rdnssLifetime) |
| 1032 | && (ev1.dnsslLifetime == ev2.dnsslLifetime); |
| 1033 | } |
| 1034 | |
Lorenzo Colitti | 8995d85 | 2016-06-23 15:24:46 +0900 | [diff] [blame] | 1035 | private void assertInvalidRa(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback, |
| 1036 | ByteBuffer packet) throws IOException, ErrnoException { |
| 1037 | ipManagerCallback.resetApfProgramWait(); |
| 1038 | apfFilter.pretendPacketReceived(packet.array()); |
| 1039 | ipManagerCallback.assertNoProgramUpdate(); |
| 1040 | } |
| 1041 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 1042 | @LargeTest |
| 1043 | public void testApfFilterRa() throws Exception { |
| 1044 | MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 1045 | TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 1046 | byte[] program = ipManagerCallback.getApfProgram(); |
| 1047 | |
| 1048 | // Verify RA is passed the first time |
| 1049 | ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]); |
| 1050 | basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6); |
| 1051 | basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); |
| 1052 | basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT); |
| 1053 | basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000); |
Lorenzo Colitti | 11e13e2 | 2016-05-20 00:04:43 +0900 | [diff] [blame] | 1054 | basePacket.position(IPV6_DEST_ADDR_OFFSET); |
| 1055 | basePacket.put(IPV6_ALL_NODES_ADDRESS); |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 1056 | assertPass(program, basePacket.array()); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 1057 | |
| 1058 | testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000); |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 1059 | verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1)); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 1060 | |
Lorenzo Colitti | 8995d85 | 2016-06-23 15:24:46 +0900 | [diff] [blame] | 1061 | // Ensure zero-length options cause the packet to be silently skipped. |
| 1062 | // Do this before we test other packets. http://b/29586253 |
| 1063 | ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap( |
| 1064 | new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); |
| 1065 | basePacket.clear(); |
| 1066 | zeroLengthOptionPacket.put(basePacket); |
| 1067 | zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE); |
| 1068 | zeroLengthOptionPacket.put((byte)0); |
| 1069 | assertInvalidRa(apfFilter, ipManagerCallback, zeroLengthOptionPacket); |
| 1070 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 1071 | // Generate several RAs with different options and lifetimes, and verify when |
| 1072 | // ApfFilter is shown these packets, it generates programs to filter them for the |
| 1073 | // appropriate lifetime. |
| 1074 | ByteBuffer prefixOptionPacket = ByteBuffer.wrap( |
| 1075 | new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]); |
| 1076 | basePacket.clear(); |
| 1077 | prefixOptionPacket.put(basePacket); |
| 1078 | prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE); |
| 1079 | prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8)); |
| 1080 | prefixOptionPacket.putInt( |
| 1081 | ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, 100); |
| 1082 | prefixOptionPacket.putInt( |
| 1083 | ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 200); |
| 1084 | testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, 100); |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 1085 | verifyRaEvent(new RaEvent(1000, 200, 100, -1, -1, -1)); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 1086 | |
| 1087 | ByteBuffer rdnssOptionPacket = ByteBuffer.wrap( |
| 1088 | new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); |
| 1089 | basePacket.clear(); |
| 1090 | rdnssOptionPacket.put(basePacket); |
| 1091 | rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE); |
| 1092 | rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); |
| 1093 | rdnssOptionPacket.putInt( |
| 1094 | ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 300); |
| 1095 | testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, 300); |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 1096 | verifyRaEvent(new RaEvent(1000, -1, -1, -1, 300, -1)); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 1097 | |
| 1098 | ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap( |
| 1099 | new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); |
| 1100 | basePacket.clear(); |
| 1101 | routeInfoOptionPacket.put(basePacket); |
| 1102 | routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE); |
| 1103 | routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); |
| 1104 | routeInfoOptionPacket.putInt( |
| 1105 | ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 400); |
| 1106 | testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, 400); |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 1107 | verifyRaEvent(new RaEvent(1000, -1, -1, 400, -1, -1)); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 1108 | |
| 1109 | ByteBuffer dnsslOptionPacket = ByteBuffer.wrap( |
| 1110 | new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]); |
| 1111 | basePacket.clear(); |
| 1112 | dnsslOptionPacket.put(basePacket); |
| 1113 | dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE); |
| 1114 | dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8)); |
| 1115 | dnsslOptionPacket.putInt( |
| 1116 | ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 2000); |
| 1117 | // Note that lifetime of 2000 will be ignored in favor of shorter |
| 1118 | // route lifetime of 1000. |
| 1119 | testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, 1000); |
Hugo Benichi | 6ccd51a | 2016-07-04 09:22:30 +0900 | [diff] [blame] | 1120 | verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, 2000)); |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 1121 | |
| 1122 | // Verify that current program filters all five RAs: |
| 1123 | verifyRaLifetime(ipManagerCallback, basePacket, 1000); |
| 1124 | verifyRaLifetime(ipManagerCallback, prefixOptionPacket, 100); |
| 1125 | verifyRaLifetime(ipManagerCallback, rdnssOptionPacket, 300); |
| 1126 | verifyRaLifetime(ipManagerCallback, routeInfoOptionPacket, 400); |
| 1127 | verifyRaLifetime(ipManagerCallback, dnsslOptionPacket, 1000); |
| 1128 | |
| 1129 | apfFilter.shutdown(); |
| 1130 | } |
| 1131 | |
| 1132 | /** |
| 1133 | * Stage a file for testing, i.e. make it native accessible. Given a resource ID, |
| 1134 | * copy that resource into the app's data directory and return the path to it. |
| 1135 | */ |
| 1136 | private String stageFile(int rawId) throws Exception { |
| 1137 | File file = new File(getContext().getFilesDir(), "staged_file"); |
| 1138 | new File(file.getParent()).mkdirs(); |
| 1139 | InputStream in = null; |
| 1140 | OutputStream out = null; |
| 1141 | try { |
| 1142 | in = getContext().getResources().openRawResource(rawId); |
| 1143 | out = new FileOutputStream(file); |
| 1144 | Streams.copy(in, out); |
| 1145 | } finally { |
| 1146 | if (in != null) in.close(); |
| 1147 | if (out != null) out.close(); |
| 1148 | } |
| 1149 | return file.getAbsolutePath(); |
| 1150 | } |
| 1151 | |
Hugo Benichi | 961ca49 | 2016-09-02 11:04:34 +0900 | [diff] [blame] | 1152 | private static void put(ByteBuffer buffer, int position, byte[] bytes) { |
| 1153 | final int original = buffer.position(); |
| 1154 | buffer.position(position); |
| 1155 | buffer.put(bytes); |
| 1156 | buffer.position(original); |
| 1157 | } |
| 1158 | |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 1159 | /** |
| 1160 | * Call the APF interpreter the run {@code program} on {@code packet} pretending the |
| 1161 | * filter was installed {@code filter_age} seconds ago. |
| 1162 | */ |
| 1163 | private native static int apfSimulate(byte[] program, byte[] packet, int filter_age); |
| 1164 | |
| 1165 | /** |
| 1166 | * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF |
| 1167 | * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d". |
| 1168 | */ |
| 1169 | private native static String compileToBpf(String filter); |
| 1170 | |
| 1171 | /** |
| 1172 | * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump |
| 1173 | * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and |
| 1174 | * at the same time using APF program {@code apf_program}. Return {@code true} if |
| 1175 | * both APF and BPF programs filter out exactly the same packets. |
| 1176 | */ |
| 1177 | private native static boolean compareBpfApf(String filter, String pcap_filename, |
| 1178 | byte[] apf_program); |
Hugo Benichi | 7d21eae | 2016-09-02 14:00:29 +0900 | [diff] [blame] | 1179 | |
| 1180 | public void testBytesToInt() { |
| 1181 | assertEquals(0x00000000, ApfFilter.bytesToInt(IPV4_ANY_HOST_ADDR)); |
| 1182 | assertEquals(0xffffffff, ApfFilter.bytesToInt(IPV4_BROADCAST_ADDRESS)); |
| 1183 | assertEquals(0x0a000001, ApfFilter.bytesToInt(MOCK_IPV4_ADDR)); |
| 1184 | assertEquals(0x0a000002, ApfFilter.bytesToInt(ANOTHER_IPV4_ADDR)); |
| 1185 | assertEquals(0x0a001fff, ApfFilter.bytesToInt(MOCK_BROADCAST_IPV4_ADDR)); |
| 1186 | assertEquals(0xe0000001, ApfFilter.bytesToInt(MOCK_MULTICAST_IPV4_ADDR)); |
| 1187 | } |
| 1188 | |
| 1189 | public void testBroadcastAddress() throws Exception { |
| 1190 | assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0)); |
| 1191 | assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32)); |
| 1192 | assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22)); |
| 1193 | assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8)); |
| 1194 | |
| 1195 | assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0)); |
| 1196 | assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32)); |
| 1197 | assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24)); |
| 1198 | assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16)); |
| 1199 | } |
| 1200 | |
| 1201 | public void assertEqualsIp(String expected, int got) throws Exception { |
| 1202 | int want = ApfFilter.bytesToInt(InetAddress.getByName(expected).getAddress()); |
| 1203 | assertEquals(want, got); |
| 1204 | } |
Paul Jensen | 9132f34 | 2016-04-13 15:00:26 -0400 | [diff] [blame] | 1205 | } |