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