• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.apf;
18 
19 import static android.net.apf.ApfGenerator.Register.R0;
20 import static android.net.apf.ApfGenerator.Register.R1;
21 import static android.system.OsConstants.AF_UNIX;
22 import static android.system.OsConstants.ARPHRD_ETHER;
23 import static android.system.OsConstants.ETH_P_ARP;
24 import static android.system.OsConstants.ETH_P_IP;
25 import static android.system.OsConstants.ETH_P_IPV6;
26 import static android.system.OsConstants.IPPROTO_ICMPV6;
27 import static android.system.OsConstants.IPPROTO_IPV6;
28 import static android.system.OsConstants.IPPROTO_TCP;
29 import static android.system.OsConstants.IPPROTO_UDP;
30 import static android.system.OsConstants.SOCK_STREAM;
31 
32 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
33 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN;
34 import static com.android.networkstack.util.NetworkStackUtils.APF_USE_RA_LIFETIME_CALCULATION_FIX_VERSION;
35 
36 import static org.junit.Assert.assertEquals;
37 import static org.junit.Assert.assertFalse;
38 import static org.junit.Assert.assertTrue;
39 import static org.junit.Assert.fail;
40 import static org.mockito.Mockito.anyBoolean;
41 import static org.mockito.Mockito.atLeastOnce;
42 import static org.mockito.Mockito.eq;
43 import static org.mockito.Mockito.mock;
44 import static org.mockito.Mockito.verify;
45 import static org.mockito.Mockito.when;
46 
47 import android.content.Context;
48 import android.net.InetAddresses;
49 import android.net.IpPrefix;
50 import android.net.LinkAddress;
51 import android.net.LinkProperties;
52 import android.net.MacAddress;
53 import android.net.NattKeepalivePacketDataParcelable;
54 import android.net.TcpKeepalivePacketDataParcelable;
55 import android.net.apf.ApfFilter.ApfConfiguration;
56 import android.net.apf.ApfGenerator.IllegalInstructionException;
57 import android.net.ip.IIpClientCallbacks;
58 import android.net.ip.IpClient.IpClientCallbacksWrapper;
59 import android.net.metrics.IpConnectivityLog;
60 import android.net.metrics.RaEvent;
61 import android.os.ConditionVariable;
62 import android.os.Parcelable;
63 import android.os.SystemClock;
64 import android.system.ErrnoException;
65 import android.system.Os;
66 import android.text.TextUtils;
67 import android.text.format.DateUtils;
68 import android.util.Log;
69 import android.util.Pair;
70 
71 import androidx.test.InstrumentationRegistry;
72 import androidx.test.filters.SmallTest;
73 import androidx.test.runner.AndroidJUnit4;
74 
75 import com.android.internal.util.HexDump;
76 import com.android.net.module.util.DnsPacket;
77 import com.android.net.module.util.Inet4AddressUtils;
78 import com.android.net.module.util.InterfaceParams;
79 import com.android.net.module.util.NetworkStackConstants;
80 import com.android.net.module.util.PacketBuilder;
81 import com.android.net.module.util.SharedLog;
82 import com.android.networkstack.apishim.NetworkInformationShimImpl;
83 import com.android.server.networkstack.tests.R;
84 
85 import libcore.io.IoUtils;
86 import libcore.io.Streams;
87 
88 import org.junit.Assert;
89 import org.junit.Before;
90 import org.junit.Test;
91 import org.junit.runner.RunWith;
92 import org.mockito.ArgumentCaptor;
93 import org.mockito.Mock;
94 import org.mockito.MockitoAnnotations;
95 
96 import java.io.File;
97 import java.io.FileDescriptor;
98 import java.io.FileOutputStream;
99 import java.io.IOException;
100 import java.io.InputStream;
101 import java.io.OutputStream;
102 import java.net.Inet4Address;
103 import java.net.Inet6Address;
104 import java.net.InetAddress;
105 import java.nio.ByteBuffer;
106 import java.nio.charset.StandardCharsets;
107 import java.util.ArrayList;
108 import java.util.Arrays;
109 import java.util.HashMap;
110 import java.util.List;
111 import java.util.Random;
112 
113 /**
114  * Tests for APF program generator and interpreter.
115  *
116  * Build, install and run with:
117  *  runtest frameworks-net -c android.net.apf.ApfTest
118  */
119 @RunWith(AndroidJUnit4.class)
120 @SmallTest
121 public class ApfTest {
122     private static final int TIMEOUT_MS = 500;
123     private static final int MIN_APF_VERSION = 2;
124 
125     @Mock IpConnectivityLog mLog;
126     @Mock ApfFilter.Dependencies mDependencies;
127     @Mock Context mContext;
128 
129     @Before
setUp()130     public void setUp() throws Exception {
131         MockitoAnnotations.initMocks(this);
132         when(mDependencies.isFeatureEnabled(eq(mContext),
133                 eq(APF_USE_RA_LIFETIME_CALCULATION_FIX_VERSION), anyBoolean())).thenReturn(true);
134         // Load up native shared library containing APF interpreter exposed via JNI.
135         System.loadLibrary("networkstacktestsjni");
136     }
137 
138     private static final String TAG = "ApfTest";
139     // Expected return codes from APF interpreter.
140     private static final int PASS = 1;
141     private static final int DROP = 0;
142     // Interpreter will just accept packets without link layer headers, so pad fake packet to at
143     // least the minimum packet size.
144     private static final int MIN_PKT_SIZE = 15;
145 
146     private static final ApfCapabilities MOCK_APF_CAPABILITIES =
147             new ApfCapabilities(2, 4096, ARPHRD_ETHER);
148 
149     private static final boolean DROP_MULTICAST = true;
150     private static final boolean ALLOW_MULTICAST = false;
151 
152     private static final boolean DROP_802_3_FRAMES = true;
153     private static final boolean ALLOW_802_3_FRAMES = false;
154 
155     private static final int MIN_RDNSS_LIFETIME_SEC = 0;
156 
157     // Constants for opcode encoding
158     private static final byte LI_OP   = (byte)(13 << 3);
159     private static final byte LDDW_OP = (byte)(22 << 3);
160     private static final byte STDW_OP = (byte)(23 << 3);
161     private static final byte SIZE0   = (byte)(0 << 1);
162     private static final byte SIZE8   = (byte)(1 << 1);
163     private static final byte SIZE16  = (byte)(2 << 1);
164     private static final byte SIZE32  = (byte)(3 << 1);
165     private static final byte R1_REG = 1;
166 
getDefaultConfig()167     private static ApfConfiguration getDefaultConfig() {
168         ApfFilter.ApfConfiguration config = new ApfConfiguration();
169         config.apfCapabilities = MOCK_APF_CAPABILITIES;
170         config.multicastFilter = ALLOW_MULTICAST;
171         config.ieee802_3Filter = ALLOW_802_3_FRAMES;
172         config.ethTypeBlackList = new int[0];
173         config.minRdnssLifetimeSec = MIN_RDNSS_LIFETIME_SEC;
174         config.minRdnssLifetimeSec = 67;
175         return config;
176     }
177 
label(int code)178     private static String label(int code) {
179         switch (code) {
180             case PASS: return "PASS";
181             case DROP: return "DROP";
182             default:   return "UNKNOWN";
183         }
184     }
185 
assertReturnCodesEqual(String msg, int expected, int got)186     private static void assertReturnCodesEqual(String msg, int expected, int got) {
187         assertEquals(msg, label(expected), label(got));
188     }
189 
assertReturnCodesEqual(int expected, int got)190     private static void assertReturnCodesEqual(int expected, int got) {
191         assertEquals(label(expected), label(got));
192     }
193 
assertVerdict(int expected, byte[] program, byte[] packet, int filterAge)194     private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
195         final String msg = "Unexpected APF verdict. To debug:\n"
196                 + "  apf_run --program " + HexDump.toHexString(program)
197                 + " --packet " + HexDump.toHexString(packet) + " --trace | less\n  ";
198         assertReturnCodesEqual(msg, expected, apfSimulate(program, packet, null, filterAge));
199     }
200 
assertVerdict(String msg, int expected, byte[] program, byte[] packet, int filterAge)201     private void assertVerdict(String msg, int expected, byte[] program, byte[] packet,
202             int filterAge) {
203         assertReturnCodesEqual(msg, expected, apfSimulate(program, packet, null, filterAge));
204     }
205 
assertVerdict(int expected, byte[] program, byte[] packet)206     private void assertVerdict(int expected, byte[] program, byte[] packet) {
207         assertVerdict(expected, program, packet, 0);
208     }
209 
assertPass(byte[] program, byte[] packet, int filterAge)210     private void assertPass(byte[] program, byte[] packet, int filterAge) {
211         assertVerdict(PASS, program, packet, filterAge);
212     }
213 
assertPass(byte[] program, byte[] packet)214     private void assertPass(byte[] program, byte[] packet) {
215         assertVerdict(PASS, program, packet);
216     }
217 
assertDrop(byte[] program, byte[] packet, int filterAge)218     private void assertDrop(byte[] program, byte[] packet, int filterAge) {
219         assertVerdict(DROP, program, packet, filterAge);
220     }
221 
assertDrop(byte[] program, byte[] packet)222     private void assertDrop(byte[] program, byte[] packet) {
223         assertVerdict(DROP, program, packet);
224     }
225 
assertProgramEquals(byte[] expected, byte[] program)226     private void assertProgramEquals(byte[] expected, byte[] program) throws AssertionError {
227         // assertArrayEquals() would only print one byte, making debugging difficult.
228         if (!Arrays.equals(expected, program)) {
229             throw new AssertionError(
230                     "\nexpected: " + HexDump.toHexString(expected) +
231                     "\nactual:   " + HexDump.toHexString(program));
232         }
233     }
234 
assertDataMemoryContents( int expected, byte[] program, byte[] packet, byte[] data, byte[] expected_data)235     private void assertDataMemoryContents(
236             int expected, byte[] program, byte[] packet, byte[] data, byte[] expected_data)
237             throws IllegalInstructionException, Exception {
238         assertReturnCodesEqual(expected, apfSimulate(program, packet, data, 0 /* filterAge */));
239 
240         // assertArrayEquals() would only print one byte, making debugging difficult.
241         if (!Arrays.equals(expected_data, data)) {
242             throw new Exception(
243                     "\nprogram:     " + HexDump.toHexString(program) +
244                     "\ndata memory: " + HexDump.toHexString(data) +
245                     "\nexpected:    " + HexDump.toHexString(expected_data));
246         }
247     }
248 
assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)249     private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
250             throws IllegalInstructionException {
251         assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, null,
252               filterAge));
253     }
254 
assertPass(ApfGenerator gen, byte[] packet, int filterAge)255     private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
256             throws IllegalInstructionException {
257         assertVerdict(PASS, gen, packet, filterAge);
258     }
259 
assertDrop(ApfGenerator gen, byte[] packet, int filterAge)260     private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge)
261             throws IllegalInstructionException {
262         assertVerdict(DROP, gen, packet, filterAge);
263     }
264 
assertPass(ApfGenerator gen)265     private void assertPass(ApfGenerator gen)
266             throws IllegalInstructionException {
267         assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0);
268     }
269 
assertDrop(ApfGenerator gen)270     private void assertDrop(ApfGenerator gen)
271             throws IllegalInstructionException {
272         assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0);
273     }
274 
275     /**
276      * Test each instruction by generating a program containing the instruction,
277      * generating bytecode for that program and running it through the
278      * interpreter to verify it functions correctly.
279      */
280     @Test
testApfInstructions()281     public void testApfInstructions() throws IllegalInstructionException {
282         // Empty program should pass because having the program counter reach the
283         // location immediately after the program indicates the packet should be
284         // passed to the AP.
285         ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
286         assertPass(gen);
287 
288         // Test jumping to pass label.
289         gen = new ApfGenerator(MIN_APF_VERSION);
290         gen.addJump(gen.PASS_LABEL);
291         byte[] program = gen.generate();
292         assertEquals(1, program.length);
293         assertEquals((14 << 3) | (0 << 1) | 0, program[0]);
294         assertPass(program, new byte[MIN_PKT_SIZE], 0);
295 
296         // Test jumping to drop label.
297         gen = new ApfGenerator(MIN_APF_VERSION);
298         gen.addJump(gen.DROP_LABEL);
299         program = gen.generate();
300         assertEquals(2, program.length);
301         assertEquals((14 << 3) | (1 << 1) | 0, program[0]);
302         assertEquals(1, program[1]);
303         assertDrop(program, new byte[15], 15);
304 
305         // Test jumping if equal to 0.
306         gen = new ApfGenerator(MIN_APF_VERSION);
307         gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
308         assertDrop(gen);
309 
310         // Test jumping if not equal to 0.
311         gen = new ApfGenerator(MIN_APF_VERSION);
312         gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
313         assertPass(gen);
314         gen = new ApfGenerator(MIN_APF_VERSION);
315         gen.addLoadImmediate(R0, 1);
316         gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
317         assertDrop(gen);
318 
319         // Test jumping if registers equal.
320         gen = new ApfGenerator(MIN_APF_VERSION);
321         gen.addJumpIfR0EqualsR1(gen.DROP_LABEL);
322         assertDrop(gen);
323 
324         // Test jumping if registers not equal.
325         gen = new ApfGenerator(MIN_APF_VERSION);
326         gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
327         assertPass(gen);
328         gen = new ApfGenerator(MIN_APF_VERSION);
329         gen.addLoadImmediate(R0, 1);
330         gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
331         assertDrop(gen);
332 
333         // Test load immediate.
334         gen = new ApfGenerator(MIN_APF_VERSION);
335         gen.addLoadImmediate(R0, 1234567890);
336         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
337         assertDrop(gen);
338 
339         // Test add.
340         gen = new ApfGenerator(MIN_APF_VERSION);
341         gen.addAdd(1234567890);
342         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
343         assertDrop(gen);
344 
345         // Test subtract.
346         gen = new ApfGenerator(MIN_APF_VERSION);
347         gen.addAdd(-1234567890);
348         gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
349         assertDrop(gen);
350 
351         // Test or.
352         gen = new ApfGenerator(MIN_APF_VERSION);
353         gen.addOr(1234567890);
354         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
355         assertDrop(gen);
356 
357         // Test and.
358         gen = new ApfGenerator(MIN_APF_VERSION);
359         gen.addLoadImmediate(R0, 1234567890);
360         gen.addAnd(123456789);
361         gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
362         assertDrop(gen);
363 
364         // Test left shift.
365         gen = new ApfGenerator(MIN_APF_VERSION);
366         gen.addLoadImmediate(R0, 1234567890);
367         gen.addLeftShift(1);
368         gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
369         assertDrop(gen);
370 
371         // Test right shift.
372         gen = new ApfGenerator(MIN_APF_VERSION);
373         gen.addLoadImmediate(R0, 1234567890);
374         gen.addRightShift(1);
375         gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
376         assertDrop(gen);
377 
378         // Test multiply.
379         gen = new ApfGenerator(MIN_APF_VERSION);
380         gen.addLoadImmediate(R0, 123456789);
381         gen.addMul(2);
382         gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
383         assertDrop(gen);
384 
385         // Test divide.
386         gen = new ApfGenerator(MIN_APF_VERSION);
387         gen.addLoadImmediate(R0, 1234567890);
388         gen.addDiv(2);
389         gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
390         assertDrop(gen);
391 
392         // Test divide by zero.
393         gen = new ApfGenerator(MIN_APF_VERSION);
394         gen.addDiv(0);
395         gen.addJump(gen.DROP_LABEL);
396         assertPass(gen);
397 
398         // Test add.
399         gen = new ApfGenerator(MIN_APF_VERSION);
400         gen.addLoadImmediate(R1, 1234567890);
401         gen.addAddR1();
402         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
403         assertDrop(gen);
404 
405         // Test subtract.
406         gen = new ApfGenerator(MIN_APF_VERSION);
407         gen.addLoadImmediate(R1, -1234567890);
408         gen.addAddR1();
409         gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
410         assertDrop(gen);
411 
412         // Test or.
413         gen = new ApfGenerator(MIN_APF_VERSION);
414         gen.addLoadImmediate(R1, 1234567890);
415         gen.addOrR1();
416         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
417         assertDrop(gen);
418 
419         // Test and.
420         gen = new ApfGenerator(MIN_APF_VERSION);
421         gen.addLoadImmediate(R0, 1234567890);
422         gen.addLoadImmediate(R1, 123456789);
423         gen.addAndR1();
424         gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
425         assertDrop(gen);
426 
427         // Test left shift.
428         gen = new ApfGenerator(MIN_APF_VERSION);
429         gen.addLoadImmediate(R0, 1234567890);
430         gen.addLoadImmediate(R1, 1);
431         gen.addLeftShiftR1();
432         gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
433         assertDrop(gen);
434 
435         // Test right shift.
436         gen = new ApfGenerator(MIN_APF_VERSION);
437         gen.addLoadImmediate(R0, 1234567890);
438         gen.addLoadImmediate(R1, -1);
439         gen.addLeftShiftR1();
440         gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
441         assertDrop(gen);
442 
443         // Test multiply.
444         gen = new ApfGenerator(MIN_APF_VERSION);
445         gen.addLoadImmediate(R0, 123456789);
446         gen.addLoadImmediate(R1, 2);
447         gen.addMulR1();
448         gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
449         assertDrop(gen);
450 
451         // Test divide.
452         gen = new ApfGenerator(MIN_APF_VERSION);
453         gen.addLoadImmediate(R0, 1234567890);
454         gen.addLoadImmediate(R1, 2);
455         gen.addDivR1();
456         gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
457         assertDrop(gen);
458 
459         // Test divide by zero.
460         gen = new ApfGenerator(MIN_APF_VERSION);
461         gen.addDivR1();
462         gen.addJump(gen.DROP_LABEL);
463         assertPass(gen);
464 
465         // Test byte load.
466         gen = new ApfGenerator(MIN_APF_VERSION);
467         gen.addLoad8(R0, 1);
468         gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
469         assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
470 
471         // Test out of bounds load.
472         gen = new ApfGenerator(MIN_APF_VERSION);
473         gen.addLoad8(R0, 16);
474         gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
475         assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
476 
477         // Test half-word load.
478         gen = new ApfGenerator(MIN_APF_VERSION);
479         gen.addLoad16(R0, 1);
480         gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
481         assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
482 
483         // Test word load.
484         gen = new ApfGenerator(MIN_APF_VERSION);
485         gen.addLoad32(R0, 1);
486         gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
487         assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
488 
489         // Test byte indexed load.
490         gen = new ApfGenerator(MIN_APF_VERSION);
491         gen.addLoadImmediate(R1, 1);
492         gen.addLoad8Indexed(R0, 0);
493         gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
494         assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
495 
496         // Test out of bounds indexed load.
497         gen = new ApfGenerator(MIN_APF_VERSION);
498         gen.addLoadImmediate(R1, 8);
499         gen.addLoad8Indexed(R0, 8);
500         gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
501         assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
502 
503         // Test half-word indexed load.
504         gen = new ApfGenerator(MIN_APF_VERSION);
505         gen.addLoadImmediate(R1, 1);
506         gen.addLoad16Indexed(R0, 0);
507         gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
508         assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
509 
510         // Test word indexed load.
511         gen = new ApfGenerator(MIN_APF_VERSION);
512         gen.addLoadImmediate(R1, 1);
513         gen.addLoad32Indexed(R0, 0);
514         gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
515         assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
516 
517         // Test jumping if greater than.
518         gen = new ApfGenerator(MIN_APF_VERSION);
519         gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
520         assertPass(gen);
521         gen = new ApfGenerator(MIN_APF_VERSION);
522         gen.addLoadImmediate(R0, 1);
523         gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
524         assertDrop(gen);
525 
526         // Test jumping if less than.
527         gen = new ApfGenerator(MIN_APF_VERSION);
528         gen.addJumpIfR0LessThan(0, gen.DROP_LABEL);
529         assertPass(gen);
530         gen = new ApfGenerator(MIN_APF_VERSION);
531         gen.addJumpIfR0LessThan(1, gen.DROP_LABEL);
532         assertDrop(gen);
533 
534         // Test jumping if any bits set.
535         gen = new ApfGenerator(MIN_APF_VERSION);
536         gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
537         assertPass(gen);
538         gen = new ApfGenerator(MIN_APF_VERSION);
539         gen.addLoadImmediate(R0, 1);
540         gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
541         assertDrop(gen);
542         gen = new ApfGenerator(MIN_APF_VERSION);
543         gen.addLoadImmediate(R0, 3);
544         gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
545         assertDrop(gen);
546 
547         // Test jumping if register greater than.
548         gen = new ApfGenerator(MIN_APF_VERSION);
549         gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
550         assertPass(gen);
551         gen = new ApfGenerator(MIN_APF_VERSION);
552         gen.addLoadImmediate(R0, 2);
553         gen.addLoadImmediate(R1, 1);
554         gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
555         assertDrop(gen);
556 
557         // Test jumping if register less than.
558         gen = new ApfGenerator(MIN_APF_VERSION);
559         gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
560         assertPass(gen);
561         gen = new ApfGenerator(MIN_APF_VERSION);
562         gen.addLoadImmediate(R1, 1);
563         gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
564         assertDrop(gen);
565 
566         // Test jumping if any bits set in register.
567         gen = new ApfGenerator(MIN_APF_VERSION);
568         gen.addLoadImmediate(R1, 3);
569         gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
570         assertPass(gen);
571         gen = new ApfGenerator(MIN_APF_VERSION);
572         gen.addLoadImmediate(R1, 3);
573         gen.addLoadImmediate(R0, 1);
574         gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
575         assertDrop(gen);
576         gen = new ApfGenerator(MIN_APF_VERSION);
577         gen.addLoadImmediate(R1, 3);
578         gen.addLoadImmediate(R0, 3);
579         gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
580         assertDrop(gen);
581 
582         // Test load from memory.
583         gen = new ApfGenerator(MIN_APF_VERSION);
584         gen.addLoadFromMemory(R0, 0);
585         gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
586         assertDrop(gen);
587 
588         // Test store to memory.
589         gen = new ApfGenerator(MIN_APF_VERSION);
590         gen.addLoadImmediate(R1, 1234567890);
591         gen.addStoreToMemory(R1, 12);
592         gen.addLoadFromMemory(R0, 12);
593         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
594         assertDrop(gen);
595 
596         // Test filter age pre-filled memory.
597         gen = new ApfGenerator(MIN_APF_VERSION);
598         gen.addLoadFromMemory(R0, gen.FILTER_AGE_MEMORY_SLOT);
599         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
600         assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890);
601 
602         // Test packet size pre-filled memory.
603         gen = new ApfGenerator(MIN_APF_VERSION);
604         gen.addLoadFromMemory(R0, gen.PACKET_SIZE_MEMORY_SLOT);
605         gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL);
606         assertDrop(gen);
607 
608         // Test IPv4 header size pre-filled memory.
609         gen = new ApfGenerator(MIN_APF_VERSION);
610         gen.addLoadFromMemory(R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
611         gen.addJumpIfR0Equals(20, gen.DROP_LABEL);
612         assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0);
613 
614         // Test not.
615         gen = new ApfGenerator(MIN_APF_VERSION);
616         gen.addLoadImmediate(R0, 1234567890);
617         gen.addNot(R0);
618         gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL);
619         assertDrop(gen);
620 
621         // Test negate.
622         gen = new ApfGenerator(MIN_APF_VERSION);
623         gen.addLoadImmediate(R0, 1234567890);
624         gen.addNeg(R0);
625         gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
626         assertDrop(gen);
627 
628         // Test move.
629         gen = new ApfGenerator(MIN_APF_VERSION);
630         gen.addLoadImmediate(R1, 1234567890);
631         gen.addMove(R0);
632         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
633         assertDrop(gen);
634         gen = new ApfGenerator(MIN_APF_VERSION);
635         gen.addLoadImmediate(R0, 1234567890);
636         gen.addMove(R1);
637         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
638         assertDrop(gen);
639 
640         // Test swap.
641         gen = new ApfGenerator(MIN_APF_VERSION);
642         gen.addLoadImmediate(R1, 1234567890);
643         gen.addSwap();
644         gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
645         assertDrop(gen);
646         gen = new ApfGenerator(MIN_APF_VERSION);
647         gen.addLoadImmediate(R0, 1234567890);
648         gen.addSwap();
649         gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
650         assertDrop(gen);
651 
652         // Test jump if bytes not equal.
653         gen = new ApfGenerator(MIN_APF_VERSION);
654         gen.addLoadImmediate(R0, 1);
655         gen.addJumpIfBytesNotEqual(R0, new byte[]{123}, gen.DROP_LABEL);
656         program = gen.generate();
657         assertEquals(6, program.length);
658         assertEquals((13 << 3) | (1 << 1) | 0, program[0]);
659         assertEquals(1, program[1]);
660         assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]);
661         assertEquals(1, program[3]);
662         assertEquals(1, program[4]);
663         assertEquals(123, program[5]);
664         assertDrop(program, new byte[MIN_PKT_SIZE], 0);
665         gen = new ApfGenerator(MIN_APF_VERSION);
666         gen.addLoadImmediate(R0, 1);
667         gen.addJumpIfBytesNotEqual(R0, new byte[]{123}, gen.DROP_LABEL);
668         byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
669         assertPass(gen, packet123, 0);
670         gen = new ApfGenerator(MIN_APF_VERSION);
671         gen.addJumpIfBytesNotEqual(R0, new byte[]{123}, gen.DROP_LABEL);
672         assertDrop(gen, packet123, 0);
673         gen = new ApfGenerator(MIN_APF_VERSION);
674         gen.addLoadImmediate(R0, 1);
675         gen.addJumpIfBytesNotEqual(R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
676         byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
677         assertDrop(gen, packet12345, 0);
678         gen = new ApfGenerator(MIN_APF_VERSION);
679         gen.addLoadImmediate(R0, 1);
680         gen.addJumpIfBytesNotEqual(R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL);
681         assertPass(gen, packet12345, 0);
682     }
683 
684     @Test(expected = ApfGenerator.IllegalInstructionException.class)
testApfGeneratorWantsV2OrGreater()685     public void testApfGeneratorWantsV2OrGreater() throws Exception {
686         // The minimum supported APF version is 2.
687         new ApfGenerator(1);
688     }
689 
690     @Test
testApfDataOpcodesWantApfV3()691     public void testApfDataOpcodesWantApfV3() throws IllegalInstructionException, Exception {
692         ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
693         try {
694             gen.addStoreData(R0, 0);
695             fail();
696         } catch (IllegalInstructionException expected) {
697             /* pass */
698         }
699         try {
700             gen.addLoadData(R0, 0);
701             fail();
702         } catch (IllegalInstructionException expected) {
703             /* pass */
704         }
705     }
706 
707     /**
708      * Test that the generator emits immediates using the shortest possible encoding.
709      */
710     @Test
testImmediateEncoding()711     public void testImmediateEncoding() throws IllegalInstructionException {
712         ApfGenerator gen;
713 
714         // 0-byte immediate: li R0, 0
715         gen = new ApfGenerator(4);
716         gen.addLoadImmediate(R0, 0);
717         assertProgramEquals(new byte[]{LI_OP | SIZE0}, gen.generate());
718 
719         // 1-byte immediate: li R0, 42
720         gen = new ApfGenerator(4);
721         gen.addLoadImmediate(R0, 42);
722         assertProgramEquals(new byte[]{LI_OP | SIZE8, 42}, gen.generate());
723 
724         // 2-byte immediate: li R1, 0x1234
725         gen = new ApfGenerator(4);
726         gen.addLoadImmediate(R1, 0x1234);
727         assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1_REG, 0x12, 0x34}, gen.generate());
728 
729         // 4-byte immediate: li R0, 0x12345678
730         gen = new ApfGenerator(3);
731         gen.addLoadImmediate(R0, 0x12345678);
732         assertProgramEquals(
733                 new byte[]{LI_OP | SIZE32, 0x12, 0x34, 0x56, 0x78},
734                 gen.generate());
735     }
736 
737     /**
738      * Test that the generator emits negative immediates using the shortest possible encoding.
739      */
740     @Test
testNegativeImmediateEncoding()741     public void testNegativeImmediateEncoding() throws IllegalInstructionException {
742         ApfGenerator gen;
743 
744         // 1-byte negative immediate: li R0, -42
745         gen = new ApfGenerator(3);
746         gen.addLoadImmediate(R0, -42);
747         assertProgramEquals(new byte[]{LI_OP | SIZE8, -42}, gen.generate());
748 
749         // 2-byte negative immediate: li R1, -0x1122
750         gen = new ApfGenerator(3);
751         gen.addLoadImmediate(R1, -0x1122);
752         assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1_REG, (byte)0xEE, (byte)0xDE},
753                 gen.generate());
754 
755         // 4-byte negative immediate: li R0, -0x11223344
756         gen = new ApfGenerator(3);
757         gen.addLoadImmediate(R0, -0x11223344);
758         assertProgramEquals(
759                 new byte[]{LI_OP | SIZE32, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
760                 gen.generate());
761     }
762 
763     /**
764      * Test that the generator correctly emits positive and negative immediates for LDDW/STDW.
765      */
766     @Test
testLoadStoreDataEncoding()767     public void testLoadStoreDataEncoding() throws IllegalInstructionException {
768         ApfGenerator gen;
769 
770         // Load data with no offset: lddw R0, [0 + r1]
771         gen = new ApfGenerator(3);
772         gen.addLoadData(R0, 0);
773         assertProgramEquals(new byte[]{LDDW_OP | SIZE0}, gen.generate());
774 
775         // Store data with 8bit negative offset: lddw r0, [-42 + r1]
776         gen = new ApfGenerator(3);
777         gen.addStoreData(R0, -42);
778         assertProgramEquals(new byte[]{STDW_OP | SIZE8, -42}, gen.generate());
779 
780         // Store data to R1 with 16bit negative offset: stdw r1, [-0x1122 + r0]
781         gen = new ApfGenerator(3);
782         gen.addStoreData(R1, -0x1122);
783         assertProgramEquals(new byte[]{STDW_OP | SIZE16 | R1_REG, (byte)0xEE, (byte)0xDE},
784                 gen.generate());
785 
786         // Load data to R1 with 32bit negative offset: lddw r1, [0xDEADBEEF + r0]
787         gen = new ApfGenerator(3);
788         gen.addLoadData(R1, 0xDEADBEEF);
789         assertProgramEquals(
790                 new byte[]{LDDW_OP | SIZE32 | R1_REG,
791                         (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF},
792                 gen.generate());
793     }
794 
795     /**
796      * Test that the interpreter correctly executes STDW with a negative 8bit offset
797      */
798     @Test
testApfDataWrite()799     public void testApfDataWrite() throws IllegalInstructionException, Exception {
800         byte[] packet = new byte[MIN_PKT_SIZE];
801         byte[] data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
802         byte[] expected_data = data.clone();
803 
804         // No memory access instructions: should leave the data segment untouched.
805         ApfGenerator gen = new ApfGenerator(3);
806         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
807 
808         // Expect value 0x87654321 to be stored starting from address -11 from the end of the
809         // data buffer, in big-endian order.
810         gen = new ApfGenerator(3);
811         gen.addLoadImmediate(R0, 0x87654321);
812         gen.addLoadImmediate(R1, -5);
813         gen.addStoreData(R0, -6);  // -5 + -6 = -11 (offset +5 with data_len=16)
814         expected_data[5] = (byte)0x87;
815         expected_data[6] = (byte)0x65;
816         expected_data[7] = (byte)0x43;
817         expected_data[8] = (byte)0x21;
818         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
819     }
820 
821     /**
822      * Test that the interpreter correctly executes LDDW with a negative 16bit offset
823      */
824     @Test
testApfDataRead()825     public void testApfDataRead() throws IllegalInstructionException, Exception {
826         // Program that DROPs if address 10 (-6) contains 0x87654321.
827         ApfGenerator gen = new ApfGenerator(3);
828         gen.addLoadImmediate(R1, 1000);
829         gen.addLoadData(R0, -1006);  // 1000 + -1006 = -6 (offset +10 with data_len=16)
830         gen.addJumpIfR0Equals(0x87654321, gen.DROP_LABEL);
831         byte[] program = gen.generate();
832         byte[] packet = new byte[MIN_PKT_SIZE];
833 
834         // Content is incorrect (last byte does not match) -> PASS
835         byte[] data = new byte[16];
836         data[10] = (byte)0x87;
837         data[11] = (byte)0x65;
838         data[12] = (byte)0x43;
839         data[13] = (byte)0x00;  // != 0x21
840         byte[] expected_data = data.clone();
841         assertDataMemoryContents(PASS, program, packet, data, expected_data);
842 
843         // Fix the last byte -> conditional jump taken -> DROP
844         data[13] = (byte)0x21;
845         expected_data = data;
846         assertDataMemoryContents(DROP, program, packet, data, expected_data);
847     }
848 
849     /**
850      * Test that the interpreter correctly executes LDDW followed by a STDW.
851      * To cover a few more edge cases, LDDW has a 0bit offset, while STDW has a positive 8bit
852      * offset.
853      */
854     @Test
testApfDataReadModifyWrite()855     public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception {
856         ApfGenerator gen = new ApfGenerator(3);
857         gen.addLoadImmediate(R1, -22);
858         gen.addLoadData(R0, 0);  // Load from address 32 -22 + 0 = 10
859         gen.addAdd(0x78453412);  // 87654321 + 78453412 = FFAA7733
860         gen.addStoreData(R0, 4);  // Write back to address 32 -22 + 4 = 14
861 
862         byte[] packet = new byte[MIN_PKT_SIZE];
863         byte[] data = new byte[32];
864         data[10] = (byte)0x87;
865         data[11] = (byte)0x65;
866         data[12] = (byte)0x43;
867         data[13] = (byte)0x21;
868         byte[] expected_data = data.clone();
869         expected_data[14] = (byte)0xFF;
870         expected_data[15] = (byte)0xAA;
871         expected_data[16] = (byte)0x77;
872         expected_data[17] = (byte)0x33;
873         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
874     }
875 
876     @Test
testApfDataBoundChecking()877     public void testApfDataBoundChecking() throws IllegalInstructionException, Exception {
878         byte[] packet = new byte[MIN_PKT_SIZE];
879         byte[] data = new byte[32];
880         byte[] expected_data = data;
881 
882         // Program that DROPs unconditionally. This is our the baseline.
883         ApfGenerator gen = new ApfGenerator(3);
884         gen.addLoadImmediate(R0, 3);
885         gen.addLoadData(R1, 7);
886         gen.addJump(gen.DROP_LABEL);
887         assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
888 
889         // Same program as before, but this time we're trying to load past the end of the data.
890         gen = new ApfGenerator(3);
891         gen.addLoadImmediate(R0, 20);
892         gen.addLoadData(R1, 15);  // 20 + 15 > 32
893         gen.addJump(gen.DROP_LABEL);  // Not reached.
894         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
895 
896         // Subtracting an immediate should work...
897         gen = new ApfGenerator(3);
898         gen.addLoadImmediate(R0, 20);
899         gen.addLoadData(R1, -4);
900         gen.addJump(gen.DROP_LABEL);
901         assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
902 
903         // ...and underflowing simply wraps around to the end of the buffer...
904         gen = new ApfGenerator(3);
905         gen.addLoadImmediate(R0, 20);
906         gen.addLoadData(R1, -30);
907         gen.addJump(gen.DROP_LABEL);
908         assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
909 
910         // ...but doesn't allow accesses before the start of the buffer
911         gen = new ApfGenerator(3);
912         gen.addLoadImmediate(R0, 20);
913         gen.addLoadData(R1, -1000);
914         gen.addJump(gen.DROP_LABEL);  // Not reached.
915         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
916     }
917 
918     /**
919      * Generate some BPF programs, translate them to APF, then run APF and BPF programs
920      * over packet traces and verify both programs filter out the same packets.
921      */
922     @Test
testApfAgainstBpf()923     public void testApfAgainstBpf() throws Exception {
924         String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
925                 "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
926                 "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000",
927                 "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" };
928         String pcap_filename = stageFile(R.raw.apf);
929         for (String tcpdump_filter : tcpdump_filters) {
930             byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter));
931             assertTrue("Failed to match for filter: " + tcpdump_filter,
932                     compareBpfApf(tcpdump_filter, pcap_filename, apf_program));
933         }
934     }
935 
936     /**
937      * Generate APF program, run pcap file though APF filter, then check all the packets in the file
938      * should be dropped.
939      */
940     @Test
testApfFilterPcapFile()941     public void testApfFilterPcapFile() throws Exception {
942         final byte[] MOCK_PCAP_IPV4_ADDR = {(byte) 172, 16, 7, (byte) 151};
943         String pcapFilename = stageFile(R.raw.apfPcap);
944         MockIpClientCallback ipClientCallback = new MockIpClientCallback();
945         LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_PCAP_IPV4_ADDR), 16);
946         LinkProperties lp = new LinkProperties();
947         lp.addLinkAddress(link);
948 
949         ApfConfiguration config = getDefaultConfig();
950         ApfCapabilities MOCK_APF_PCAP_CAPABILITIES = new ApfCapabilities(4, 1700, ARPHRD_ETHER);
951         config.apfCapabilities = MOCK_APF_PCAP_CAPABILITIES;
952         config.multicastFilter = DROP_MULTICAST;
953         config.ieee802_3Filter = DROP_802_3_FRAMES;
954         TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog,
955                 mDependencies);
956         apfFilter.setLinkProperties(lp);
957         byte[] program = ipClientCallback.getApfProgram();
958         byte[] data = new byte[ApfFilter.Counter.totalSize()];
959         final boolean result;
960 
961         result = dropsAllPackets(program, data, pcapFilename);
962         Log.i(TAG, "testApfFilterPcapFile(): Data counters: " + HexDump.toHexString(data, false));
963 
964         assertTrue("Failed to drop all packets by filter. \nAPF counters:" +
965             HexDump.toHexString(data, false), result);
966     }
967 
968     private class MockIpClientCallback extends IpClientCallbacksWrapper {
969         private final ConditionVariable mGotApfProgram = new ConditionVariable();
970         private byte[] mLastApfProgram;
971 
MockIpClientCallback()972         MockIpClientCallback() {
973             super(mock(IIpClientCallbacks.class), mock(SharedLog.class),
974                     NetworkInformationShimImpl.newInstance());
975         }
976 
977         @Override
installPacketFilter(byte[] filter)978         public void installPacketFilter(byte[] filter) {
979             mLastApfProgram = filter;
980             mGotApfProgram.open();
981         }
982 
resetApfProgramWait()983         public void resetApfProgramWait() {
984             mGotApfProgram.close();
985         }
986 
getApfProgram()987         public byte[] getApfProgram() {
988             assertTrue(mGotApfProgram.block(TIMEOUT_MS));
989             return mLastApfProgram;
990         }
991 
assertNoProgramUpdate()992         public void assertNoProgramUpdate() {
993             assertFalse(mGotApfProgram.block(TIMEOUT_MS));
994         }
995     }
996 
997     private static class TestApfFilter extends ApfFilter {
998         public static final byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
999 
1000         private FileDescriptor mWriteSocket;
1001         private long mCurrentTimeMs = SystemClock.elapsedRealtime();
1002 
TestApfFilter(Context context, ApfConfiguration config, IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log, ApfFilter.Dependencies deps)1003         public TestApfFilter(Context context, ApfConfiguration config,
1004                 IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log,
1005                 ApfFilter.Dependencies deps) throws Exception {
1006             super(context, config, InterfaceParams.getByName("lo"), ipClientCallback, log, deps);
1007         }
1008 
1009         // Pretend an RA packet has been received and show it to ApfFilter.
pretendPacketReceived(byte[] packet)1010         public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException {
1011             // ApfFilter's ReceiveThread will be waiting to read this.
1012             Os.write(mWriteSocket, packet, 0, packet.length);
1013         }
1014 
1015         // Simulate current time changes
increaseCurrentTimeSeconds(int delta)1016         public void increaseCurrentTimeSeconds(int delta) {
1017             mCurrentTimeMs += delta * DateUtils.SECOND_IN_MILLIS;
1018         }
1019 
1020         @Override
currentTimeSeconds()1021         protected long currentTimeSeconds() {
1022             return mCurrentTimeMs / DateUtils.SECOND_IN_MILLIS;
1023         }
1024 
1025         @Override
maybeStartFilter()1026         public synchronized void maybeStartFilter() {
1027             mHardwareAddress = MOCK_MAC_ADDR;
1028             installNewProgramLocked();
1029 
1030             // Create two sockets, "readSocket" and "mWriteSocket" and connect them together.
1031             FileDescriptor readSocket = new FileDescriptor();
1032             mWriteSocket = new FileDescriptor();
1033             try {
1034                 Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket);
1035             } catch (ErrnoException e) {
1036                 fail();
1037                 return;
1038             }
1039             // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs.
1040             // This allows us to pretend RA packets have been recieved via pretendPacketReceived().
1041             mReceiveThread = new ReceiveThread(readSocket);
1042             mReceiveThread.start();
1043         }
1044 
1045         @Override
shutdown()1046         public void shutdown() {
1047             super.shutdown();
1048             IoUtils.closeQuietly(mWriteSocket);
1049         }
1050     }
1051 
1052     private static final int ETH_HEADER_LEN               = 14;
1053     private static final int ETH_DEST_ADDR_OFFSET         = 0;
1054     private static final int ETH_ETHERTYPE_OFFSET         = 12;
1055     private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
1056             {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
1057     private static final byte[] ETH_MULTICAST_MDNS_v4_MAC_ADDRESS =
1058             {(byte) 0x01, (byte) 0x00, (byte) 0x5e, (byte) 0x00, (byte) 0x00, (byte) 0xfb};
1059     private static final byte[] ETH_MULTICAST_MDNS_V6_MAC_ADDRESS =
1060             {(byte) 0x33, (byte) 0x33, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xfb};
1061 
1062     private static final int IP_HEADER_OFFSET = ETH_HEADER_LEN;
1063 
1064     private static final int IPV4_HEADER_LEN          = 20;
1065     private static final int IPV4_TOTAL_LENGTH_OFFSET = IP_HEADER_OFFSET + 2;
1066     private static final int IPV4_PROTOCOL_OFFSET     = IP_HEADER_OFFSET + 9;
1067     private static final int IPV4_SRC_ADDR_OFFSET     = IP_HEADER_OFFSET + 12;
1068     private static final int IPV4_DEST_ADDR_OFFSET    = IP_HEADER_OFFSET + 16;
1069 
1070     private static final int IPV4_TCP_HEADER_LEN           = 20;
1071     private static final int IPV4_TCP_HEADER_OFFSET        = IP_HEADER_OFFSET + IPV4_HEADER_LEN;
1072     private static final int IPV4_TCP_SRC_PORT_OFFSET      = IPV4_TCP_HEADER_OFFSET + 0;
1073     private static final int IPV4_TCP_DEST_PORT_OFFSET     = IPV4_TCP_HEADER_OFFSET + 2;
1074     private static final int IPV4_TCP_SEQ_NUM_OFFSET       = IPV4_TCP_HEADER_OFFSET + 4;
1075     private static final int IPV4_TCP_ACK_NUM_OFFSET       = IPV4_TCP_HEADER_OFFSET + 8;
1076     private static final int IPV4_TCP_HEADER_LENGTH_OFFSET = IPV4_TCP_HEADER_OFFSET + 12;
1077     private static final int IPV4_TCP_HEADER_FLAG_OFFSET   = IPV4_TCP_HEADER_OFFSET + 13;
1078 
1079     private static final int IPV4_UDP_HEADER_OFFSET    = IP_HEADER_OFFSET + IPV4_HEADER_LEN;
1080     private static final int IPV4_UDP_SRC_PORT_OFFSET  = IPV4_UDP_HEADER_OFFSET + 0;
1081     private static final int IPV4_UDP_DEST_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 2;
1082     private static final int IPV4_UDP_LENGTH_OFFSET    = IPV4_UDP_HEADER_OFFSET + 4;
1083     private static final int IPV4_UDP_PAYLOAD_OFFSET   = IPV4_UDP_HEADER_OFFSET + 8;
1084     private static final byte[] IPV4_BROADCAST_ADDRESS =
1085             {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
1086 
1087     private static final int IPV6_HEADER_LEN             = 40;
1088     private static final int IPV6_PAYLOAD_LENGTH_OFFSET  = IP_HEADER_OFFSET + 4;
1089     private static final int IPV6_NEXT_HEADER_OFFSET     = IP_HEADER_OFFSET + 6;
1090     private static final int IPV6_SRC_ADDR_OFFSET        = IP_HEADER_OFFSET + 8;
1091     private static final int IPV6_DEST_ADDR_OFFSET       = IP_HEADER_OFFSET + 24;
1092     private static final int IPV6_PAYLOAD_OFFSET = IP_HEADER_OFFSET + IPV6_HEADER_LEN;
1093     private static final int IPV6_TCP_SRC_PORT_OFFSET    = IPV6_PAYLOAD_OFFSET + 0;
1094     private static final int IPV6_TCP_DEST_PORT_OFFSET   = IPV6_PAYLOAD_OFFSET + 2;
1095     private static final int IPV6_TCP_SEQ_NUM_OFFSET     = IPV6_PAYLOAD_OFFSET + 4;
1096     private static final int IPV6_TCP_ACK_NUM_OFFSET     = IPV6_PAYLOAD_OFFSET + 8;
1097     // The IPv6 all nodes address ff02::1
1098     private static final byte[] IPV6_ALL_NODES_ADDRESS   =
1099             { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
1100     private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
1101             { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
1102     private static final byte[] IPV6_SOLICITED_NODE_MULTICAST_ADDRESS = {
1103             (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1104             (byte) 0xff, (byte) 0xab, (byte) 0xcd, (byte) 0xef,
1105     };
1106 
1107     private static final int ICMP6_TYPE_OFFSET           = IP_HEADER_OFFSET + IPV6_HEADER_LEN;
1108     private static final int ICMP6_ROUTER_SOLICITATION   = 133;
1109     private static final int ICMP6_ROUTER_ADVERTISEMENT  = 134;
1110     private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
1111     private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
1112 
1113     private static final int ICMP6_RA_HEADER_LEN = 16;
1114     private static final int ICMP6_RA_CHECKSUM_OFFSET =
1115             IP_HEADER_OFFSET + IPV6_HEADER_LEN + 2;
1116     private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
1117             IP_HEADER_OFFSET + IPV6_HEADER_LEN + 6;
1118     private static final int ICMP6_RA_REACHABLE_TIME_OFFSET =
1119             IP_HEADER_OFFSET + IPV6_HEADER_LEN + 8;
1120     private static final int ICMP6_RA_RETRANSMISSION_TIMER_OFFSET =
1121             IP_HEADER_OFFSET + IPV6_HEADER_LEN + 12;
1122     private static final int ICMP6_RA_OPTION_OFFSET =
1123             IP_HEADER_OFFSET + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
1124 
1125     private static final int ICMP6_PREFIX_OPTION_TYPE                      = 3;
1126     private static final int ICMP6_PREFIX_OPTION_LEN                       = 32;
1127     private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET     = 4;
1128     private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
1129 
1130     // From RFC6106: Recursive DNS Server option
1131     private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
1132     // From RFC6106: DNS Search List option
1133     private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
1134 
1135     // From RFC4191: Route Information option
1136     private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
1137     // Above three options all have the same format:
1138     private static final int ICMP6_4_BYTE_OPTION_LEN      = 8;
1139     private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
1140     private static final int ICMP6_4_BYTE_LIFETIME_LEN    = 4;
1141 
1142     private static final int UDP_HEADER_LEN              = 8;
1143     private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22;
1144 
1145     private static final int DHCP_CLIENT_PORT       = 68;
1146     private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
1147 
1148     private static final int ARP_HEADER_OFFSET          = ETH_HEADER_LEN;
1149     private static final byte[] ARP_IPV4_REQUEST_HEADER = {
1150             0, 1, // Hardware type: Ethernet (1)
1151             8, 0, // Protocol type: IP (0x0800)
1152             6,    // Hardware size: 6
1153             4,    // Protocol size: 4
1154             0, 1  // Opcode: request (1)
1155     };
1156     private static final byte[] ARP_IPV4_REPLY_HEADER = {
1157             0, 1, // Hardware type: Ethernet (1)
1158             8, 0, // Protocol type: IP (0x0800)
1159             6,    // Hardware size: 6
1160             4,    // Protocol size: 4
1161             0, 2  // Opcode: reply (2)
1162     };
1163     private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
1164     private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
1165 
1166     private static final byte[] MOCK_IPV4_ADDR           = {10, 0, 0, 1};
1167     private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19
1168     private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1};
1169     private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
1170     private static final byte[] IPV4_SOURCE_ADDR         = {10, 0, 0, 3};
1171     private static final byte[] ANOTHER_IPV4_SOURCE_ADDR = {(byte) 192, 0, 2, 1};
1172     private static final byte[] BUG_PROBE_SOURCE_ADDR1   = {0, 0, 1, 2};
1173     private static final byte[] BUG_PROBE_SOURCE_ADDR2   = {3, 4, 0, 0};
1174     private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};
1175     private static final byte[] IPV4_MDNS_MULTICAST_ADDR = {(byte) 224, 0, 0, (byte) 251};
1176     private static final byte[] IPV6_MDNS_MULTICAST_ADDR =
1177             {(byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfb};
1178     private static final int IPV6_UDP_DEST_PORT_OFFSET = IPV6_PAYLOAD_OFFSET + 2;
1179     private static final int MDNS_UDP_PORT = 5353;
1180 
1181     // Helper to initialize a default apfFilter.
setupApfFilter( IpClientCallbacksWrapper ipClientCallback, ApfConfiguration config)1182     private ApfFilter setupApfFilter(
1183             IpClientCallbacksWrapper ipClientCallback, ApfConfiguration config) throws Exception {
1184         LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
1185         LinkProperties lp = new LinkProperties();
1186         lp.addLinkAddress(link);
1187         TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog,
1188                 mDependencies);
1189         apfFilter.setLinkProperties(lp);
1190         return apfFilter;
1191     }
1192 
setIpv4VersionFields(ByteBuffer packet)1193     private static void setIpv4VersionFields(ByteBuffer packet) {
1194         packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
1195         packet.put(IP_HEADER_OFFSET, (byte) 0x45);
1196     }
1197 
setIpv6VersionFields(ByteBuffer packet)1198     private static void setIpv6VersionFields(ByteBuffer packet) {
1199         packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
1200         packet.put(IP_HEADER_OFFSET, (byte) 0x60);
1201     }
1202 
makeIpv4Packet(int proto)1203     private static ByteBuffer makeIpv4Packet(int proto) {
1204         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1205         setIpv4VersionFields(packet);
1206         packet.put(IPV4_PROTOCOL_OFFSET, (byte) proto);
1207         return packet;
1208     }
1209 
makeIpv6Packet(int nextHeader)1210     private static ByteBuffer makeIpv6Packet(int nextHeader) {
1211         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1212         setIpv6VersionFields(packet);
1213         packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) nextHeader);
1214         return packet;
1215     }
1216 
1217     @Test
testApfFilterIPv4()1218     public void testApfFilterIPv4() throws Exception {
1219         MockIpClientCallback ipClientCallback = new MockIpClientCallback();
1220         LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
1221         LinkProperties lp = new LinkProperties();
1222         lp.addLinkAddress(link);
1223 
1224         ApfConfiguration config = getDefaultConfig();
1225         config.multicastFilter = DROP_MULTICAST;
1226         TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog,
1227                 mDependencies);
1228         apfFilter.setLinkProperties(lp);
1229 
1230         byte[] program = ipClientCallback.getApfProgram();
1231 
1232         // Verify empty packet of 100 zero bytes is passed
1233         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1234         assertPass(program, packet.array());
1235 
1236         // Verify unicast IPv4 packet is passed
1237         put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
1238         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1239         put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
1240         assertPass(program, packet.array());
1241 
1242         // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088)
1243         put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
1244         assertDrop(program, packet.array());
1245         put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
1246         assertDrop(program, packet.array());
1247 
1248         // Verify multicast/broadcast IPv4, not DHCP to us, is dropped
1249         put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
1250         assertDrop(program, packet.array());
1251         packet.put(IP_HEADER_OFFSET, (byte) 0x45);
1252         assertDrop(program, packet.array());
1253         packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
1254         assertDrop(program, packet.array());
1255         packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
1256         assertDrop(program, packet.array());
1257         put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR);
1258         assertDrop(program, packet.array());
1259         put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
1260         assertDrop(program, packet.array());
1261         put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
1262         assertDrop(program, packet.array());
1263 
1264         // Verify broadcast IPv4 DHCP to us is passed
1265         put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
1266         assertPass(program, packet.array());
1267 
1268         // Verify unicast IPv4 DHCP to us is passed
1269         put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
1270         assertPass(program, packet.array());
1271 
1272         apfFilter.shutdown();
1273     }
1274 
1275     @Test
testApfFilterIPv6()1276     public void testApfFilterIPv6() throws Exception {
1277         MockIpClientCallback ipClientCallback = new MockIpClientCallback();
1278         ApfConfiguration config = getDefaultConfig();
1279         TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog,
1280                 mDependencies);
1281         byte[] program = ipClientCallback.getApfProgram();
1282 
1283         // Verify empty IPv6 packet is passed
1284         ByteBuffer packet = makeIpv6Packet(IPPROTO_UDP);
1285         assertPass(program, packet.array());
1286 
1287         // Verify empty ICMPv6 packet is passed
1288         packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
1289         assertPass(program, packet.array());
1290 
1291         // Verify empty ICMPv6 NA packet is passed
1292         packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
1293         assertPass(program, packet.array());
1294 
1295         // Verify ICMPv6 NA to ff02::1 is dropped
1296         put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
1297         assertDrop(program, packet.array());
1298 
1299         // Verify ICMPv6 NA to ff02::2 is dropped
1300         put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
1301         assertDrop(program, packet.array());
1302 
1303         // Verify ICMPv6 NA to Solicited-Node Multicast is passed
1304         put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_SOLICITED_NODE_MULTICAST_ADDRESS);
1305         assertPass(program, packet.array());
1306 
1307         // Verify ICMPv6 RS to any is dropped
1308         packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION);
1309         assertDrop(program, packet.array());
1310         put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
1311         assertDrop(program, packet.array());
1312 
1313         apfFilter.shutdown();
1314     }
1315 
fillQuestionSection(ByteBuffer buf, String... qnames)1316     private static void fillQuestionSection(ByteBuffer buf, String... qnames) throws IOException {
1317         buf.put(new DnsPacket.DnsHeader(0 /* id */, 0 /* flags */, qnames.length, 0 /* ancount */)
1318                 .getBytes());
1319         for (String qname : qnames) {
1320             buf.put(DnsPacket.DnsRecord.makeQuestion(qname, 0 /* nsType */, 0 /* nsClass */)
1321                     .getBytes());
1322         }
1323     }
1324 
makeMdnsV4Packet(String... qnames)1325     private static byte[] makeMdnsV4Packet(String... qnames) throws IOException {
1326         final ByteBuffer buf = ByteBuffer.wrap(new byte[256]);
1327         final PacketBuilder builder = new PacketBuilder(buf);
1328         builder.writeL2Header(MacAddress.fromString("11:22:33:44:55:66"),
1329                 MacAddress.fromBytes(ETH_MULTICAST_MDNS_v4_MAC_ADDRESS),
1330                 (short) ETH_P_IP);
1331         builder.writeIpv4Header((byte) 0 /* tos */, (short) 0 /* id */,
1332                 (short) 0 /* flagsAndFragmentOffset */, (byte) 0 /* ttl */, (byte) IPPROTO_UDP,
1333                 (Inet4Address) Inet4Address.getByAddress(IPV4_SOURCE_ADDR),
1334                 (Inet4Address) Inet4Address.getByAddress(IPV4_MDNS_MULTICAST_ADDR));
1335         builder.writeUdpHeader((short) MDNS_UDP_PORT, (short) MDNS_UDP_PORT);
1336         fillQuestionSection(buf, qnames);
1337         return builder.finalizePacket().array();
1338     }
1339 
makeMdnsV6Packet(String... qnames)1340     private static byte[] makeMdnsV6Packet(String... qnames) throws IOException {
1341         ByteBuffer buf = ByteBuffer.wrap(new byte[256]);
1342         final PacketBuilder builder = new PacketBuilder(buf);
1343         builder.writeL2Header(MacAddress.fromString("11:22:33:44:55:66"),
1344                 MacAddress.fromBytes(ETH_MULTICAST_MDNS_V6_MAC_ADDRESS),
1345                 (short) ETH_P_IPV6);
1346         builder.writeIpv6Header(0x680515ca /* vtf */, (byte) IPPROTO_UDP, (short) 0 /* hopLimit */,
1347                 (Inet6Address) InetAddress.getByAddress(IPV6_ANOTHER_ADDR),
1348                 (Inet6Address) Inet6Address.getByAddress(IPV6_MDNS_MULTICAST_ADDR));
1349         builder.writeUdpHeader((short) MDNS_UDP_PORT, (short) MDNS_UDP_PORT);
1350         fillQuestionSection(buf, qnames);
1351         return builder.finalizePacket().array();
1352     }
1353 
putLabel(ByteBuffer buf, String label)1354     private static void putLabel(ByteBuffer buf, String label) {
1355         final byte[] bytes = label.getBytes(StandardCharsets.UTF_8);
1356         buf.put((byte) bytes.length);
1357         buf.put(bytes);
1358     }
1359 
putPointer(ByteBuffer buf, int offset)1360     private static void putPointer(ByteBuffer buf, int offset) {
1361         short pointer = (short) (offset | 0xc000);
1362         buf.putShort(pointer);
1363     }
1364 
1365 
1366     // Simplistic DNS compression code that intentionally does not depend on production code.
getDnsLabels(int startOffset, String... names)1367     private static List<Pair<Integer, String>> getDnsLabels(int startOffset, String... names) {
1368         // Maps all possible name suffixes to packet offsets.
1369         final HashMap<String, Integer> mPointerOffsets = new HashMap<>();
1370         final List<Pair<Integer, String>> out = new ArrayList<>();
1371         int offset = startOffset;
1372         for (int i = 0; i < names.length; i++) {
1373             String name = names[i];
1374             while (true) {
1375                 if (name.length() == 0) {
1376                     out.add(label(""));
1377                     offset += 1 + 4;  // 1-byte label, DNS query
1378                     break;
1379                 }
1380 
1381                 final int pointerOffset = mPointerOffsets.getOrDefault(name, -1);
1382                 if (pointerOffset != -1) {
1383                     out.add(pointer(pointerOffset));
1384                     offset += 2 + 4; // 2-byte pointer, DNS query
1385                     break;
1386                 }
1387 
1388                 mPointerOffsets.put(name, offset);
1389 
1390                 final int indexOfDot = name.indexOf(".");
1391                 final String label;
1392                 if (indexOfDot == -1) {
1393                     label = name;
1394                     name = "";
1395                 } else {
1396                     label = name.substring(0, indexOfDot);
1397                     name = name.substring(indexOfDot + 1);
1398                 }
1399                 out.add(label(label));
1400                 offset += 1 + label.length();
1401             }
1402         }
1403         return out;
1404     }
1405 
label(String label)1406     static Pair<Integer, String> label(String label) {
1407         return Pair.create(label.length(), label);
1408     }
1409 
pointer(int offset)1410     static Pair<Integer, String> pointer(int offset) {
1411         return Pair.create(0xc000 | offset, null);
1412     }
1413 
1414     @Test
testGetDnsLabels()1415     public void testGetDnsLabels() throws Exception {
1416         int startOffset = 12;
1417         List<Pair<Integer, String>> actual = getDnsLabels(startOffset, "myservice.tcp.local");
1418         assertEquals(4, actual.size());
1419         assertEquals(label("myservice"), actual.get(0));
1420         assertEquals(label("tcp"), actual.get(1));
1421         assertEquals(label("local"), actual.get(2));
1422         assertEquals(label(""), actual.get(3));
1423 
1424         startOffset = 30;
1425         actual = getDnsLabels(startOffset,
1426                 "myservice.tcp.local", "foo.tcp.local", "myhostname.local", "bar.udp.local",
1427                 "foo.myhostname.local");
1428         final int tcpLocalOffset = startOffset + 1 + "myservice".length();
1429         final int localOffset = startOffset + 1 + "myservice".length() + 1 + "tcp".length();
1430         final int myhostnameLocalOffset = 30
1431                 + 1 + "myservice".length() + 1 + "tcp".length() + 1 + "local".length() + 1 + 4
1432                 + 1 + "foo".length() + 2 + 4;
1433 
1434         assertEquals(13, actual.size());
1435         assertEquals(label("myservice"), actual.get(0));
1436         assertEquals(label("tcp"), actual.get(1));
1437         assertEquals(label("local"), actual.get(2));
1438         assertEquals(label(""), actual.get(3));
1439         assertEquals(label("foo"), actual.get(4));
1440         assertEquals(pointer(tcpLocalOffset), actual.get(5));
1441         assertEquals(label("myhostname"), actual.get(6));
1442         assertEquals(pointer(localOffset), actual.get(7));
1443         assertEquals(label("bar"), actual.get(8));
1444         assertEquals(label("udp"), actual.get(9));
1445         assertEquals(pointer(localOffset), actual.get(10));
1446         assertEquals(label("foo"), actual.get(11));
1447         assertEquals(pointer(myhostnameLocalOffset), actual.get(12));
1448 
1449     }
1450 
makeMdnsCompressedV6Packet(String... names)1451     private static byte[] makeMdnsCompressedV6Packet(String... names) throws IOException {
1452         ByteBuffer questions = ByteBuffer.allocate(1500);
1453         questions.put(new DnsPacket.DnsHeader(123, 0, names.length, 0).getBytes());
1454         final List<Pair<Integer, String>> labels = getDnsLabels(questions.position(), names);
1455         for (Pair<Integer, String> label : labels) {
1456             final String name = label.second;
1457             if (name == null) {
1458                 putPointer(questions, label.first);
1459             } else {
1460                 putLabel(questions, name);
1461             }
1462             if (TextUtils.isEmpty(name)) {
1463                 questions.put(new byte[4]);
1464             }
1465         }
1466         questions.flip();
1467 
1468         ByteBuffer buf = PacketBuilder.allocate(/*hasEther=*/ true, IPPROTO_IPV6, IPPROTO_UDP,
1469                 questions.limit());
1470         final PacketBuilder builder = new PacketBuilder(buf);
1471         builder.writeL2Header(MacAddress.fromString("11:22:33:44:55:66"),
1472                 MacAddress.fromBytes(ETH_MULTICAST_MDNS_V6_MAC_ADDRESS),
1473                 (short) ETH_P_IPV6);
1474         builder.writeIpv6Header(0x680515ca /* vtf */, (byte) IPPROTO_UDP, (short) 0 /* hopLimit */,
1475                 (Inet6Address) InetAddress.getByAddress(IPV6_ANOTHER_ADDR),
1476                 (Inet6Address) Inet6Address.getByAddress(IPV6_MDNS_MULTICAST_ADDR));
1477         builder.writeUdpHeader((short) MDNS_UDP_PORT, (short) MDNS_UDP_PORT);
1478 
1479         buf.put(questions);
1480 
1481         return builder.finalizePacket().array();
1482     }
1483 
makeMdnsCompressedV6Packet()1484     private static byte[] makeMdnsCompressedV6Packet() throws IOException {
1485         return makeMdnsCompressedV6Packet("myservice.tcp.local", "googlecast.tcp.local",
1486                 "matter.tcp.local", "myhostname.local");
1487     }
1488 
makeMdnsCompressedV6PacketWithManyNames()1489     private static byte[] makeMdnsCompressedV6PacketWithManyNames() throws IOException {
1490         return makeMdnsCompressedV6Packet("myservice.tcp.local", "googlecast.tcp.local",
1491                 "matter.tcp.local", "myhostname.local", "myhostname2.local", "myhostname3.local",
1492                 "myhostname4.local", "myhostname5.local", "myhostname6.local", "myhostname7.local");
1493 
1494     }
1495 
1496     /** Adds to the program a no-op instruction that is one byte long. */
addOneByteNoop(ApfGenerator gen)1497     private void addOneByteNoop(ApfGenerator gen) {
1498         gen.addOr(0);
1499     }
1500 
1501     @Test
testAddOneByteNoopAddsOneByte()1502     public void testAddOneByteNoopAddsOneByte() throws Exception {
1503         ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
1504         addOneByteNoop(gen);
1505         assertEquals(1, gen.generate().length);
1506 
1507         final int count = 42;
1508         gen = new ApfGenerator(MIN_APF_VERSION);
1509         for (int i = 0; i < count; i++) {
1510             addOneByteNoop(gen);
1511         }
1512         assertEquals(count, gen.generate().length);
1513     }
1514 
1515     @Test
testQnameEncoding()1516     public void testQnameEncoding() {
1517         String[] qname = new String[]{"abcd", "ef", "日本"};
1518         byte[] encodedQname = ApfFilter.encodeQname(qname);
1519         Assert.assertArrayEquals(
1520                 new byte[]{0x04, 0x61, 0x62, 0x63, 0x64, 0x02, 0x65, 0x66, 0x06, (byte) 0xe6,
1521                         (byte) 0x97, (byte) 0xa5, (byte) 0xe6, (byte) 0x9c, (byte) 0xac, 0x00},
1522                 encodedQname);
1523     }
1524 
1525     @Test
testApfFilterMdns()1526     public void testApfFilterMdns() throws Exception {
1527         final byte[] unicastIpv4Addr = {(byte) 192, 0, 2, 63};
1528 
1529         MockIpClientCallback ipClientCallback = new MockIpClientCallback();
1530         LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
1531         LinkProperties lp = new LinkProperties();
1532         lp.addLinkAddress(link);
1533 
1534         ApfConfiguration config = getDefaultConfig();
1535         TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog,
1536                 mDependencies);
1537         apfFilter.setLinkProperties(lp);
1538 
1539         // Construct IPv4 mDNS packet
1540         byte[] mdnsv4packet = makeMdnsV4Packet("test.local");
1541         byte[] mdnsv6packet = makeMdnsV6Packet("test.local");
1542         byte[] program = ipClientCallback.getApfProgram();
1543         // mDNSv4 packet is passed if no mDns filter is turned on
1544         assertPass(program, mdnsv4packet);
1545         // mDNSv6 packet is passed if no mDNS filter is turned on
1546         assertPass(program, mdnsv6packet);
1547 
1548         // mDNSv4 packet with qname in the allowlist is passed
1549         apfFilter.addToMdnsAllowList(new String[]{"test", "local"});
1550         apfFilter.addToMdnsAllowList(new String[]{"abcd", "local"});
1551         apfFilter.setMulticastFilter(true);
1552         program = ipClientCallback.getApfProgram();
1553         assertPass(program, mdnsv4packet);
1554         assertPass(program, mdnsv6packet);
1555 
1556         mdnsv4packet = makeMdnsV4Packet("abcd.local");
1557         mdnsv6packet = makeMdnsV6Packet("abcd.local");
1558         assertPass(program, mdnsv4packet);
1559         assertPass(program, mdnsv6packet);
1560 
1561         // mDNSv4 packet with qname not in the allowlist is dropped
1562         mdnsv4packet = makeMdnsV4Packet("ffff.local");
1563         mdnsv6packet = makeMdnsV6Packet("ffff.local");
1564         assertDrop(program, mdnsv4packet);
1565         assertDrop(program, mdnsv6packet);
1566 
1567         apfFilter.removeFromAllowList(new String[]{"abcd", "local"});
1568         program = ipClientCallback.getApfProgram();
1569         mdnsv4packet = makeMdnsV4Packet("abcd.local");
1570         mdnsv6packet = makeMdnsV6Packet("abcd.local");
1571         assertDrop(program, mdnsv4packet);
1572         assertDrop(program, mdnsv6packet);
1573 
1574         apfFilter.shutdown();
1575     }
1576 
generateDnsFilter(boolean ipv6, String... labels)1577     private ApfGenerator generateDnsFilter(boolean ipv6, String... labels) throws Exception {
1578         ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
1579         gen.addLoadImmediate(R1, ipv6 ? IPV6_HEADER_LEN : IPV4_HEADER_LEN);
1580         DnsUtils.generateFilter(gen, labels);
1581         return gen;
1582     }
1583 
doTestDnsParsing(boolean expectPass, boolean ipv6, String filterName, byte[] pkt)1584     private void doTestDnsParsing(boolean expectPass, boolean ipv6, String filterName,
1585             byte[] pkt) throws Exception {
1586         final String[] labels = filterName.split(/*regex=*/ "[.]");
1587         ApfGenerator gen = generateDnsFilter(ipv6, labels);
1588 
1589         // Hack to prevent the APF instruction limit triggering.
1590         for (int i = 0; i < 500; i++) {
1591             addOneByteNoop(gen);
1592         }
1593 
1594         byte[] program = gen.generate();
1595         Log.d(TAG, "prog_len=" + program.length);
1596         if (expectPass) {
1597             assertPass(program, pkt, 0);
1598         } else {
1599             assertDrop(program, pkt, 0);
1600         }
1601     }
1602 
doTestDnsParsing(boolean expectPass, boolean ipv6, String filterName, String... packetNames)1603     private void doTestDnsParsing(boolean expectPass, boolean ipv6, String filterName,
1604             String... packetNames) throws Exception {
1605         final byte[] pkt = ipv6 ? makeMdnsV6Packet(packetNames) : makeMdnsV4Packet(packetNames);
1606         doTestDnsParsing(expectPass, ipv6, filterName, pkt);
1607     }
1608 
1609     @Test
testDnsParsing()1610     public void testDnsParsing() throws Exception {
1611         final boolean ipv4 = false, ipv6 = true;
1612 
1613         // Packets with one question.
1614         // Names don't start with _ because DnsPacket thinks such names are invalid.
1615         doTestDnsParsing(true, ipv6, "googlecast.tcp.local", "googlecast.tcp.local");
1616         doTestDnsParsing(true, ipv4, "googlecast.tcp.local", "googlecast.tcp.local");
1617         doTestDnsParsing(false, ipv6, "googlecast.tcp.lozal", "googlecast.tcp.local");
1618         doTestDnsParsing(false, ipv4, "googlecast.tcp.lozal", "googlecast.tcp.local");
1619         doTestDnsParsing(false, ipv6, "googlecast.udp.local", "googlecast.tcp.local");
1620         doTestDnsParsing(false, ipv4, "googlecast.udp.local", "googlecast.tcp.local");
1621 
1622         // Packets with multiple questions that can't be compressed. Not realistic for MDNS since
1623         // everything ends in .local, but useful to ensure only the non-compression code is tested.
1624         doTestDnsParsing(true, ipv6, "googlecast.tcp.local",
1625                 "googlecast.tcp.local", "developer.android.com");
1626         doTestDnsParsing(true, ipv4, "googlecast.tcp.local",
1627                 "developer.android.com", "googlecast.tcp.local");
1628         doTestDnsParsing(false, ipv4, "googlecast.tcp.local",
1629                 "developer.android.com", "googlecast.tcp.invalid");
1630         doTestDnsParsing(true, ipv6, "googlecast.tcp.local",
1631                 "developer.android.com", "www.google.co.jp", "googlecast.tcp.local");
1632         doTestDnsParsing(false, ipv4, "veryverylongservicename.tcp.local",
1633                 "www.google.co.jp", "veryverylongservicename.tcp.invalid");
1634         doTestDnsParsing(true, ipv6, "googlecast.tcp.local",
1635                 "www.google.co.jp", "googlecast.tcp.local", "developer.android.com");
1636 
1637         // Name with duplicate labels.
1638         doTestDnsParsing(true, ipv6, "local.tcp.local", "local.tcp.local");
1639 
1640         final byte[] pkt = makeMdnsCompressedV6Packet();
1641         doTestDnsParsing(true, ipv6, "googlecast.tcp.local", pkt);
1642         doTestDnsParsing(true, ipv6, "matter.tcp.local", pkt);
1643         doTestDnsParsing(true, ipv6, "myservice.tcp.local", pkt);
1644         doTestDnsParsing(false, ipv6, "otherservice.tcp.local", pkt);
1645     }
1646 
doTestDnsParsingProgramLength(int expectedLength, String filterName)1647     private void doTestDnsParsingProgramLength(int expectedLength,
1648             String filterName) throws Exception {
1649         final String[] labels = filterName.split(/*regex=*/ "[.]");
1650 
1651         ApfGenerator gen = generateDnsFilter(/*ipv6=*/ true, labels);
1652         assertEquals("Program for " + filterName + " had unexpected length:",
1653                 expectedLength, gen.generate().length);
1654     }
1655 
1656     /**
1657      * Rough metric of code size. Checks how large the generated filter is in various scenarios.
1658      * Helps ensure any changes to the code do not substantially increase APF code size.
1659      */
1660     @Test
testDnsParsingProgramLength()1661     public void testDnsParsingProgramLength() throws Exception {
1662         doTestDnsParsingProgramLength(237, "MyDevice.local");
1663         doTestDnsParsingProgramLength(285, "_googlecast.tcp.local");
1664         doTestDnsParsingProgramLength(291, "_googlecast12345.tcp.local");
1665         doTestDnsParsingProgramLength(244, "_googlecastZtcp.local");
1666         doTestDnsParsingProgramLength(249, "_googlecastZtcp12345.local");
1667     }
1668 
doTestDnsParsingNecessaryOverhead(int expectedNecessaryOverhead, String filterName, byte[] pkt, String description)1669     private void doTestDnsParsingNecessaryOverhead(int expectedNecessaryOverhead,
1670             String filterName, byte[] pkt, String description) throws Exception {
1671         final String[] labels = filterName.split(/*regex=*/ "[.]");
1672 
1673         // Check that the generated code, when the program contains the specified number of extra
1674         // bytes, is capable of dropping the packet.
1675         ApfGenerator gen = generateDnsFilter(/*ipv6=*/ true, labels);
1676         for (int i = 0; i < expectedNecessaryOverhead; i++) {
1677             addOneByteNoop(gen);
1678         }
1679         final byte[] programWithJustEnoughOverhead = gen.generate();
1680         assertVerdict(
1681                 "Overhead too low: filter for " + filterName + " with " + expectedNecessaryOverhead
1682                         + " extra instructions unexpectedly passed " + description,
1683                 DROP, programWithJustEnoughOverhead, pkt, 0);
1684 
1685         if (expectedNecessaryOverhead == 0) return;
1686 
1687         // Check that the generated code, without the specified number of extra program bytes,
1688         // cannot correctly drop the packet because it hits the interpreter instruction limit.
1689         gen = generateDnsFilter(/*ipv6=*/ true, labels);
1690         for (int i = 0; i < expectedNecessaryOverhead - 1; i++) {
1691             addOneByteNoop(gen);
1692         }
1693         final byte[] programWithNotEnoughOverhead = gen.generate();
1694 
1695         assertVerdict(
1696                 "Overhead too high: filter for " + filterName + " with " + expectedNecessaryOverhead
1697                         + " extra instructions unexpectedly dropped " + description,
1698                 PASS, programWithNotEnoughOverhead, pkt, 0);
1699     }
1700 
doTestDnsParsingNecessaryOverhead(int expectedNecessaryOverhead, String filterName, String... packetNames)1701     private void doTestDnsParsingNecessaryOverhead(int expectedNecessaryOverhead,
1702             String filterName, String... packetNames) throws Exception {
1703         doTestDnsParsingNecessaryOverhead(expectedNecessaryOverhead, filterName,
1704                 makeMdnsV6Packet(packetNames),
1705                 "IPv6 MDNS packet containing: " + Arrays.toString(packetNames));
1706     }
1707 
1708     /**
1709      * Rough metric of filter efficiency. Because the filter uses backwards jumps, on complex
1710      * packets it will not finish running before the interpreter hits the maximum number of allowed
1711      * instructions (== number of bytes in the program) and unconditionally accepts the packet.
1712      * This test checks much extra code the program must contain in order for the generated filter
1713      * to successfully drop the packet. It helps ensure any changes to the code do not reduce the
1714      * complexity of packets that the APF code can drop.
1715      */
1716     @Test
testDnsParsingNecessaryOverhead()1717     public void testDnsParsingNecessaryOverhead() throws Exception {
1718         // Simple packets can be parsed with zero extra code.
1719         doTestDnsParsingNecessaryOverhead(0, "googlecast.tcp.local",
1720                 "matter.tcp.local", "developer.android.com");
1721 
1722         doTestDnsParsingNecessaryOverhead(0, "googlecast.tcp.local",
1723                 "developer.android.com", "matter.tcp.local");
1724 
1725         doTestDnsParsingNecessaryOverhead(0, "googlecast.tcp.local",
1726                 "developer.android.com", "matter.tcp.local", "www.google.co.jp");
1727 
1728         doTestDnsParsingNecessaryOverhead(0, "googlecast.tcp.local",
1729                 "developer.android.com", "matter.tcp.local", "www.google.co.jp",
1730                 "example.org");
1731 
1732         // More complicated packets cause more instructions to be run and can only be dropped if
1733         // the program contains lots of extra code.
1734         doTestDnsParsingNecessaryOverhead(57, "googlecast.tcp.local",
1735                 "developer.android.com", "matter.tcp.local", "www.google.co.jp",
1736                 "example.org", "otherexample.net");
1737 
1738         doTestDnsParsingNecessaryOverhead(115, "googlecast.tcp.local",
1739                 "developer.android.com", "matter.tcp.local", "www.google.co.jp",
1740                 "example.org", "otherexample.net", "docs.new");
1741 
1742         doTestDnsParsingNecessaryOverhead(0, "foo.tcp.local",
1743                 makeMdnsCompressedV6Packet(), "compressed packet");
1744 
1745         doTestDnsParsingNecessaryOverhead(235, "foo.tcp.local",
1746                 makeMdnsCompressedV6PacketWithManyNames(), "compressed packet with many names");
1747     }
1748 
1749     @Test
testApfFilterMulticast()1750     public void testApfFilterMulticast() throws Exception {
1751         final byte[] unicastIpv4Addr   = {(byte)192,0,2,63};
1752         final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
1753         final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
1754         final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
1755 
1756         MockIpClientCallback ipClientCallback = new MockIpClientCallback();
1757         LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
1758         LinkProperties lp = new LinkProperties();
1759         lp.addLinkAddress(link);
1760 
1761         ApfConfiguration config = getDefaultConfig();
1762         config.ieee802_3Filter = DROP_802_3_FRAMES;
1763         TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog,
1764                 mDependencies);
1765         apfFilter.setLinkProperties(lp);
1766 
1767         byte[] program = ipClientCallback.getApfProgram();
1768 
1769         // Construct IPv4 and IPv6 multicast packets.
1770         ByteBuffer mcastv4packet = makeIpv4Packet(IPPROTO_UDP);
1771         put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
1772 
1773         ByteBuffer mcastv6packet = makeIpv6Packet(IPPROTO_UDP);
1774         put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
1775 
1776         // Construct IPv4 broadcast packet.
1777         ByteBuffer bcastv4packet1 = makeIpv4Packet(IPPROTO_UDP);
1778         bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
1779         bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1780         put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
1781 
1782         ByteBuffer bcastv4packet2 = makeIpv4Packet(IPPROTO_UDP);
1783         bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS);
1784         bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1785         put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
1786 
1787         // Construct IPv4 broadcast with L2 unicast address packet (b/30231088).
1788         ByteBuffer bcastv4unicastl2packet = makeIpv4Packet(IPPROTO_UDP);
1789         bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR);
1790         bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1791         put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr);
1792 
1793         // Verify initially disabled multicast filter is off
1794         assertPass(program, mcastv4packet.array());
1795         assertPass(program, mcastv6packet.array());
1796         assertPass(program, bcastv4packet1.array());
1797         assertPass(program, bcastv4packet2.array());
1798         assertPass(program, bcastv4unicastl2packet.array());
1799 
1800         // Turn on multicast filter and verify it works
1801         ipClientCallback.resetApfProgramWait();
1802         apfFilter.setMulticastFilter(true);
1803         program = ipClientCallback.getApfProgram();
1804         assertDrop(program, mcastv4packet.array());
1805         assertDrop(program, mcastv6packet.array());
1806         assertDrop(program, bcastv4packet1.array());
1807         assertDrop(program, bcastv4packet2.array());
1808         assertDrop(program, bcastv4unicastl2packet.array());
1809 
1810         // Turn off multicast filter and verify it's off
1811         ipClientCallback.resetApfProgramWait();
1812         apfFilter.setMulticastFilter(false);
1813         program = ipClientCallback.getApfProgram();
1814         assertPass(program, mcastv4packet.array());
1815         assertPass(program, mcastv6packet.array());
1816         assertPass(program, bcastv4packet1.array());
1817         assertPass(program, bcastv4packet2.array());
1818         assertPass(program, bcastv4unicastl2packet.array());
1819 
1820         // Verify it can be initialized to on
1821         ipClientCallback.resetApfProgramWait();
1822         apfFilter.shutdown();
1823         config.multicastFilter = DROP_MULTICAST;
1824         config.ieee802_3Filter = DROP_802_3_FRAMES;
1825         apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog, mDependencies);
1826         apfFilter.setLinkProperties(lp);
1827         program = ipClientCallback.getApfProgram();
1828         assertDrop(program, mcastv4packet.array());
1829         assertDrop(program, mcastv6packet.array());
1830         assertDrop(program, bcastv4packet1.array());
1831         assertDrop(program, bcastv4unicastl2packet.array());
1832 
1833         // Verify that ICMPv6 multicast is not dropped.
1834         mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
1835         assertPass(program, mcastv6packet.array());
1836 
1837         apfFilter.shutdown();
1838     }
1839 
1840     @Test
testApfFilterMulticastPingWhileDozing()1841     public void testApfFilterMulticastPingWhileDozing() throws Exception {
1842         MockIpClientCallback ipClientCallback = new MockIpClientCallback();
1843         ApfFilter apfFilter = setupApfFilter(ipClientCallback, getDefaultConfig());
1844 
1845         // Construct a multicast ICMPv6 ECHO request.
1846         final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
1847         ByteBuffer packet = makeIpv6Packet(IPPROTO_ICMPV6);
1848         packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
1849         put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
1850 
1851         // Normally, we let multicast pings alone...
1852         assertPass(ipClientCallback.getApfProgram(), packet.array());
1853 
1854         // ...and even while dozing...
1855         apfFilter.setDozeMode(true);
1856         assertPass(ipClientCallback.getApfProgram(), packet.array());
1857 
1858         // ...but when the multicast filter is also enabled, drop the multicast pings to save power.
1859         apfFilter.setMulticastFilter(true);
1860         assertDrop(ipClientCallback.getApfProgram(), packet.array());
1861 
1862         // However, we should still let through all other ICMPv6 types.
1863         ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
1864         setIpv6VersionFields(packet);
1865         packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_ICMPV6);
1866         raPacket.put(ICMP6_TYPE_OFFSET, (byte) NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT);
1867         assertPass(ipClientCallback.getApfProgram(), raPacket.array());
1868 
1869         // Now wake up from doze mode to ensure that we no longer drop the packets.
1870         // (The multicast filter is still enabled at this point).
1871         apfFilter.setDozeMode(false);
1872         assertPass(ipClientCallback.getApfProgram(), packet.array());
1873 
1874         apfFilter.shutdown();
1875     }
1876 
1877     @Test
testApfFilter802_3()1878     public void testApfFilter802_3() throws Exception {
1879         MockIpClientCallback ipClientCallback = new MockIpClientCallback();
1880         ApfConfiguration config = getDefaultConfig();
1881         ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
1882         byte[] program = ipClientCallback.getApfProgram();
1883 
1884         // Verify empty packet of 100 zero bytes is passed
1885         // Note that eth-type = 0 makes it an IEEE802.3 frame
1886         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1887         assertPass(program, packet.array());
1888 
1889         // Verify empty packet with IPv4 is passed
1890         setIpv4VersionFields(packet);
1891         assertPass(program, packet.array());
1892 
1893         // Verify empty IPv6 packet is passed
1894         setIpv6VersionFields(packet);
1895         assertPass(program, packet.array());
1896 
1897         // Now turn on the filter
1898         ipClientCallback.resetApfProgramWait();
1899         apfFilter.shutdown();
1900         config.ieee802_3Filter = DROP_802_3_FRAMES;
1901         apfFilter = setupApfFilter(ipClientCallback, config);
1902         program = ipClientCallback.getApfProgram();
1903 
1904         // Verify that IEEE802.3 frame is dropped
1905         // In this case ethtype is used for payload length
1906         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)(100 - 14));
1907         assertDrop(program, packet.array());
1908 
1909         // Verify that IPv4 (as example of Ethernet II) frame will pass
1910         setIpv4VersionFields(packet);
1911         assertPass(program, packet.array());
1912 
1913         // Verify that IPv6 (as example of Ethernet II) frame will pass
1914         setIpv6VersionFields(packet);
1915         assertPass(program, packet.array());
1916 
1917         apfFilter.shutdown();
1918     }
1919 
1920     @Test
testApfFilterEthTypeBL()1921     public void testApfFilterEthTypeBL() throws Exception {
1922         final int[] emptyBlackList = {};
1923         final int[] ipv4BlackList = {ETH_P_IP};
1924         final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
1925 
1926         MockIpClientCallback ipClientCallback = new MockIpClientCallback();
1927         ApfConfiguration config = getDefaultConfig();
1928         ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
1929         byte[] program = ipClientCallback.getApfProgram();
1930 
1931         // Verify empty packet of 100 zero bytes is passed
1932         // Note that eth-type = 0 makes it an IEEE802.3 frame
1933         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1934         assertPass(program, packet.array());
1935 
1936         // Verify empty packet with IPv4 is passed
1937         setIpv4VersionFields(packet);
1938         assertPass(program, packet.array());
1939 
1940         // Verify empty IPv6 packet is passed
1941         setIpv6VersionFields(packet);
1942         assertPass(program, packet.array());
1943 
1944         // Now add IPv4 to the black list
1945         ipClientCallback.resetApfProgramWait();
1946         apfFilter.shutdown();
1947         config.ethTypeBlackList = ipv4BlackList;
1948         apfFilter = setupApfFilter(ipClientCallback, config);
1949         program = ipClientCallback.getApfProgram();
1950 
1951         // Verify that IPv4 frame will be dropped
1952         setIpv4VersionFields(packet);
1953         assertDrop(program, packet.array());
1954 
1955         // Verify that IPv6 frame will pass
1956         setIpv6VersionFields(packet);
1957         assertPass(program, packet.array());
1958 
1959         // Now let us have both IPv4 and IPv6 in the black list
1960         ipClientCallback.resetApfProgramWait();
1961         apfFilter.shutdown();
1962         config.ethTypeBlackList = ipv4Ipv6BlackList;
1963         apfFilter = setupApfFilter(ipClientCallback, config);
1964         program = ipClientCallback.getApfProgram();
1965 
1966         // Verify that IPv4 frame will be dropped
1967         setIpv4VersionFields(packet);
1968         assertDrop(program, packet.array());
1969 
1970         // Verify that IPv6 frame will be dropped
1971         setIpv6VersionFields(packet);
1972         assertDrop(program, packet.array());
1973 
1974         apfFilter.shutdown();
1975     }
1976 
getProgram(MockIpClientCallback cb, ApfFilter filter, LinkProperties lp)1977     private byte[] getProgram(MockIpClientCallback cb, ApfFilter filter, LinkProperties lp) {
1978         cb.resetApfProgramWait();
1979         filter.setLinkProperties(lp);
1980         return cb.getApfProgram();
1981     }
1982 
verifyArpFilter(byte[] program, int filterResult)1983     private void verifyArpFilter(byte[] program, int filterResult) {
1984         // Verify ARP request packet
1985         assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
1986         assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
1987         assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
1988 
1989         // Verify ARP reply packets from different source ip
1990         assertDrop(program, arpReply(IPV4_ANY_HOST_ADDR, IPV4_ANY_HOST_ADDR));
1991         assertPass(program, arpReply(ANOTHER_IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
1992         assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR1, IPV4_ANY_HOST_ADDR));
1993         assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR2, IPV4_ANY_HOST_ADDR));
1994 
1995         // Verify unicast ARP reply packet is always accepted.
1996         assertPass(program, arpReply(IPV4_SOURCE_ADDR, MOCK_IPV4_ADDR));
1997         assertPass(program, arpReply(IPV4_SOURCE_ADDR, ANOTHER_IPV4_ADDR));
1998         assertPass(program, arpReply(IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
1999 
2000         // Verify GARP reply packets are always filtered
2001         assertDrop(program, garpReply());
2002     }
2003 
2004     @Test
testApfFilterArp()2005     public void testApfFilterArp() throws Exception {
2006         MockIpClientCallback ipClientCallback = new MockIpClientCallback();
2007         ApfConfiguration config = getDefaultConfig();
2008         config.multicastFilter = DROP_MULTICAST;
2009         config.ieee802_3Filter = DROP_802_3_FRAMES;
2010         TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog,
2011                 mDependencies);
2012 
2013         // Verify initially ARP request filter is off, and GARP filter is on.
2014         verifyArpFilter(ipClientCallback.getApfProgram(), PASS);
2015 
2016         // Inform ApfFilter of our address and verify ARP filtering is on
2017         LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
2018         LinkProperties lp = new LinkProperties();
2019         assertTrue(lp.addLinkAddress(linkAddress));
2020         verifyArpFilter(getProgram(ipClientCallback, apfFilter, lp), DROP);
2021 
2022         // Inform ApfFilter of loss of IP and verify ARP filtering is off
2023         verifyArpFilter(getProgram(ipClientCallback, apfFilter, new LinkProperties()), PASS);
2024 
2025         apfFilter.shutdown();
2026     }
2027 
arpReply(byte[] sip, byte[] tip)2028     private static byte[] arpReply(byte[] sip, byte[] tip) {
2029         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
2030         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
2031         put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
2032         put(packet, ARP_SOURCE_IP_ADDRESS_OFFSET, sip);
2033         put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
2034         return packet.array();
2035     }
2036 
arpRequestBroadcast(byte[] tip)2037     private static byte[] arpRequestBroadcast(byte[] tip) {
2038         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
2039         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
2040         put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
2041         put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REQUEST_HEADER);
2042         put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
2043         return packet.array();
2044     }
2045 
garpReply()2046     private static byte[] garpReply() {
2047         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
2048         packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
2049         put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
2050         put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
2051         put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR);
2052         return packet.array();
2053     }
2054 
2055     private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 5};
2056     private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 6};
2057     private static final byte[] IPV4_ANOTHER_ADDR = {10, 0 , 0, 7};
2058     private static final byte[] IPV6_KEEPALIVE_SRC_ADDR =
2059             {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf1};
2060     private static final byte[] IPV6_KEEPALIVE_DST_ADDR =
2061             {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf2};
2062     private static final byte[] IPV6_ANOTHER_ADDR =
2063             {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf5};
2064 
2065     @Test
testApfFilterKeepaliveAck()2066     public void testApfFilterKeepaliveAck() throws Exception {
2067         final MockIpClientCallback cb = new MockIpClientCallback();
2068         final ApfConfiguration config = getDefaultConfig();
2069         config.multicastFilter = DROP_MULTICAST;
2070         config.ieee802_3Filter = DROP_802_3_FRAMES;
2071         final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog,
2072                 mDependencies);
2073         byte[] program;
2074         final int srcPort = 12345;
2075         final int dstPort = 54321;
2076         final int seqNum = 2123456789;
2077         final int ackNum = 1234567890;
2078         final int anotherSrcPort = 23456;
2079         final int anotherDstPort = 65432;
2080         final int anotherSeqNum = 2123456780;
2081         final int anotherAckNum = 1123456789;
2082         final int slot1 = 1;
2083         final int slot2 = 2;
2084         final int window = 14480;
2085         final int windowScale = 4;
2086 
2087         // src: 10.0.0.5, port: 12345
2088         // dst: 10.0.0.6, port: 54321
2089         InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR);
2090         InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR);
2091 
2092         final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable();
2093         parcel.srcAddress = srcAddr.getAddress();
2094         parcel.srcPort = srcPort;
2095         parcel.dstAddress = dstAddr.getAddress();
2096         parcel.dstPort = dstPort;
2097         parcel.seq = seqNum;
2098         parcel.ack = ackNum;
2099 
2100         apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
2101         program = cb.getApfProgram();
2102 
2103         // Verify IPv4 keepalive ack packet is dropped
2104         // src: 10.0.0.6, port: 54321
2105         // dst: 10.0.0.5, port: 12345
2106         assertDrop(program,
2107                 ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
2108                         dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
2109         // Verify IPv4 non-keepalive ack packet from the same source address is passed
2110         assertPass(program,
2111                 ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
2112                         dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */));
2113         assertPass(program,
2114                 ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
2115                         dstPort, srcPort, ackNum, seqNum + 1, 10 /* dataLength */));
2116         // Verify IPv4 packet from another address is passed
2117         assertPass(program,
2118                 ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
2119                         anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
2120 
2121         // Remove IPv4 keepalive filter
2122         apfFilter.removeKeepalivePacketFilter(slot1);
2123 
2124         try {
2125             // src: 2404:0:0:0:0:0:faf1, port: 12345
2126             // dst: 2404:0:0:0:0:0:faf2, port: 54321
2127             srcAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_SRC_ADDR);
2128             dstAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_DST_ADDR);
2129 
2130             final TcpKeepalivePacketDataParcelable ipv6Parcel =
2131                     new TcpKeepalivePacketDataParcelable();
2132             ipv6Parcel.srcAddress = srcAddr.getAddress();
2133             ipv6Parcel.srcPort = srcPort;
2134             ipv6Parcel.dstAddress = dstAddr.getAddress();
2135             ipv6Parcel.dstPort = dstPort;
2136             ipv6Parcel.seq = seqNum;
2137             ipv6Parcel.ack = ackNum;
2138 
2139             apfFilter.addTcpKeepalivePacketFilter(slot1, ipv6Parcel);
2140             program = cb.getApfProgram();
2141 
2142             // Verify IPv6 keepalive ack packet is dropped
2143             // src: 2404:0:0:0:0:0:faf2, port: 54321
2144             // dst: 2404:0:0:0:0:0:faf1, port: 12345
2145             assertDrop(program,
2146                     ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
2147                             dstPort, srcPort, ackNum, seqNum + 1));
2148             // Verify IPv6 non-keepalive ack packet from the same source address is passed
2149             assertPass(program,
2150                     ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
2151                             dstPort, srcPort, ackNum + 100, seqNum));
2152             // Verify IPv6 packet from another address is passed
2153             assertPass(program,
2154                     ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
2155                             anotherDstPort, anotherSeqNum, anotherAckNum));
2156 
2157             // Remove IPv6 keepalive filter
2158             apfFilter.removeKeepalivePacketFilter(slot1);
2159 
2160             // Verify multiple filters
2161             apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
2162             apfFilter.addTcpKeepalivePacketFilter(slot2, ipv6Parcel);
2163             program = cb.getApfProgram();
2164 
2165             // Verify IPv4 keepalive ack packet is dropped
2166             // src: 10.0.0.6, port: 54321
2167             // dst: 10.0.0.5, port: 12345
2168             assertDrop(program,
2169                     ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
2170                             dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
2171             // Verify IPv4 non-keepalive ack packet from the same source address is passed
2172             assertPass(program,
2173                     ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
2174                             dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */));
2175             // Verify IPv4 packet from another address is passed
2176             assertPass(program,
2177                     ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
2178                             anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
2179 
2180             // Verify IPv6 keepalive ack packet is dropped
2181             // src: 2404:0:0:0:0:0:faf2, port: 54321
2182             // dst: 2404:0:0:0:0:0:faf1, port: 12345
2183             assertDrop(program,
2184                     ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
2185                             dstPort, srcPort, ackNum, seqNum + 1));
2186             // Verify IPv6 non-keepalive ack packet from the same source address is passed
2187             assertPass(program,
2188                     ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
2189                             dstPort, srcPort, ackNum + 100, seqNum));
2190             // Verify IPv6 packet from another address is passed
2191             assertPass(program,
2192                     ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
2193                             anotherDstPort, anotherSeqNum, anotherAckNum));
2194 
2195             // Remove keepalive filters
2196             apfFilter.removeKeepalivePacketFilter(slot1);
2197             apfFilter.removeKeepalivePacketFilter(slot2);
2198         } catch (UnsupportedOperationException e) {
2199             // TODO: support V6 packets
2200         }
2201 
2202         program = cb.getApfProgram();
2203 
2204         // Verify IPv4, IPv6 packets are passed
2205         assertPass(program,
2206                 ipv4TcpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
2207                         dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
2208         assertPass(program,
2209                 ipv6TcpPacket(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
2210                         dstPort, srcPort, ackNum, seqNum + 1));
2211         assertPass(program,
2212                 ipv4TcpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, srcPort,
2213                         dstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
2214         assertPass(program,
2215                 ipv6TcpPacket(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, srcPort,
2216                         dstPort, anotherSeqNum, anotherAckNum));
2217 
2218         apfFilter.shutdown();
2219     }
2220 
ipv4TcpPacket(byte[] sip, byte[] dip, int sport, int dport, int seq, int ack, int dataLength)2221     private static byte[] ipv4TcpPacket(byte[] sip, byte[] dip, int sport,
2222             int dport, int seq, int ack, int dataLength) {
2223         final int totalLength = dataLength + IPV4_HEADER_LEN + IPV4_TCP_HEADER_LEN;
2224 
2225         ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]);
2226 
2227         // Ethertype and IPv4 header
2228         setIpv4VersionFields(packet);
2229         packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
2230         packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_TCP);
2231         put(packet, IPV4_SRC_ADDR_OFFSET, sip);
2232         put(packet, IPV4_DEST_ADDR_OFFSET, dip);
2233         packet.putShort(IPV4_TCP_SRC_PORT_OFFSET, (short) sport);
2234         packet.putShort(IPV4_TCP_DEST_PORT_OFFSET, (short) dport);
2235         packet.putInt(IPV4_TCP_SEQ_NUM_OFFSET, seq);
2236         packet.putInt(IPV4_TCP_ACK_NUM_OFFSET, ack);
2237 
2238         // TCP header length 5(20 bytes), reserved 3 bits, NS=0
2239         packet.put(IPV4_TCP_HEADER_LENGTH_OFFSET, (byte) 0x50);
2240         // TCP flags: ACK set
2241         packet.put(IPV4_TCP_HEADER_FLAG_OFFSET, (byte) 0x10);
2242         return packet.array();
2243     }
2244 
ipv6TcpPacket(byte[] sip, byte[] tip, int sport, int dport, int seq, int ack)2245     private static byte[] ipv6TcpPacket(byte[] sip, byte[] tip, int sport,
2246             int dport, int seq, int ack) {
2247         ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
2248         setIpv6VersionFields(packet);
2249         packet.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_TCP);
2250         put(packet, IPV6_SRC_ADDR_OFFSET, sip);
2251         put(packet, IPV6_DEST_ADDR_OFFSET, tip);
2252         packet.putShort(IPV6_TCP_SRC_PORT_OFFSET, (short) sport);
2253         packet.putShort(IPV6_TCP_DEST_PORT_OFFSET, (short) dport);
2254         packet.putInt(IPV6_TCP_SEQ_NUM_OFFSET, seq);
2255         packet.putInt(IPV6_TCP_ACK_NUM_OFFSET, ack);
2256         return packet.array();
2257     }
2258 
2259     @Test
testApfFilterNattKeepalivePacket()2260     public void testApfFilterNattKeepalivePacket() throws Exception {
2261         final MockIpClientCallback cb = new MockIpClientCallback();
2262         final ApfConfiguration config = getDefaultConfig();
2263         config.multicastFilter = DROP_MULTICAST;
2264         config.ieee802_3Filter = DROP_802_3_FRAMES;
2265         final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog,
2266                 mDependencies);
2267         byte[] program;
2268         final int srcPort = 1024;
2269         final int dstPort = 4500;
2270         final int slot1 = 1;
2271         // NAT-T keepalive
2272         final byte[] kaPayload = {(byte) 0xff};
2273         final byte[] nonKaPayload = {(byte) 0xfe};
2274 
2275         // src: 10.0.0.5, port: 1024
2276         // dst: 10.0.0.6, port: 4500
2277         InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR);
2278         InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR);
2279 
2280         final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable();
2281         parcel.srcAddress = srcAddr.getAddress();
2282         parcel.srcPort = srcPort;
2283         parcel.dstAddress = dstAddr.getAddress();
2284         parcel.dstPort = dstPort;
2285 
2286         apfFilter.addNattKeepalivePacketFilter(slot1, parcel);
2287         program = cb.getApfProgram();
2288 
2289         // Verify IPv4 keepalive packet is dropped
2290         // src: 10.0.0.6, port: 4500
2291         // dst: 10.0.0.5, port: 1024
2292         byte[] pkt = ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR,
2293                     IPV4_KEEPALIVE_SRC_ADDR, dstPort, srcPort, 1 /* dataLength */);
2294         System.arraycopy(kaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, kaPayload.length);
2295         assertDrop(program, pkt);
2296 
2297         // Verify a packet with payload length 1 byte but it is not 0xff will pass the filter.
2298         System.arraycopy(nonKaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, nonKaPayload.length);
2299         assertPass(program, pkt);
2300 
2301         // Verify IPv4 non-keepalive response packet from the same source address is passed
2302         assertPass(program,
2303                 ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
2304                         dstPort, srcPort, 10 /* dataLength */));
2305 
2306         // Verify IPv4 non-keepalive response packet from other source address is passed
2307         assertPass(program,
2308                 ipv4UdpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
2309                         dstPort, srcPort, 10 /* dataLength */));
2310 
2311         apfFilter.removeKeepalivePacketFilter(slot1);
2312         apfFilter.shutdown();
2313     }
2314 
ipv4UdpPacket(byte[] sip, byte[] dip, int sport, int dport, int dataLength)2315     private static byte[] ipv4UdpPacket(byte[] sip, byte[] dip, int sport,
2316             int dport, int dataLength) {
2317         final int totalLength = dataLength + IPV4_HEADER_LEN + UDP_HEADER_LEN;
2318         final int udpLength = UDP_HEADER_LEN + dataLength;
2319         ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]);
2320 
2321         // Ethertype and IPv4 header
2322         setIpv4VersionFields(packet);
2323         packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
2324         packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_UDP);
2325         put(packet, IPV4_SRC_ADDR_OFFSET, sip);
2326         put(packet, IPV4_DEST_ADDR_OFFSET, dip);
2327         packet.putShort(IPV4_UDP_SRC_PORT_OFFSET, (short) sport);
2328         packet.putShort(IPV4_UDP_DEST_PORT_OFFSET, (short) dport);
2329         packet.putShort(IPV4_UDP_LENGTH_OFFSET, (short) udpLength);
2330 
2331         return packet.array();
2332     }
2333 
addRdnssOption(ByteBuffer packet, int lifetime, String... servers)2334     private void addRdnssOption(ByteBuffer packet, int lifetime, String... servers)
2335             throws Exception {
2336         int optionLength = 1 + 2 * servers.length;   // In 8-byte units
2337         packet.put((byte) ICMP6_RDNSS_OPTION_TYPE);  // Type
2338         packet.put((byte) optionLength);             // Length
2339         packet.putShort((short) 0);                  // Reserved
2340         packet.putInt(lifetime);                     // Lifetime
2341         for (String server : servers) {
2342             packet.put(InetAddress.getByName(server).getAddress());
2343         }
2344     }
2345 
addRioOption(ByteBuffer packet, int lifetime, String prefixString)2346     private void addRioOption(ByteBuffer packet, int lifetime, String prefixString)
2347             throws Exception {
2348         IpPrefix prefix = new IpPrefix(prefixString);
2349 
2350         int optionLength;
2351         if (prefix.getPrefixLength() == 0) {
2352             optionLength = 1;
2353         } else if (prefix.getPrefixLength() <= 64) {
2354             optionLength = 2;
2355         } else {
2356             optionLength = 3;
2357         }
2358 
2359         packet.put((byte) ICMP6_ROUTE_INFO_OPTION_TYPE);  // Type
2360         packet.put((byte) optionLength);                  // Length in 8-byte units
2361         packet.put((byte) prefix.getPrefixLength());      // Prefix length
2362         packet.put((byte) 0b00011000);                    // Pref = high
2363         packet.putInt(lifetime);                          // Lifetime
2364 
2365         byte[] prefixBytes = prefix.getRawAddress();
2366         packet.put(prefixBytes, 0, (optionLength - 1) * 8);
2367     }
2368 
addPioOption(ByteBuffer packet, int valid, int preferred, String prefixString)2369     private void addPioOption(ByteBuffer packet, int valid, int preferred, String prefixString) {
2370         IpPrefix prefix = new IpPrefix(prefixString);
2371         packet.put((byte) ICMP6_PREFIX_OPTION_TYPE);  // Type
2372         packet.put((byte) 4);                         // Length in 8-byte units
2373         packet.put((byte) prefix.getPrefixLength());  // Prefix length
2374         packet.put((byte) 0b11000000);                // L = 1, A = 1
2375         packet.putInt(valid);
2376         packet.putInt(preferred);
2377         packet.putInt(0);                             // Reserved
2378         packet.put(prefix.getRawAddress());
2379     }
2380 
buildLargeRa()2381     private byte[] buildLargeRa() throws Exception {
2382         InetAddress src = InetAddress.getByName("fe80::1234:abcd");
2383 
2384         ByteBuffer packet = ByteBuffer.wrap(new byte[1514]);
2385         packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
2386         packet.position(ETH_HEADER_LEN);
2387 
2388         packet.putInt(0x60012345);                                  // Version, tclass, flowlabel
2389         packet.putShort((short) 0);                                 // Payload length; updated later
2390         packet.put((byte) IPPROTO_ICMPV6);                          // Next header
2391         packet.put((byte) 0xff);                                    // Hop limit
2392         packet.put(src.getAddress());                               // Source address
2393         packet.put(IPV6_ALL_NODES_ADDRESS);                         // Destination address
2394 
2395         packet.put((byte) ICMP6_ROUTER_ADVERTISEMENT);              // Type
2396         packet.put((byte) 0);                                       // Code (0)
2397         packet.putShort((short) 0);                                 // Checksum (ignored)
2398         packet.put((byte) 64);                                      // Hop limit
2399         packet.put((byte) 0);                                       // M/O, reserved
2400         packet.putShort((short) 1800);                              // Router lifetime
2401         packet.putInt(30_000);                                      // Reachable time
2402         packet.putInt(1000);                                        // Retrans timer
2403 
2404         addRioOption(packet, 1200, "64:ff9b::/96");
2405         addRdnssOption(packet, 7200, "2001:db8:1::1", "2001:db8:1::2");
2406         addRioOption(packet, 2100, "2000::/3");
2407         addRioOption(packet, 2400, "::/0");
2408         addPioOption(packet, 600, 300, "2001:db8:a::/64");
2409         addRioOption(packet, 1500, "2001:db8:c:d::/64");
2410         addPioOption(packet, 86400, 43200, "fd95:d1e:12::/64");
2411 
2412         int length = packet.position();
2413         packet.putShort(IPV6_PAYLOAD_LENGTH_OFFSET, (short) length);
2414 
2415         // Don't pass the Ra constructor a packet that is longer than the actual RA.
2416         // This relies on the fact that all the relative writes to the byte buffer are at the end.
2417         byte[] packetArray = new byte[length];
2418         packet.rewind();
2419         packet.get(packetArray);
2420         return packetArray;
2421     }
2422 
2423     @Test
testRaToString()2424     public void testRaToString() throws Exception {
2425         MockIpClientCallback cb = new MockIpClientCallback();
2426         ApfConfiguration config = getDefaultConfig();
2427         TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog, mDependencies);
2428 
2429         byte[] packet = buildLargeRa();
2430         ApfFilter.Ra ra = apfFilter.new Ra(packet, packet.length);
2431         String expected = "RA fe80::1234:abcd -> ff02::1 1800s "
2432                 + "2001:db8:a::/64 600s/300s fd95:d1e:12::/64 86400s/43200s "
2433                 + "DNS 7200s 2001:db8:1::1 2001:db8:1::2 "
2434                 + "RIO 1200s 64:ff9b::/96 RIO 2100s 2000::/3 "
2435                 + "RIO 2400s ::/0 RIO 1500s 2001:db8:c:d::/64 ";
2436         assertEquals(expected, ra.toString());
2437     }
2438 
2439     // Verify that the last program pushed to the IpClient.Callback properly filters the
2440     // given packet for the given lifetime.
verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime)2441     private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
2442         verifyRaLifetime(program, packet, lifetime, 0);
2443     }
2444 
2445     // Verify that the last program pushed to the IpClient.Callback properly filters the
2446     // given packet for the given lifetime and programInstallTime. programInstallTime is
2447     // the time difference between when RA is last seen and the program is installed.
verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime, int programInstallTime)2448     private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime,
2449             int programInstallTime) {
2450         final int FRACTION_OF_LIFETIME = 6;
2451         final int ageLimit = lifetime / FRACTION_OF_LIFETIME - programInstallTime;
2452 
2453         // Verify new program should drop RA for 1/6th its lifetime and pass afterwards.
2454         assertDrop(program, packet.array());
2455         assertDrop(program, packet.array(), ageLimit);
2456         assertPass(program, packet.array(), ageLimit + 1);
2457         assertPass(program, packet.array(), lifetime);
2458         // Verify RA checksum is ignored
2459         final short originalChecksum = packet.getShort(ICMP6_RA_CHECKSUM_OFFSET);
2460         packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
2461         assertDrop(program, packet.array());
2462         packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
2463         assertDrop(program, packet.array());
2464         packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum);
2465 
2466         // Verify other changes to RA (e.g., a change in the source address) make it not match.
2467         final int offset = IPV6_SRC_ADDR_OFFSET + 5;
2468         final byte originalByte = packet.get(offset);
2469         packet.put(offset, (byte) (~originalByte));
2470         assertPass(program, packet.array());
2471         packet.put(offset, originalByte);
2472         assertDrop(program, packet.array());
2473     }
2474 
2475     // Test that when ApfFilter is shown the given packet, it generates a program to filter it
2476     // for the given lifetime.
verifyRaLifetime(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback, ByteBuffer packet, int lifetime)2477     private void verifyRaLifetime(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
2478             ByteBuffer packet, int lifetime) throws IOException, ErrnoException {
2479         // Verify new program generated if ApfFilter witnesses RA
2480         ipClientCallback.resetApfProgramWait();
2481         apfFilter.pretendPacketReceived(packet.array());
2482         byte[] program = ipClientCallback.getApfProgram();
2483         verifyRaLifetime(program, packet, lifetime);
2484     }
2485 
verifyRaEvent(RaEvent expected)2486     private void verifyRaEvent(RaEvent expected) {
2487         ArgumentCaptor<IpConnectivityLog.Event> captor =
2488                 ArgumentCaptor.forClass(IpConnectivityLog.Event.class);
2489         verify(mLog, atLeastOnce()).log(captor.capture());
2490         RaEvent got = lastRaEvent(captor.getAllValues());
2491         if (!raEventEquals(expected, got)) {
2492             assertEquals(expected, got);  // fail for printing an assertion error message.
2493         }
2494     }
2495 
lastRaEvent(List<IpConnectivityLog.Event> events)2496     private RaEvent lastRaEvent(List<IpConnectivityLog.Event> events) {
2497         RaEvent got = null;
2498         for (Parcelable ev : events) {
2499             if (ev instanceof RaEvent) {
2500                 got = (RaEvent) ev;
2501             }
2502         }
2503         return got;
2504     }
2505 
raEventEquals(RaEvent ev1, RaEvent ev2)2506     private boolean raEventEquals(RaEvent ev1, RaEvent ev2) {
2507         return (ev1 != null) && (ev2 != null)
2508                 && (ev1.routerLifetime == ev2.routerLifetime)
2509                 && (ev1.prefixValidLifetime == ev2.prefixValidLifetime)
2510                 && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime)
2511                 && (ev1.routeInfoLifetime == ev2.routeInfoLifetime)
2512                 && (ev1.rdnssLifetime == ev2.rdnssLifetime)
2513                 && (ev1.dnsslLifetime == ev2.dnsslLifetime);
2514     }
2515 
assertInvalidRa(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback, ByteBuffer packet)2516     private void assertInvalidRa(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
2517             ByteBuffer packet) throws IOException, ErrnoException {
2518         ipClientCallback.resetApfProgramWait();
2519         apfFilter.pretendPacketReceived(packet.array());
2520         ipClientCallback.assertNoProgramUpdate();
2521     }
2522 
makeBaseRaPacket()2523     private ByteBuffer makeBaseRaPacket() {
2524         ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
2525         final int ROUTER_LIFETIME = 1000;
2526         final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN;
2527         // IPv6, traffic class = 0, flow label = 0x12345
2528         final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;
2529 
2530         basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
2531         basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
2532                 VERSION_TRAFFIC_CLASS_FLOW_LABEL);
2533         basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte) IPPROTO_ICMPV6);
2534         basePacket.put(ICMP6_TYPE_OFFSET, (byte) ICMP6_ROUTER_ADVERTISEMENT);
2535         basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short) ROUTER_LIFETIME);
2536         basePacket.position(IPV6_DEST_ADDR_OFFSET);
2537         basePacket.put(IPV6_ALL_NODES_ADDRESS);
2538 
2539         return basePacket;
2540     }
2541 
2542     @Test
testApfFilterRa()2543     public void testApfFilterRa() throws Exception {
2544         MockIpClientCallback ipClientCallback = new MockIpClientCallback();
2545         ApfConfiguration config = getDefaultConfig();
2546         config.multicastFilter = DROP_MULTICAST;
2547         config.ieee802_3Filter = DROP_802_3_FRAMES;
2548         TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog,
2549                 mDependencies);
2550         byte[] program = ipClientCallback.getApfProgram();
2551 
2552         final int ROUTER_LIFETIME = 1000;
2553         final int PREFIX_VALID_LIFETIME = 200;
2554         final int PREFIX_PREFERRED_LIFETIME = 100;
2555         final int RDNSS_LIFETIME  = 300;
2556         final int ROUTE_LIFETIME  = 400;
2557         // Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000.
2558         final int DNSSL_LIFETIME  = 2000;
2559         final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN;
2560         // IPv6, traffic class = 0, flow label = 0x12345
2561         final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;
2562 
2563         // Verify RA is passed the first time
2564         ByteBuffer basePacket = makeBaseRaPacket();
2565         assertPass(program, basePacket.array());
2566 
2567         verifyRaLifetime(apfFilter, ipClientCallback, basePacket, ROUTER_LIFETIME);
2568         verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
2569 
2570         ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
2571         basePacket.clear();
2572         newFlowLabelPacket.put(basePacket);
2573         // Check that changes are ignored in every byte of the flow label.
2574         newFlowLabelPacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
2575                 VERSION_TRAFFIC_CLASS_FLOW_LABEL + 0x11111);
2576 
2577         // Ensure zero-length options cause the packet to be silently skipped.
2578         // Do this before we test other packets. http://b/29586253
2579         ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(
2580                 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
2581         basePacket.clear();
2582         zeroLengthOptionPacket.put(basePacket);
2583         zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
2584         zeroLengthOptionPacket.put((byte)0);
2585         assertInvalidRa(apfFilter, ipClientCallback, zeroLengthOptionPacket);
2586 
2587         // Generate several RAs with different options and lifetimes, and verify when
2588         // ApfFilter is shown these packets, it generates programs to filter them for the
2589         // appropriate lifetime.
2590         ByteBuffer prefixOptionPacket = ByteBuffer.wrap(
2591                 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]);
2592         basePacket.clear();
2593         prefixOptionPacket.put(basePacket);
2594         addPioOption(prefixOptionPacket, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME,
2595                 "2001:db8::/64");
2596         verifyRaLifetime(
2597                 apfFilter, ipClientCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
2598         verifyRaEvent(new RaEvent(
2599                 ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1));
2600 
2601         ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
2602                 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + 2 * IPV6_ADDR_LEN]);
2603         basePacket.clear();
2604         rdnssOptionPacket.put(basePacket);
2605         addRdnssOption(rdnssOptionPacket, RDNSS_LIFETIME,
2606                 "2001:4860:4860::8888", "2001:4860:4860::8844");
2607         verifyRaLifetime(apfFilter, ipClientCallback, rdnssOptionPacket, RDNSS_LIFETIME);
2608         verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
2609 
2610         final int lowLifetime = 60;
2611         ByteBuffer lowLifetimeRdnssOptionPacket = ByteBuffer.wrap(
2612                 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]);
2613         basePacket.clear();
2614         lowLifetimeRdnssOptionPacket.put(basePacket);
2615         addRdnssOption(lowLifetimeRdnssOptionPacket, lowLifetime, "2620:fe::9");
2616         verifyRaLifetime(apfFilter, ipClientCallback, lowLifetimeRdnssOptionPacket,
2617                 ROUTER_LIFETIME);
2618         verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, lowLifetime, -1));
2619 
2620         ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
2621                 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]);
2622         basePacket.clear();
2623         routeInfoOptionPacket.put(basePacket);
2624         addRioOption(routeInfoOptionPacket, ROUTE_LIFETIME, "64:ff9b::/96");
2625         verifyRaLifetime(apfFilter, ipClientCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
2626         verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
2627 
2628         // Check that RIOs differing only in the first 4 bytes are different.
2629         ByteBuffer similarRouteInfoOptionPacket = ByteBuffer.wrap(
2630                 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]);
2631         basePacket.clear();
2632         similarRouteInfoOptionPacket.put(basePacket);
2633         addRioOption(similarRouteInfoOptionPacket, ROUTE_LIFETIME, "64:ff9b::/64");
2634         // Packet should be passed because it is different.
2635         program = ipClientCallback.getApfProgram();
2636         assertPass(program, similarRouteInfoOptionPacket.array());
2637 
2638         ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
2639                 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
2640         basePacket.clear();
2641         dnsslOptionPacket.put(basePacket);
2642         dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
2643         dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
2644         dnsslOptionPacket.putInt(
2645                 ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME);
2646         verifyRaLifetime(apfFilter, ipClientCallback, dnsslOptionPacket, ROUTER_LIFETIME);
2647         verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME));
2648 
2649         ByteBuffer largeRaPacket = ByteBuffer.wrap(buildLargeRa());
2650         verifyRaLifetime(apfFilter, ipClientCallback, largeRaPacket, 300);
2651         verifyRaEvent(new RaEvent(1800, 600, 300, 1200, 7200, -1));
2652 
2653         // Verify that current program filters all the RAs (note: ApfFilter.MAX_RAS == 10).
2654         program = ipClientCallback.getApfProgram();
2655         verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
2656         verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME);
2657         verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
2658         verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
2659         verifyRaLifetime(program, lowLifetimeRdnssOptionPacket, ROUTER_LIFETIME);
2660         verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
2661         verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME);
2662         verifyRaLifetime(program, largeRaPacket, 300);
2663 
2664         apfFilter.shutdown();
2665     }
2666 
2667     @Test
testRaWithDifferentReachableTimeAndRetransTimer()2668     public void testRaWithDifferentReachableTimeAndRetransTimer() throws Exception {
2669         final MockIpClientCallback ipClientCallback = new MockIpClientCallback();
2670         final ApfConfiguration config = getDefaultConfig();
2671         config.multicastFilter = DROP_MULTICAST;
2672         config.ieee802_3Filter = DROP_802_3_FRAMES;
2673         final TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog,
2674                 mDependencies);
2675         byte[] program = ipClientCallback.getApfProgram();
2676         final int RA_REACHABLE_TIME = 1800;
2677         final int RA_RETRANSMISSION_TIMER = 1234;
2678 
2679         // Create an Ra packet without options
2680         // Reachable time = 1800, retransmission timer = 1234
2681         ByteBuffer raPacket = makeBaseRaPacket();
2682         raPacket.position(ICMP6_RA_REACHABLE_TIME_OFFSET);
2683         raPacket.putInt(RA_REACHABLE_TIME);
2684         raPacket.putInt(RA_RETRANSMISSION_TIMER);
2685         // First RA passes filter
2686         assertPass(program, raPacket.array());
2687 
2688         // Assume apf is shown the given RA, it generates program to filter it.
2689         ipClientCallback.resetApfProgramWait();
2690         apfFilter.pretendPacketReceived(raPacket.array());
2691         program = ipClientCallback.getApfProgram();
2692         assertDrop(program, raPacket.array());
2693 
2694         // A packet with different reachable time should be passed.
2695         // Reachable time = 2300, retransmission timer = 1234
2696         raPacket.clear();
2697         raPacket.putInt(ICMP6_RA_REACHABLE_TIME_OFFSET, RA_REACHABLE_TIME + 500);
2698         assertPass(program, raPacket.array());
2699 
2700         // A packet with different retransmission timer should be passed.
2701         // Reachable time = 1800, retransmission timer = 2234
2702         raPacket.clear();
2703         raPacket.putInt(ICMP6_RA_REACHABLE_TIME_OFFSET, RA_REACHABLE_TIME);
2704         raPacket.putInt(ICMP6_RA_RETRANSMISSION_TIMER_OFFSET, RA_RETRANSMISSION_TIMER + 1000);
2705         assertPass(program, raPacket.array());
2706     }
2707 
2708     // The ByteBuffer is always created by ByteBuffer#wrap in the helper functions
2709     @SuppressWarnings("ByteBufferBackingArray")
2710     @Test
testRaWithProgramInstalledSomeTimeAfterLastSeen()2711     public void testRaWithProgramInstalledSomeTimeAfterLastSeen() throws Exception {
2712         final MockIpClientCallback ipClientCallback = new MockIpClientCallback();
2713         final ApfConfiguration config = getDefaultConfig();
2714         config.multicastFilter = DROP_MULTICAST;
2715         config.ieee802_3Filter = DROP_802_3_FRAMES;
2716         final TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog,
2717                 mDependencies);
2718         byte[] program = ipClientCallback.getApfProgram();
2719 
2720         final int routerLifetime = 1000;
2721         final int timePassedSeconds = 12;
2722 
2723         // Verify that when the program is generated and installed some time after RA is last seen
2724         // it should be installed with the correct remaining lifetime.
2725         ByteBuffer basePacket = makeBaseRaPacket();
2726         verifyRaLifetime(apfFilter, ipClientCallback, basePacket, routerLifetime);
2727         apfFilter.increaseCurrentTimeSeconds(timePassedSeconds);
2728         synchronized (apfFilter) {
2729             apfFilter.installNewProgramLocked();
2730         }
2731         program = ipClientCallback.getApfProgram();
2732         verifyRaLifetime(program, basePacket, routerLifetime, timePassedSeconds);
2733 
2734         // Packet should be passed if the program is installed after 1/6 * lifetime from last seen
2735         apfFilter.increaseCurrentTimeSeconds((int) (routerLifetime / 6) - timePassedSeconds - 1);
2736         synchronized (apfFilter) {
2737             apfFilter.installNewProgramLocked();
2738         }
2739         program = ipClientCallback.getApfProgram();
2740         assertDrop(program, basePacket.array());
2741         apfFilter.increaseCurrentTimeSeconds(1);
2742         synchronized (apfFilter) {
2743             apfFilter.installNewProgramLocked();
2744         }
2745         program = ipClientCallback.getApfProgram();
2746         assertPass(program, basePacket.array());
2747 
2748         apfFilter.shutdown();
2749     }
2750 
2751     // The ByteBuffer is always created by ByteBuffer#wrap in the helper functions
2752     @SuppressWarnings("ByteBufferBackingArray")
2753     @Test
testRaWithoutLifetimeCalculationFix()2754     public void testRaWithoutLifetimeCalculationFix() throws Exception {
2755         final MockIpClientCallback ipClientCallback = new MockIpClientCallback();
2756         final ApfConfiguration config = getDefaultConfig();
2757         config.multicastFilter = DROP_MULTICAST;
2758         config.ieee802_3Filter = DROP_802_3_FRAMES;
2759         // Disable the RA lifetime calculation fix in aosp/2276160
2760         when(mDependencies.isFeatureEnabled(eq(mContext),
2761                 eq(APF_USE_RA_LIFETIME_CALCULATION_FIX_VERSION), anyBoolean())).thenReturn(false);
2762         final TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog,
2763                 mDependencies);
2764         byte[] program = ipClientCallback.getApfProgram();
2765 
2766         final int routerLifetime = 1000;
2767         final int timePassedSeconds = 12;
2768 
2769         // Verify that when the program is generated and installed without the RA lifetime
2770         // calculation fix, it should be installed with the old buggy behavior.
2771         ByteBuffer basePacket = makeBaseRaPacket();
2772         verifyRaLifetime(apfFilter, ipClientCallback, basePacket, routerLifetime);
2773         apfFilter.increaseCurrentTimeSeconds(timePassedSeconds);
2774         synchronized (apfFilter) {
2775             apfFilter.installNewProgramLocked();
2776         }
2777         program = ipClientCallback.getApfProgram();
2778         final int ageLimit = (routerLifetime - timePassedSeconds) / 6;
2779         assertDrop(program, basePacket.array());
2780         assertDrop(program, basePacket.array(), ageLimit);
2781         assertPass(program, basePacket.array(), ageLimit + 1);
2782         assertPass(program, basePacket.array(), routerLifetime);
2783 
2784         apfFilter.shutdown();
2785     }
2786 
2787     /**
2788      * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
2789      * copy that resource into the app's data directory and return the path to it.
2790      */
stageFile(int rawId)2791     private String stageFile(int rawId) throws Exception {
2792         File file = new File(InstrumentationRegistry.getContext().getFilesDir(), "staged_file");
2793         new File(file.getParent()).mkdirs();
2794         InputStream in = null;
2795         OutputStream out = null;
2796         try {
2797             in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
2798             out = new FileOutputStream(file);
2799             Streams.copy(in, out);
2800         } finally {
2801             if (in != null) in.close();
2802             if (out != null) out.close();
2803         }
2804         return file.getAbsolutePath();
2805     }
2806 
put(ByteBuffer buffer, int position, byte[] bytes)2807     private static void put(ByteBuffer buffer, int position, byte[] bytes) {
2808         final int original = buffer.position();
2809         buffer.position(position);
2810         buffer.put(bytes);
2811         buffer.position(original);
2812     }
2813 
2814     @Test
testRaParsing()2815     public void testRaParsing() throws Exception {
2816         final int maxRandomPacketSize = 512;
2817         final Random r = new Random();
2818         MockIpClientCallback cb = new MockIpClientCallback();
2819         ApfConfiguration config = getDefaultConfig();
2820         config.multicastFilter = DROP_MULTICAST;
2821         config.ieee802_3Filter = DROP_802_3_FRAMES;
2822         TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog, mDependencies);
2823         for (int i = 0; i < 1000; i++) {
2824             byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
2825             r.nextBytes(packet);
2826             try {
2827                 apfFilter.new Ra(packet, packet.length);
2828             } catch (ApfFilter.InvalidRaException e) {
2829             } catch (Exception e) {
2830                 throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
2831             }
2832         }
2833     }
2834 
2835     @Test
testRaProcessing()2836     public void testRaProcessing() throws Exception {
2837         final int maxRandomPacketSize = 512;
2838         final Random r = new Random();
2839         MockIpClientCallback cb = new MockIpClientCallback();
2840         ApfConfiguration config = getDefaultConfig();
2841         config.multicastFilter = DROP_MULTICAST;
2842         config.ieee802_3Filter = DROP_802_3_FRAMES;
2843         TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog, mDependencies);
2844         for (int i = 0; i < 1000; i++) {
2845             byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
2846             r.nextBytes(packet);
2847             try {
2848                 apfFilter.processRa(packet, packet.length);
2849             } catch (Exception e) {
2850                 throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
2851             }
2852         }
2853     }
2854 
2855     /**
2856      * Call the APF interpreter to run {@code program} on {@code packet} with persistent memory
2857      * segment {@data} pretending the filter was installed {@code filter_age} seconds ago.
2858      */
apfSimulate(byte[] program, byte[] packet, byte[] data, int filter_age)2859     private native static int apfSimulate(byte[] program, byte[] packet, byte[] data,
2860         int filter_age);
2861 
2862     /**
2863      * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF
2864      * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d".
2865      */
compileToBpf(String filter)2866     private native static String compileToBpf(String filter);
2867 
2868     /**
2869      * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump
2870      * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and
2871      * at the same time using APF program {@code apf_program}.  Return {@code true} if
2872      * both APF and BPF programs filter out exactly the same packets.
2873      */
compareBpfApf(String filter, String pcap_filename, byte[] apf_program)2874     private native static boolean compareBpfApf(String filter, String pcap_filename,
2875             byte[] apf_program);
2876 
2877 
2878     /**
2879      * Open packet capture file {@code pcapFilename} and run it through APF filter. Then
2880      * checks whether all the packets are dropped and populates data[] {@code data} with
2881      * the APF counters.
2882      */
dropsAllPackets(byte[] program, byte[] data, String pcapFilename)2883     private native static boolean dropsAllPackets(byte[] program, byte[] data, String pcapFilename);
2884 
2885     @Test
testBroadcastAddress()2886     public void testBroadcastAddress() throws Exception {
2887         assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
2888         assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
2889         assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22));
2890         assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8));
2891 
2892         assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0));
2893         assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32));
2894         assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24));
2895         assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16));
2896     }
2897 
assertEqualsIp(String expected, int got)2898     public void assertEqualsIp(String expected, int got) throws Exception {
2899         int want = Inet4AddressUtils.inet4AddressToIntHTH(
2900                 (Inet4Address) InetAddresses.parseNumericAddress(expected));
2901         assertEquals(want, got);
2902     }
2903 }
2904