summaryrefslogtreecommitdiff
path: root/tests/src/android/net/apf/ApfTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/android/net/apf/ApfTest.java')
-rw-r--r--tests/src/android/net/apf/ApfTest.java2110
1 files changed, 0 insertions, 2110 deletions
diff --git a/tests/src/android/net/apf/ApfTest.java b/tests/src/android/net/apf/ApfTest.java
deleted file mode 100644
index 8f2b968..0000000
--- a/tests/src/android/net/apf/ApfTest.java
+++ /dev/null
@@ -1,2110 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.apf;
-
-import static android.system.OsConstants.AF_UNIX;
-import static android.system.OsConstants.ARPHRD_ETHER;
-import static android.system.OsConstants.ETH_P_ARP;
-import static android.system.OsConstants.ETH_P_IP;
-import static android.system.OsConstants.ETH_P_IPV6;
-import static android.system.OsConstants.IPPROTO_ICMPV6;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_STREAM;
-
-import static com.android.internal.util.BitUtils.bytesToBEInt;
-import static com.android.server.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.NattKeepalivePacketDataParcelable;
-import android.net.TcpKeepalivePacketDataParcelable;
-import android.net.apf.ApfFilter.ApfConfiguration;
-import android.net.apf.ApfGenerator.IllegalInstructionException;
-import android.net.apf.ApfGenerator.Register;
-import android.net.ip.IIpClientCallbacks;
-import android.net.ip.IpClient.IpClientCallbacksWrapper;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.RaEvent;
-import android.net.util.InterfaceParams;
-import android.net.util.SharedLog;
-import android.os.ConditionVariable;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.HexDump;
-import com.android.server.networkstack.tests.R;
-import com.android.server.util.NetworkStackConstants;
-
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.util.List;
-import java.util.Random;
-
-/**
- * Tests for APF program generator and interpreter.
- *
- * Build, install and run with:
- * runtest frameworks-net -c android.net.apf.ApfTest
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ApfTest {
- private static final int TIMEOUT_MS = 500;
- private static final int MIN_APF_VERSION = 2;
-
- @Mock IpConnectivityLog mLog;
- @Mock Context mContext;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- // Load up native shared library containing APF interpreter exposed via JNI.
- System.loadLibrary("networkstacktestsjni");
- }
-
- private static final String TAG = "ApfTest";
- // Expected return codes from APF interpreter.
- private static final int PASS = 1;
- private static final int DROP = 0;
- // Interpreter will just accept packets without link layer headers, so pad fake packet to at
- // least the minimum packet size.
- private static final int MIN_PKT_SIZE = 15;
-
- private static final ApfCapabilities MOCK_APF_CAPABILITIES =
- new ApfCapabilities(2, 1700, ARPHRD_ETHER);
-
- private static final boolean DROP_MULTICAST = true;
- private static final boolean ALLOW_MULTICAST = false;
-
- private static final boolean DROP_802_3_FRAMES = true;
- private static final boolean ALLOW_802_3_FRAMES = false;
-
- // Constants for opcode encoding
- private static final byte LI_OP = (byte)(13 << 3);
- private static final byte LDDW_OP = (byte)(22 << 3);
- private static final byte STDW_OP = (byte)(23 << 3);
- private static final byte SIZE0 = (byte)(0 << 1);
- private static final byte SIZE8 = (byte)(1 << 1);
- private static final byte SIZE16 = (byte)(2 << 1);
- private static final byte SIZE32 = (byte)(3 << 1);
- private static final byte R1 = 1;
-
- private static ApfConfiguration getDefaultConfig() {
- ApfFilter.ApfConfiguration config = new ApfConfiguration();
- config.apfCapabilities = MOCK_APF_CAPABILITIES;
- config.multicastFilter = ALLOW_MULTICAST;
- config.ieee802_3Filter = ALLOW_802_3_FRAMES;
- config.ethTypeBlackList = new int[0];
- return config;
- }
-
- private static String label(int code) {
- switch (code) {
- case PASS: return "PASS";
- case DROP: return "DROP";
- default: return "UNKNOWN";
- }
- }
-
- private static void assertReturnCodesEqual(int expected, int got) {
- assertEquals(label(expected), label(got));
- }
-
- private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
- assertReturnCodesEqual(expected, apfSimulate(program, packet, null, filterAge));
- }
-
- private void assertVerdict(int expected, byte[] program, byte[] packet) {
- assertReturnCodesEqual(expected, apfSimulate(program, packet, null, 0));
- }
-
- private void assertPass(byte[] program, byte[] packet, int filterAge) {
- assertVerdict(PASS, program, packet, filterAge);
- }
-
- private void assertPass(byte[] program, byte[] packet) {
- assertVerdict(PASS, program, packet);
- }
-
- private void assertDrop(byte[] program, byte[] packet, int filterAge) {
- assertVerdict(DROP, program, packet, filterAge);
- }
-
- private void assertDrop(byte[] program, byte[] packet) {
- assertVerdict(DROP, program, packet);
- }
-
- private void assertProgramEquals(byte[] expected, byte[] program) throws AssertionError {
- // assertArrayEquals() would only print one byte, making debugging difficult.
- if (!java.util.Arrays.equals(expected, program)) {
- throw new AssertionError(
- "\nexpected: " + HexDump.toHexString(expected) +
- "\nactual: " + HexDump.toHexString(program));
- }
- }
-
- private void assertDataMemoryContents(
- int expected, byte[] program, byte[] packet, byte[] data, byte[] expected_data)
- throws IllegalInstructionException, Exception {
- assertReturnCodesEqual(expected, apfSimulate(program, packet, data, 0 /* filterAge */));
-
- // assertArrayEquals() would only print one byte, making debugging difficult.
- if (!java.util.Arrays.equals(expected_data, data)) {
- throw new Exception(
- "\nprogram: " + HexDump.toHexString(program) +
- "\ndata memory: " + HexDump.toHexString(data) +
- "\nexpected: " + HexDump.toHexString(expected_data));
- }
- }
-
- private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
- throws IllegalInstructionException {
- assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, null,
- filterAge));
- }
-
- private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
- throws IllegalInstructionException {
- assertVerdict(PASS, gen, packet, filterAge);
- }
-
- private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge)
- throws IllegalInstructionException {
- assertVerdict(DROP, gen, packet, filterAge);
- }
-
- private void assertPass(ApfGenerator gen)
- throws IllegalInstructionException {
- assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0);
- }
-
- private void assertDrop(ApfGenerator gen)
- throws IllegalInstructionException {
- assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0);
- }
-
- /**
- * Test each instruction by generating a program containing the instruction,
- * generating bytecode for that program and running it through the
- * interpreter to verify it functions correctly.
- */
- @Test
- public void testApfInstructions() throws IllegalInstructionException {
- // Empty program should pass because having the program counter reach the
- // location immediately after the program indicates the packet should be
- // passed to the AP.
- ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
- assertPass(gen);
-
- // Test jumping to pass label.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJump(gen.PASS_LABEL);
- byte[] program = gen.generate();
- assertEquals(1, program.length);
- assertEquals((14 << 3) | (0 << 1) | 0, program[0]);
- assertPass(program, new byte[MIN_PKT_SIZE], 0);
-
- // Test jumping to drop label.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJump(gen.DROP_LABEL);
- program = gen.generate();
- assertEquals(2, program.length);
- assertEquals((14 << 3) | (1 << 1) | 0, program[0]);
- assertEquals(1, program[1]);
- assertDrop(program, new byte[15], 15);
-
- // Test jumping if equal to 0.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test jumping if not equal to 0.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
- assertPass(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1);
- gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test jumping if registers equal.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJumpIfR0EqualsR1(gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test jumping if registers not equal.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
- assertPass(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1);
- gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test load immediate.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test add.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addAdd(1234567890);
- gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test subtract.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addAdd(-1234567890);
- gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test or.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addOr(1234567890);
- gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test and.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addAnd(123456789);
- gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test left shift.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addLeftShift(1);
- gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test right shift.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addRightShift(1);
- gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test multiply.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 123456789);
- gen.addMul(2);
- gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test divide.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addDiv(2);
- gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test divide by zero.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addDiv(0);
- gen.addJump(gen.DROP_LABEL);
- assertPass(gen);
-
- // Test add.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 1234567890);
- gen.addAddR1();
- gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test subtract.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, -1234567890);
- gen.addAddR1();
- gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test or.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 1234567890);
- gen.addOrR1();
- gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test and.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addLoadImmediate(Register.R1, 123456789);
- gen.addAndR1();
- gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test left shift.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addLoadImmediate(Register.R1, 1);
- gen.addLeftShiftR1();
- gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test right shift.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addLoadImmediate(Register.R1, -1);
- gen.addLeftShiftR1();
- gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test multiply.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 123456789);
- gen.addLoadImmediate(Register.R1, 2);
- gen.addMulR1();
- gen.addJumpIfR0Equals(123456789 * 2, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test divide.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addLoadImmediate(Register.R1, 2);
- gen.addDivR1();
- gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test divide by zero.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addDivR1();
- gen.addJump(gen.DROP_LABEL);
- assertPass(gen);
-
- // Test byte load.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoad8(Register.R0, 1);
- gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
- assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
- // Test out of bounds load.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoad8(Register.R0, 16);
- gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
- assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
- // Test half-word load.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoad16(Register.R0, 1);
- gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
- assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
- // Test word load.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoad32(Register.R0, 1);
- gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
- assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
-
- // Test byte indexed load.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 1);
- gen.addLoad8Indexed(Register.R0, 0);
- gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
- assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
- // Test out of bounds indexed load.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 8);
- gen.addLoad8Indexed(Register.R0, 8);
- gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
- assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
- // Test half-word indexed load.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 1);
- gen.addLoad16Indexed(Register.R0, 0);
- gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
- assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
-
- // Test word indexed load.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 1);
- gen.addLoad32Indexed(Register.R0, 0);
- gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
- assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
-
- // Test jumping if greater than.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
- assertPass(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1);
- gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test jumping if less than.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJumpIfR0LessThan(0, gen.DROP_LABEL);
- assertPass(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJumpIfR0LessThan(1, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test jumping if any bits set.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
- assertPass(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1);
- gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
- assertDrop(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 3);
- gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test jumping if register greater than.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
- assertPass(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 2);
- gen.addLoadImmediate(Register.R1, 1);
- gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test jumping if register less than.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
- assertPass(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 1);
- gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test jumping if any bits set in register.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 3);
- gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
- assertPass(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 3);
- gen.addLoadImmediate(Register.R0, 1);
- gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
- assertDrop(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 3);
- gen.addLoadImmediate(Register.R0, 3);
- gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test load from memory.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadFromMemory(Register.R0, 0);
- gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test store to memory.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 1234567890);
- gen.addStoreToMemory(Register.R1, 12);
- gen.addLoadFromMemory(Register.R0, 12);
- gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test filter age pre-filled memory.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
- gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
- assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890);
-
- // Test packet size pre-filled memory.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
- gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test IPv4 header size pre-filled memory.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
- gen.addJumpIfR0Equals(20, gen.DROP_LABEL);
- assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0);
-
- // Test not.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addNot(Register.R0);
- gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test negate.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addNeg(Register.R0);
- gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test move.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 1234567890);
- gen.addMove(Register.R0);
- gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
- assertDrop(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addMove(Register.R1);
- gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test swap.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R1, 1234567890);
- gen.addSwap();
- gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
- assertDrop(gen);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1234567890);
- gen.addSwap();
- gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
- assertDrop(gen);
-
- // Test jump if bytes not equal.
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1);
- gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
- program = gen.generate();
- assertEquals(6, program.length);
- assertEquals((13 << 3) | (1 << 1) | 0, program[0]);
- assertEquals(1, program[1]);
- assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]);
- assertEquals(1, program[3]);
- assertEquals(1, program[4]);
- assertEquals(123, program[5]);
- assertDrop(program, new byte[MIN_PKT_SIZE], 0);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1);
- gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
- byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
- assertPass(gen, packet123, 0);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
- assertDrop(gen, packet123, 0);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1);
- gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
- byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
- assertDrop(gen, packet12345, 0);
- gen = new ApfGenerator(MIN_APF_VERSION);
- gen.addLoadImmediate(Register.R0, 1);
- gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL);
- assertPass(gen, packet12345, 0);
- }
-
- @Test(expected = ApfGenerator.IllegalInstructionException.class)
- public void testApfGeneratorWantsV2OrGreater() throws Exception {
- // The minimum supported APF version is 2.
- new ApfGenerator(1);
- }
-
- @Test
- public void testApfDataOpcodesWantApfV3() throws IllegalInstructionException, Exception {
- ApfGenerator gen = new ApfGenerator(MIN_APF_VERSION);
- try {
- gen.addStoreData(Register.R0, 0);
- fail();
- } catch (IllegalInstructionException expected) {
- /* pass */
- }
- try {
- gen.addLoadData(Register.R0, 0);
- fail();
- } catch (IllegalInstructionException expected) {
- /* pass */
- }
- }
-
- /**
- * Test that the generator emits immediates using the shortest possible encoding.
- */
- @Test
- public void testImmediateEncoding() throws IllegalInstructionException {
- ApfGenerator gen;
-
- // 0-byte immediate: li R0, 0
- gen = new ApfGenerator(4);
- gen.addLoadImmediate(Register.R0, 0);
- assertProgramEquals(new byte[]{LI_OP | SIZE0}, gen.generate());
-
- // 1-byte immediate: li R0, 42
- gen = new ApfGenerator(4);
- gen.addLoadImmediate(Register.R0, 42);
- assertProgramEquals(new byte[]{LI_OP | SIZE8, 42}, gen.generate());
-
- // 2-byte immediate: li R1, 0x1234
- gen = new ApfGenerator(4);
- gen.addLoadImmediate(Register.R1, 0x1234);
- assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, 0x12, 0x34}, gen.generate());
-
- // 4-byte immediate: li R0, 0x12345678
- gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R0, 0x12345678);
- assertProgramEquals(
- new byte[]{LI_OP | SIZE32, 0x12, 0x34, 0x56, 0x78},
- gen.generate());
- }
-
- /**
- * Test that the generator emits negative immediates using the shortest possible encoding.
- */
- @Test
- public void testNegativeImmediateEncoding() throws IllegalInstructionException {
- ApfGenerator gen;
-
- // 1-byte negative immediate: li R0, -42
- gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R0, -42);
- assertProgramEquals(new byte[]{LI_OP | SIZE8, -42}, gen.generate());
-
- // 2-byte negative immediate: li R1, -0x1122
- gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R1, -0x1122);
- assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
- gen.generate());
-
- // 4-byte negative immediate: li R0, -0x11223344
- gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R0, -0x11223344);
- assertProgramEquals(
- new byte[]{LI_OP | SIZE32, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
- gen.generate());
- }
-
- /**
- * Test that the generator correctly emits positive and negative immediates for LDDW/STDW.
- */
- @Test
- public void testLoadStoreDataEncoding() throws IllegalInstructionException {
- ApfGenerator gen;
-
- // Load data with no offset: lddw R0, [0 + r1]
- gen = new ApfGenerator(3);
- gen.addLoadData(Register.R0, 0);
- assertProgramEquals(new byte[]{LDDW_OP | SIZE0}, gen.generate());
-
- // Store data with 8bit negative offset: lddw r0, [-42 + r1]
- gen = new ApfGenerator(3);
- gen.addStoreData(Register.R0, -42);
- assertProgramEquals(new byte[]{STDW_OP | SIZE8, -42}, gen.generate());
-
- // Store data to R1 with 16bit negative offset: stdw r1, [-0x1122 + r0]
- gen = new ApfGenerator(3);
- gen.addStoreData(Register.R1, -0x1122);
- assertProgramEquals(new byte[]{STDW_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
- gen.generate());
-
- // Load data to R1 with 32bit negative offset: lddw r1, [0xDEADBEEF + r0]
- gen = new ApfGenerator(3);
- gen.addLoadData(Register.R1, 0xDEADBEEF);
- assertProgramEquals(
- new byte[]{LDDW_OP | SIZE32 | R1, (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF},
- gen.generate());
- }
-
- /**
- * Test that the interpreter correctly executes STDW with a negative 8bit offset
- */
- @Test
- public void testApfDataWrite() throws IllegalInstructionException, Exception {
- byte[] packet = new byte[MIN_PKT_SIZE];
- byte[] data = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
- byte[] expected_data = data.clone();
-
- // No memory access instructions: should leave the data segment untouched.
- ApfGenerator gen = new ApfGenerator(3);
- assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-
- // Expect value 0x87654321 to be stored starting from address -11 from the end of the
- // data buffer, in big-endian order.
- gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R0, 0x87654321);
- gen.addLoadImmediate(Register.R1, -5);
- gen.addStoreData(Register.R0, -6); // -5 + -6 = -11 (offset +5 with data_len=16)
- expected_data[5] = (byte)0x87;
- expected_data[6] = (byte)0x65;
- expected_data[7] = (byte)0x43;
- expected_data[8] = (byte)0x21;
- assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
- }
-
- /**
- * Test that the interpreter correctly executes LDDW with a negative 16bit offset
- */
- @Test
- public void testApfDataRead() throws IllegalInstructionException, Exception {
- // Program that DROPs if address 10 (-6) contains 0x87654321.
- ApfGenerator gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R1, 1000);
- gen.addLoadData(Register.R0, -1006); // 1000 + -1006 = -6 (offset +10 with data_len=16)
- gen.addJumpIfR0Equals(0x87654321, gen.DROP_LABEL);
- byte[] program = gen.generate();
- byte[] packet = new byte[MIN_PKT_SIZE];
-
- // Content is incorrect (last byte does not match) -> PASS
- byte[] data = new byte[16];
- data[10] = (byte)0x87;
- data[11] = (byte)0x65;
- data[12] = (byte)0x43;
- data[13] = (byte)0x00; // != 0x21
- byte[] expected_data = data.clone();
- assertDataMemoryContents(PASS, program, packet, data, expected_data);
-
- // Fix the last byte -> conditional jump taken -> DROP
- data[13] = (byte)0x21;
- expected_data = data;
- assertDataMemoryContents(DROP, program, packet, data, expected_data);
- }
-
- /**
- * Test that the interpreter correctly executes LDDW followed by a STDW.
- * To cover a few more edge cases, LDDW has a 0bit offset, while STDW has a positive 8bit
- * offset.
- */
- @Test
- public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception {
- ApfGenerator gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R1, -22);
- gen.addLoadData(Register.R0, 0); // Load from address 32 -22 + 0 = 10
- gen.addAdd(0x78453412); // 87654321 + 78453412 = FFAA7733
- gen.addStoreData(Register.R0, 4); // Write back to address 32 -22 + 4 = 14
-
- byte[] packet = new byte[MIN_PKT_SIZE];
- byte[] data = new byte[32];
- data[10] = (byte)0x87;
- data[11] = (byte)0x65;
- data[12] = (byte)0x43;
- data[13] = (byte)0x21;
- byte[] expected_data = data.clone();
- expected_data[14] = (byte)0xFF;
- expected_data[15] = (byte)0xAA;
- expected_data[16] = (byte)0x77;
- expected_data[17] = (byte)0x33;
- assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
- }
-
- @Test
- public void testApfDataBoundChecking() throws IllegalInstructionException, Exception {
- byte[] packet = new byte[MIN_PKT_SIZE];
- byte[] data = new byte[32];
- byte[] expected_data = data;
-
- // Program that DROPs unconditionally. This is our the baseline.
- ApfGenerator gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R0, 3);
- gen.addLoadData(Register.R1, 7);
- gen.addJump(gen.DROP_LABEL);
- assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
-
- // Same program as before, but this time we're trying to load past the end of the data.
- gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R0, 20);
- gen.addLoadData(Register.R1, 15); // 20 + 15 > 32
- gen.addJump(gen.DROP_LABEL); // Not reached.
- assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
-
- // Subtracting an immediate should work...
- gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R0, 20);
- gen.addLoadData(Register.R1, -4);
- gen.addJump(gen.DROP_LABEL);
- assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
-
- // ...and underflowing simply wraps around to the end of the buffer...
- gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R0, 20);
- gen.addLoadData(Register.R1, -30);
- gen.addJump(gen.DROP_LABEL);
- assertDataMemoryContents(DROP, gen.generate(), packet, data, expected_data);
-
- // ...but doesn't allow accesses before the start of the buffer
- gen = new ApfGenerator(3);
- gen.addLoadImmediate(Register.R0, 20);
- gen.addLoadData(Register.R1, -1000);
- gen.addJump(gen.DROP_LABEL); // Not reached.
- assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
- }
-
- /**
- * Generate some BPF programs, translate them to APF, then run APF and BPF programs
- * over packet traces and verify both programs filter out the same packets.
- */
- @Test
- public void testApfAgainstBpf() throws Exception {
- String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
- "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
- "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000",
- "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" };
- String pcap_filename = stageFile(R.raw.apf);
- for (String tcpdump_filter : tcpdump_filters) {
- byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter));
- assertTrue("Failed to match for filter: " + tcpdump_filter,
- compareBpfApf(tcpdump_filter, pcap_filename, apf_program));
- }
- }
-
- /**
- * Generate APF program, run pcap file though APF filter, then check all the packets in the file
- * should be dropped.
- */
- @Test
- public void testApfFilterPcapFile() throws Exception {
- final byte[] MOCK_PCAP_IPV4_ADDR = {(byte) 172, 16, 7, (byte) 151};
- String pcapFilename = stageFile(R.raw.apfPcap);
- MockIpClientCallback ipClientCallback = new MockIpClientCallback();
- LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_PCAP_IPV4_ADDR), 16);
- LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(link);
-
- ApfConfiguration config = getDefaultConfig();
- ApfCapabilities MOCK_APF_PCAP_CAPABILITIES = new ApfCapabilities(4, 1700, ARPHRD_ETHER);
- config.apfCapabilities = MOCK_APF_PCAP_CAPABILITIES;
- config.multicastFilter = DROP_MULTICAST;
- config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
- apfFilter.setLinkProperties(lp);
- byte[] program = ipClientCallback.getApfProgram();
- byte[] data = new byte[ApfFilter.Counter.totalSize()];
- final boolean result;
-
- result = dropsAllPackets(program, data, pcapFilename);
- Log.i(TAG, "testApfFilterPcapFile(): Data counters: " + HexDump.toHexString(data, false));
-
- assertTrue("Failed to drop all packets by filter. \nAPF counters:" +
- HexDump.toHexString(data, false), result);
- }
-
- private class MockIpClientCallback extends IpClientCallbacksWrapper {
- private final ConditionVariable mGotApfProgram = new ConditionVariable();
- private byte[] mLastApfProgram;
-
- MockIpClientCallback() {
- super(mock(IIpClientCallbacks.class), mock(SharedLog.class));
- }
-
- @Override
- public void installPacketFilter(byte[] filter) {
- mLastApfProgram = filter;
- mGotApfProgram.open();
- }
-
- public void resetApfProgramWait() {
- mGotApfProgram.close();
- }
-
- public byte[] getApfProgram() {
- assertTrue(mGotApfProgram.block(TIMEOUT_MS));
- return mLastApfProgram;
- }
-
- public void assertNoProgramUpdate() {
- assertFalse(mGotApfProgram.block(TIMEOUT_MS));
- }
- }
-
- private static class TestApfFilter extends ApfFilter {
- public static final byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
-
- private FileDescriptor mWriteSocket;
- private final long mFixedTimeMs = SystemClock.elapsedRealtime();
-
- public TestApfFilter(Context context, ApfConfiguration config,
- IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log) throws Exception {
- super(context, config, InterfaceParams.getByName("lo"), ipClientCallback, log);
- }
-
- // Pretend an RA packet has been received and show it to ApfFilter.
- public void pretendPacketReceived(byte[] packet) throws IOException, ErrnoException {
- // ApfFilter's ReceiveThread will be waiting to read this.
- Os.write(mWriteSocket, packet, 0, packet.length);
- }
-
- @Override
- protected long currentTimeSeconds() {
- return mFixedTimeMs / DateUtils.SECOND_IN_MILLIS;
- }
-
- @Override
- void maybeStartFilter() {
- mHardwareAddress = MOCK_MAC_ADDR;
- installNewProgramLocked();
-
- // Create two sockets, "readSocket" and "mWriteSocket" and connect them together.
- FileDescriptor readSocket = new FileDescriptor();
- mWriteSocket = new FileDescriptor();
- try {
- Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mWriteSocket, readSocket);
- } catch (ErrnoException e) {
- fail();
- return;
- }
- // Now pass readSocket to ReceiveThread as if it was setup to read raw RAs.
- // This allows us to pretend RA packets have been recieved via pretendPacketReceived().
- mReceiveThread = new ReceiveThread(readSocket);
- mReceiveThread.start();
- }
-
- @Override
- public void shutdown() {
- super.shutdown();
- IoUtils.closeQuietly(mWriteSocket);
- }
- }
-
- private static final int ETH_HEADER_LEN = 14;
- private static final int ETH_DEST_ADDR_OFFSET = 0;
- private static final int ETH_ETHERTYPE_OFFSET = 12;
- private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
- {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
-
- private static final int IPV4_HEADER_LEN = 20;
- private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
- private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
- private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
- private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12;
- private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
-
- private static final int IPV4_TCP_HEADER_LEN = 20;
- private static final int IPV4_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;
- private static final int IPV4_TCP_SRC_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 0;
- private static final int IPV4_TCP_DEST_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 2;
- private static final int IPV4_TCP_SEQ_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 4;
- private static final int IPV4_TCP_ACK_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 8;
- private static final int IPV4_TCP_HEADER_LENGTH_OFFSET = IPV4_TCP_HEADER_OFFSET + 12;
- private static final int IPV4_TCP_HEADER_FLAG_OFFSET = IPV4_TCP_HEADER_OFFSET + 13;
-
- private static final int IPV4_UDP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;;
- private static final int IPV4_UDP_SRC_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 0;
- private static final int IPV4_UDP_DEST_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 2;
- private static final int IPV4_UDP_LENGTH_OFFSET = IPV4_UDP_HEADER_OFFSET + 4;
- private static final int IPV4_UDP_PAYLOAD_OFFSET = IPV4_UDP_HEADER_OFFSET + 8;
- private static final byte[] IPV4_BROADCAST_ADDRESS =
- {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
-
- private static final int IPV6_HEADER_LEN = 40;
- private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
- private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
- private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
- private static final int IPV6_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
- private static final int IPV6_TCP_SRC_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 0;
- private static final int IPV6_TCP_DEST_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 2;
- private static final int IPV6_TCP_SEQ_NUM_OFFSET = IPV6_TCP_HEADER_OFFSET + 4;
- private static final int IPV6_TCP_ACK_NUM_OFFSET = IPV6_TCP_HEADER_OFFSET + 8;
- // The IPv6 all nodes address ff02::1
- private static final byte[] IPV6_ALL_NODES_ADDRESS =
- { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
- private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
- { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
-
- private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
- private static final int ICMP6_ROUTER_SOLICITATION = 133;
- private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
- private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
- private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
-
- private static final int ICMP6_RA_HEADER_LEN = 16;
- private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
- ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
- private static final int ICMP6_RA_CHECKSUM_OFFSET =
- ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
- private static final int ICMP6_RA_OPTION_OFFSET =
- ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
-
- private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
- private static final int ICMP6_PREFIX_OPTION_LEN = 32;
- private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
- private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
-
- // From RFC6106: Recursive DNS Server option
- private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
- // From RFC6106: DNS Search List option
- private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
-
- // From RFC4191: Route Information option
- private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
- // Above three options all have the same format:
- private static final int ICMP6_4_BYTE_OPTION_LEN = 8;
- private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
- private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
-
- private static final int UDP_HEADER_LEN = 8;
- private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22;
-
- private static final int DHCP_CLIENT_PORT = 68;
- private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
-
- private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
- private static final byte[] ARP_IPV4_REQUEST_HEADER = {
- 0, 1, // Hardware type: Ethernet (1)
- 8, 0, // Protocol type: IP (0x0800)
- 6, // Hardware size: 6
- 4, // Protocol size: 4
- 0, 1 // Opcode: request (1)
- };
- private static final byte[] ARP_IPV4_REPLY_HEADER = {
- 0, 1, // Hardware type: Ethernet (1)
- 8, 0, // Protocol type: IP (0x0800)
- 6, // Hardware size: 6
- 4, // Protocol size: 4
- 0, 2 // Opcode: reply (2)
- };
- private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
- private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
-
- private static final byte[] MOCK_IPV4_ADDR = {10, 0, 0, 1};
- private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19
- private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1};
- private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2};
- private static final byte[] IPV4_SOURCE_ADDR = {10, 0, 0, 3};
- private static final byte[] ANOTHER_IPV4_SOURCE_ADDR = {(byte) 192, 0, 2, 1};
- private static final byte[] BUG_PROBE_SOURCE_ADDR1 = {0, 0, 1, 2};
- private static final byte[] BUG_PROBE_SOURCE_ADDR2 = {3, 4, 0, 0};
- private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0};
-
- // Helper to initialize a default apfFilter.
- private ApfFilter setupApfFilter(
- IpClientCallbacksWrapper ipClientCallback, ApfConfiguration config) throws Exception {
- LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
- LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(link);
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
- apfFilter.setLinkProperties(lp);
- return apfFilter;
- }
-
- @Test
- public void testApfFilterIPv4() throws Exception {
- MockIpClientCallback ipClientCallback = new MockIpClientCallback();
- LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
- LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(link);
-
- ApfConfiguration config = getDefaultConfig();
- config.multicastFilter = DROP_MULTICAST;
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
- apfFilter.setLinkProperties(lp);
-
- byte[] program = ipClientCallback.getApfProgram();
-
- // Verify empty packet of 100 zero bytes is passed
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- assertPass(program, packet.array());
-
- // Verify unicast IPv4 packet is passed
- put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
- put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
- assertPass(program, packet.array());
-
- // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088)
- put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
- assertDrop(program, packet.array());
- put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
- assertDrop(program, packet.array());
-
- // Verify multicast/broadcast IPv4, not DHCP to us, is dropped
- put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
- assertDrop(program, packet.array());
- packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
- assertDrop(program, packet.array());
- packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
- assertDrop(program, packet.array());
- packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
- assertDrop(program, packet.array());
- put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR);
- assertDrop(program, packet.array());
- put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
- assertDrop(program, packet.array());
- put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
- assertDrop(program, packet.array());
-
- // Verify broadcast IPv4 DHCP to us is passed
- put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
- assertPass(program, packet.array());
-
- // Verify unicast IPv4 DHCP to us is passed
- put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
- assertPass(program, packet.array());
-
- apfFilter.shutdown();
- }
-
- @Test
- public void testApfFilterIPv6() throws Exception {
- MockIpClientCallback ipClientCallback = new MockIpClientCallback();
- ApfConfiguration config = getDefaultConfig();
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
- byte[] program = ipClientCallback.getApfProgram();
-
- // Verify empty IPv6 packet is passed
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- assertPass(program, packet.array());
-
- // Verify empty ICMPv6 packet is passed
- packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
- assertPass(program, packet.array());
-
- // Verify empty ICMPv6 NA packet is passed
- packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
- assertPass(program, packet.array());
-
- // Verify ICMPv6 NA to ff02::1 is dropped
- put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
- assertDrop(program, packet.array());
-
- // Verify ICMPv6 RS to any is dropped
- packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_SOLICITATION);
- assertDrop(program, packet.array());
- put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_ROUTERS_ADDRESS);
- assertDrop(program, packet.array());
-
- apfFilter.shutdown();
- }
-
- @Test
- public void testApfFilterMulticast() throws Exception {
- final byte[] unicastIpv4Addr = {(byte)192,0,2,63};
- final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
- final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
- final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
-
- MockIpClientCallback ipClientCallback = new MockIpClientCallback();
- LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
- LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(link);
-
- ApfConfiguration config = getDefaultConfig();
- config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
- apfFilter.setLinkProperties(lp);
-
- byte[] program = ipClientCallback.getApfProgram();
-
- // Construct IPv4 and IPv6 multicast packets.
- ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
- mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
- put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
-
- ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
- mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
- put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
-
- // Construct IPv4 broadcast packet.
- ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]);
- bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
- bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
- put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
-
- ByteBuffer bcastv4packet2 = ByteBuffer.wrap(new byte[100]);
- bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS);
- bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
- put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
-
- // Construct IPv4 broadcast with L2 unicast address packet (b/30231088).
- ByteBuffer bcastv4unicastl2packet = ByteBuffer.wrap(new byte[100]);
- bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR);
- bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
- put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr);
-
- // Verify initially disabled multicast filter is off
- assertPass(program, mcastv4packet.array());
- assertPass(program, mcastv6packet.array());
- assertPass(program, bcastv4packet1.array());
- assertPass(program, bcastv4packet2.array());
- assertPass(program, bcastv4unicastl2packet.array());
-
- // Turn on multicast filter and verify it works
- ipClientCallback.resetApfProgramWait();
- apfFilter.setMulticastFilter(true);
- program = ipClientCallback.getApfProgram();
- assertDrop(program, mcastv4packet.array());
- assertDrop(program, mcastv6packet.array());
- assertDrop(program, bcastv4packet1.array());
- assertDrop(program, bcastv4packet2.array());
- assertDrop(program, bcastv4unicastl2packet.array());
-
- // Turn off multicast filter and verify it's off
- ipClientCallback.resetApfProgramWait();
- apfFilter.setMulticastFilter(false);
- program = ipClientCallback.getApfProgram();
- assertPass(program, mcastv4packet.array());
- assertPass(program, mcastv6packet.array());
- assertPass(program, bcastv4packet1.array());
- assertPass(program, bcastv4packet2.array());
- assertPass(program, bcastv4unicastl2packet.array());
-
- // Verify it can be initialized to on
- ipClientCallback.resetApfProgramWait();
- apfFilter.shutdown();
- config.multicastFilter = DROP_MULTICAST;
- config.ieee802_3Filter = DROP_802_3_FRAMES;
- apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
- apfFilter.setLinkProperties(lp);
- program = ipClientCallback.getApfProgram();
- assertDrop(program, mcastv4packet.array());
- assertDrop(program, mcastv6packet.array());
- assertDrop(program, bcastv4packet1.array());
- assertDrop(program, bcastv4unicastl2packet.array());
-
- // Verify that ICMPv6 multicast is not dropped.
- mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
- assertPass(program, mcastv6packet.array());
-
- apfFilter.shutdown();
- }
-
- @Test
- public void testApfFilterMulticastPingWhileDozing() throws Exception {
- MockIpClientCallback ipClientCallback = new MockIpClientCallback();
- ApfFilter apfFilter = setupApfFilter(ipClientCallback, getDefaultConfig());
-
- // Construct a multicast ICMPv6 ECHO request.
- final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
- packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
- put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
-
- // Normally, we let multicast pings alone...
- assertPass(ipClientCallback.getApfProgram(), packet.array());
-
- // ...and even while dozing...
- apfFilter.setDozeMode(true);
- assertPass(ipClientCallback.getApfProgram(), packet.array());
-
- // ...but when the multicast filter is also enabled, drop the multicast pings to save power.
- apfFilter.setMulticastFilter(true);
- assertDrop(ipClientCallback.getApfProgram(), packet.array());
-
- // However, we should still let through all other ICMPv6 types.
- ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
- raPacket.put(ICMP6_TYPE_OFFSET, (byte) NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT);
- assertPass(ipClientCallback.getApfProgram(), raPacket.array());
-
- // Now wake up from doze mode to ensure that we no longer drop the packets.
- // (The multicast filter is still enabled at this point).
- apfFilter.setDozeMode(false);
- assertPass(ipClientCallback.getApfProgram(), packet.array());
-
- apfFilter.shutdown();
- }
-
- @Test
- public void testApfFilter802_3() throws Exception {
- MockIpClientCallback ipClientCallback = new MockIpClientCallback();
- ApfConfiguration config = getDefaultConfig();
- ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
- byte[] program = ipClientCallback.getApfProgram();
-
- // Verify empty packet of 100 zero bytes is passed
- // Note that eth-type = 0 makes it an IEEE802.3 frame
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- assertPass(program, packet.array());
-
- // Verify empty packet with IPv4 is passed
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
- assertPass(program, packet.array());
-
- // Verify empty IPv6 packet is passed
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- assertPass(program, packet.array());
-
- // Now turn on the filter
- ipClientCallback.resetApfProgramWait();
- apfFilter.shutdown();
- config.ieee802_3Filter = DROP_802_3_FRAMES;
- apfFilter = setupApfFilter(ipClientCallback, config);
- program = ipClientCallback.getApfProgram();
-
- // Verify that IEEE802.3 frame is dropped
- // In this case ethtype is used for payload length
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)(100 - 14));
- assertDrop(program, packet.array());
-
- // Verify that IPv4 (as example of Ethernet II) frame will pass
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
- assertPass(program, packet.array());
-
- // Verify that IPv6 (as example of Ethernet II) frame will pass
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- assertPass(program, packet.array());
-
- apfFilter.shutdown();
- }
-
- @Test
- public void testApfFilterEthTypeBL() throws Exception {
- final int[] emptyBlackList = {};
- final int[] ipv4BlackList = {ETH_P_IP};
- final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
-
- MockIpClientCallback ipClientCallback = new MockIpClientCallback();
- ApfConfiguration config = getDefaultConfig();
- ApfFilter apfFilter = setupApfFilter(ipClientCallback, config);
- byte[] program = ipClientCallback.getApfProgram();
-
- // Verify empty packet of 100 zero bytes is passed
- // Note that eth-type = 0 makes it an IEEE802.3 frame
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- assertPass(program, packet.array());
-
- // Verify empty packet with IPv4 is passed
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
- assertPass(program, packet.array());
-
- // Verify empty IPv6 packet is passed
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- assertPass(program, packet.array());
-
- // Now add IPv4 to the black list
- ipClientCallback.resetApfProgramWait();
- apfFilter.shutdown();
- config.ethTypeBlackList = ipv4BlackList;
- apfFilter = setupApfFilter(ipClientCallback, config);
- program = ipClientCallback.getApfProgram();
-
- // Verify that IPv4 frame will be dropped
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
- assertDrop(program, packet.array());
-
- // Verify that IPv6 frame will pass
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- assertPass(program, packet.array());
-
- // Now let us have both IPv4 and IPv6 in the black list
- ipClientCallback.resetApfProgramWait();
- apfFilter.shutdown();
- config.ethTypeBlackList = ipv4Ipv6BlackList;
- apfFilter = setupApfFilter(ipClientCallback, config);
- program = ipClientCallback.getApfProgram();
-
- // Verify that IPv4 frame will be dropped
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
- assertDrop(program, packet.array());
-
- // Verify that IPv6 frame will be dropped
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- assertDrop(program, packet.array());
-
- apfFilter.shutdown();
- }
-
- private byte[] getProgram(MockIpClientCallback cb, ApfFilter filter, LinkProperties lp) {
- cb.resetApfProgramWait();
- filter.setLinkProperties(lp);
- return cb.getApfProgram();
- }
-
- private void verifyArpFilter(byte[] program, int filterResult) {
- // Verify ARP request packet
- assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
- assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
- assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
-
- // Verify ARP reply packets from different source ip
- assertDrop(program, arpReply(IPV4_ANY_HOST_ADDR, IPV4_ANY_HOST_ADDR));
- assertPass(program, arpReply(ANOTHER_IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
- assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR1, IPV4_ANY_HOST_ADDR));
- assertPass(program, arpReply(BUG_PROBE_SOURCE_ADDR2, IPV4_ANY_HOST_ADDR));
-
- // Verify unicast ARP reply packet is always accepted.
- assertPass(program, arpReply(IPV4_SOURCE_ADDR, MOCK_IPV4_ADDR));
- assertPass(program, arpReply(IPV4_SOURCE_ADDR, ANOTHER_IPV4_ADDR));
- assertPass(program, arpReply(IPV4_SOURCE_ADDR, IPV4_ANY_HOST_ADDR));
-
- // Verify GARP reply packets are always filtered
- assertDrop(program, garpReply());
- }
-
- @Test
- public void testApfFilterArp() throws Exception {
- MockIpClientCallback ipClientCallback = new MockIpClientCallback();
- ApfConfiguration config = getDefaultConfig();
- config.multicastFilter = DROP_MULTICAST;
- config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
-
- // Verify initially ARP request filter is off, and GARP filter is on.
- verifyArpFilter(ipClientCallback.getApfProgram(), PASS);
-
- // Inform ApfFilter of our address and verify ARP filtering is on
- LinkAddress linkAddress = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 24);
- LinkProperties lp = new LinkProperties();
- assertTrue(lp.addLinkAddress(linkAddress));
- verifyArpFilter(getProgram(ipClientCallback, apfFilter, lp), DROP);
-
- // Inform ApfFilter of loss of IP and verify ARP filtering is off
- verifyArpFilter(getProgram(ipClientCallback, apfFilter, new LinkProperties()), PASS);
-
- apfFilter.shutdown();
- }
-
- private static byte[] arpReply(byte[] sip, byte[] tip) {
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
- put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
- put(packet, ARP_SOURCE_IP_ADDRESS_OFFSET, sip);
- put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
- return packet.array();
- }
-
- private static byte[] arpRequestBroadcast(byte[] tip) {
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
- put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
- put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REQUEST_HEADER);
- put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
- return packet.array();
- }
-
- private static byte[] garpReply() {
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
- put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
- put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
- put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR);
- return packet.array();
- }
-
- private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 5};
- private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 6};
- private static final byte[] IPV4_ANOTHER_ADDR = {10, 0 , 0, 7};
- private static final byte[] IPV6_KEEPALIVE_SRC_ADDR =
- {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf1};
- private static final byte[] IPV6_KEEPALIVE_DST_ADDR =
- {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf2};
- private static final byte[] IPV6_ANOTHER_ADDR =
- {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf5};
-
- @Test
- public void testApfFilterKeepaliveAck() throws Exception {
- final MockIpClientCallback cb = new MockIpClientCallback();
- final ApfConfiguration config = getDefaultConfig();
- config.multicastFilter = DROP_MULTICAST;
- config.ieee802_3Filter = DROP_802_3_FRAMES;
- final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
- byte[] program;
- final int srcPort = 12345;
- final int dstPort = 54321;
- final int seqNum = 2123456789;
- final int ackNum = 1234567890;
- final int anotherSrcPort = 23456;
- final int anotherDstPort = 65432;
- final int anotherSeqNum = 2123456780;
- final int anotherAckNum = 1123456789;
- final int slot1 = 1;
- final int slot2 = 2;
- final int window = 14480;
- final int windowScale = 4;
-
- // src: 10.0.0.5, port: 12345
- // dst: 10.0.0.6, port: 54321
- InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR);
- InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR);
-
- final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable();
- parcel.srcAddress = srcAddr.getAddress();
- parcel.srcPort = srcPort;
- parcel.dstAddress = dstAddr.getAddress();
- parcel.dstPort = dstPort;
- parcel.seq = seqNum;
- parcel.ack = ackNum;
-
- apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
- program = cb.getApfProgram();
-
- // Verify IPv4 keepalive ack packet is dropped
- // src: 10.0.0.6, port: 54321
- // dst: 10.0.0.5, port: 12345
- assertDrop(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
- // Verify IPv4 non-keepalive ack packet from the same source address is passed
- assertPass(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */));
- assertPass(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, ackNum, seqNum + 1, 10 /* dataLength */));
- // Verify IPv4 packet from another address is passed
- assertPass(program,
- ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
- anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
-
- // Remove IPv4 keepalive filter
- apfFilter.removeKeepalivePacketFilter(slot1);
-
- try {
- // src: 2404:0:0:0:0:0:faf1, port: 12345
- // dst: 2404:0:0:0:0:0:faf2, port: 54321
- srcAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_SRC_ADDR);
- dstAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_DST_ADDR);
-
- final TcpKeepalivePacketDataParcelable ipv6Parcel =
- new TcpKeepalivePacketDataParcelable();
- ipv6Parcel.srcAddress = srcAddr.getAddress();
- ipv6Parcel.srcPort = srcPort;
- ipv6Parcel.dstAddress = dstAddr.getAddress();
- ipv6Parcel.dstPort = dstPort;
- ipv6Parcel.seq = seqNum;
- ipv6Parcel.ack = ackNum;
-
- apfFilter.addTcpKeepalivePacketFilter(slot1, ipv6Parcel);
- program = cb.getApfProgram();
-
- // Verify IPv6 keepalive ack packet is dropped
- // src: 2404:0:0:0:0:0:faf2, port: 54321
- // dst: 2404:0:0:0:0:0:faf1, port: 12345
- assertDrop(program,
- ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, ackNum, seqNum + 1));
- // Verify IPv6 non-keepalive ack packet from the same source address is passed
- assertPass(program,
- ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, ackNum + 100, seqNum));
- // Verify IPv6 packet from another address is passed
- assertPass(program,
- ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
- anotherDstPort, anotherSeqNum, anotherAckNum));
-
- // Remove IPv6 keepalive filter
- apfFilter.removeKeepalivePacketFilter(slot1);
-
- // Verify multiple filters
- apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
- apfFilter.addTcpKeepalivePacketFilter(slot2, ipv6Parcel);
- program = cb.getApfProgram();
-
- // Verify IPv4 keepalive ack packet is dropped
- // src: 10.0.0.6, port: 54321
- // dst: 10.0.0.5, port: 12345
- assertDrop(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
- // Verify IPv4 non-keepalive ack packet from the same source address is passed
- assertPass(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */));
- // Verify IPv4 packet from another address is passed
- assertPass(program,
- ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
- anotherDstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
-
- // Verify IPv6 keepalive ack packet is dropped
- // src: 2404:0:0:0:0:0:faf2, port: 54321
- // dst: 2404:0:0:0:0:0:faf1, port: 12345
- assertDrop(program,
- ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, ackNum, seqNum + 1));
- // Verify IPv6 non-keepalive ack packet from the same source address is passed
- assertPass(program,
- ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, ackNum + 100, seqNum));
- // Verify IPv6 packet from another address is passed
- assertPass(program,
- ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
- anotherDstPort, anotherSeqNum, anotherAckNum));
-
- // Remove keepalive filters
- apfFilter.removeKeepalivePacketFilter(slot1);
- apfFilter.removeKeepalivePacketFilter(slot2);
- } catch (UnsupportedOperationException e) {
- // TODO: support V6 packets
- }
-
- program = cb.getApfProgram();
-
- // Verify IPv4, IPv6 packets are passed
- assertPass(program,
- ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
- assertPass(program,
- ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, ackNum, seqNum + 1));
- assertPass(program,
- ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, srcPort,
- dstPort, anotherSeqNum, anotherAckNum, 0 /* dataLength */));
- assertPass(program,
- ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, srcPort,
- dstPort, anotherSeqNum, anotherAckNum));
-
- apfFilter.shutdown();
- }
-
- private static byte[] ipv4Packet(byte[] sip, byte[] dip, int sport,
- int dport, int seq, int ack, int dataLength) {
- final int totalLength = dataLength + IPV4_HEADER_LEN + IPV4_TCP_HEADER_LEN;
-
- ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]);
-
- // ether type
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
-
- // IPv4 header
- packet.put(IPV4_VERSION_IHL_OFFSET, (byte) 0x45);
- packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
- packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_TCP);
- put(packet, IPV4_SRC_ADDR_OFFSET, sip);
- put(packet, IPV4_DEST_ADDR_OFFSET, dip);
- packet.putShort(IPV4_TCP_SRC_PORT_OFFSET, (short) sport);
- packet.putShort(IPV4_TCP_DEST_PORT_OFFSET, (short) dport);
- packet.putInt(IPV4_TCP_SEQ_NUM_OFFSET, seq);
- packet.putInt(IPV4_TCP_ACK_NUM_OFFSET, ack);
-
- // TCP header length 5(20 bytes), reserved 3 bits, NS=0
- packet.put(IPV4_TCP_HEADER_LENGTH_OFFSET, (byte) 0x50);
- // TCP flags: ACK set
- packet.put(IPV4_TCP_HEADER_FLAG_OFFSET, (byte) 0x10);
- return packet.array();
- }
-
- private static byte[] ipv6Packet(byte[] sip, byte[] tip, int sport,
- int dport, int seq, int ack) {
- ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
- put(packet, IPV6_SRC_ADDR_OFFSET, sip);
- put(packet, IPV6_DEST_ADDR_OFFSET, tip);
- packet.putShort(IPV6_TCP_SRC_PORT_OFFSET, (short) sport);
- packet.putShort(IPV6_TCP_DEST_PORT_OFFSET, (short) dport);
- packet.putInt(IPV6_TCP_SEQ_NUM_OFFSET, seq);
- packet.putInt(IPV6_TCP_ACK_NUM_OFFSET, ack);
- return packet.array();
- }
-
- @Test
- public void testApfFilterNattKeepalivePacket() throws Exception {
- final MockIpClientCallback cb = new MockIpClientCallback();
- final ApfConfiguration config = getDefaultConfig();
- config.multicastFilter = DROP_MULTICAST;
- config.ieee802_3Filter = DROP_802_3_FRAMES;
- final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
- byte[] program;
- final int srcPort = 1024;
- final int dstPort = 4500;
- final int slot1 = 1;
- // NAT-T keepalive
- final byte[] kaPayload = {(byte) 0xff};
- final byte[] nonKaPayload = {(byte) 0xfe};
-
- // src: 10.0.0.5, port: 1024
- // dst: 10.0.0.6, port: 4500
- InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR);
- InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR);
-
- final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable();
- parcel.srcAddress = srcAddr.getAddress();
- parcel.srcPort = srcPort;
- parcel.dstAddress = dstAddr.getAddress();
- parcel.dstPort = dstPort;
-
- apfFilter.addNattKeepalivePacketFilter(slot1, parcel);
- program = cb.getApfProgram();
-
- // Verify IPv4 keepalive packet is dropped
- // src: 10.0.0.6, port: 4500
- // dst: 10.0.0.5, port: 1024
- byte[] pkt = ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR,
- IPV4_KEEPALIVE_SRC_ADDR, dstPort, srcPort, 1 /* dataLength */);
- System.arraycopy(kaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, kaPayload.length);
- assertDrop(program, pkt);
-
- // Verify a packet with payload length 1 byte but it is not 0xff will pass the filter.
- System.arraycopy(nonKaPayload, 0, pkt, IPV4_UDP_PAYLOAD_OFFSET, nonKaPayload.length);
- assertPass(program, pkt);
-
- // Verify IPv4 non-keepalive response packet from the same source address is passed
- assertPass(program,
- ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, 10 /* dataLength */));
-
- // Verify IPv4 non-keepalive response packet from other source address is passed
- assertPass(program,
- ipv4UdpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
- dstPort, srcPort, 10 /* dataLength */));
-
- apfFilter.removeKeepalivePacketFilter(slot1);
- apfFilter.shutdown();
- }
-
- private static byte[] ipv4UdpPacket(byte[] sip, byte[] dip, int sport,
- int dport, int dataLength) {
- final int totalLength = dataLength + IPV4_HEADER_LEN + UDP_HEADER_LEN;
- final int udpLength = UDP_HEADER_LEN + dataLength;
- ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]);
-
- // ether type
- packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
-
- // IPv4 header
- packet.put(IPV4_VERSION_IHL_OFFSET, (byte) 0x45);
- packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
- packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_UDP);
- put(packet, IPV4_SRC_ADDR_OFFSET, sip);
- put(packet, IPV4_DEST_ADDR_OFFSET, dip);
- packet.putShort(IPV4_UDP_SRC_PORT_OFFSET, (short) sport);
- packet.putShort(IPV4_UDP_DEST_PORT_OFFSET, (short) dport);
- packet.putShort(IPV4_UDP_LENGTH_OFFSET, (short) udpLength);
-
- return packet.array();
- }
-
- // Verify that the last program pushed to the IpClient.Callback properly filters the
- // given packet for the given lifetime.
- private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
- final int FRACTION_OF_LIFETIME = 6;
- final int ageLimit = lifetime / FRACTION_OF_LIFETIME;
-
- // Verify new program should drop RA for 1/6th its lifetime and pass afterwards.
- assertDrop(program, packet.array());
- assertDrop(program, packet.array(), ageLimit);
- assertPass(program, packet.array(), ageLimit + 1);
- assertPass(program, packet.array(), lifetime);
- // Verify RA checksum is ignored
- final short originalChecksum = packet.getShort(ICMP6_RA_CHECKSUM_OFFSET);
- packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
- assertDrop(program, packet.array());
- packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
- assertDrop(program, packet.array());
- packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, originalChecksum);
-
- // Verify other changes to RA make it not match filter
- final byte originalFirstByte = packet.get(0);
- packet.put(0, (byte)-1);
- assertPass(program, packet.array());
- packet.put(0, (byte)0);
- assertDrop(program, packet.array());
- packet.put(0, originalFirstByte);
- }
-
- // Test that when ApfFilter is shown the given packet, it generates a program to filter it
- // for the given lifetime.
- private void verifyRaLifetime(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
- ByteBuffer packet, int lifetime) throws IOException, ErrnoException {
- // Verify new program generated if ApfFilter witnesses RA
- ipClientCallback.resetApfProgramWait();
- apfFilter.pretendPacketReceived(packet.array());
- byte[] program = ipClientCallback.getApfProgram();
- verifyRaLifetime(program, packet, lifetime);
- }
-
- private void verifyRaEvent(RaEvent expected) {
- ArgumentCaptor<IpConnectivityLog.Event> captor =
- ArgumentCaptor.forClass(IpConnectivityLog.Event.class);
- verify(mLog, atLeastOnce()).log(captor.capture());
- RaEvent got = lastRaEvent(captor.getAllValues());
- if (!raEventEquals(expected, got)) {
- assertEquals(expected, got); // fail for printing an assertion error message.
- }
- }
-
- private RaEvent lastRaEvent(List<IpConnectivityLog.Event> events) {
- RaEvent got = null;
- for (Parcelable ev : events) {
- if (ev instanceof RaEvent) {
- got = (RaEvent) ev;
- }
- }
- return got;
- }
-
- private boolean raEventEquals(RaEvent ev1, RaEvent ev2) {
- return (ev1 != null) && (ev2 != null)
- && (ev1.routerLifetime == ev2.routerLifetime)
- && (ev1.prefixValidLifetime == ev2.prefixValidLifetime)
- && (ev1.prefixPreferredLifetime == ev2.prefixPreferredLifetime)
- && (ev1.routeInfoLifetime == ev2.routeInfoLifetime)
- && (ev1.rdnssLifetime == ev2.rdnssLifetime)
- && (ev1.dnsslLifetime == ev2.dnsslLifetime);
- }
-
- private void assertInvalidRa(TestApfFilter apfFilter, MockIpClientCallback ipClientCallback,
- ByteBuffer packet) throws IOException, ErrnoException {
- ipClientCallback.resetApfProgramWait();
- apfFilter.pretendPacketReceived(packet.array());
- ipClientCallback.assertNoProgramUpdate();
- }
-
- @Test
- public void testApfFilterRa() throws Exception {
- MockIpClientCallback ipClientCallback = new MockIpClientCallback();
- ApfConfiguration config = getDefaultConfig();
- config.multicastFilter = DROP_MULTICAST;
- config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
- byte[] program = ipClientCallback.getApfProgram();
-
- final int ROUTER_LIFETIME = 1000;
- final int PREFIX_VALID_LIFETIME = 200;
- final int PREFIX_PREFERRED_LIFETIME = 100;
- final int RDNSS_LIFETIME = 300;
- final int ROUTE_LIFETIME = 400;
- // Note that lifetime of 2000 will be ignored in favor of shorter route lifetime of 1000.
- final int DNSSL_LIFETIME = 2000;
- final int VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET = ETH_HEADER_LEN;
- // IPv6, traffic class = 0, flow label = 0x12345
- final int VERSION_TRAFFIC_CLASS_FLOW_LABEL = 0x60012345;
-
- // Verify RA is passed the first time
- ByteBuffer basePacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
- basePacket.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
- basePacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
- VERSION_TRAFFIC_CLASS_FLOW_LABEL);
- basePacket.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
- basePacket.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_ROUTER_ADVERTISEMENT);
- basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)ROUTER_LIFETIME);
- basePacket.position(IPV6_DEST_ADDR_OFFSET);
- basePacket.put(IPV6_ALL_NODES_ADDRESS);
- assertPass(program, basePacket.array());
-
- verifyRaLifetime(apfFilter, ipClientCallback, basePacket, ROUTER_LIFETIME);
- verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, -1));
-
- ByteBuffer newFlowLabelPacket = ByteBuffer.wrap(new byte[ICMP6_RA_OPTION_OFFSET]);
- basePacket.clear();
- newFlowLabelPacket.put(basePacket);
- // Check that changes are ignored in every byte of the flow label.
- newFlowLabelPacket.putInt(VERSION_TRAFFIC_CLASS_FLOW_LABEL_OFFSET,
- VERSION_TRAFFIC_CLASS_FLOW_LABEL + 0x11111);
-
- // Ensure zero-length options cause the packet to be silently skipped.
- // Do this before we test other packets. http://b/29586253
- ByteBuffer zeroLengthOptionPacket = ByteBuffer.wrap(
- new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
- basePacket.clear();
- zeroLengthOptionPacket.put(basePacket);
- zeroLengthOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
- zeroLengthOptionPacket.put((byte)0);
- assertInvalidRa(apfFilter, ipClientCallback, zeroLengthOptionPacket);
-
- // Generate several RAs with different options and lifetimes, and verify when
- // ApfFilter is shown these packets, it generates programs to filter them for the
- // appropriate lifetime.
- ByteBuffer prefixOptionPacket = ByteBuffer.wrap(
- new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_LEN]);
- basePacket.clear();
- prefixOptionPacket.put(basePacket);
- prefixOptionPacket.put((byte)ICMP6_PREFIX_OPTION_TYPE);
- prefixOptionPacket.put((byte)(ICMP6_PREFIX_OPTION_LEN / 8));
- prefixOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
- PREFIX_PREFERRED_LIFETIME);
- prefixOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
- PREFIX_VALID_LIFETIME);
- verifyRaLifetime(
- apfFilter, ipClientCallback, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
- verifyRaEvent(new RaEvent(
- ROUTER_LIFETIME, PREFIX_VALID_LIFETIME, PREFIX_PREFERRED_LIFETIME, -1, -1, -1));
-
- ByteBuffer rdnssOptionPacket = ByteBuffer.wrap(
- new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
- basePacket.clear();
- rdnssOptionPacket.put(basePacket);
- rdnssOptionPacket.put((byte)ICMP6_RDNSS_OPTION_TYPE);
- rdnssOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
- rdnssOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, RDNSS_LIFETIME);
- verifyRaLifetime(apfFilter, ipClientCallback, rdnssOptionPacket, RDNSS_LIFETIME);
- verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1));
-
- ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap(
- new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
- basePacket.clear();
- routeInfoOptionPacket.put(basePacket);
- routeInfoOptionPacket.put((byte)ICMP6_ROUTE_INFO_OPTION_TYPE);
- routeInfoOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
- routeInfoOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, ROUTE_LIFETIME);
- verifyRaLifetime(apfFilter, ipClientCallback, routeInfoOptionPacket, ROUTE_LIFETIME);
- verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, ROUTE_LIFETIME, -1, -1));
-
- ByteBuffer dnsslOptionPacket = ByteBuffer.wrap(
- new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN]);
- basePacket.clear();
- dnsslOptionPacket.put(basePacket);
- dnsslOptionPacket.put((byte)ICMP6_DNSSL_OPTION_TYPE);
- dnsslOptionPacket.put((byte)(ICMP6_4_BYTE_OPTION_LEN / 8));
- dnsslOptionPacket.putInt(
- ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_LIFETIME_OFFSET, DNSSL_LIFETIME);
- verifyRaLifetime(apfFilter, ipClientCallback, dnsslOptionPacket, ROUTER_LIFETIME);
- verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, -1, DNSSL_LIFETIME));
-
- // Verify that current program filters all five RAs:
- program = ipClientCallback.getApfProgram();
- verifyRaLifetime(program, basePacket, ROUTER_LIFETIME);
- verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME);
- verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME);
- verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME);
- verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME);
- verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME);
-
- apfFilter.shutdown();
- }
-
- /**
- * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
- * copy that resource into the app's data directory and return the path to it.
- */
- private String stageFile(int rawId) throws Exception {
- File file = new File(InstrumentationRegistry.getContext().getFilesDir(), "staged_file");
- new File(file.getParent()).mkdirs();
- InputStream in = null;
- OutputStream out = null;
- try {
- in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
- out = new FileOutputStream(file);
- Streams.copy(in, out);
- } finally {
- if (in != null) in.close();
- if (out != null) out.close();
- }
- return file.getAbsolutePath();
- }
-
- private static void put(ByteBuffer buffer, int position, byte[] bytes) {
- final int original = buffer.position();
- buffer.position(position);
- buffer.put(bytes);
- buffer.position(original);
- }
-
- @Test
- public void testRaParsing() throws Exception {
- final int maxRandomPacketSize = 512;
- final Random r = new Random();
- MockIpClientCallback cb = new MockIpClientCallback();
- ApfConfiguration config = getDefaultConfig();
- config.multicastFilter = DROP_MULTICAST;
- config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
- for (int i = 0; i < 1000; i++) {
- byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
- r.nextBytes(packet);
- try {
- apfFilter.new Ra(packet, packet.length);
- } catch (ApfFilter.InvalidRaException e) {
- } catch (Exception e) {
- throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
- }
- }
- }
-
- @Test
- public void testRaProcessing() throws Exception {
- final int maxRandomPacketSize = 512;
- final Random r = new Random();
- MockIpClientCallback cb = new MockIpClientCallback();
- ApfConfiguration config = getDefaultConfig();
- config.multicastFilter = DROP_MULTICAST;
- config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
- for (int i = 0; i < 1000; i++) {
- byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
- r.nextBytes(packet);
- try {
- apfFilter.processRa(packet, packet.length);
- } catch (Exception e) {
- throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
- }
- }
- }
-
- /**
- * Call the APF interpreter to run {@code program} on {@code packet} with persistent memory
- * segment {@data} pretending the filter was installed {@code filter_age} seconds ago.
- */
- private native static int apfSimulate(byte[] program, byte[] packet, byte[] data,
- int filter_age);
-
- /**
- * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF
- * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d".
- */
- private native static String compileToBpf(String filter);
-
- /**
- * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump
- * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and
- * at the same time using APF program {@code apf_program}. Return {@code true} if
- * both APF and BPF programs filter out exactly the same packets.
- */
- private native static boolean compareBpfApf(String filter, String pcap_filename,
- byte[] apf_program);
-
-
- /**
- * Open packet capture file {@code pcapFilename} and run it through APF filter. Then
- * checks whether all the packets are dropped and populates data[] {@code data} with
- * the APF counters.
- */
- private native static boolean dropsAllPackets(byte[] program, byte[] data, String pcapFilename);
-
- @Test
- public void testBroadcastAddress() throws Exception {
- assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
- assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
- assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22));
- assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8));
-
- assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0));
- assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32));
- assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24));
- assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16));
- }
-
- public void assertEqualsIp(String expected, int got) throws Exception {
- int want = bytesToBEInt(InetAddress.getByName(expected).getAddress());
- assertEquals(want, got);
- }
-}