blob: 8f2b9680786016d2424826dbd394a9adbed5170e [file] [log] [blame]
Paul Jensen9132f342016-04-13 15:00:26 -04001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net.apf;
18
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +090019import static android.system.OsConstants.AF_UNIX;
20import static android.system.OsConstants.ARPHRD_ETHER;
21import static android.system.OsConstants.ETH_P_ARP;
22import static android.system.OsConstants.ETH_P_IP;
23import static android.system.OsConstants.ETH_P_IPV6;
24import static android.system.OsConstants.IPPROTO_ICMPV6;
Xiao Mad36a89c2019-02-10 14:52:37 +090025import static android.system.OsConstants.IPPROTO_TCP;
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +090026import static android.system.OsConstants.IPPROTO_UDP;
27import static android.system.OsConstants.SOCK_STREAM;
28
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090029import static com.android.internal.util.BitUtils.bytesToBEInt;
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090030import static com.android.server.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +090031
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090032import static org.junit.Assert.assertEquals;
33import static org.junit.Assert.assertFalse;
34import static org.junit.Assert.assertTrue;
35import static org.junit.Assert.fail;
36import static org.mockito.Mockito.atLeastOnce;
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090037import static org.mockito.Mockito.mock;
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090038import static org.mockito.Mockito.verify;
39
Bernie Innocentie2c70f82018-03-28 20:11:49 +090040import android.content.Context;
Hugo Benichi7d21eae2016-09-02 14:00:29 +090041import android.net.LinkAddress;
42import android.net.LinkProperties;
Aaron Huang56f9e412019-05-13 05:13:09 -070043import android.net.NattKeepalivePacketDataParcelable;
Xiao Ma6b4de8f2019-02-15 19:18:21 +090044import android.net.TcpKeepalivePacketDataParcelable;
Hugo Benichi72166362017-10-13 16:32:20 +090045import android.net.apf.ApfFilter.ApfConfiguration;
Paul Jensen9132f342016-04-13 15:00:26 -040046import android.net.apf.ApfGenerator.IllegalInstructionException;
47import android.net.apf.ApfGenerator.Register;
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090048import android.net.ip.IIpClientCallbacks;
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090049import android.net.ip.IpClient.IpClientCallbacksWrapper;
Hugo Benichi6ccd51a2016-07-04 09:22:30 +090050import android.net.metrics.IpConnectivityLog;
51import android.net.metrics.RaEvent;
Erik Kline8bd00d52017-12-08 17:47:50 +090052import android.net.util.InterfaceParams;
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090053import android.net.util.SharedLog;
Paul Jensen9132f342016-04-13 15:00:26 -040054import android.os.ConditionVariable;
Hugo Benichi6ccd51a2016-07-04 09:22:30 +090055import android.os.Parcelable;
Hugo Benichi4456f332016-12-19 14:50:52 +090056import android.os.SystemClock;
Paul Jensen9132f342016-04-13 15:00:26 -040057import android.system.ErrnoException;
58import android.system.Os;
Hugo Benichi4456f332016-12-19 14:50:52 +090059import android.text.format.DateUtils;
Aaron Huang785e5f12018-10-31 15:57:48 +080060import android.util.Log;
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +090061
Brett Chabot8091d9e2019-02-26 14:52:33 -080062import androidx.test.InstrumentationRegistry;
63import androidx.test.filters.SmallTest;
64import androidx.test.runner.AndroidJUnit4;
65
Hugo Benichi0668a612016-10-06 15:19:36 +090066import com.android.internal.util.HexDump;
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090067import com.android.server.networkstack.tests.R;
68import com.android.server.util.NetworkStackConstants;
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +090069
70import libcore.io.IoUtils;
71import libcore.io.Streams;
72
73import org.junit.Before;
74import org.junit.Test;
75import org.junit.runner.RunWith;
76import org.mockito.ArgumentCaptor;
77import org.mockito.Mock;
78import org.mockito.MockitoAnnotations;
79
Paul Jensen9132f342016-04-13 15:00:26 -040080import java.io.File;
81import java.io.FileDescriptor;
82import java.io.FileOutputStream;
83import java.io.IOException;
84import java.io.InputStream;
85import java.io.OutputStream;
86import java.net.InetAddress;
Paul Jensen9132f342016-04-13 15:00:26 -040087import java.nio.ByteBuffer;
Hugo Benichi6ccd51a2016-07-04 09:22:30 +090088import java.util.List;
Hugo Benichi0668a612016-10-06 15:19:36 +090089import java.util.Random;
Paul Jensen9132f342016-04-13 15:00:26 -040090
91/**
92 * Tests for APF program generator and interpreter.
93 *
94 * Build, install and run with:
Hugo Benichi495a17b2017-01-12 15:31:05 +090095 * runtest frameworks-net -c android.net.apf.ApfTest
Paul Jensen9132f342016-04-13 15:00:26 -040096 */
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090097@RunWith(AndroidJUnit4.class)
98@SmallTest
99public class ApfTest {
Paul Jensen9132f342016-04-13 15:00:26 -0400100 private static final int TIMEOUT_MS = 500;
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900101 private static final int MIN_APF_VERSION = 2;
Paul Jensen9132f342016-04-13 15:00:26 -0400102
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900103 @Mock IpConnectivityLog mLog;
Bernie Innocentie2c70f82018-03-28 20:11:49 +0900104 @Mock Context mContext;
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900105
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900106 @Before
Paul Jensen9132f342016-04-13 15:00:26 -0400107 public void setUp() throws Exception {
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900108 MockitoAnnotations.initMocks(this);
Paul Jensen9132f342016-04-13 15:00:26 -0400109 // Load up native shared library containing APF interpreter exposed via JNI.
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900110 System.loadLibrary("networkstacktestsjni");
Paul Jensen9132f342016-04-13 15:00:26 -0400111 }
112
Aaron Huang785e5f12018-10-31 15:57:48 +0800113 private static final String TAG = "ApfTest";
Paul Jensen9132f342016-04-13 15:00:26 -0400114 // Expected return codes from APF interpreter.
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900115 private static final int PASS = 1;
116 private static final int DROP = 0;
Paul Jensen9132f342016-04-13 15:00:26 -0400117 // Interpreter will just accept packets without link layer headers, so pad fake packet to at
118 // least the minimum packet size.
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900119 private static final int MIN_PKT_SIZE = 15;
Paul Jensen9132f342016-04-13 15:00:26 -0400120
Hugo Benichi72166362017-10-13 16:32:20 +0900121 private static final ApfCapabilities MOCK_APF_CAPABILITIES =
122 new ApfCapabilities(2, 1700, ARPHRD_ETHER);
123
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900124 private static final boolean DROP_MULTICAST = true;
125 private static final boolean ALLOW_MULTICAST = false;
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900126
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900127 private static final boolean DROP_802_3_FRAMES = true;
128 private static final boolean ALLOW_802_3_FRAMES = false;
129
130 // Constants for opcode encoding
131 private static final byte LI_OP = (byte)(13 << 3);
132 private static final byte LDDW_OP = (byte)(22 << 3);
133 private static final byte STDW_OP = (byte)(23 << 3);
134 private static final byte SIZE0 = (byte)(0 << 1);
135 private static final byte SIZE8 = (byte)(1 << 1);
136 private static final byte SIZE16 = (byte)(2 << 1);
137 private static final byte SIZE32 = (byte)(3 << 1);
138 private static final byte R1 = 1;
Ahmed ElArabawy8537c582017-06-12 18:01:11 -0700139
Hugo Benichi72166362017-10-13 16:32:20 +0900140 private static ApfConfiguration getDefaultConfig() {
141 ApfFilter.ApfConfiguration config = new ApfConfiguration();
142 config.apfCapabilities = MOCK_APF_CAPABILITIES;
143 config.multicastFilter = ALLOW_MULTICAST;
144 config.ieee802_3Filter = ALLOW_802_3_FRAMES;
145 config.ethTypeBlackList = new int[0];
146 return config;
147 }
148
Hugo Benichi961ca492016-09-02 11:04:34 +0900149 private static String label(int code) {
150 switch (code) {
151 case PASS: return "PASS";
152 case DROP: return "DROP";
153 default: return "UNKNOWN";
154 }
155 }
156
157 private static void assertReturnCodesEqual(int expected, int got) {
158 assertEquals(label(expected), label(got));
159 }
160
Paul Jensen9132f342016-04-13 15:00:26 -0400161 private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
Bernie Innocentia9949e92018-03-22 23:07:47 +0900162 assertReturnCodesEqual(expected, apfSimulate(program, packet, null, filterAge));
Hugo Benichi961ca492016-09-02 11:04:34 +0900163 }
164
165 private void assertVerdict(int expected, byte[] program, byte[] packet) {
Bernie Innocentia9949e92018-03-22 23:07:47 +0900166 assertReturnCodesEqual(expected, apfSimulate(program, packet, null, 0));
Paul Jensen9132f342016-04-13 15:00:26 -0400167 }
168
169 private void assertPass(byte[] program, byte[] packet, int filterAge) {
170 assertVerdict(PASS, program, packet, filterAge);
171 }
172
Hugo Benichi961ca492016-09-02 11:04:34 +0900173 private void assertPass(byte[] program, byte[] packet) {
174 assertVerdict(PASS, program, packet);
175 }
176
Paul Jensen9132f342016-04-13 15:00:26 -0400177 private void assertDrop(byte[] program, byte[] packet, int filterAge) {
178 assertVerdict(DROP, program, packet, filterAge);
179 }
180
Hugo Benichi961ca492016-09-02 11:04:34 +0900181 private void assertDrop(byte[] program, byte[] packet) {
182 assertVerdict(DROP, program, packet);
183 }
184
Bernie Innocenti18050002018-04-19 20:53:00 +0900185 private void assertProgramEquals(byte[] expected, byte[] program) throws AssertionError {
186 // assertArrayEquals() would only print one byte, making debugging difficult.
187 if (!java.util.Arrays.equals(expected, program)) {
188 throw new AssertionError(
189 "\nexpected: " + HexDump.toHexString(expected) +
190 "\nactual: " + HexDump.toHexString(program));
191 }
192 }
193
194 private void assertDataMemoryContents(
195 int expected, byte[] program, byte[] packet, byte[] data, byte[] expected_data)
196 throws IllegalInstructionException, Exception {
Bernie Innocentia9949e92018-03-22 23:07:47 +0900197 assertReturnCodesEqual(expected, apfSimulate(program, packet, data, 0 /* filterAge */));
198
199 // assertArrayEquals() would only print one byte, making debugging difficult.
200 if (!java.util.Arrays.equals(expected_data, data)) {
201 throw new Exception(
Bernie Innocenti18050002018-04-19 20:53:00 +0900202 "\nprogram: " + HexDump.toHexString(program) +
Bernie Innocentia9949e92018-03-22 23:07:47 +0900203 "\ndata memory: " + HexDump.toHexString(data) +
Bernie Innocenti545d9362018-04-16 23:27:51 +0900204 "\nexpected: " + HexDump.toHexString(expected_data));
Bernie Innocentia9949e92018-03-22 23:07:47 +0900205 }
206 }
207
Paul Jensen9132f342016-04-13 15:00:26 -0400208 private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
209 throws IllegalInstructionException {
Bernie Innocentia9949e92018-03-22 23:07:47 +0900210 assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, null,
211 filterAge));
Paul Jensen9132f342016-04-13 15:00:26 -0400212 }
213
214 private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
215 throws IllegalInstructionException {
216 assertVerdict(PASS, gen, packet, filterAge);
217 }
218
219 private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge)
220 throws IllegalInstructionException {
221 assertVerdict(DROP, gen, packet, filterAge);
222 }
223
224 private void assertPass(ApfGenerator gen)
225 throws IllegalInstructionException {
226 assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0);
227 }
228
229 private void assertDrop(ApfGenerator gen)
230 throws IllegalInstructionException {
231 assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0);
232 }
233
234 /**
235 * Test each instruction by generating a program containing the instruction,
236 * generating bytecode for that program and running it through the
237 * interpreter to verify it functions correctly.
238 */
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900239 @Test
Paul Jensen9132f342016-04-13 15:00:26 -0400240 public void testApfInstructions() throws IllegalInstructionException {
241 // Empty program should pass because having the program counter reach the
242 // location immediately after the program indicates the packet should be
243 // passed to the AP.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900244 ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400245 assertPass(gen);
246
247 // Test jumping to pass label.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900248 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400249 gen.addJump(gen.PASS_LABEL);
250 byte[] program = gen.generate();
251 assertEquals(1, program.length);
252 assertEquals((14 << 3) | (0 << 1) | 0, program[0]);
253 assertPass(program, new byte[MIN_PKT_SIZE], 0);
254
255 // Test jumping to drop label.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900256 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400257 gen.addJump(gen.DROP_LABEL);
258 program = gen.generate();
259 assertEquals(2, program.length);
260 assertEquals((14 << 3) | (1 << 1) | 0, program[0]);
261 assertEquals(1, program[1]);
262 assertDrop(program, new byte[15], 15);
263
264 // Test jumping if equal to 0.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900265 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400266 gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
267 assertDrop(gen);
268
269 // Test jumping if not equal to 0.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900270 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400271 gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
272 assertPass(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900273 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400274 gen.addLoadImmediate(Register.R0, 1);
275 gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
276 assertDrop(gen);
277
278 // Test jumping if registers equal.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900279 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400280 gen.addJumpIfR0EqualsR1(gen.DROP_LABEL);
281 assertDrop(gen);
282
283 // Test jumping if registers not equal.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900284 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400285 gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
286 assertPass(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900287 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400288 gen.addLoadImmediate(Register.R0, 1);
289 gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
290 assertDrop(gen);
291
292 // Test load immediate.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900293 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400294 gen.addLoadImmediate(Register.R0, 1234567890);
295 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
296 assertDrop(gen);
297
298 // Test add.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900299 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400300 gen.addAdd(1234567890);
301 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
302 assertDrop(gen);
303
304 // Test subtract.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900305 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400306 gen.addAdd(-1234567890);
307 gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
308 assertDrop(gen);
309
310 // Test or.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900311 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400312 gen.addOr(1234567890);
313 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
314 assertDrop(gen);
315
316 // Test and.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900317 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400318 gen.addLoadImmediate(Register.R0, 1234567890);
319 gen.addAnd(123456789);
320 gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
321 assertDrop(gen);
322
323 // Test left shift.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900324 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400325 gen.addLoadImmediate(Register.R0, 1234567890);
326 gen.addLeftShift(1);
327 gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
328 assertDrop(gen);
329
330 // Test right shift.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900331 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400332 gen.addLoadImmediate(Register.R0, 1234567890);
333 gen.addRightShift(1);
334 gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
335 assertDrop(gen);
336
337 // Test multiply.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900338 gen = new ApfGenerator(MIN_APF_VERSION);
Andreas Gampe5b003112018-06-13 11:35:16 -0700339 gen.addLoadImmediate(Register.R0, 123456789);
Paul Jensen9132f342016-04-13 15:00:26 -0400340 gen.addMul(2);
Andreas Gampe5b003112018-06-13 11:35:16 -0700341 gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
Paul Jensen9132f342016-04-13 15:00:26 -0400342 assertDrop(gen);
343
344 // Test divide.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900345 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400346 gen.addLoadImmediate(Register.R0, 1234567890);
347 gen.addDiv(2);
348 gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
349 assertDrop(gen);
350
351 // Test divide by zero.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900352 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400353 gen.addDiv(0);
354 gen.addJump(gen.DROP_LABEL);
355 assertPass(gen);
356
357 // Test add.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900358 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400359 gen.addLoadImmediate(Register.R1, 1234567890);
360 gen.addAddR1();
361 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
362 assertDrop(gen);
363
364 // Test subtract.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900365 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400366 gen.addLoadImmediate(Register.R1, -1234567890);
367 gen.addAddR1();
368 gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
369 assertDrop(gen);
370
371 // Test or.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900372 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400373 gen.addLoadImmediate(Register.R1, 1234567890);
374 gen.addOrR1();
375 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
376 assertDrop(gen);
377
378 // Test and.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900379 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400380 gen.addLoadImmediate(Register.R0, 1234567890);
381 gen.addLoadImmediate(Register.R1, 123456789);
382 gen.addAndR1();
383 gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
384 assertDrop(gen);
385
386 // Test left shift.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900387 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400388 gen.addLoadImmediate(Register.R0, 1234567890);
389 gen.addLoadImmediate(Register.R1, 1);
390 gen.addLeftShiftR1();
391 gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
392 assertDrop(gen);
393
394 // Test right shift.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900395 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400396 gen.addLoadImmediate(Register.R0, 1234567890);
397 gen.addLoadImmediate(Register.R1, -1);
398 gen.addLeftShiftR1();
399 gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
400 assertDrop(gen);
401
402 // Test multiply.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900403 gen = new ApfGenerator(MIN_APF_VERSION);
Andreas Gampe5b003112018-06-13 11:35:16 -0700404 gen.addLoadImmediate(Register.R0, 123456789);
Paul Jensen9132f342016-04-13 15:00:26 -0400405 gen.addLoadImmediate(Register.R1, 2);
406 gen.addMulR1();
Andreas Gampe5b003112018-06-13 11:35:16 -0700407 gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
Paul Jensen9132f342016-04-13 15:00:26 -0400408 assertDrop(gen);
409
410 // Test divide.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900411 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400412 gen.addLoadImmediate(Register.R0, 1234567890);
413 gen.addLoadImmediate(Register.R1, 2);
414 gen.addDivR1();
415 gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
416 assertDrop(gen);
417
418 // Test divide by zero.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900419 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400420 gen.addDivR1();
421 gen.addJump(gen.DROP_LABEL);
422 assertPass(gen);
423
424 // Test byte load.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900425 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400426 gen.addLoad8(Register.R0, 1);
427 gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
428 assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
429
430 // Test out of bounds load.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900431 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400432 gen.addLoad8(Register.R0, 16);
433 gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
434 assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
435
436 // Test half-word load.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900437 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400438 gen.addLoad16(Register.R0, 1);
439 gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
440 assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
441
442 // Test word load.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900443 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400444 gen.addLoad32(Register.R0, 1);
445 gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
446 assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
447
448 // Test byte indexed load.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900449 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400450 gen.addLoadImmediate(Register.R1, 1);
451 gen.addLoad8Indexed(Register.R0, 0);
452 gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
453 assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
454
455 // Test out of bounds indexed load.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900456 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400457 gen.addLoadImmediate(Register.R1, 8);
458 gen.addLoad8Indexed(Register.R0, 8);
459 gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
460 assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
461
462 // Test half-word indexed load.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900463 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400464 gen.addLoadImmediate(Register.R1, 1);
465 gen.addLoad16Indexed(Register.R0, 0);
466 gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
467 assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
468
469 // Test word indexed load.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900470 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400471 gen.addLoadImmediate(Register.R1, 1);
472 gen.addLoad32Indexed(Register.R0, 0);
473 gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
474 assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
475
476 // Test jumping if greater than.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900477 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400478 gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
479 assertPass(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900480 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400481 gen.addLoadImmediate(Register.R0, 1);
482 gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
483 assertDrop(gen);
484
485 // Test jumping if less than.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900486 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400487 gen.addJumpIfR0LessThan(0, gen.DROP_LABEL);
488 assertPass(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900489 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400490 gen.addJumpIfR0LessThan(1, gen.DROP_LABEL);
491 assertDrop(gen);
492
493 // Test jumping if any bits set.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900494 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400495 gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
496 assertPass(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900497 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400498 gen.addLoadImmediate(Register.R0, 1);
499 gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
500 assertDrop(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900501 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400502 gen.addLoadImmediate(Register.R0, 3);
503 gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
504 assertDrop(gen);
505
506 // Test jumping if register greater than.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900507 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400508 gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
509 assertPass(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900510 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400511 gen.addLoadImmediate(Register.R0, 2);
512 gen.addLoadImmediate(Register.R1, 1);
513 gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
514 assertDrop(gen);
515
516 // Test jumping if register less than.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900517 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400518 gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
519 assertPass(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900520 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400521 gen.addLoadImmediate(Register.R1, 1);
522 gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
523 assertDrop(gen);
524
525 // Test jumping if any bits set in register.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900526 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400527 gen.addLoadImmediate(Register.R1, 3);
528 gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
529 assertPass(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900530 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400531 gen.addLoadImmediate(Register.R1, 3);
532 gen.addLoadImmediate(Register.R0, 1);
533 gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
534 assertDrop(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900535 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400536 gen.addLoadImmediate(Register.R1, 3);
537 gen.addLoadImmediate(Register.R0, 3);
538 gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
539 assertDrop(gen);
540
541 // Test load from memory.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900542 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400543 gen.addLoadFromMemory(Register.R0, 0);
544 gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
545 assertDrop(gen);
546
547 // Test store to memory.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900548 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400549 gen.addLoadImmediate(Register.R1, 1234567890);
550 gen.addStoreToMemory(Register.R1, 12);
551 gen.addLoadFromMemory(Register.R0, 12);
552 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
553 assertDrop(gen);
554
555 // Test filter age pre-filled memory.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900556 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400557 gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
558 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
559 assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890);
560
561 // Test packet size pre-filled memory.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900562 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400563 gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
564 gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL);
565 assertDrop(gen);
566
567 // Test IPv4 header size pre-filled memory.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900568 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400569 gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
570 gen.addJumpIfR0Equals(20, gen.DROP_LABEL);
571 assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0);
572
573 // Test not.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900574 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400575 gen.addLoadImmediate(Register.R0, 1234567890);
576 gen.addNot(Register.R0);
577 gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL);
578 assertDrop(gen);
579
580 // Test negate.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900581 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400582 gen.addLoadImmediate(Register.R0, 1234567890);
583 gen.addNeg(Register.R0);
584 gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
585 assertDrop(gen);
586
587 // Test move.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900588 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400589 gen.addLoadImmediate(Register.R1, 1234567890);
590 gen.addMove(Register.R0);
591 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
592 assertDrop(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900593 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400594 gen.addLoadImmediate(Register.R0, 1234567890);
595 gen.addMove(Register.R1);
596 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
597 assertDrop(gen);
598
599 // Test swap.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900600 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400601 gen.addLoadImmediate(Register.R1, 1234567890);
602 gen.addSwap();
603 gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
604 assertDrop(gen);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900605 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400606 gen.addLoadImmediate(Register.R0, 1234567890);
607 gen.addSwap();
608 gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
609 assertDrop(gen);
610
611 // Test jump if bytes not equal.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900612 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400613 gen.addLoadImmediate(Register.R0, 1);
614 gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
615 program = gen.generate();
616 assertEquals(6, program.length);
617 assertEquals((13 << 3) | (1 << 1) | 0, program[0]);
618 assertEquals(1, program[1]);
619 assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]);
620 assertEquals(1, program[3]);
621 assertEquals(1, program[4]);
622 assertEquals(123, program[5]);
623 assertDrop(program, new byte[MIN_PKT_SIZE], 0);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900624 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400625 gen.addLoadImmediate(Register.R0, 1);
626 gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
Hugo Benichi961ca492016-09-02 11:04:34 +0900627 byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
Paul Jensen9132f342016-04-13 15:00:26 -0400628 assertPass(gen, packet123, 0);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900629 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400630 gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
631 assertDrop(gen, packet123, 0);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900632 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400633 gen.addLoadImmediate(Register.R0, 1);
634 gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
Hugo Benichi961ca492016-09-02 11:04:34 +0900635 byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
Paul Jensen9132f342016-04-13 15:00:26 -0400636 assertDrop(gen, packet12345, 0);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900637 gen = new ApfGenerator(MIN_APF_VERSION);
Paul Jensen9132f342016-04-13 15:00:26 -0400638 gen.addLoadImmediate(Register.R0, 1);
639 gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL);
640 assertPass(gen, packet12345, 0);
641 }
642
Bernie Innocentia9949e92018-03-22 23:07:47 +0900643 @Test(expected = ApfGenerator.IllegalInstructionException.class)
644 public void testApfGeneratorWantsV2OrGreater() throws Exception {
645 // The minimum supported APF version is 2.
646 new ApfGenerator(1);
647 }
648
649 @Test
650 public void testApfDataOpcodesWantApfV3() throws IllegalInstructionException, Exception {
651 ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
652 try {
653 gen.addStoreData(Register.R0, 0);
654 fail();
655 } catch (IllegalInstructionException expected) {
656 /* pass */
657 }
658 try {
659 gen.addLoadData(Register.R0, 0);
660 fail();
661 } catch (IllegalInstructionException expected) {
662 /* pass */
663 }
664 }
665
Bernie Innocenti18050002018-04-19 20:53:00 +0900666 /**
667 * Test that the generator emits immediates using the shortest possible encoding.
668 */
669 @Test
670 public void testImmediateEncoding() throws IllegalInstructionException {
Bernie Innocenti18050002018-04-19 20:53:00 +0900671 ApfGenerator gen;
672
673 // 0-byte immediate: li R0, 0
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900674 gen = new ApfGenerator(4);
Bernie Innocenti18050002018-04-19 20:53:00 +0900675 gen.addLoadImmediate(Register.R0, 0);
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900676 assertProgramEquals(new byte[]{LI_OP | SIZE0}, gen.generate());
Bernie Innocenti18050002018-04-19 20:53:00 +0900677
678 // 1-byte immediate: li R0, 42
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900679 gen = new ApfGenerator(4);
Bernie Innocenti18050002018-04-19 20:53:00 +0900680 gen.addLoadImmediate(Register.R0, 42);
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900681 assertProgramEquals(new byte[]{LI_OP | SIZE8, 42}, gen.generate());
Bernie Innocenti18050002018-04-19 20:53:00 +0900682
683 // 2-byte immediate: li R1, 0x1234
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900684 gen = new ApfGenerator(4);
Bernie Innocenti18050002018-04-19 20:53:00 +0900685 gen.addLoadImmediate(Register.R1, 0x1234);
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900686 assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, 0x12, 0x34}, gen.generate());
Bernie Innocenti18050002018-04-19 20:53:00 +0900687
688 // 4-byte immediate: li R0, 0x12345678
689 gen = new ApfGenerator(3);
690 gen.addLoadImmediate(Register.R0, 0x12345678);
691 assertProgramEquals(
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900692 new byte[]{LI_OP | SIZE32, 0x12, 0x34, 0x56, 0x78},
Bernie Innocenti18050002018-04-19 20:53:00 +0900693 gen.generate());
694 }
695
696 /**
697 * Test that the generator emits negative immediates using the shortest possible encoding.
698 */
699 @Test
700 public void testNegativeImmediateEncoding() throws IllegalInstructionException {
Bernie Innocenti18050002018-04-19 20:53:00 +0900701 ApfGenerator gen;
702
703 // 1-byte negative immediate: li R0, -42
704 gen = new ApfGenerator(3);
705 gen.addLoadImmediate(Register.R0, -42);
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900706 assertProgramEquals(new byte[]{LI_OP | SIZE8, -42}, gen.generate());
Bernie Innocenti18050002018-04-19 20:53:00 +0900707
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900708 // 2-byte negative immediate: li R1, -0x1122
Bernie Innocenti18050002018-04-19 20:53:00 +0900709 gen = new ApfGenerator(3);
710 gen.addLoadImmediate(Register.R1, -0x1122);
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900711 assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
Bernie Innocenti18050002018-04-19 20:53:00 +0900712 gen.generate());
713
714 // 4-byte negative immediate: li R0, -0x11223344
715 gen = new ApfGenerator(3);
716 gen.addLoadImmediate(Register.R0, -0x11223344);
717 assertProgramEquals(
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900718 new byte[]{LI_OP | SIZE32, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
Bernie Innocenti18050002018-04-19 20:53:00 +0900719 gen.generate());
720 }
721
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900722 /**
723 * Test that the generator correctly emits positive and negative immediates for LDDW/STDW.
724 */
725 @Test
726 public void testLoadStoreDataEncoding() throws IllegalInstructionException {
727 ApfGenerator gen;
728
729 // Load data with no offset: lddw R0, [0 + r1]
730 gen = new ApfGenerator(3);
731 gen.addLoadData(Register.R0, 0);
732 assertProgramEquals(new byte[]{LDDW_OP | SIZE0}, gen.generate());
733
734 // Store data with 8bit negative offset: lddw r0, [-42 + r1]
735 gen = new ApfGenerator(3);
736 gen.addStoreData(Register.R0, -42);
737 assertProgramEquals(new byte[]{STDW_OP | SIZE8, -42}, gen.generate());
738
739 // Store data to R1 with 16bit negative offset: stdw r1, [-0x1122 + r0]
740 gen = new ApfGenerator(3);
741 gen.addStoreData(Register.R1, -0x1122);
742 assertProgramEquals(new byte[]{STDW_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
743 gen.generate());
744
745 // Load data to R1 with 32bit negative offset: lddw r1, [0xDEADBEEF + r0]
746 gen = new ApfGenerator(3);
747 gen.addLoadData(Register.R1, 0xDEADBEEF);
748 assertProgramEquals(
749 new byte[]{LDDW_OP | SIZE32 | R1, (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF},
750 gen.generate());
751 }
752
753 /**
754 * Test that the interpreter correctly executes STDW with a negative 8bit offset
755 */
Bernie Innocentia9949e92018-03-22 23:07:47 +0900756 @Test
757 public void testApfDataWrite() throws IllegalInstructionException, Exception {
758 byte[] packet = new byte[MIN_PKT_SIZE];
Bernie Innocenti545d9362018-04-16 23:27:51 +0900759 byte[] data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
Bernie Innocentia9949e92018-03-22 23:07:47 +0900760 byte[] expected_data = data.clone();
761
762 // No memory access instructions: should leave the data segment untouched.
763 ApfGenerator gen = new ApfGenerator(3);
764 assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
765
Bernie Innocenti545d9362018-04-16 23:27:51 +0900766 // Expect value 0x87654321 to be stored starting from address -11 from the end of the
767 // data buffer, in big-endian order.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900768 gen = new ApfGenerator(3);
769 gen.addLoadImmediate(Register.R0, 0x87654321);
Bernie Innocenti545d9362018-04-16 23:27:51 +0900770 gen.addLoadImmediate(Register.R1, -5);
771 gen.addStoreData(Register.R0, -6); // -5 + -6 = -11 (offset +5 with data_len=16)
Bernie Innocentia9949e92018-03-22 23:07:47 +0900772 expected_data[5] = (byte)0x87;
773 expected_data[6] = (byte)0x65;
774 expected_data[7] = (byte)0x43;
775 expected_data[8] = (byte)0x21;
776 assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
777 }
778
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900779 /**
780 * Test that the interpreter correctly executes LDDW with a negative 16bit offset
781 */
Bernie Innocentia9949e92018-03-22 23:07:47 +0900782 @Test
783 public void testApfDataRead() throws IllegalInstructionException, Exception {
Bernie Innocenti545d9362018-04-16 23:27:51 +0900784 // Program that DROPs if address 10 (-6) contains 0x87654321.
Bernie Innocentia9949e92018-03-22 23:07:47 +0900785 ApfGenerator gen = new ApfGenerator(3);
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900786 gen.addLoadImmediate(Register.R1, 1000);
787 gen.addLoadData(Register.R0, -1006); // 1000 + -1006 = -6 (offset +10 with data_len=16)
Bernie Innocentia9949e92018-03-22 23:07:47 +0900788 gen.addJumpIfR0Equals(0x87654321, gen.DROP_LABEL);
789 byte[] program = gen.generate();
790 byte[] packet = new byte[MIN_PKT_SIZE];
791
792 // Content is incorrect (last byte does not match) -> PASS
Bernie Innocenti545d9362018-04-16 23:27:51 +0900793 byte[] data = new byte[16];
Bernie Innocentia9949e92018-03-22 23:07:47 +0900794 data[10] = (byte)0x87;
795 data[11] = (byte)0x65;
796 data[12] = (byte)0x43;
797 data[13] = (byte)0x00; // != 0x21
798 byte[] expected_data = data.clone();
799 assertDataMemoryContents(PASS, program, packet, data, expected_data);
800
801 // Fix the last byte -> conditional jump taken -> DROP
802 data[13] = (byte)0x21;
803 expected_data = data;
804 assertDataMemoryContents(DROP, program, packet, data, expected_data);
805 }
806
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900807 /**
808 * Test that the interpreter correctly executes LDDW followed by a STDW.
809 * To cover a few more edge cases, LDDW has a 0bit offset, while STDW has a positive 8bit
810 * offset.
811 */
Bernie Innocentia9949e92018-03-22 23:07:47 +0900812 @Test
813 public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception {
814 ApfGenerator gen = new ApfGenerator(3);
Bernie Innocenti545d9362018-04-16 23:27:51 +0900815 gen.addLoadImmediate(Register.R1, -22);
816 gen.addLoadData(Register.R0, 0); // Load from address 32 -22 + 0 = 10
Bernie Innocentia9949e92018-03-22 23:07:47 +0900817 gen.addAdd(0x78453412); // 87654321 + 78453412 = FFAA7733
Bernie Innocenti545d9362018-04-16 23:27:51 +0900818 gen.addStoreData(Register.R0, 4); // Write back to address 32 -22 + 4 = 14
Bernie Innocentia9949e92018-03-22 23:07:47 +0900819
820 byte[] packet = new byte[MIN_PKT_SIZE];
821 byte[] data = new byte[32];
822 data[10] = (byte)0x87;
823 data[11] = (byte)0x65;
824 data[12] = (byte)0x43;
825 data[13] = (byte)0x21;
826 byte[] expected_data = data.clone();
827 expected_data[14] = (byte)0xFF;
828 expected_data[15] = (byte)0xAA;
829 expected_data[16] = (byte)0x77;
830 expected_data[17] = (byte)0x33;
831 assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
832 }
833
834 @Test
835 public void testApfDataBoundChecking() throws IllegalInstructionException, Exception {
836 byte[] packet = new byte[MIN_PKT_SIZE];
837 byte[] data = new byte[32];
838 byte[] expected_data = data;
839
840 // Program that DROPs unconditionally. This is our the baseline.
841 ApfGenerator gen = new ApfGenerator(3);
842 gen.addLoadImmediate(Register.R0, 3);
843 gen.addLoadData(Register.R1, 7);
844 gen.addJump(gen.DROP_LABEL);
845 assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
846
847 // Same program as before, but this time we're trying to load past the end of the data.
848 gen = new ApfGenerator(3);
849 gen.addLoadImmediate(Register.R0, 20);
850 gen.addLoadData(Register.R1, 15); // 20 + 15 > 32
851 gen.addJump(gen.DROP_LABEL); // Not reached.
852 assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
853
854 // Subtracting an immediate should work...
855 gen = new ApfGenerator(3);
856 gen.addLoadImmediate(Register.R0, 20);
857 gen.addLoadData(Register.R1, -4);
858 gen.addJump(gen.DROP_LABEL);
859 assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
860
Bernie Innocenti545d9362018-04-16 23:27:51 +0900861 // ...and underflowing simply wraps around to the end of the buffer...
Bernie Innocentia9949e92018-03-22 23:07:47 +0900862 gen = new ApfGenerator(3);
863 gen.addLoadImmediate(Register.R0, 20);
864 gen.addLoadData(Register.R1, -30);
Bernie Innocenti545d9362018-04-16 23:27:51 +0900865 gen.addJump(gen.DROP_LABEL);
866 assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
867
868 // ...but doesn't allow accesses before the start of the buffer
869 gen = new ApfGenerator(3);
870 gen.addLoadImmediate(Register.R0, 20);
871 gen.addLoadData(Register.R1, -1000);
Bernie Innocentia9949e92018-03-22 23:07:47 +0900872 gen.addJump(gen.DROP_LABEL); // Not reached.
873 assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
874 }
875
Paul Jensen9132f342016-04-13 15:00:26 -0400876 /**
877 * Generate some BPF programs, translate them to APF, then run APF and BPF programs
878 * over packet traces and verify both programs filter out the same packets.
879 */
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900880 @Test
Paul Jensen9132f342016-04-13 15:00:26 -0400881 public void testApfAgainstBpf() throws Exception {
882 String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
883 "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
884 "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000",
885 "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" };
886 String pcap_filename = stageFile(R.raw.apf);
887 for (String tcpdump_filter : tcpdump_filters) {
888 byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter));
889 assertTrue("Failed to match for filter: " + tcpdump_filter,
890 compareBpfApf(tcpdump_filter, pcap_filename, apf_program));
891 }
892 }
893
Aaron Huang785e5f12018-10-31 15:57:48 +0800894 /**
895 * Generate APF program, run pcap file though APF filter, then check all the packets in the file
896 * should be dropped.
897 */
898 @Test
899 public void testApfFilterPcapFile() throws Exception {
900 final byte[] MOCK_PCAP_IPV4_ADDR = {(byte) 172, 16, 7, (byte) 151};
901 String pcapFilename = stageFile(R.raw.apfPcap);
902 MockIpClientCallback ipClientCallback = new MockIpClientCallback();
903 LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_PCAP_IPV4_ADDR), 16);
904 LinkProperties lp = new LinkProperties();
905 lp.addLinkAddress(link);
906
907 ApfConfiguration config = getDefaultConfig();
908 ApfCapabilities MOCK_APF_PCAP_CAPABILITIES = new ApfCapabilities(4, 1700, ARPHRD_ETHER);
909 config.apfCapabilities = MOCK_APF_PCAP_CAPABILITIES;
910 config.multicastFilter = DROP_MULTICAST;
911 config.ieee802_3Filter = DROP_802_3_FRAMES;
912 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
913 apfFilter.setLinkProperties(lp);
914 byte[] program = ipClientCallback.getApfProgram();
915 byte[] data = new byte[ApfFilter.Counter.totalSize()];
916 final boolean result;
917
918 result = dropsAllPackets(program, data, pcapFilename);
919 Log.i(TAG, "testApfFilterPcapFile(): Data counters: " + HexDump.toHexString(data, false));
920
921 assertTrue("Failed to drop all packets by filter. \nAPF counters:" +
922 HexDump.toHexString(data, false), result);
923 }
924
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900925 private class MockIpClientCallback extends IpClientCallbacksWrapper {
Paul Jensen9132f342016-04-13 15:00:26 -0400926 private final ConditionVariable mGotApfProgram = new ConditionVariable();
927 private byte[] mLastApfProgram;
928
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900929 MockIpClientCallback() {
930 super(mock(IIpClientCallbacks.class), mock(SharedLog.class));
931 }
932
Paul Jensen9132f342016-04-13 15:00:26 -0400933 @Override
934 public void installPacketFilter(byte[] filter) {
935 mLastApfProgram = filter;
936 mGotApfProgram.open();
937 }
938
939 public void resetApfProgramWait() {
940 mGotApfProgram.close();
941 }
942
943 public byte[] getApfProgram() {
944 assertTrue(mGotApfProgram.block(TIMEOUT_MS));
945 return mLastApfProgram;
946 }
Lorenzo Colitti8995d852016-06-23 15:24:46 +0900947
948 public void assertNoProgramUpdate() {
949 assertFalse(mGotApfProgram.block(TIMEOUT_MS));
950 }
Paul Jensen9132f342016-04-13 15:00:26 -0400951 }
952
953 private static class TestApfFilter extends ApfFilter {
Bernie Innocenti3d479d92018-04-20 23:31:33 +0900954 public static final byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
Paul Jensen9132f342016-04-13 15:00:26 -0400955
Hugo Benichi72166362017-10-13 16:32:20 +0900956 private FileDescriptor mWriteSocket;
Hugo Benichi4456f332016-12-19 14:50:52 +0900957 private final long mFixedTimeMs = SystemClock.elapsedRealtime();
958
Bernie Innocentie2c70f82018-03-28 20:11:49 +0900959 public TestApfFilter(Context context, ApfConfiguration config,
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900960 IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log) throws Exception {
Erik Kline8d1fe542018-03-12 23:18:58 +0900961 super(context, config, InterfaceParams.getByName("lo"), ipClientCallback, log);
Paul Jensen9132f342016-04-13 15:00:26 -0400962 }
963
964 // Pretend an RA packet has been received and show it to ApfFilter.
965 public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException {
966 // ApfFilter's ReceiveThread will be waiting to read this.
967 Os.write(mWriteSocket, packet, 0, packet.length);
968 }
969
970 @Override
Hugo Benichi4456f332016-12-19 14:50:52 +0900971 protected long currentTimeSeconds() {
972 return mFixedTimeMs / DateUtils.SECOND_IN_MILLIS;
973 }
974
975 @Override
Paul Jensen9132f342016-04-13 15:00:26 -0400976 void maybeStartFilter() {
977 mHardwareAddress = MOCK_MAC_ADDR;
978 installNewProgramLocked();
979
980 // Create two sockets, "readSocket" and "mWriteSocket" and connect them together.
981 FileDescriptor readSocket = new FileDescriptor();
982 mWriteSocket = new FileDescriptor();
983 try {
984 Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket);
985 } catch (ErrnoException e) {
986 fail();
987 return;
988 }
989 // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs.
990 // This allows us to pretend RA packets have been recieved via pretendPacketReceived().
991 mReceiveThread = new ReceiveThread(readSocket);
992 mReceiveThread.start();
993 }
994
995 @Override
996 public void shutdown() {
997 super.shutdown();
998 IoUtils.closeQuietly(mWriteSocket);
999 }
1000 }
1001
Aaron Huang56f9e412019-05-13 05:13:09 -07001002 private static final int ETH_HEADER_LEN = 14;
1003 private static final int ETH_DEST_ADDR_OFFSET = 0;
1004 private static final int ETH_ETHERTYPE_OFFSET = 12;
Hugo Benichi961ca492016-09-02 11:04:34 +09001005 private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
1006 {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
Paul Jensen9132f342016-04-13 15:00:26 -04001007
Aaron Huang56f9e412019-05-13 05:13:09 -07001008 private static final int IPV4_HEADER_LEN = 20;
1009 private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
Aaron Huang75a60432019-02-20 17:14:02 +08001010 private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
Aaron Huang56f9e412019-05-13 05:13:09 -07001011 private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
1012 private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12;
1013 private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
1014
1015 private static final int IPV4_TCP_HEADER_LEN = 20;
1016 private static final int IPV4_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;
1017 private static final int IPV4_TCP_SRC_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 0;
1018 private static final int IPV4_TCP_DEST_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 2;
1019 private static final int IPV4_TCP_SEQ_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 4;
1020 private static final int IPV4_TCP_ACK_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 8;
Aaron Huanga63c40e2019-01-15 16:53:51 +08001021 private static final int IPV4_TCP_HEADER_LENGTH_OFFSET = IPV4_TCP_HEADER_OFFSET + 12;
Aaron Huang56f9e412019-05-13 05:13:09 -07001022 private static final int IPV4_TCP_HEADER_FLAG_OFFSET = IPV4_TCP_HEADER_OFFSET + 13;
1023
1024 private static final int IPV4_UDP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;;
1025 private static final int IPV4_UDP_SRC_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 0;
1026 private static final int IPV4_UDP_DEST_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 2;
1027 private static final int IPV4_UDP_LENGTH_OFFSET = IPV4_UDP_HEADER_OFFSET + 4;
1028 private static final int IPV4_UDP_PAYLOAD_OFFSET = IPV4_UDP_HEADER_OFFSET + 8;
Hugo Benichi961ca492016-09-02 11:04:34 +09001029 private static final byte[] IPV4_BROADCAST_ADDRESS =
1030 {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
Paul Jensen9132f342016-04-13 15:00:26 -04001031
Aaron Huang56f9e412019-05-13 05:13:09 -07001032 private static final int IPV6_HEADER_LEN = 40;
1033 private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
1034 private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
1035 private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
1036 private static final int IPV6_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
1037 private static final int IPV6_TCP_SRC_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 0;
1038 private static final int IPV6_TCP_DEST_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 2;
1039 private static final int IPV6_TCP_SEQ_NUM_OFFSET = IPV6_TCP_HEADER_OFFSET + 4;
1040 private static final int IPV6_TCP_ACK_NUM_OFFSET = IPV6_TCP_HEADER_OFFSET + 8;
Paul Jensen9132f342016-04-13 15:00:26 -04001041 // The IPv6 all nodes address ff02::1
Aaron Huang56f9e412019-05-13 05:13:09 -07001042 private static final byte[] IPV6_ALL_NODES_ADDRESS =
Hugo Benichi961ca492016-09-02 11:04:34 +09001043 { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
Hugo Benichi02428982016-12-03 02:41:05 +09001044 private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
1045 { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
Paul Jensen9132f342016-04-13 15:00:26 -04001046
Aaron Huang56f9e412019-05-13 05:13:09 -07001047 private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
1048 private static final int ICMP6_ROUTER_SOLICITATION = 133;
1049 private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
Hugo Benichi02428982016-12-03 02:41:05 +09001050 private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
Paul Jensen9132f342016-04-13 15:00:26 -04001051 private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
1052
1053 private static final int ICMP6_RA_HEADER_LEN = 16;
1054 private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
1055 ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
1056 private static final int ICMP6_RA_CHECKSUM_OFFSET =
1057 ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
1058 private static final int ICMP6_RA_OPTION_OFFSET =
1059 ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
1060
Aaron Huang56f9e412019-05-13 05:13:09 -07001061 private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
1062 private static final int ICMP6_PREFIX_OPTION_LEN = 32;
1063 private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
Paul Jensen9132f342016-04-13 15:00:26 -04001064 private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
1065
1066 // From RFC6106: Recursive DNS Server option
1067 private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
1068 // From RFC6106: DNS Search List option
1069 private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
1070
1071 // From RFC4191: Route Information option
1072 private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
1073 // Above three options all have the same format:
Aaron Huang56f9e412019-05-13 05:13:09 -07001074 private static final int ICMP6_4_BYTE_OPTION_LEN = 8;
Paul Jensen9132f342016-04-13 15:00:26 -04001075 private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
Aaron Huang56f9e412019-05-13 05:13:09 -07001076 private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
Paul Jensen9132f342016-04-13 15:00:26 -04001077
Aaron Huang56f9e412019-05-13 05:13:09 -07001078 private static final int UDP_HEADER_LEN = 8;
Paul Jensen9132f342016-04-13 15:00:26 -04001079 private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22;
1080
Aaron Huang56f9e412019-05-13 05:13:09 -07001081 private static final int DHCP_CLIENT_PORT = 68;
Paul Jensen9132f342016-04-13 15:00:26 -04001082 private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
1083
Aaron Huang56f9e412019-05-13 05:13:09 -07001084 private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
Hugo Benichi961ca492016-09-02 11:04:34 +09001085 private static final byte[] ARP_IPV4_REQUEST_HEADER = {
Paul Jensen9132f342016-04-13 15:00:26 -04001086 0, 1, // Hardware type: Ethernet (1)
1087 8, 0, // Protocol type: IP (0x0800)
1088 6, // Hardware size: 6
1089 4, // Protocol size: 4
1090 0, 1 // Opcode: request (1)
1091 };
Hugo Benichi961ca492016-09-02 11:04:34 +09001092 private static final byte[] ARP_IPV4_REPLY_HEADER = {
Hugo Benichi38db9762016-07-12 15:08:50 +09001093 0, 1, // Hardware type: Ethernet (1)
1094 8, 0, // Protocol type: IP (0x0800)
1095 6, // Hardware size: 6
1096 4, // Protocol size: 4
1097 0, 2 // Opcode: reply (2)
1098 };
Aaron Huang04ed6a32018-11-15 20:30:46 +08001099 private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
1100 private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
Paul Jensen9132f342016-04-13 15:00:26 -04001101
Hugo Benichi961ca492016-09-02 11:04:34 +09001102 private static final byte[] MOCK_IPV4_ADDR = {10, 0, 0, 1};
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001103 private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19
Hugo Benichi961ca492016-09-02 11:04:34 +09001104 private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1};
1105 private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2};
Aaron Huang04ed6a32018-11-15 20:30:46 +08001106 private static final byte[] IPV4_SOURCE_ADDR = {10, 0, 0, 3};
1107 private static final byte[] ANOTHER_IPV4_SOURCE_ADDR = {(byte) 192, 0, 2, 1};
1108 private static final byte[] BUG_PROBE_SOURCE_ADDR1 = {0, 0, 1, 2};
1109 private static final byte[] BUG_PROBE_SOURCE_ADDR2 = {3, 4, 0, 0};
Hugo Benichi961ca492016-09-02 11:04:34 +09001110 private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0};
Paul Jensen9132f342016-04-13 15:00:26 -04001111
Bernie Innocentie2c70f82018-03-28 20:11:49 +09001112 // Helper to initialize a default apfFilter.
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +09001113 private ApfFilter setupApfFilter(
1114 IpClientCallbacksWrapper ipClientCallback, ApfConfiguration config) throws Exception {
Bernie Innocentie2c70f82018-03-28 20:11:49 +09001115 LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
1116 LinkProperties lp = new LinkProperties();
1117 lp.addLinkAddress(link);
Erik Kline8d1fe542018-03-12 23:18:58 +09001118 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
Bernie Innocentie2c70f82018-03-28 20:11:49 +09001119 apfFilter.setLinkProperties(lp);
1120 return apfFilter;
1121 }
1122
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001123 @Test
Paul Jensen9132f342016-04-13 15:00:26 -04001124 public void testApfFilterIPv4() throws Exception {
Erik Kline8d1fe542018-03-12 23:18:58 +09001125 MockIpClientCallback ipClientCallback = new MockIpClientCallback();
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001126 LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
1127 LinkProperties lp = new LinkProperties();
1128 lp.addLinkAddress(link);
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001129
Hugo Benichi72166362017-10-13 16:32:20 +09001130 ApfConfiguration config = getDefaultConfig();
1131 config.multicastFilter = DROP_MULTICAST;
Erik Kline8d1fe542018-03-12 23:18:58 +09001132 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001133 apfFilter.setLinkProperties(lp);
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001134
Erik Kline8d1fe542018-03-12 23:18:58 +09001135 byte[] program = ipClientCallback.getApfProgram();
Paul Jensen9132f342016-04-13 15:00:26 -04001136
1137 // Verify empty packet of 100 zero bytes is passed
1138 ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
Hugo Benichi961ca492016-09-02 11:04:34 +09001139 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001140
1141 // Verify unicast IPv4 packet is passed
Hugo Benichi961ca492016-09-02 11:04:34 +09001142 put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
Paul Jensen9132f342016-04-13 15:00:26 -04001143 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
Hugo Benichi961ca492016-09-02 11:04:34 +09001144 put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
1145 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001146
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001147 // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088)
Hugo Benichi961ca492016-09-02 11:04:34 +09001148 put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001149 assertDrop(program, packet.array());
Hugo Benichi961ca492016-09-02 11:04:34 +09001150 put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001151 assertDrop(program, packet.array());
Hugo Benichi961ca492016-09-02 11:04:34 +09001152
1153 // Verify multicast/broadcast IPv4, not DHCP to us, is dropped
1154 put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
1155 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001156 packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
Hugo Benichi961ca492016-09-02 11:04:34 +09001157 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001158 packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
Hugo Benichi961ca492016-09-02 11:04:34 +09001159 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001160 packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
Hugo Benichi961ca492016-09-02 11:04:34 +09001161 assertDrop(program, packet.array());
1162 put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR);
1163 assertDrop(program, packet.array());
1164 put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
1165 assertDrop(program, packet.array());
1166 put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
1167 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001168
1169 // Verify broadcast IPv4 DHCP to us is passed
Hugo Benichi961ca492016-09-02 11:04:34 +09001170 put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
1171 assertPass(program, packet.array());
1172
1173 // Verify unicast IPv4 DHCP to us is passed
1174 put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
1175 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001176
1177 apfFilter.shutdown();
1178 }
1179
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001180 @Test
Paul Jensen9132f342016-04-13 15:00:26 -04001181 public void testApfFilterIPv6() throws Exception {
Erik Kline8d1fe542018-03-12 23:18:58 +09001182 MockIpClientCallback ipClientCallback = new MockIpClientCallback();
Hugo Benichi72166362017-10-13 16:32:20 +09001183 ApfConfiguration config = getDefaultConfig();
Erik Kline8d1fe542018-03-12 23:18:58 +09001184 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
1185 byte[] program = ipClientCallback.getApfProgram();
Paul Jensen9132f342016-04-13 15:00:26 -04001186
1187 // Verify empty IPv6 packet is passed
1188 ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1189 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
Hugo Benichi961ca492016-09-02 11:04:34 +09001190 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001191
1192 // Verify empty ICMPv6 packet is passed
1193 packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
Hugo Benichi961ca492016-09-02 11:04:34 +09001194 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001195
1196 // Verify empty ICMPv6 NA packet is passed
1197 packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
Hugo Benichi961ca492016-09-02 11:04:34 +09001198 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001199
1200 // Verify ICMPv6 NA to ff02::1 is dropped
Hugo Benichi961ca492016-09-02 11:04:34 +09001201 put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
1202 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001203
Hugo Benichi02428982016-12-03 02:41:05 +09001204 // Verify ICMPv6 RS to any is dropped
1205 packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION);
1206 assertDrop(program, packet.array());
1207 put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
1208 assertDrop(program, packet.array());
1209
Paul Jensen9132f342016-04-13 15:00:26 -04001210 apfFilter.shutdown();
1211 }
1212
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001213 @Test
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001214 public void testApfFilterMulticast() throws Exception {
Hugo Benichi961ca492016-09-02 11:04:34 +09001215 final byte[] unicastIpv4Addr = {(byte)192,0,2,63};
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001216 final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
Hugo Benichi961ca492016-09-02 11:04:34 +09001217 final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
1218 final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
1219
Erik Kline8d1fe542018-03-12 23:18:58 +09001220 MockIpClientCallback ipClientCallback = new MockIpClientCallback();
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001221 LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
1222 LinkProperties lp = new LinkProperties();
1223 lp.addLinkAddress(link);
1224
Hugo Benichi72166362017-10-13 16:32:20 +09001225 ApfConfiguration config = getDefaultConfig();
1226 config.ieee802_3Filter = DROP_802_3_FRAMES;
Erik Kline8d1fe542018-03-12 23:18:58 +09001227 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001228 apfFilter.setLinkProperties(lp);
1229
Erik Kline8d1fe542018-03-12 23:18:58 +09001230 byte[] program = ipClientCallback.getApfProgram();
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001231
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001232 // Construct IPv4 and IPv6 multicast packets.
Paul Jensenf8a01e82016-05-26 09:16:11 -04001233 ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
1234 mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
Hugo Benichi961ca492016-09-02 11:04:34 +09001235 put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001236
Paul Jensenf8a01e82016-05-26 09:16:11 -04001237 ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
1238 mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
1239 mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
Hugo Benichi961ca492016-09-02 11:04:34 +09001240 put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
Paul Jensenf8a01e82016-05-26 09:16:11 -04001241
1242 // Construct IPv4 broadcast packet.
Hugo Benichi961ca492016-09-02 11:04:34 +09001243 ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]);
1244 bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
1245 bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1246 put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
1247
1248 ByteBuffer bcastv4packet2 = ByteBuffer.wrap(new byte[100]);
1249 bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS);
1250 bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1251 put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
1252
1253 // Construct IPv4 broadcast with L2 unicast address packet (b/30231088).
1254 ByteBuffer bcastv4unicastl2packet = ByteBuffer.wrap(new byte[100]);
1255 bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR);
1256 bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1257 put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr);
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001258
Paul Jensen9132f342016-04-13 15:00:26 -04001259 // Verify initially disabled multicast filter is off
Hugo Benichi961ca492016-09-02 11:04:34 +09001260 assertPass(program, mcastv4packet.array());
1261 assertPass(program, mcastv6packet.array());
1262 assertPass(program, bcastv4packet1.array());
1263 assertPass(program, bcastv4packet2.array());
1264 assertPass(program, bcastv4unicastl2packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001265
1266 // Turn on multicast filter and verify it works
Erik Kline8d1fe542018-03-12 23:18:58 +09001267 ipClientCallback.resetApfProgramWait();
Paul Jensen9132f342016-04-13 15:00:26 -04001268 apfFilter.setMulticastFilter(true);
Erik Kline8d1fe542018-03-12 23:18:58 +09001269 program = ipClientCallback.getApfProgram();
Hugo Benichi961ca492016-09-02 11:04:34 +09001270 assertDrop(program, mcastv4packet.array());
1271 assertDrop(program, mcastv6packet.array());
1272 assertDrop(program, bcastv4packet1.array());
1273 assertDrop(program, bcastv4packet2.array());
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001274 assertDrop(program, bcastv4unicastl2packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001275
1276 // Turn off multicast filter and verify it's off
Erik Kline8d1fe542018-03-12 23:18:58 +09001277 ipClientCallback.resetApfProgramWait();
Paul Jensen9132f342016-04-13 15:00:26 -04001278 apfFilter.setMulticastFilter(false);
Erik Kline8d1fe542018-03-12 23:18:58 +09001279 program = ipClientCallback.getApfProgram();
Hugo Benichi961ca492016-09-02 11:04:34 +09001280 assertPass(program, mcastv4packet.array());
1281 assertPass(program, mcastv6packet.array());
1282 assertPass(program, bcastv4packet1.array());
1283 assertPass(program, bcastv4packet2.array());
1284 assertPass(program, bcastv4unicastl2packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001285
1286 // Verify it can be initialized to on
Erik Kline8d1fe542018-03-12 23:18:58 +09001287 ipClientCallback.resetApfProgramWait();
Paul Jensen9132f342016-04-13 15:00:26 -04001288 apfFilter.shutdown();
Hugo Benichi72166362017-10-13 16:32:20 +09001289 config.multicastFilter = DROP_MULTICAST;
1290 config.ieee802_3Filter = DROP_802_3_FRAMES;
Erik Kline8d1fe542018-03-12 23:18:58 +09001291 apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001292 apfFilter.setLinkProperties(lp);
Erik Kline8d1fe542018-03-12 23:18:58 +09001293 program = ipClientCallback.getApfProgram();
Hugo Benichi961ca492016-09-02 11:04:34 +09001294 assertDrop(program, mcastv4packet.array());
1295 assertDrop(program, mcastv6packet.array());
1296 assertDrop(program, bcastv4packet1.array());
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001297 assertDrop(program, bcastv4unicastl2packet.array());
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001298
1299 // Verify that ICMPv6 multicast is not dropped.
Paul Jensenf8a01e82016-05-26 09:16:11 -04001300 mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
Hugo Benichi961ca492016-09-02 11:04:34 +09001301 assertPass(program, mcastv6packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001302
1303 apfFilter.shutdown();
1304 }
1305
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001306 @Test
Bernie Innocentie2c70f82018-03-28 20:11:49 +09001307 public void testApfFilterMulticastPingWhileDozing() throws Exception {
Erik Kline8d1fe542018-03-12 23:18:58 +09001308 MockIpClientCallback ipClientCallback = new MockIpClientCallback();
1309 ApfFilter apfFilter = setupApfFilter(ipClientCallback, getDefaultConfig());
Bernie Innocentie2c70f82018-03-28 20:11:49 +09001310
1311 // Construct a multicast ICMPv6 ECHO request.
1312 final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
1313 ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1314 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
1315 packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
1316 packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
1317 put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
1318
1319 // Normally, we let multicast pings alone...
Erik Kline8d1fe542018-03-12 23:18:58 +09001320 assertPass(ipClientCallback.getApfProgram(), packet.array());
Bernie Innocentie2c70f82018-03-28 20:11:49 +09001321
1322 // ...and even while dozing...
1323 apfFilter.setDozeMode(true);
Erik Kline8d1fe542018-03-12 23:18:58 +09001324 assertPass(ipClientCallback.getApfProgram(), packet.array());
Bernie Innocentie2c70f82018-03-28 20:11:49 +09001325
1326 // ...but when the multicast filter is also enabled, drop the multicast pings to save power.
1327 apfFilter.setMulticastFilter(true);
Erik Kline8d1fe542018-03-12 23:18:58 +09001328 assertDrop(ipClientCallback.getApfProgram(), packet.array());
Bernie Innocentie2c70f82018-03-28 20:11:49 +09001329
1330 // However, we should still let through all other ICMPv6 types.
1331 ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +09001332 raPacket.put(ICMP6_TYPE_OFFSET, (byte) NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT);
Erik Kline8d1fe542018-03-12 23:18:58 +09001333 assertPass(ipClientCallback.getApfProgram(), raPacket.array());
Bernie Innocentie2c70f82018-03-28 20:11:49 +09001334
1335 // Now wake up from doze mode to ensure that we no longer drop the packets.
1336 // (The multicast filter is still enabled at this point).
1337 apfFilter.setDozeMode(false);
Erik Kline8d1fe542018-03-12 23:18:58 +09001338 assertPass(ipClientCallback.getApfProgram(), packet.array());
Bernie Innocentie2c70f82018-03-28 20:11:49 +09001339
1340 apfFilter.shutdown();
1341 }
1342
1343 @Test
Ahmed ElArabawy8537c582017-06-12 18:01:11 -07001344 public void testApfFilter802_3() throws Exception {
Erik Kline8d1fe542018-03-12 23:18:58 +09001345 MockIpClientCallback ipClientCallback = new MockIpClientCallback();
Hugo Benichi72166362017-10-13 16:32:20 +09001346 ApfConfiguration config = getDefaultConfig();
Erik Kline8d1fe542018-03-12 23:18:58 +09001347 ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
1348 byte[] program = ipClientCallback.getApfProgram();
Ahmed ElArabawy8537c582017-06-12 18:01:11 -07001349
1350 // Verify empty packet of 100 zero bytes is passed
1351 // Note that eth-type = 0 makes it an IEEE802.3 frame
1352 ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1353 assertPass(program, packet.array());
1354
1355 // Verify empty packet with IPv4 is passed
1356 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1357 assertPass(program, packet.array());
1358
1359 // Verify empty IPv6 packet is passed
1360 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
1361 assertPass(program, packet.array());
1362
1363 // Now turn on the filter
Erik Kline8d1fe542018-03-12 23:18:58 +09001364 ipClientCallback.resetApfProgramWait();
Ahmed ElArabawy8537c582017-06-12 18:01:11 -07001365 apfFilter.shutdown();
Hugo Benichi72166362017-10-13 16:32:20 +09001366 config.ieee802_3Filter = DROP_802_3_FRAMES;
Erik Kline8d1fe542018-03-12 23:18:58 +09001367 apfFilter = setupApfFilter(ipClientCallback, config);
1368 program = ipClientCallback.getApfProgram();
Ahmed ElArabawy8537c582017-06-12 18:01:11 -07001369
1370 // Verify that IEEE802.3 frame is dropped
1371 // In this case ethtype is used for payload length
1372 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)(100 - 14));
1373 assertDrop(program, packet.array());
1374
1375 // Verify that IPv4 (as example of Ethernet II) frame will pass
1376 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1377 assertPass(program, packet.array());
1378
1379 // Verify that IPv6 (as example of Ethernet II) frame will pass
1380 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
1381 assertPass(program, packet.array());
1382
1383 apfFilter.shutdown();
1384 }
1385
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001386 @Test
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001387 public void testApfFilterEthTypeBL() throws Exception {
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001388 final int[] emptyBlackList = {};
1389 final int[] ipv4BlackList = {ETH_P_IP};
1390 final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
1391
Erik Kline8d1fe542018-03-12 23:18:58 +09001392 MockIpClientCallback ipClientCallback = new MockIpClientCallback();
Hugo Benichi72166362017-10-13 16:32:20 +09001393 ApfConfiguration config = getDefaultConfig();
Erik Kline8d1fe542018-03-12 23:18:58 +09001394 ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
1395 byte[] program = ipClientCallback.getApfProgram();
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001396
1397 // Verify empty packet of 100 zero bytes is passed
1398 // Note that eth-type = 0 makes it an IEEE802.3 frame
1399 ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1400 assertPass(program, packet.array());
1401
1402 // Verify empty packet with IPv4 is passed
1403 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1404 assertPass(program, packet.array());
1405
1406 // Verify empty IPv6 packet is passed
1407 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
1408 assertPass(program, packet.array());
1409
1410 // Now add IPv4 to the black list
Erik Kline8d1fe542018-03-12 23:18:58 +09001411 ipClientCallback.resetApfProgramWait();
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001412 apfFilter.shutdown();
Hugo Benichi72166362017-10-13 16:32:20 +09001413 config.ethTypeBlackList = ipv4BlackList;
Erik Kline8d1fe542018-03-12 23:18:58 +09001414 apfFilter = setupApfFilter(ipClientCallback, config);
1415 program = ipClientCallback.getApfProgram();
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001416
1417 // Verify that IPv4 frame will be dropped
1418 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1419 assertDrop(program, packet.array());
1420
1421 // Verify that IPv6 frame will pass
1422 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
1423 assertPass(program, packet.array());
1424
1425 // Now let us have both IPv4 and IPv6 in the black list
Erik Kline8d1fe542018-03-12 23:18:58 +09001426 ipClientCallback.resetApfProgramWait();
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001427 apfFilter.shutdown();
Hugo Benichi72166362017-10-13 16:32:20 +09001428 config.ethTypeBlackList = ipv4Ipv6BlackList;
Erik Kline8d1fe542018-03-12 23:18:58 +09001429 apfFilter = setupApfFilter(ipClientCallback, config);
1430 program = ipClientCallback.getApfProgram();
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001431
1432 // Verify that IPv4 frame will be dropped
1433 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
1434 assertDrop(program, packet.array());
1435
1436 // Verify that IPv6 frame will be dropped
1437 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
1438 assertDrop(program, packet.array());
1439
1440 apfFilter.shutdown();
1441 }
1442
Erik Kline8d1fe542018-03-12 23:18:58 +09001443 private byte[] getProgram(MockIpClientCallback cb, ApfFilter filter, LinkProperties lp) {
Hugo Benichi38db9762016-07-12 15:08:50 +09001444 cb.resetApfProgramWait();
1445 filter.setLinkProperties(lp);
1446 return cb.getApfProgram();
1447 }
1448
1449 private void verifyArpFilter(byte[] program, int filterResult) {
1450 // Verify ARP request packet
Hugo Benichi961ca492016-09-02 11:04:34 +09001451 assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
1452 assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
1453 assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
Hugo Benichi38db9762016-07-12 15:08:50 +09001454
Aaron Huang04ed6a32018-11-15 20:30:46 +08001455 // Verify ARP reply packets from different source ip
1456 assertDrop(program, arpReply(IPV4_ANY_HOST_ADDR, IPV4_ANY_HOST_ADDR));
1457 assertPass(program, arpReply(ANOTHER_IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
1458 assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR1, IPV4_ANY_HOST_ADDR));
1459 assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR2, IPV4_ANY_HOST_ADDR));
1460
Hugo Benichi38db9762016-07-12 15:08:50 +09001461 // Verify unicast ARP reply packet is always accepted.
Aaron Huang04ed6a32018-11-15 20:30:46 +08001462 assertPass(program, arpReply(IPV4_SOURCE_ADDR, MOCK_IPV4_ADDR));
1463 assertPass(program, arpReply(IPV4_SOURCE_ADDR, ANOTHER_IPV4_ADDR));
1464 assertPass(program, arpReply(IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
Hugo Benichi38db9762016-07-12 15:08:50 +09001465
1466 // Verify GARP reply packets are always filtered
Hugo Benichi961ca492016-09-02 11:04:34 +09001467 assertDrop(program, garpReply());
Paul Jensen9132f342016-04-13 15:00:26 -04001468 }
1469
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001470 @Test
Paul Jensen9132f342016-04-13 15:00:26 -04001471 public void testApfFilterArp() throws Exception {
Erik Kline8d1fe542018-03-12 23:18:58 +09001472 MockIpClientCallback ipClientCallback = new MockIpClientCallback();
Hugo Benichi72166362017-10-13 16:32:20 +09001473 ApfConfiguration config = getDefaultConfig();
1474 config.multicastFilter = DROP_MULTICAST;
1475 config.ieee802_3Filter = DROP_802_3_FRAMES;
Erik Kline8d1fe542018-03-12 23:18:58 +09001476 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
Paul Jensen9132f342016-04-13 15:00:26 -04001477
Hugo Benichi38db9762016-07-12 15:08:50 +09001478 // Verify initially ARP request filter is off, and GARP filter is on.
Erik Kline8d1fe542018-03-12 23:18:58 +09001479 verifyArpFilter(ipClientCallback.getApfProgram(), PASS);
Paul Jensen9132f342016-04-13 15:00:26 -04001480
1481 // Inform ApfFilter of our address and verify ARP filtering is on
Hugo Benichi38db9762016-07-12 15:08:50 +09001482 LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
Paul Jensen9132f342016-04-13 15:00:26 -04001483 LinkProperties lp = new LinkProperties();
Hugo Benichi38db9762016-07-12 15:08:50 +09001484 assertTrue(lp.addLinkAddress(linkAddress));
Erik Kline8d1fe542018-03-12 23:18:58 +09001485 verifyArpFilter(getProgram(ipClientCallback, apfFilter, lp), DROP);
Paul Jensen9132f342016-04-13 15:00:26 -04001486
1487 // Inform ApfFilter of loss of IP and verify ARP filtering is off
Erik Kline8d1fe542018-03-12 23:18:58 +09001488 verifyArpFilter(getProgram(ipClientCallback, apfFilter, new LinkProperties()), PASS);
Paul Jensen9132f342016-04-13 15:00:26 -04001489
1490 apfFilter.shutdown();
1491 }
1492
Aaron Huang04ed6a32018-11-15 20:30:46 +08001493 private static byte[] arpReply(byte[] sip, byte[] tip) {
Hugo Benichi38db9762016-07-12 15:08:50 +09001494 ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1495 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
Hugo Benichi961ca492016-09-02 11:04:34 +09001496 put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001497 put(packet, ARP_SOURCE_IP_ADDRESS_OFFSET, sip);
Hugo Benichi961ca492016-09-02 11:04:34 +09001498 put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
Hugo Benichi38db9762016-07-12 15:08:50 +09001499 return packet.array();
1500 }
1501
Aaron Huang04ed6a32018-11-15 20:30:46 +08001502 private static byte[] arpRequestBroadcast(byte[] tip) {
Hugo Benichi38db9762016-07-12 15:08:50 +09001503 ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1504 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001505 put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
1506 put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REQUEST_HEADER);
Hugo Benichi961ca492016-09-02 11:04:34 +09001507 put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
Hugo Benichi38db9762016-07-12 15:08:50 +09001508 return packet.array();
1509 }
1510
1511 private static byte[] garpReply() {
1512 ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1513 packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
Hugo Benichi961ca492016-09-02 11:04:34 +09001514 put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
1515 put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
1516 put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR);
Hugo Benichi38db9762016-07-12 15:08:50 +09001517 return packet.array();
1518 }
1519
Aaron Huanga63c40e2019-01-15 16:53:51 +08001520 private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 5};
1521 private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 6};
1522 private static final byte[] IPV4_ANOTHER_ADDR = {10, 0 , 0, 7};
1523 private static final byte[] IPV6_KEEPALIVE_SRC_ADDR =
1524 {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf1};
1525 private static final byte[] IPV6_KEEPALIVE_DST_ADDR =
1526 {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf2};
1527 private static final byte[] IPV6_ANOTHER_ADDR =
1528 {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf5};
1529
1530 @Test
1531 public void testApfFilterKeepaliveAck() throws Exception {
1532 final MockIpClientCallback cb = new MockIpClientCallback();
1533 final ApfConfiguration config = getDefaultConfig();
1534 config.multicastFilter = DROP_MULTICAST;
1535 config.ieee802_3Filter = DROP_802_3_FRAMES;
1536 final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
1537 byte[] program;
1538 final int srcPort = 12345;
1539 final int dstPort = 54321;
1540 final int seqNum = 2123456789;
1541 final int ackNum = 1234567890;
1542 final int anotherSrcPort = 23456;
1543 final int anotherDstPort = 65432;
1544 final int anotherSeqNum = 2123456780;
1545 final int anotherAckNum = 1123456789;
1546 final int slot1 = 1;
1547 final int slot2 = 2;
1548 final int window = 14480;
1549 final int windowScale = 4;
1550
1551 // src: 10.0.0.5, port: 12345
1552 // dst: 10.0.0.6, port: 54321
1553 InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR);
1554 InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR);
1555
Xiao Ma6b4de8f2019-02-15 19:18:21 +09001556 final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable();
1557 parcel.srcAddress = srcAddr.getAddress();
1558 parcel.srcPort = srcPort;
1559 parcel.dstAddress = dstAddr.getAddress();
1560 parcel.dstPort = dstPort;
1561 parcel.seq = seqNum;
1562 parcel.ack = ackNum;
Aaron Huanga63c40e2019-01-15 16:53:51 +08001563
Mark Chiend0f8ca82019-04-29 09:46:04 -07001564 apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001565 program = cb.getApfProgram();
1566
1567 // Verify IPv4 keepalive ack packet is dropped
1568 // src: 10.0.0.6, port: 54321
1569 // dst: 10.0.0.5, port: 12345
1570 assertDrop(program,
1571 ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
1572 dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
1573 // Verify IPv4 non-keepalive ack packet from the same source address is passed
1574 assertPass(program,
1575 ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
1576 dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */));
1577 assertPass(program,
1578 ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
1579 dstPort, srcPort, ackNum, seqNum + 1, 10 /* dataLength */));
1580 // Verify IPv4 packet from another address is passed
1581 assertPass(program,
1582 ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
Xiao Mad36a89c2019-02-10 14:52:37 +09001583 anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
Aaron Huanga63c40e2019-01-15 16:53:51 +08001584
1585 // Remove IPv4 keepalive filter
1586 apfFilter.removeKeepalivePacketFilter(slot1);
1587
1588 try {
1589 // src: 2404:0:0:0:0:0:faf1, port: 12345
1590 // dst: 2404:0:0:0:0:0:faf2, port: 54321
1591 srcAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_SRC_ADDR);
1592 dstAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_DST_ADDR);
Xiao Ma6b4de8f2019-02-15 19:18:21 +09001593
1594 final TcpKeepalivePacketDataParcelable ipv6Parcel =
1595 new TcpKeepalivePacketDataParcelable();
1596 ipv6Parcel.srcAddress = srcAddr.getAddress();
1597 ipv6Parcel.srcPort = srcPort;
1598 ipv6Parcel.dstAddress = dstAddr.getAddress();
1599 ipv6Parcel.dstPort = dstPort;
1600 ipv6Parcel.seq = seqNum;
1601 ipv6Parcel.ack = ackNum;
1602
Mark Chiend0f8ca82019-04-29 09:46:04 -07001603 apfFilter.addTcpKeepalivePacketFilter(slot1, ipv6Parcel);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001604 program = cb.getApfProgram();
1605
1606 // Verify IPv6 keepalive ack packet is dropped
1607 // src: 2404:0:0:0:0:0:faf2, port: 54321
1608 // dst: 2404:0:0:0:0:0:faf1, port: 12345
1609 assertDrop(program,
1610 ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
1611 dstPort, srcPort, ackNum, seqNum + 1));
1612 // Verify IPv6 non-keepalive ack packet from the same source address is passed
1613 assertPass(program,
1614 ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
1615 dstPort, srcPort, ackNum + 100, seqNum));
1616 // Verify IPv6 packet from another address is passed
1617 assertPass(program,
1618 ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
1619 anotherDstPort, anotherSeqNum, anotherAckNum));
1620
1621 // Remove IPv6 keepalive filter
1622 apfFilter.removeKeepalivePacketFilter(slot1);
1623
1624 // Verify multiple filters
Mark Chiend0f8ca82019-04-29 09:46:04 -07001625 apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
1626 apfFilter.addTcpKeepalivePacketFilter(slot2, ipv6Parcel);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001627 program = cb.getApfProgram();
1628
1629 // Verify IPv4 keepalive ack packet is dropped
1630 // src: 10.0.0.6, port: 54321
1631 // dst: 10.0.0.5, port: 12345
1632 assertDrop(program,
1633 ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
Xiao Mad36a89c2019-02-10 14:52:37 +09001634 dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
Aaron Huanga63c40e2019-01-15 16:53:51 +08001635 // Verify IPv4 non-keepalive ack packet from the same source address is passed
1636 assertPass(program,
1637 ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
Xiao Mad36a89c2019-02-10 14:52:37 +09001638 dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */));
Aaron Huanga63c40e2019-01-15 16:53:51 +08001639 // Verify IPv4 packet from another address is passed
1640 assertPass(program,
1641 ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
Xiao Mad36a89c2019-02-10 14:52:37 +09001642 anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
Aaron Huanga63c40e2019-01-15 16:53:51 +08001643
1644 // Verify IPv6 keepalive ack packet is dropped
1645 // src: 2404:0:0:0:0:0:faf2, port: 54321
1646 // dst: 2404:0:0:0:0:0:faf1, port: 12345
1647 assertDrop(program,
1648 ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
1649 dstPort, srcPort, ackNum, seqNum + 1));
1650 // Verify IPv6 non-keepalive ack packet from the same source address is passed
1651 assertPass(program,
1652 ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
1653 dstPort, srcPort, ackNum + 100, seqNum));
1654 // Verify IPv6 packet from another address is passed
1655 assertPass(program,
1656 ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
1657 anotherDstPort, anotherSeqNum, anotherAckNum));
1658
1659 // Remove keepalive filters
1660 apfFilter.removeKeepalivePacketFilter(slot1);
1661 apfFilter.removeKeepalivePacketFilter(slot2);
Xiao Ma6b4de8f2019-02-15 19:18:21 +09001662 } catch (UnsupportedOperationException e) {
Aaron Huanga63c40e2019-01-15 16:53:51 +08001663 // TODO: support V6 packets
1664 }
1665
1666 program = cb.getApfProgram();
1667
1668 // Verify IPv4, IPv6 packets are passed
1669 assertPass(program,
1670 ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
Xiao Mad36a89c2019-02-10 14:52:37 +09001671 dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
Aaron Huanga63c40e2019-01-15 16:53:51 +08001672 assertPass(program,
1673 ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
1674 dstPort, srcPort, ackNum, seqNum + 1));
1675 assertPass(program,
1676 ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, srcPort,
Xiao Mad36a89c2019-02-10 14:52:37 +09001677 dstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
Aaron Huanga63c40e2019-01-15 16:53:51 +08001678 assertPass(program,
1679 ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, srcPort,
1680 dstPort, anotherSeqNum, anotherAckNum));
1681
1682 apfFilter.shutdown();
1683 }
1684
Xiao Mad36a89c2019-02-10 14:52:37 +09001685 private static byte[] ipv4Packet(byte[] sip, byte[] dip, int sport,
1686 int dport, int seq, int ack, int dataLength) {
1687 final int totalLength = dataLength + IPV4_HEADER_LEN + IPV4_TCP_HEADER_LEN;
1688
1689 ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]);
1690
1691 // ether type
Aaron Huanga63c40e2019-01-15 16:53:51 +08001692 packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
Xiao Mad36a89c2019-02-10 14:52:37 +09001693
1694 // IPv4 header
Aaron Huanga63c40e2019-01-15 16:53:51 +08001695 packet.put(IPV4_VERSION_IHL_OFFSET, (byte) 0x45);
Xiao Mad36a89c2019-02-10 14:52:37 +09001696 packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
1697 packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_TCP);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001698 put(packet, IPV4_SRC_ADDR_OFFSET, sip);
Xiao Mad36a89c2019-02-10 14:52:37 +09001699 put(packet, IPV4_DEST_ADDR_OFFSET, dip);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001700 packet.putShort(IPV4_TCP_SRC_PORT_OFFSET, (short) sport);
1701 packet.putShort(IPV4_TCP_DEST_PORT_OFFSET, (short) dport);
1702 packet.putInt(IPV4_TCP_SEQ_NUM_OFFSET, seq);
1703 packet.putInt(IPV4_TCP_ACK_NUM_OFFSET, ack);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001704
Xiao Mad36a89c2019-02-10 14:52:37 +09001705 // TCP header length 5(20 bytes), reserved 3 bits, NS=0
Aaron Huanga63c40e2019-01-15 16:53:51 +08001706 packet.put(IPV4_TCP_HEADER_LENGTH_OFFSET, (byte) 0x50);
Xiao Mad36a89c2019-02-10 14:52:37 +09001707 // TCP flags: ACK set
1708 packet.put(IPV4_TCP_HEADER_FLAG_OFFSET, (byte) 0x10);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001709 return packet.array();
1710 }
1711
1712 private static byte[] ipv6Packet(byte[] sip, byte[] tip, int sport,
1713 int dport, int seq, int ack) {
1714 ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
1715 packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
1716 put(packet, IPV6_SRC_ADDR_OFFSET, sip);
1717 put(packet, IPV6_DEST_ADDR_OFFSET, tip);
1718 packet.putShort(IPV6_TCP_SRC_PORT_OFFSET, (short) sport);
1719 packet.putShort(IPV6_TCP_DEST_PORT_OFFSET, (short) dport);
1720 packet.putInt(IPV6_TCP_SEQ_NUM_OFFSET, seq);
1721 packet.putInt(IPV6_TCP_ACK_NUM_OFFSET, ack);
1722 return packet.array();
1723 }
1724
Aaron Huang56f9e412019-05-13 05:13:09 -07001725 @Test
1726 public void testApfFilterNattKeepalivePacket() throws Exception {
1727 final MockIpClientCallback cb = new MockIpClientCallback();
1728 final ApfConfiguration config = getDefaultConfig();
1729 config.multicastFilter = DROP_MULTICAST;
1730 config.ieee802_3Filter = DROP_802_3_FRAMES;
1731 final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
1732 byte[] program;
1733 final int srcPort = 1024;
1734 final int dstPort = 4500;
1735 final int slot1 = 1;
1736 // NAT-T keepalive
Aaron Huang4a40e912019-05-15 00:17:35 -07001737 final byte[] kaPayload = {(byte) 0xff};
1738 final byte[] nonKaPayload = {(byte) 0xfe};
Aaron Huang56f9e412019-05-13 05:13:09 -07001739
1740 // src: 10.0.0.5, port: 1024
1741 // dst: 10.0.0.6, port: 4500
1742 InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR);
1743 InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR);
1744
1745 final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable();
1746 parcel.srcAddress = srcAddr.getAddress();
1747 parcel.srcPort = srcPort;
1748 parcel.dstAddress = dstAddr.getAddress();
1749 parcel.dstPort = dstPort;
1750
1751 apfFilter.addNattKeepalivePacketFilter(slot1, parcel);
1752 program = cb.getApfProgram();
1753
1754 // Verify IPv4 keepalive packet is dropped
1755 // src: 10.0.0.6, port: 4500
1756 // dst: 10.0.0.5, port: 1024
Aaron Huang4a40e912019-05-15 00:17:35 -07001757 byte[] pkt = ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR,
Aaron Huang56f9e412019-05-13 05:13:09 -07001758 IPV4_KEEPALIVE_SRC_ADDR, dstPort, srcPort, 1 /* dataLength */);
Aaron Huang4a40e912019-05-15 00:17:35 -07001759 System.arraycopy(kaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, kaPayload.length);
1760 assertDrop(program, pkt);
1761
1762 // Verify a packet with payload length 1 byte but it is not 0xff will pass the filter.
1763 System.arraycopy(nonKaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, nonKaPayload.length);
1764 assertPass(program, pkt);
1765
1766 // Verify IPv4 non-keepalive response packet from the same source address is passed
Aaron Huang56f9e412019-05-13 05:13:09 -07001767 assertPass(program,
1768 ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
1769 dstPort, srcPort, 10 /* dataLength */));
Aaron Huang4a40e912019-05-15 00:17:35 -07001770
1771 // Verify IPv4 non-keepalive response packet from other source address is passed
Aaron Huang56f9e412019-05-13 05:13:09 -07001772 assertPass(program,
1773 ipv4UdpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
1774 dstPort, srcPort, 10 /* dataLength */));
1775
1776 apfFilter.removeKeepalivePacketFilter(slot1);
1777 apfFilter.shutdown();
1778 }
1779
1780 private static byte[] ipv4UdpPacket(byte[] sip, byte[] dip, int sport,
1781 int dport, int dataLength) {
1782 final int totalLength = dataLength + IPV4_HEADER_LEN + UDP_HEADER_LEN;
1783 final int udpLength = UDP_HEADER_LEN + dataLength;
1784 ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]);
1785
1786 // ether type
1787 packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
1788
1789 // IPv4 header
1790 packet.put(IPV4_VERSION_IHL_OFFSET, (byte) 0x45);
1791 packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
1792 packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_UDP);
1793 put(packet, IPV4_SRC_ADDR_OFFSET, sip);
1794 put(packet, IPV4_DEST_ADDR_OFFSET, dip);
1795 packet.putShort(IPV4_UDP_SRC_PORT_OFFSET, (short) sport);
1796 packet.putShort(IPV4_UDP_DEST_PORT_OFFSET, (short) dport);
1797 packet.putShort(IPV4_UDP_LENGTH_OFFSET, (short) udpLength);
1798
1799 return packet.array();
1800 }
1801
Erik Kline8d1fe542018-03-12 23:18:58 +09001802 // Verify that the last program pushed to the IpClient.Callback properly filters the
Paul Jensen9132f342016-04-13 15:00:26 -04001803 // given packet for the given lifetime.
Hugo Benichi4456f332016-12-19 14:50:52 +09001804 private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
1805 final int FRACTION_OF_LIFETIME = 6;
1806 final int ageLimit = lifetime / FRACTION_OF_LIFETIME;
Paul Jensen9132f342016-04-13 15:00:26 -04001807
Hugo Benichi4456f332016-12-19 14:50:52 +09001808 // Verify new program should drop RA for 1/6th its lifetime and pass afterwards.
Hugo Benichi961ca492016-09-02 11:04:34 +09001809 assertDrop(program, packet.array());
Hugo Benichi4456f332016-12-19 14:50:52 +09001810 assertDrop(program, packet.array(), ageLimit);
1811 assertPass(program, packet.array(), ageLimit + 1);
Paul Jensen9132f342016-04-13 15:00:26 -04001812 assertPass(program, packet.array(), lifetime);
Paul Jensen9132f342016-04-13 15:00:26 -04001813 // Verify RA checksum is ignored
Hugo Benichi4456f332016-12-19 14:50:52 +09001814 final short originalChecksum = packet.getShort(ICMP6_RA_CHECKSUM_OFFSET);
Paul Jensen9132f342016-04-13 15:00:26 -04001815 packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
Hugo Benichi961ca492016-09-02 11:04:34 +09001816 assertDrop(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001817 packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
Hugo Benichi961ca492016-09-02 11:04:34 +09001818 assertDrop(program, packet.array());
Hugo Benichi4456f332016-12-19 14:50:52 +09001819 packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum);
Paul Jensen9132f342016-04-13 15:00:26 -04001820
1821 // Verify other changes to RA make it not match filter
Hugo Benichi4456f332016-12-19 14:50:52 +09001822 final byte originalFirstByte = packet.get(0);
Paul Jensen9132f342016-04-13 15:00:26 -04001823 packet.put(0, (byte)-1);
Hugo Benichi961ca492016-09-02 11:04:34 +09001824 assertPass(program, packet.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001825 packet.put(0, (byte)0);
Hugo Benichi961ca492016-09-02 11:04:34 +09001826 assertDrop(program, packet.array());
Hugo Benichi4456f332016-12-19 14:50:52 +09001827 packet.put(0, originalFirstByte);
Paul Jensen9132f342016-04-13 15:00:26 -04001828 }
1829
1830 // Test that when ApfFilter is shown the given packet, it generates a program to filter it
1831 // for the given lifetime.
Erik Kline8d1fe542018-03-12 23:18:58 +09001832 private void verifyRaLifetime(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
Paul Jensen9132f342016-04-13 15:00:26 -04001833 ByteBuffer packet, int lifetime) throws IOException, ErrnoException {
1834 // Verify new program generated if ApfFilter witnesses RA
Erik Kline8d1fe542018-03-12 23:18:58 +09001835 ipClientCallback.resetApfProgramWait();
Paul Jensen9132f342016-04-13 15:00:26 -04001836 apfFilter.pretendPacketReceived(packet.array());
Erik Kline8d1fe542018-03-12 23:18:58 +09001837 byte[] program = ipClientCallback.getApfProgram();
Hugo Benichi4456f332016-12-19 14:50:52 +09001838 verifyRaLifetime(program, packet, lifetime);
Paul Jensen9132f342016-04-13 15:00:26 -04001839 }
1840
Hugo Benichi6ccd51a2016-07-04 09:22:30 +09001841 private void verifyRaEvent(RaEvent expected) {
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +09001842 ArgumentCaptor<IpConnectivityLog.Event> captor =
1843 ArgumentCaptor.forClass(IpConnectivityLog.Event.class);
Hugo Benichi6ccd51a2016-07-04 09:22:30 +09001844 verify(mLog, atLeastOnce()).log(captor.capture());
1845 RaEvent got = lastRaEvent(captor.getAllValues());
1846 if (!raEventEquals(expected, got)) {
1847 assertEquals(expected, got); // fail for printing an assertion error message.
1848 }
1849 }
1850
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +09001851 private RaEvent lastRaEvent(List<IpConnectivityLog.Event> events) {
Hugo Benichi6ccd51a2016-07-04 09:22:30 +09001852 RaEvent got = null;
1853 for (Parcelable ev : events) {
1854 if (ev instanceof RaEvent) {
1855 got = (RaEvent) ev;
1856 }
1857 }
1858 return got;
1859 }
1860
1861 private boolean raEventEquals(RaEvent ev1, RaEvent ev2) {
1862 return (ev1 != null) && (ev2 != null)
1863 && (ev1.routerLifetime == ev2.routerLifetime)
1864 && (ev1.prefixValidLifetime == ev2.prefixValidLifetime)
1865 && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime)
1866 && (ev1.routeInfoLifetime == ev2.routeInfoLifetime)
1867 && (ev1.rdnssLifetime == ev2.rdnssLifetime)
1868 && (ev1.dnsslLifetime == ev2.dnsslLifetime);
1869 }
1870
Erik Kline8d1fe542018-03-12 23:18:58 +09001871 private void assertInvalidRa(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
Lorenzo Colitti8995d852016-06-23 15:24:46 +09001872 ByteBuffer packet) throws IOException, ErrnoException {
Erik Kline8d1fe542018-03-12 23:18:58 +09001873 ipClientCallback.resetApfProgramWait();
Lorenzo Colitti8995d852016-06-23 15:24:46 +09001874 apfFilter.pretendPacketReceived(packet.array());
Erik Kline8d1fe542018-03-12 23:18:58 +09001875 ipClientCallback.assertNoProgramUpdate();
Lorenzo Colitti8995d852016-06-23 15:24:46 +09001876 }
1877
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001878 @Test
Paul Jensen9132f342016-04-13 15:00:26 -04001879 public void testApfFilterRa() throws Exception {
Erik Kline8d1fe542018-03-12 23:18:58 +09001880 MockIpClientCallback ipClientCallback = new MockIpClientCallback();
Hugo Benichi72166362017-10-13 16:32:20 +09001881 ApfConfiguration config = getDefaultConfig();
1882 config.multicastFilter = DROP_MULTICAST;
1883 config.ieee802_3Filter = DROP_802_3_FRAMES;
Erik Kline8d1fe542018-03-12 23:18:58 +09001884 TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
1885 byte[] program = ipClientCallback.getApfProgram();
Paul Jensen9132f342016-04-13 15:00:26 -04001886
Hugo Benichi4456f332016-12-19 14:50:52 +09001887 final int ROUTER_LIFETIME = 1000;
1888 final int PREFIX_VALID_LIFETIME = 200;
1889 final int PREFIX_PREFERRED_LIFETIME = 100;
1890 final int RDNSS_LIFETIME = 300;
1891 final int ROUTE_LIFETIME = 400;
1892 // Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000.
1893 final int DNSSL_LIFETIME = 2000;
Joel Scherpelz967dec72017-05-24 15:08:39 +09001894 final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN;
1895 // IPv6, traffic class = 0, flow label = 0x12345
1896 final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;
Hugo Benichi4456f332016-12-19 14:50:52 +09001897
Paul Jensen9132f342016-04-13 15:00:26 -04001898 // Verify RA is passed the first time
1899 ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
1900 basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
Joel Scherpelz967dec72017-05-24 15:08:39 +09001901 basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
1902 VERSION_TRAFFIC_CLASS_FLOW_LABEL);
Paul Jensen9132f342016-04-13 15:00:26 -04001903 basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
1904 basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
Hugo Benichi4456f332016-12-19 14:50:52 +09001905 basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)ROUTER_LIFETIME);
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001906 basePacket.position(IPV6_DEST_ADDR_OFFSET);
1907 basePacket.put(IPV6_ALL_NODES_ADDRESS);
Hugo Benichi961ca492016-09-02 11:04:34 +09001908 assertPass(program, basePacket.array());
Paul Jensen9132f342016-04-13 15:00:26 -04001909
Erik Kline8d1fe542018-03-12 23:18:58 +09001910 verifyRaLifetime(apfFilter, ipClientCallback, basePacket, ROUTER_LIFETIME);
Hugo Benichi4456f332016-12-19 14:50:52 +09001911 verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
Paul Jensen9132f342016-04-13 15:00:26 -04001912
Joel Scherpelz967dec72017-05-24 15:08:39 +09001913 ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
1914 basePacket.clear();
1915 newFlowLabelPacket.put(basePacket);
1916 // Check that changes are ignored in every byte of the flow label.
1917 newFlowLabelPacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
1918 VERSION_TRAFFIC_CLASS_FLOW_LABEL + 0x11111);
1919
Lorenzo Colitti8995d852016-06-23 15:24:46 +09001920 // Ensure zero-length options cause the packet to be silently skipped.
1921 // Do this before we test other packets. http://b/29586253
1922 ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(
1923 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
1924 basePacket.clear();
1925 zeroLengthOptionPacket.put(basePacket);
1926 zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
1927 zeroLengthOptionPacket.put((byte)0);
Erik Kline8d1fe542018-03-12 23:18:58 +09001928 assertInvalidRa(apfFilter, ipClientCallback, zeroLengthOptionPacket);
Lorenzo Colitti8995d852016-06-23 15:24:46 +09001929
Paul Jensen9132f342016-04-13 15:00:26 -04001930 // Generate several RAs with different options and lifetimes, and verify when
1931 // ApfFilter is shown these packets, it generates programs to filter them for the
1932 // appropriate lifetime.
1933 ByteBuffer prefixOptionPacket = ByteBuffer.wrap(
1934 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]);
1935 basePacket.clear();
1936 prefixOptionPacket.put(basePacket);
1937 prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
1938 prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8));
1939 prefixOptionPacket.putInt(
Hugo Benichi4456f332016-12-19 14:50:52 +09001940 ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
1941 PREFIX_PREFERRED_LIFETIME);
Paul Jensen9132f342016-04-13 15:00:26 -04001942 prefixOptionPacket.putInt(
Hugo Benichi4456f332016-12-19 14:50:52 +09001943 ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
1944 PREFIX_VALID_LIFETIME);
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001945 verifyRaLifetime(
Erik Kline8d1fe542018-03-12 23:18:58 +09001946 apfFilter, ipClientCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
Hugo Benichi4456f332016-12-19 14:50:52 +09001947 verifyRaEvent(new RaEvent(
1948 ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1));
Paul Jensen9132f342016-04-13 15:00:26 -04001949
1950 ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
1951 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
1952 basePacket.clear();
1953 rdnssOptionPacket.put(basePacket);
1954 rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE);
1955 rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
1956 rdnssOptionPacket.putInt(
Hugo Benichi4456f332016-12-19 14:50:52 +09001957 ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, RDNSS_LIFETIME);
Erik Kline8d1fe542018-03-12 23:18:58 +09001958 verifyRaLifetime(apfFilter, ipClientCallback, rdnssOptionPacket, RDNSS_LIFETIME);
Hugo Benichi4456f332016-12-19 14:50:52 +09001959 verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
Paul Jensen9132f342016-04-13 15:00:26 -04001960
1961 ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
1962 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
1963 basePacket.clear();
1964 routeInfoOptionPacket.put(basePacket);
1965 routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE);
1966 routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
1967 routeInfoOptionPacket.putInt(
Hugo Benichi4456f332016-12-19 14:50:52 +09001968 ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, ROUTE_LIFETIME);
Erik Kline8d1fe542018-03-12 23:18:58 +09001969 verifyRaLifetime(apfFilter, ipClientCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
Hugo Benichi4456f332016-12-19 14:50:52 +09001970 verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
Paul Jensen9132f342016-04-13 15:00:26 -04001971
1972 ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
1973 new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
1974 basePacket.clear();
1975 dnsslOptionPacket.put(basePacket);
1976 dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
1977 dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
1978 dnsslOptionPacket.putInt(
Hugo Benichi4456f332016-12-19 14:50:52 +09001979 ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME);
Erik Kline8d1fe542018-03-12 23:18:58 +09001980 verifyRaLifetime(apfFilter, ipClientCallback, dnsslOptionPacket, ROUTER_LIFETIME);
Hugo Benichi4456f332016-12-19 14:50:52 +09001981 verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME));
Paul Jensen9132f342016-04-13 15:00:26 -04001982
1983 // Verify that current program filters all five RAs:
Erik Kline8d1fe542018-03-12 23:18:58 +09001984 program = ipClientCallback.getApfProgram();
Hugo Benichi4456f332016-12-19 14:50:52 +09001985 verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
Joel Scherpelz967dec72017-05-24 15:08:39 +09001986 verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME);
Hugo Benichi4456f332016-12-19 14:50:52 +09001987 verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
1988 verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
1989 verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
1990 verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME);
Paul Jensen9132f342016-04-13 15:00:26 -04001991
1992 apfFilter.shutdown();
1993 }
1994
1995 /**
1996 * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
1997 * copy that resource into the app's data directory and return the path to it.
1998 */
1999 private String stageFile(int rawId) throws Exception {
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002000 File file = new File(InstrumentationRegistry.getContext().getFilesDir(), "staged_file");
Paul Jensen9132f342016-04-13 15:00:26 -04002001 new File(file.getParent()).mkdirs();
2002 InputStream in = null;
2003 OutputStream out = null;
2004 try {
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002005 in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
Paul Jensen9132f342016-04-13 15:00:26 -04002006 out = new FileOutputStream(file);
2007 Streams.copy(in, out);
2008 } finally {
2009 if (in != null) in.close();
2010 if (out != null) out.close();
2011 }
2012 return file.getAbsolutePath();
2013 }
2014
Hugo Benichi961ca492016-09-02 11:04:34 +09002015 private static void put(ByteBuffer buffer, int position, byte[] bytes) {
2016 final int original = buffer.position();
2017 buffer.position(position);
2018 buffer.put(bytes);
2019 buffer.position(original);
2020 }
2021
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002022 @Test
Hugo Benichi0668a612016-10-06 15:19:36 +09002023 public void testRaParsing() throws Exception {
2024 final int maxRandomPacketSize = 512;
2025 final Random r = new Random();
Erik Kline8d1fe542018-03-12 23:18:58 +09002026 MockIpClientCallback cb = new MockIpClientCallback();
Hugo Benichi72166362017-10-13 16:32:20 +09002027 ApfConfiguration config = getDefaultConfig();
2028 config.multicastFilter = DROP_MULTICAST;
2029 config.ieee802_3Filter = DROP_802_3_FRAMES;
Bernie Innocentie2c70f82018-03-28 20:11:49 +09002030 TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
Hugo Benichi0668a612016-10-06 15:19:36 +09002031 for (int i = 0; i < 1000; i++) {
2032 byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
2033 r.nextBytes(packet);
2034 try {
2035 apfFilter.new Ra(packet, packet.length);
2036 } catch (ApfFilter.InvalidRaException e) {
2037 } catch (Exception e) {
2038 throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
2039 }
2040 }
2041 }
2042
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002043 @Test
Hugo Benichi0668a612016-10-06 15:19:36 +09002044 public void testRaProcessing() throws Exception {
2045 final int maxRandomPacketSize = 512;
2046 final Random r = new Random();
Erik Kline8d1fe542018-03-12 23:18:58 +09002047 MockIpClientCallback cb = new MockIpClientCallback();
Hugo Benichi72166362017-10-13 16:32:20 +09002048 ApfConfiguration config = getDefaultConfig();
2049 config.multicastFilter = DROP_MULTICAST;
2050 config.ieee802_3Filter = DROP_802_3_FRAMES;
Bernie Innocentie2c70f82018-03-28 20:11:49 +09002051 TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
Hugo Benichi0668a612016-10-06 15:19:36 +09002052 for (int i = 0; i < 1000; i++) {
2053 byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
2054 r.nextBytes(packet);
2055 try {
2056 apfFilter.processRa(packet, packet.length);
2057 } catch (Exception e) {
2058 throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
2059 }
2060 }
2061 }
2062
Paul Jensen9132f342016-04-13 15:00:26 -04002063 /**
Bernie Innocentia9949e92018-03-22 23:07:47 +09002064 * Call the APF interpreter to run {@code program} on {@code packet} with persistent memory
2065 * segment {@data} pretending the filter was installed {@code filter_age} seconds ago.
Paul Jensen9132f342016-04-13 15:00:26 -04002066 */
Bernie Innocentia9949e92018-03-22 23:07:47 +09002067 private native static int apfSimulate(byte[] program, byte[] packet, byte[] data,
2068 int filter_age);
Paul Jensen9132f342016-04-13 15:00:26 -04002069
2070 /**
2071 * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF
2072 * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d".
2073 */
2074 private native static String compileToBpf(String filter);
2075
2076 /**
2077 * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump
2078 * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and
2079 * at the same time using APF program {@code apf_program}. Return {@code true} if
2080 * both APF and BPF programs filter out exactly the same packets.
2081 */
2082 private native static boolean compareBpfApf(String filter, String pcap_filename,
2083 byte[] apf_program);
Hugo Benichi7d21eae2016-09-02 14:00:29 +09002084
Aaron Huang785e5f12018-10-31 15:57:48 +08002085
2086 /**
2087 * Open packet capture file {@code pcapFilename} and run it through APF filter. Then
2088 * checks whether all the packets are dropped and populates data[] {@code data} with
2089 * the APF counters.
2090 */
2091 private native static boolean dropsAllPackets(byte[] program, byte[] data, String pcapFilename);
2092
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002093 @Test
Hugo Benichi7d21eae2016-09-02 14:00:29 +09002094 public void testBroadcastAddress() throws Exception {
2095 assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
2096 assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
2097 assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22));
2098 assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8));
2099
2100 assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0));
2101 assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32));
2102 assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24));
2103 assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16));
2104 }
2105
2106 public void assertEqualsIp(String expected, int got) throws Exception {
Hugo Benichi495a17b2017-01-12 15:31:05 +09002107 int want = bytesToBEInt(InetAddress.getByName(expected).getAddress());
Hugo Benichi7d21eae2016-09-02 14:00:29 +09002108 assertEquals(want, got);
2109 }
Paul Jensen9132f342016-04-13 15:00:26 -04002110}