ApfTest.java revision 4fc3ee5be223122792ebc0ee8a05c93d93e26a52
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        public void assertNoProgramUpdate() {
557            assertFalse(mGotApfProgram.block(TIMEOUT_MS));
558        }
559    }
560
561    private static class TestApfFilter extends ApfFilter {
562        public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6};
563        private FileDescriptor mWriteSocket;
564
565        public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter) throws
566                Exception {
567            super(new ApfCapabilities(2, 1000, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
568                    ipManagerCallback, multicastFilter);
569        }
570
571        // Pretend an RA packet has been received and show it to ApfFilter.
572        public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException {
573            // ApfFilter's ReceiveThread will be waiting to read this.
574            Os.write(mWriteSocket, packet, 0, packet.length);
575        }
576
577        @Override
578        void maybeStartFilter() {
579            mHardwareAddress = MOCK_MAC_ADDR;
580            installNewProgramLocked();
581
582            // Create two sockets, "readSocket" and "mWriteSocket" and connect them together.
583            FileDescriptor readSocket = new FileDescriptor();
584            mWriteSocket = new FileDescriptor();
585            try {
586                Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket);
587            } catch (ErrnoException e) {
588                fail();
589                return;
590            }
591            // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs.
592            // This allows us to pretend RA packets have been recieved via pretendPacketReceived().
593            mReceiveThread = new ReceiveThread(readSocket);
594            mReceiveThread.start();
595        }
596
597        @Override
598        public void shutdown() {
599            super.shutdown();
600            IoUtils.closeQuietly(mWriteSocket);
601        }
602    }
603
604    private static final int ETH_HEADER_LEN = 14;
605    private static final int ETH_ETHERTYPE_OFFSET = 12;
606    private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
607        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
608
609    private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
610    private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
611    private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
612
613    private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
614    private static final int IPV6_HEADER_LEN = 40;
615    private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
616    // The IPv6 all nodes address ff02::1
617    private static final byte[] IPV6_ALL_NODES_ADDRESS =
618            new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
619
620    private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
621    private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
622    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
623
624    private static final int ICMP6_RA_HEADER_LEN = 16;
625    private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
626            ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
627    private static final int ICMP6_RA_CHECKSUM_OFFSET =
628            ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
629    private static final int ICMP6_RA_OPTION_OFFSET =
630            ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
631
632    private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
633    private static final int ICMP6_PREFIX_OPTION_LEN = 32;
634    private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
635    private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
636
637    // From RFC6106: Recursive DNS Server option
638    private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
639    // From RFC6106: DNS Search List option
640    private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
641
642    // From RFC4191: Route Information option
643    private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
644    // Above three options all have the same format:
645    private static final int ICMP6_4_BYTE_OPTION_LEN = 8;
646    private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
647    private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
648
649    private static final int UDP_HEADER_LEN = 8;
650    private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22;
651
652    private static final int DHCP_CLIENT_PORT = 68;
653    private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
654
655    private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
656    private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
657            0, 1, // Hardware type: Ethernet (1)
658            8, 0, // Protocol type: IP (0x0800)
659            6,    // Hardware size: 6
660            4,    // Protocol size: 4
661            0, 1  // Opcode: request (1)
662    };
663    private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
664
665    private static final byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1};
666
667    @LargeTest
668    public void testApfFilterIPv4() throws Exception {
669        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
670        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */);
671        byte[] program = ipManagerCallback.getApfProgram();
672
673        // Verify empty packet of 100 zero bytes is passed
674        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
675        assertPass(program, packet.array(), 0);
676
677        // Verify unicast IPv4 packet is passed
678        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
679        assertPass(program, packet.array(), 0);
680
681        // Verify broadcast IPv4, not DHCP to us, is dropped
682        packet.put(ETH_BROADCAST_MAC_ADDRESS);
683        assertDrop(program, packet.array(), 0);
684        packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
685        assertDrop(program, packet.array(), 0);
686        packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
687        assertDrop(program, packet.array(), 0);
688        packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
689        assertDrop(program, packet.array(), 0);
690
691        // Verify broadcast IPv4 DHCP to us is passed
692        packet.position(DHCP_CLIENT_MAC_OFFSET);
693        packet.put(TestApfFilter.MOCK_MAC_ADDR);
694        assertPass(program, packet.array(), 0);
695
696        apfFilter.shutdown();
697    }
698
699    @LargeTest
700    public void testApfFilterIPv6() throws Exception {
701        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
702        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */);
703        byte[] program = ipManagerCallback.getApfProgram();
704
705        // Verify empty IPv6 packet is passed
706        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
707        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
708        assertPass(program, packet.array(), 0);
709
710        // Verify empty ICMPv6 packet is passed
711        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
712        assertPass(program, packet.array(), 0);
713
714        // Verify empty ICMPv6 NA packet is passed
715        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
716        assertPass(program, packet.array(), 0);
717
718        // Verify ICMPv6 NA to ff02::1 is dropped
719        packet.position(IPV6_DEST_ADDR_OFFSET);
720        packet.put(IPV6_ALL_NODES_ADDRESS);
721        assertDrop(program, packet.array(), 0);
722
723        apfFilter.shutdown();
724    }
725
726    @LargeTest
727    public void testApfFilterMulticast() throws Exception {
728        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
729        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */);
730        byte[] program = ipManagerCallback.getApfProgram();
731
732        // Construct IPv4 and IPv6 multicast packets.
733        ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
734        mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
735        mcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
736        mcastv4packet.put(new byte[]{(byte)224,0,0,1});
737
738        ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
739        mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
740        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
741        mcastv6packet.position(IPV6_DEST_ADDR_OFFSET);
742        mcastv6packet.put(new byte[]{(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb});
743
744        // Construct IPv4 broadcast packet.
745        ByteBuffer bcastv4packet = ByteBuffer.wrap(new byte[100]);
746        bcastv4packet.put(ETH_BROADCAST_MAC_ADDRESS);
747        bcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
748        bcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
749        bcastv4packet.put(new byte[]{(byte)192,(byte)0,(byte)2,(byte)63});
750
751        // Verify initially disabled multicast filter is off
752        assertPass(program, bcastv4packet.array(), 0);
753        assertPass(program, mcastv4packet.array(), 0);
754        assertPass(program, mcastv6packet.array(), 0);
755
756        // Turn on multicast filter and verify it works
757        ipManagerCallback.resetApfProgramWait();
758        apfFilter.setMulticastFilter(true);
759        program = ipManagerCallback.getApfProgram();
760        assertDrop(program, bcastv4packet.array(), 0);
761        assertDrop(program, mcastv4packet.array(), 0);
762        assertDrop(program, mcastv6packet.array(), 0);
763
764        // Turn off multicast filter and verify it's off
765        ipManagerCallback.resetApfProgramWait();
766        apfFilter.setMulticastFilter(false);
767        program = ipManagerCallback.getApfProgram();
768        assertPass(program, bcastv4packet.array(), 0);
769        assertPass(program, mcastv4packet.array(), 0);
770        assertPass(program, mcastv6packet.array(), 0);
771
772        // Verify it can be initialized to on
773        ipManagerCallback.resetApfProgramWait();
774        apfFilter.shutdown();
775        apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */);
776        program = ipManagerCallback.getApfProgram();
777        assertDrop(program, bcastv4packet.array(), 0);
778        assertDrop(program, mcastv4packet.array(), 0);
779        assertDrop(program, mcastv6packet.array(), 0);
780
781        // Verify that ICMPv6 multicast is not dropped.
782        mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
783        assertPass(program, mcastv6packet.array(), 0);
784
785        apfFilter.shutdown();
786    }
787
788    private void verifyArpFilter(MockIpManagerCallback ipManagerCallback, ApfFilter apfFilter,
789            LinkProperties linkProperties, int filterResult) {
790        ipManagerCallback.resetApfProgramWait();
791        apfFilter.setLinkProperties(linkProperties);
792        byte[] program = ipManagerCallback.getApfProgram();
793        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
794        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
795        assertPass(program, packet.array(), 0);
796        packet.position(ARP_HEADER_OFFSET);
797        packet.put(ARP_IPV4_REQUEST_HEADER);
798        assertVerdict(filterResult, program, packet.array(), 0);
799        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
800        packet.put(MOCK_IPV4_ADDR);
801        assertPass(program, packet.array(), 0);
802    }
803
804    @LargeTest
805    public void testApfFilterArp() throws Exception {
806        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
807        ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */);
808        byte[] program = ipManagerCallback.getApfProgram();
809
810        // Verify initially ARP filter is off
811        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
812        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
813        assertPass(program, packet.array(), 0);
814        packet.position(ARP_HEADER_OFFSET);
815        packet.put(ARP_IPV4_REQUEST_HEADER);
816        assertPass(program, packet.array(), 0);
817        packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
818        packet.put(MOCK_IPV4_ADDR);
819        assertPass(program, packet.array(), 0);
820
821        // Inform ApfFilter of our address and verify ARP filtering is on
822        LinkProperties lp = new LinkProperties();
823        assertTrue(lp.addLinkAddress(
824                new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24)));
825        verifyArpFilter(ipManagerCallback, apfFilter, lp, DROP);
826
827        // Inform ApfFilter of loss of IP and verify ARP filtering is off
828        verifyArpFilter(ipManagerCallback, apfFilter, new LinkProperties(), PASS);
829
830        apfFilter.shutdown();
831    }
832
833    // Verify that the last program pushed to the IpManager.Callback properly filters the
834    // given packet for the given lifetime.
835    private void verifyRaLifetime(MockIpManagerCallback ipManagerCallback, ByteBuffer packet,
836            int lifetime) {
837        byte[] program = ipManagerCallback.getApfProgram();
838
839        // Verify new program should drop RA for 1/6th its lifetime
840        assertDrop(program, packet.array(), 0);
841        assertDrop(program, packet.array(), lifetime/6);
842        assertPass(program, packet.array(), lifetime/6 + 1);
843        assertPass(program, packet.array(), lifetime);
844
845        // Verify RA checksum is ignored
846        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
847        assertDrop(program, packet.array(), 0);
848        packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
849        assertDrop(program, packet.array(), 0);
850
851        // Verify other changes to RA make it not match filter
852        packet.put(0, (byte)-1);
853        assertPass(program, packet.array(), 0);
854        packet.put(0, (byte)0);
855        assertDrop(program, packet.array(), 0);
856    }
857
858    // Test that when ApfFilter is shown the given packet, it generates a program to filter it
859    // for the given lifetime.
860    private void testRaLifetime(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
861            ByteBuffer packet, int lifetime) throws IOException, ErrnoException {
862        // Verify new program generated if ApfFilter witnesses RA
863        ipManagerCallback.resetApfProgramWait();
864        apfFilter.pretendPacketReceived(packet.array());
865        ipManagerCallback.getApfProgram();
866
867        verifyRaLifetime(ipManagerCallback, packet, lifetime);
868    }
869
870    private void assertInvalidRa(TestApfFilter apfFilter, MockIpManagerCallback ipManagerCallback,
871            ByteBuffer packet) throws IOException, ErrnoException {
872        ipManagerCallback.resetApfProgramWait();
873        apfFilter.pretendPacketReceived(packet.array());
874        ipManagerCallback.assertNoProgramUpdate();
875    }
876
877    @LargeTest
878    public void testApfFilterRa() throws Exception {
879        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
880        TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */);
881        byte[] program = ipManagerCallback.getApfProgram();
882
883        // Verify RA is passed the first time
884        ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
885        basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
886        basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
887        basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
888        basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000);
889        basePacket.position(IPV6_DEST_ADDR_OFFSET);
890        basePacket.put(IPV6_ALL_NODES_ADDRESS);
891        assertPass(program, basePacket.array(), 0);
892
893        testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
894
895        // Ensure zero-length options cause the packet to be silently skipped.
896        // Do this before we test other packets. http://b/29586253
897        ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(
898                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
899        basePacket.clear();
900        zeroLengthOptionPacket.put(basePacket);
901        zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
902        zeroLengthOptionPacket.put((byte)0);
903        assertInvalidRa(apfFilter, ipManagerCallback, zeroLengthOptionPacket);
904
905        // Generate several RAs with different options and lifetimes, and verify when
906        // ApfFilter is shown these packets, it generates programs to filter them for the
907        // appropriate lifetime.
908        ByteBuffer prefixOptionPacket = ByteBuffer.wrap(
909                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]);
910        basePacket.clear();
911        prefixOptionPacket.put(basePacket);
912        prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
913        prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8));
914        prefixOptionPacket.putInt(
915                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, 100);
916        prefixOptionPacket.putInt(
917                ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 200);
918        testRaLifetime(apfFilter, ipManagerCallback, prefixOptionPacket, 100);
919
920        ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
921                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
922        basePacket.clear();
923        rdnssOptionPacket.put(basePacket);
924        rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE);
925        rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
926        rdnssOptionPacket.putInt(
927                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 300);
928        testRaLifetime(apfFilter, ipManagerCallback, rdnssOptionPacket, 300);
929
930        ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
931                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
932        basePacket.clear();
933        routeInfoOptionPacket.put(basePacket);
934        routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE);
935        routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
936        routeInfoOptionPacket.putInt(
937                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 400);
938        testRaLifetime(apfFilter, ipManagerCallback, routeInfoOptionPacket, 400);
939
940        ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
941                new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
942        basePacket.clear();
943        dnsslOptionPacket.put(basePacket);
944        dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
945        dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
946        dnsslOptionPacket.putInt(
947                ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, 2000);
948        // Note that lifetime of 2000 will be ignored in favor of shorter
949        // route lifetime of 1000.
950        testRaLifetime(apfFilter, ipManagerCallback, dnsslOptionPacket, 1000);
951
952        // Verify that current program filters all five RAs:
953        verifyRaLifetime(ipManagerCallback, basePacket, 1000);
954        verifyRaLifetime(ipManagerCallback, prefixOptionPacket, 100);
955        verifyRaLifetime(ipManagerCallback, rdnssOptionPacket, 300);
956        verifyRaLifetime(ipManagerCallback, routeInfoOptionPacket, 400);
957        verifyRaLifetime(ipManagerCallback, dnsslOptionPacket, 1000);
958
959        apfFilter.shutdown();
960    }
961
962    /**
963     * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
964     * copy that resource into the app's data directory and return the path to it.
965     */
966    private String stageFile(int rawId) throws Exception {
967        File file = new File(getContext().getFilesDir(), "staged_file");
968        new File(file.getParent()).mkdirs();
969        InputStream in = null;
970        OutputStream out = null;
971        try {
972            in = getContext().getResources().openRawResource(rawId);
973            out = new FileOutputStream(file);
974            Streams.copy(in, out);
975        } finally {
976            if (in != null) in.close();
977            if (out != null) out.close();
978        }
979        return file.getAbsolutePath();
980    }
981
982    /**
983     * Call the APF interpreter the run {@code program} on {@code packet} pretending the
984     * filter was installed {@code filter_age} seconds ago.
985     */
986    private native static int apfSimulate(byte[] program, byte[] packet, int filter_age);
987
988    /**
989     * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF
990     * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d".
991     */
992    private native static String compileToBpf(String filter);
993
994    /**
995     * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump
996     * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and
997     * at the same time using APF program {@code apf_program}.  Return {@code true} if
998     * both APF and BPF programs filter out exactly the same packets.
999     */
1000    private native static boolean compareBpfApf(String filter, String pcap_filename,
1001            byte[] apf_program);
1002}
1003