blob: 6092fddc6be8e3e5e9f49ec94d9dad22c8eaa893 [file] [log] [blame]
Paul Jensen9132f342016-04-13 15:00:26 -04001/*
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
Hugo Benichi7d21eae2016-09-02 14:00:29 +090023import android.net.LinkAddress;
24import android.net.LinkProperties;
25import android.net.NetworkUtils;
Paul Jensen9132f342016-04-13 15:00:26 -040026import android.net.apf.ApfCapabilities;
27import android.net.apf.ApfFilter;
28import android.net.apf.ApfGenerator;
29import android.net.apf.ApfGenerator.IllegalInstructionException;
30import android.net.apf.ApfGenerator.Register;
31import android.net.ip.IpManager;
Hugo Benichi6ccd51a2016-07-04 09:22:30 +090032import android.net.metrics.IpConnectivityLog;
33import android.net.metrics.RaEvent;
Paul Jensen9132f342016-04-13 15:00:26 -040034import android.os.ConditionVariable;
Hugo Benichi6ccd51a2016-07-04 09:22:30 +090035import android.os.Parcelable;
Paul Jensen9132f342016-04-13 15:00:26 -040036import android.system.ErrnoException;
37import android.system.Os;
38import android.test.AndroidTestCase;
39import android.test.suitebuilder.annotation.LargeTest;
40
Hugo Benichi6ccd51a2016-07-04 09:22:30 +090041import org.mockito.ArgumentCaptor;
42import org.mockito.Mock;
43import org.mockito.MockitoAnnotations;
44import static org.mockito.Mockito.atLeastOnce;
45import static org.mockito.Mockito.verify;
46
Paul Jensen9132f342016-04-13 15:00:26 -040047import java.io.File;
48import java.io.FileDescriptor;
49import java.io.FileOutputStream;
50import java.io.IOException;
51import java.io.InputStream;
52import java.io.OutputStream;
53import java.net.InetAddress;
54import java.net.NetworkInterface;
55import java.nio.ByteBuffer;
Hugo Benichi6ccd51a2016-07-04 09:22:30 +090056import java.util.List;
Paul Jensen9132f342016-04-13 15:00:26 -040057
58import libcore.io.IoUtils;
59import libcore.io.Streams;
60
61/**
62 * Tests for APF program generator and interpreter.
63 *
64 * Build, install and run with:
Hugo Benichi961ca492016-09-02 11:04:34 +090065 * runtest frameworks-services -c android.net.apf.ApfTest
Paul Jensen9132f342016-04-13 15:00:26 -040066 */
67public class ApfTest extends AndroidTestCase {
68 private static final int TIMEOUT_MS = 500;
69
Hugo Benichi6ccd51a2016-07-04 09:22:30 +090070 @Mock IpConnectivityLog mLog;
71
Paul Jensen9132f342016-04-13 15:00:26 -040072 @Override
73 public void setUp() throws Exception {
74 super.setUp();
Hugo Benichi6ccd51a2016-07-04 09:22:30 +090075 MockitoAnnotations.initMocks(this);
Paul Jensen9132f342016-04-13 15:00:26 -040076 // 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 Benichi6ccd51a2016-07-04 09:22:30 +090087 private final static boolean DROP_MULTICAST = true;
88 private final static boolean ALLOW_MULTICAST = false;
89
Hugo Benichi961ca492016-09-02 11:04:34 +090090 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 Jensen9132f342016-04-13 15:00:26 -0400102 private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
Hugo Benichi961ca492016-09-02 11:04:34 +0900103 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 Jensen9132f342016-04-13 15:00:26 -0400108 }
109
110 private void assertPass(byte[] program, byte[] packet, int filterAge) {
111 assertVerdict(PASS, program, packet, filterAge);
112 }
113
Hugo Benichi961ca492016-09-02 11:04:34 +0900114 private void assertPass(byte[] program, byte[] packet) {
115 assertVerdict(PASS, program, packet);
116 }
117
Paul Jensen9132f342016-04-13 15:00:26 -0400118 private void assertDrop(byte[] program, byte[] packet, int filterAge) {
119 assertVerdict(DROP, program, packet, filterAge);
120 }
121
Hugo Benichi961ca492016-09-02 11:04:34 +0900122 private void assertDrop(byte[] program, byte[] packet) {
123 assertVerdict(DROP, program, packet);
124 }
125
Paul Jensen9132f342016-04-13 15:00:26 -0400126 private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
127 throws IllegalInstructionException {
Hugo Benichi961ca492016-09-02 11:04:34 +0900128 assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, filterAge));
Paul Jensen9132f342016-04-13 15:00:26 -0400129 }
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 Benichi961ca492016-09-02 11:04:34 +0900544 byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
Paul Jensen9132f342016-04-13 15:00:26 -0400545 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 Benichi961ca492016-09-02 11:04:34 +0900552 byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
Paul Jensen9132f342016-04-13 15:00:26 -0400553 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 Colitti8995d852016-06-23 15:24:46 +0900596
597 public void assertNoProgramUpdate() {
598 assertFalse(mGotApfProgram.block(TIMEOUT_MS));
599 }
Paul Jensen9132f342016-04-13 15:00:26 -0400600 }
601
602 private static class TestApfFilter extends ApfFilter {
Hugo Benichi961ca492016-09-02 11:04:34 +0900603 public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
Paul Jensen9132f342016-04-13 15:00:26 -0400604 private FileDescriptor mWriteSocket;
605
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900606 public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
607 IpConnectivityLog log) throws Exception {
Hugo Benichi0dc1d312016-09-02 12:40:31 +0900608 super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900609 ipManagerCallback, multicastFilter, log);
Paul Jensen9132f342016-04-13 15:00:26 -0400610 }
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 Benichi38db9762016-07-12 15:08:50 +0900646 private static final int ETH_DEST_ADDR_OFFSET = 0;
Paul Jensen9132f342016-04-13 15:00:26 -0400647 private static final int ETH_ETHERTYPE_OFFSET = 12;
Hugo Benichi961ca492016-09-02 11:04:34 +0900648 private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
649 {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
Paul Jensen9132f342016-04-13 15:00:26 -0400650
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 Benichi961ca492016-09-02 11:04:34 +0900654 private static final byte[] IPV4_BROADCAST_ADDRESS =
655 {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
Paul Jensen9132f342016-04-13 15:00:26 -0400656
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 Benichi961ca492016-09-02 11:04:34 +0900662 { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
Hugo Benichi0cc49bb2016-12-08 16:34:46 +0900663 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 Jensen9132f342016-04-13 15:00:26 -0400665
666 private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
Hugo Benichi0cc49bb2016-12-08 16:34:46 +0900667 private static final int ICMP6_ROUTER_SOLICITATION = 133;
Paul Jensen9132f342016-04-13 15:00:26 -0400668 private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
Hugo Benichi0cc49bb2016-12-08 16:34:46 +0900669 private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
Paul Jensen9132f342016-04-13 15:00:26 -0400670 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 Benichi4fc3ee52016-06-02 11:20:27 +0900703 private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
Hugo Benichi961ca492016-09-02 11:04:34 +0900704 private static final byte[] ARP_IPV4_REQUEST_HEADER = {
Paul Jensen9132f342016-04-13 15:00:26 -0400705 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 Benichi961ca492016-09-02 11:04:34 +0900711 private static final byte[] ARP_IPV4_REPLY_HEADER = {
Hugo Benichi38db9762016-07-12 15:08:50 +0900712 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 Benichi4fc3ee52016-06-02 11:20:27 +0900718 private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
Paul Jensen9132f342016-04-13 15:00:26 -0400719
Hugo Benichi961ca492016-09-02 11:04:34 +0900720 private static final byte[] MOCK_IPV4_ADDR = {10, 0, 0, 1};
Hugo Benichi7d21eae2016-09-02 14:00:29 +0900721 private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19
Hugo Benichi961ca492016-09-02 11:04:34 +0900722 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 Jensen9132f342016-04-13 15:00:26 -0400725
726 @LargeTest
727 public void testApfFilterIPv4() throws Exception {
728 MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
Hugo Benichi7d21eae2016-09-02 14:00:29 +0900729 LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
730 LinkProperties lp = new LinkProperties();
731 lp.addLinkAddress(link);
Hugo Benichi0dc1d312016-09-02 12:40:31 +0900732
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900733 ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
Hugo Benichi7d21eae2016-09-02 14:00:29 +0900734 apfFilter.setLinkProperties(lp);
Hugo Benichi0dc1d312016-09-02 12:40:31 +0900735
Paul Jensen9132f342016-04-13 15:00:26 -0400736 byte[] program = ipManagerCallback.getApfProgram();
737
738 // Verify empty packet of 100 zero bytes is passed
739 ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
Hugo Benichi961ca492016-09-02 11:04:34 +0900740 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400741
742 // Verify unicast IPv4 packet is passed
Hugo Benichi961ca492016-09-02 11:04:34 +0900743 put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
Paul Jensen9132f342016-04-13 15:00:26 -0400744 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
Hugo Benichi961ca492016-09-02 11:04:34 +0900745 put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
746 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400747
Hugo Benichi0dc1d312016-09-02 12:40:31 +0900748 // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088)
Hugo Benichi961ca492016-09-02 11:04:34 +0900749 put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
Hugo Benichi0dc1d312016-09-02 12:40:31 +0900750 assertDrop(program, packet.array());
Hugo Benichi961ca492016-09-02 11:04:34 +0900751 put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
Hugo Benichi7d21eae2016-09-02 14:00:29 +0900752 assertDrop(program, packet.array());
Hugo Benichi961ca492016-09-02 11:04:34 +0900753
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 Jensen9132f342016-04-13 15:00:26 -0400757 packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
Hugo Benichi961ca492016-09-02 11:04:34 +0900758 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400759 packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
Hugo Benichi961ca492016-09-02 11:04:34 +0900760 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400761 packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
Hugo Benichi961ca492016-09-02 11:04:34 +0900762 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 Jensen9132f342016-04-13 15:00:26 -0400769
770 // Verify broadcast IPv4 DHCP to us is passed
Hugo Benichi961ca492016-09-02 11:04:34 +0900771 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 Jensen9132f342016-04-13 15:00:26 -0400777
778 apfFilter.shutdown();
779 }
780
781 @LargeTest
782 public void testApfFilterIPv6() throws Exception {
783 MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900784 ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
Paul Jensen9132f342016-04-13 15:00:26 -0400785 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 Benichi961ca492016-09-02 11:04:34 +0900790 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400791
792 // Verify empty ICMPv6 packet is passed
793 packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
Hugo Benichi961ca492016-09-02 11:04:34 +0900794 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400795
796 // Verify empty ICMPv6 NA packet is passed
797 packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
Hugo Benichi961ca492016-09-02 11:04:34 +0900798 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400799
800 // Verify ICMPv6 NA to ff02::1 is dropped
Hugo Benichi961ca492016-09-02 11:04:34 +0900801 put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
802 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400803
Hugo Benichi0cc49bb2016-12-08 16:34:46 +0900804 // 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 Jensen9132f342016-04-13 15:00:26 -0400810 apfFilter.shutdown();
811 }
812
813 @LargeTest
Lorenzo Colitti11e13e22016-05-20 00:04:43 +0900814 public void testApfFilterMulticast() throws Exception {
Hugo Benichi961ca492016-09-02 11:04:34 +0900815 final byte[] unicastIpv4Addr = {(byte)192,0,2,63};
Hugo Benichi7d21eae2016-09-02 14:00:29 +0900816 final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
Hugo Benichi961ca492016-09-02 11:04:34 +0900817 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 Benichi7d21eae2016-09-02 14:00:29 +0900820 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 Colitti11e13e22016-05-20 00:04:43 +0900830 // Construct IPv4 and IPv6 multicast packets.
Paul Jensenf8a01e82016-05-26 09:16:11 -0400831 ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
832 mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
Hugo Benichi961ca492016-09-02 11:04:34 +0900833 put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
Lorenzo Colitti11e13e22016-05-20 00:04:43 +0900834
Paul Jensenf8a01e82016-05-26 09:16:11 -0400835 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 Benichi961ca492016-09-02 11:04:34 +0900838 put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
Paul Jensenf8a01e82016-05-26 09:16:11 -0400839
840 // Construct IPv4 broadcast packet.
Hugo Benichi961ca492016-09-02 11:04:34 +0900841 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 Colitti11e13e22016-05-20 00:04:43 +0900856
Paul Jensen9132f342016-04-13 15:00:26 -0400857 // Verify initially disabled multicast filter is off
Hugo Benichi961ca492016-09-02 11:04:34 +0900858 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 Jensen9132f342016-04-13 15:00:26 -0400863
864 // Turn on multicast filter and verify it works
865 ipManagerCallback.resetApfProgramWait();
866 apfFilter.setMulticastFilter(true);
867 program = ipManagerCallback.getApfProgram();
Hugo Benichi961ca492016-09-02 11:04:34 +0900868 assertDrop(program, mcastv4packet.array());
869 assertDrop(program, mcastv6packet.array());
870 assertDrop(program, bcastv4packet1.array());
871 assertDrop(program, bcastv4packet2.array());
Hugo Benichi7d21eae2016-09-02 14:00:29 +0900872 assertDrop(program, bcastv4unicastl2packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400873
874 // Turn off multicast filter and verify it's off
875 ipManagerCallback.resetApfProgramWait();
876 apfFilter.setMulticastFilter(false);
877 program = ipManagerCallback.getApfProgram();
Hugo Benichi961ca492016-09-02 11:04:34 +0900878 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 Jensen9132f342016-04-13 15:00:26 -0400883
884 // Verify it can be initialized to on
885 ipManagerCallback.resetApfProgramWait();
886 apfFilter.shutdown();
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900887 apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
Hugo Benichi7d21eae2016-09-02 14:00:29 +0900888 apfFilter.setLinkProperties(lp);
Paul Jensen9132f342016-04-13 15:00:26 -0400889 program = ipManagerCallback.getApfProgram();
Hugo Benichi961ca492016-09-02 11:04:34 +0900890 assertDrop(program, mcastv4packet.array());
891 assertDrop(program, mcastv6packet.array());
892 assertDrop(program, bcastv4packet1.array());
Hugo Benichi7d21eae2016-09-02 14:00:29 +0900893 assertDrop(program, bcastv4unicastl2packet.array());
Lorenzo Colitti11e13e22016-05-20 00:04:43 +0900894
895 // Verify that ICMPv6 multicast is not dropped.
Paul Jensenf8a01e82016-05-26 09:16:11 -0400896 mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
Hugo Benichi961ca492016-09-02 11:04:34 +0900897 assertPass(program, mcastv6packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400898
899 apfFilter.shutdown();
900 }
901
Hugo Benichi38db9762016-07-12 15:08:50 +0900902 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 Benichi961ca492016-09-02 11:04:34 +0900910 assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
911 assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
912 assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
Hugo Benichi38db9762016-07-12 15:08:50 +0900913
914 // Verify unicast ARP reply packet is always accepted.
Hugo Benichi961ca492016-09-02 11:04:34 +0900915 assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR));
916 assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR));
917 assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR));
Hugo Benichi38db9762016-07-12 15:08:50 +0900918
919 // Verify GARP reply packets are always filtered
Hugo Benichi961ca492016-09-02 11:04:34 +0900920 assertDrop(program, garpReply());
Paul Jensen9132f342016-04-13 15:00:26 -0400921 }
922
923 @LargeTest
924 public void testApfFilterArp() throws Exception {
925 MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900926 ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
Paul Jensen9132f342016-04-13 15:00:26 -0400927
Hugo Benichi38db9762016-07-12 15:08:50 +0900928 // Verify initially ARP request filter is off, and GARP filter is on.
929 verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
Paul Jensen9132f342016-04-13 15:00:26 -0400930
931 // Inform ApfFilter of our address and verify ARP filtering is on
Hugo Benichi38db9762016-07-12 15:08:50 +0900932 LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
Paul Jensen9132f342016-04-13 15:00:26 -0400933 LinkProperties lp = new LinkProperties();
Hugo Benichi38db9762016-07-12 15:08:50 +0900934 assertTrue(lp.addLinkAddress(linkAddress));
935 verifyArpFilter(getProgram(ipManagerCallback, apfFilter, lp), DROP);
Paul Jensen9132f342016-04-13 15:00:26 -0400936
937 // Inform ApfFilter of loss of IP and verify ARP filtering is off
Hugo Benichi38db9762016-07-12 15:08:50 +0900938 verifyArpFilter(getProgram(ipManagerCallback, apfFilter, new LinkProperties()), PASS);
Paul Jensen9132f342016-04-13 15:00:26 -0400939
940 apfFilter.shutdown();
941 }
942
Hugo Benichi38db9762016-07-12 15:08:50 +0900943 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 Benichi961ca492016-09-02 11:04:34 +0900946 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 Benichi38db9762016-07-12 15:08:50 +0900949 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 Benichi961ca492016-09-02 11:04:34 +0900955 put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
956 put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
Hugo Benichi38db9762016-07-12 15:08:50 +0900957 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 Benichi961ca492016-09-02 11:04:34 +0900963 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 Benichi38db9762016-07-12 15:08:50 +0900966 return packet.array();
967 }
968
Paul Jensen9132f342016-04-13 15:00:26 -0400969 // 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 Benichi961ca492016-09-02 11:04:34 +0900976 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400977 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 Benichi961ca492016-09-02 11:04:34 +0900983 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400984 packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
Hugo Benichi961ca492016-09-02 11:04:34 +0900985 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400986
987 // Verify other changes to RA make it not match filter
988 packet.put(0, (byte)-1);
Hugo Benichi961ca492016-09-02 11:04:34 +0900989 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400990 packet.put(0, (byte)0);
Hugo Benichi961ca492016-09-02 11:04:34 +0900991 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -0400992 }
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 Benichi6ccd51a2016-07-04 09:22:30 +09001006 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 Colitti8995d852016-06-23 15:24:46 +09001035 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 Jensen9132f342016-04-13 15:00:26 -04001042 @LargeTest
1043 public void testApfFilterRa() throws Exception {
1044 MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
Hugo Benichi6ccd51a2016-07-04 09:22:30 +09001045 TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
Paul Jensen9132f342016-04-13 15:00:26 -04001046 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 Colitti11e13e22016-05-20 00:04:43 +09001054 basePacket.position(IPV6_DEST_ADDR_OFFSET);
1055 basePacket.put(IPV6_ALL_NODES_ADDRESS);
Hugo Benichi961ca492016-09-02 11:04:34 +09001056 assertPass(program, basePacket.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001057
1058 testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
Hugo Benichi6ccd51a2016-07-04 09:22:30 +09001059 verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1));
Paul Jensen9132f342016-04-13 15:00:26 -04001060
Lorenzo Colitti8995d852016-06-23 15:24:46 +09001061 // 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 Jensen9132f342016-04-13 15:00:26 -04001071 // 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 Benichi6ccd51a2016-07-04 09:22:30 +09001085 verifyRaEvent(new RaEvent(1000, 200, 100, -1, -1, -1));
Paul Jensen9132f342016-04-13 15:00:26 -04001086
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 Benichi6ccd51a2016-07-04 09:22:30 +09001096 verifyRaEvent(new RaEvent(1000, -1, -1, -1, 300, -1));
Paul Jensen9132f342016-04-13 15:00:26 -04001097
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 Benichi6ccd51a2016-07-04 09:22:30 +09001107 verifyRaEvent(new RaEvent(1000, -1, -1, 400, -1, -1));
Paul Jensen9132f342016-04-13 15:00:26 -04001108
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 Benichi6ccd51a2016-07-04 09:22:30 +09001120 verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, 2000));
Paul Jensen9132f342016-04-13 15:00:26 -04001121
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 Benichi961ca492016-09-02 11:04:34 +09001152 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 Jensen9132f342016-04-13 15:00:26 -04001159 /**
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 Benichi7d21eae2016-09-02 14:00:29 +09001179
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 Jensen9132f342016-04-13 15:00:26 -04001205}