summaryrefslogtreecommitdiff
path: root/tests/src
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2019-05-13 19:01:09 +0900
committerRemi NGUYEN VAN <reminv@google.com>2019-05-21 15:23:23 +0900
commitee88a138295217a08a55ba482db019e55e5f3fbe (patch)
tree0adb4fcf8fe109bb0edebb05ec06e85265608b12 /tests/src
parent43e4dc3db27fc3dac79f56ec213d71161fe6905a (diff)
Move the NetworkStack tests to unit/ to add an integration test.
Test: m Change-Id: If638183f45956b60d694c859a759dd761c0598b2
Diffstat (limited to 'tests/src')
-rw-r--r--tests/src/android/net/apf/ApfTest.java2110
-rw-r--r--tests/src/android/net/apf/Bpf2Apf.java327
-rw-r--r--tests/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java170
-rw-r--r--tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java544
-rw-r--r--tests/src/android/net/dhcp/DhcpPacketTest.java1117
-rw-r--r--tests/src/android/net/dhcp/DhcpServerTest.java333
-rw-r--r--tests/src/android/net/dhcp/DhcpServingParamsTest.java221
-rw-r--r--tests/src/android/net/ip/IpClientTest.java547
-rw-r--r--tests/src/android/net/ip/IpReachabilityMonitorTest.java67
-rw-r--r--tests/src/android/net/util/ConnectivityPacketSummaryTest.java419
-rw-r--r--tests/src/android/net/util/PacketReaderTest.java211
-rw-r--r--tests/src/com/android/server/connectivity/NetworkMonitorTest.java1022
-rw-r--r--tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java663
-rw-r--r--tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java149
-rw-r--r--tests/src/com/android/server/util/SharedLogTest.java97
15 files changed, 0 insertions, 7997 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);
- }
-}
diff --git a/tests/src/android/net/apf/Bpf2Apf.java b/tests/src/android/net/apf/Bpf2Apf.java
deleted file mode 100644
index 5d57cde..0000000
--- a/tests/src/android/net/apf/Bpf2Apf.java
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (C) 2015 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 android.net.apf.ApfGenerator;
-import android.net.apf.ApfGenerator.IllegalInstructionException;
-import android.net.apf.ApfGenerator.Register;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-
-/**
- * BPF to APF translator.
- *
- * Note: This is for testing purposes only and is not guaranteed to support
- * translation of all BPF programs.
- *
- * Example usage:
- * javac net/java/android/net/apf/ApfGenerator.java \
- * tests/servicestests/src/android/net/apf/Bpf2Apf.java
- * sudo tcpdump -i em1 -d icmp | java -classpath tests/servicestests/src:net/java \
- * android.net.apf.Bpf2Apf
- */
-public class Bpf2Apf {
- private static int parseImm(String line, String arg) {
- if (!arg.startsWith("#0x")) {
- throw new IllegalArgumentException("Unhandled instruction: " + line);
- }
- final long val_long = Long.parseLong(arg.substring(3), 16);
- if (val_long < 0 || val_long > Long.parseLong("ffffffff", 16)) {
- throw new IllegalArgumentException("Unhandled instruction: " + line);
- }
- return new Long((val_long << 32) >> 32).intValue();
- }
-
- /**
- * Convert a single line of "tcpdump -d" (human readable BPF program dump) {@code line} into
- * APF instruction(s) and append them to {@code gen}. Here's an example line:
- * (001) jeq #0x86dd jt 2 jf 7
- */
- private static void convertLine(String line, ApfGenerator gen)
- throws IllegalInstructionException {
- if (line.indexOf("(") != 0 || line.indexOf(")") != 4 || line.indexOf(" ") != 5) {
- throw new IllegalArgumentException("Unhandled instruction: " + line);
- }
- int label = Integer.parseInt(line.substring(1, 4));
- gen.defineLabel(Integer.toString(label));
- String opcode = line.substring(6, 10).trim();
- String arg = line.substring(15, Math.min(32, line.length())).trim();
- switch (opcode) {
- case "ld":
- case "ldh":
- case "ldb":
- case "ldx":
- case "ldxb":
- case "ldxh":
- Register dest = opcode.contains("x") ? Register.R1 : Register.R0;
- if (arg.equals("4*([14]&0xf)")) {
- if (!opcode.equals("ldxb")) {
- throw new IllegalArgumentException("Unhandled instruction: " + line);
- }
- gen.addLoadFromMemory(dest, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
- break;
- }
- if (arg.equals("#pktlen")) {
- if (!opcode.equals("ld")) {
- throw new IllegalArgumentException("Unhandled instruction: " + line);
- }
- gen.addLoadFromMemory(dest, gen.PACKET_SIZE_MEMORY_SLOT);
- break;
- }
- if (arg.startsWith("#0x")) {
- if (!opcode.equals("ld")) {
- throw new IllegalArgumentException("Unhandled instruction: " + line);
- }
- gen.addLoadImmediate(dest, parseImm(line, arg));
- break;
- }
- if (arg.startsWith("M[")) {
- if (!opcode.startsWith("ld")) {
- throw new IllegalArgumentException("Unhandled instruction: " + line);
- }
- int memory_slot = Integer.parseInt(arg.substring(2, arg.length() - 1));
- if (memory_slot < 0 || memory_slot >= gen.MEMORY_SLOTS ||
- // Disallow use of pre-filled slots as BPF programs might
- // wrongfully assume they're initialized to 0.
- (memory_slot >= gen.FIRST_PREFILLED_MEMORY_SLOT &&
- memory_slot <= gen.LAST_PREFILLED_MEMORY_SLOT)) {
- throw new IllegalArgumentException("Unhandled instruction: " + line);
- }
- gen.addLoadFromMemory(dest, memory_slot);
- break;
- }
- if (arg.startsWith("[x + ")) {
- int offset = Integer.parseInt(arg.substring(5, arg.length() - 1));
- switch (opcode) {
- case "ld":
- case "ldx":
- gen.addLoad32Indexed(dest, offset);
- break;
- case "ldh":
- case "ldxh":
- gen.addLoad16Indexed(dest, offset);
- break;
- case "ldb":
- case "ldxb":
- gen.addLoad8Indexed(dest, offset);
- break;
- }
- } else {
- int offset = Integer.parseInt(arg.substring(1, arg.length() - 1));
- switch (opcode) {
- case "ld":
- case "ldx":
- gen.addLoad32(dest, offset);
- break;
- case "ldh":
- case "ldxh":
- gen.addLoad16(dest, offset);
- break;
- case "ldb":
- case "ldxb":
- gen.addLoad8(dest, offset);
- break;
- }
- }
- break;
- case "st":
- case "stx":
- Register src = opcode.contains("x") ? Register.R1 : Register.R0;
- if (!arg.startsWith("M[")) {
- throw new IllegalArgumentException("Unhandled instruction: " + line);
- }
- int memory_slot = Integer.parseInt(arg.substring(2, arg.length() - 1));
- if (memory_slot < 0 || memory_slot >= gen.MEMORY_SLOTS ||
- // Disallow overwriting pre-filled slots
- (memory_slot >= gen.FIRST_PREFILLED_MEMORY_SLOT &&
- memory_slot <= gen.LAST_PREFILLED_MEMORY_SLOT)) {
- throw new IllegalArgumentException("Unhandled instruction: " + line);
- }
- gen.addStoreToMemory(src, memory_slot);
- break;
- case "add":
- case "and":
- case "or":
- case "sub":
- if (arg.equals("x")) {
- switch(opcode) {
- case "add":
- gen.addAddR1();
- break;
- case "and":
- gen.addAndR1();
- break;
- case "or":
- gen.addOrR1();
- break;
- case "sub":
- gen.addNeg(Register.R1);
- gen.addAddR1();
- gen.addNeg(Register.R1);
- break;
- }
- } else {
- int imm = parseImm(line, arg);
- switch(opcode) {
- case "add":
- gen.addAdd(imm);
- break;
- case "and":
- gen.addAnd(imm);
- break;
- case "or":
- gen.addOr(imm);
- break;
- case "sub":
- gen.addAdd(-imm);
- break;
- }
- }
- break;
- case "jeq":
- case "jset":
- case "jgt":
- case "jge":
- int val = 0;
- boolean reg_compare;
- if (arg.startsWith("x")) {
- reg_compare = true;
- } else {
- reg_compare = false;
- val = parseImm(line, arg);
- }
- int jt_offset = line.indexOf("jt");
- int jf_offset = line.indexOf("jf");
- String true_label = line.substring(jt_offset + 2, jf_offset).trim();
- String false_label = line.substring(jf_offset + 2).trim();
- boolean true_label_is_fallthrough = Integer.parseInt(true_label) == label + 1;
- boolean false_label_is_fallthrough = Integer.parseInt(false_label) == label + 1;
- if (true_label_is_fallthrough && false_label_is_fallthrough)
- break;
- switch (opcode) {
- case "jeq":
- if (!true_label_is_fallthrough) {
- if (reg_compare) {
- gen.addJumpIfR0EqualsR1(true_label);
- } else {
- gen.addJumpIfR0Equals(val, true_label);
- }
- }
- if (!false_label_is_fallthrough) {
- if (!true_label_is_fallthrough) {
- gen.addJump(false_label);
- } else if (reg_compare) {
- gen.addJumpIfR0NotEqualsR1(false_label);
- } else {
- gen.addJumpIfR0NotEquals(val, false_label);
- }
- }
- break;
- case "jset":
- if (reg_compare) {
- gen.addJumpIfR0AnyBitsSetR1(true_label);
- } else {
- gen.addJumpIfR0AnyBitsSet(val, true_label);
- }
- if (!false_label_is_fallthrough) {
- gen.addJump(false_label);
- }
- break;
- case "jgt":
- if (!true_label_is_fallthrough ||
- // We have no less-than-or-equal-to register to register
- // comparison instruction, so in this case we'll jump
- // around an unconditional jump.
- (!false_label_is_fallthrough && reg_compare)) {
- if (reg_compare) {
- gen.addJumpIfR0GreaterThanR1(true_label);
- } else {
- gen.addJumpIfR0GreaterThan(val, true_label);
- }
- }
- if (!false_label_is_fallthrough) {
- if (!true_label_is_fallthrough || reg_compare) {
- gen.addJump(false_label);
- } else {
- gen.addJumpIfR0LessThan(val + 1, false_label);
- }
- }
- break;
- case "jge":
- if (!false_label_is_fallthrough ||
- // We have no greater-than-or-equal-to register to register
- // comparison instruction, so in this case we'll jump
- // around an unconditional jump.
- (!true_label_is_fallthrough && reg_compare)) {
- if (reg_compare) {
- gen.addJumpIfR0LessThanR1(false_label);
- } else {
- gen.addJumpIfR0LessThan(val, false_label);
- }
- }
- if (!true_label_is_fallthrough) {
- if (!false_label_is_fallthrough || reg_compare) {
- gen.addJump(true_label);
- } else {
- gen.addJumpIfR0GreaterThan(val - 1, true_label);
- }
- }
- break;
- }
- break;
- case "ret":
- if (arg.equals("#0")) {
- gen.addJump(gen.DROP_LABEL);
- } else {
- gen.addJump(gen.PASS_LABEL);
- }
- break;
- case "tax":
- gen.addMove(Register.R1);
- break;
- case "txa":
- gen.addMove(Register.R0);
- break;
- default:
- throw new IllegalArgumentException("Unhandled instruction: " + line);
- }
- }
-
- /**
- * Convert the output of "tcpdump -d" (human readable BPF program dump) {@code bpf} into an APF
- * program and return it.
- */
- public static byte[] convert(String bpf) throws IllegalInstructionException {
- ApfGenerator gen = new ApfGenerator(3);
- for (String line : bpf.split("\\n")) convertLine(line, gen);
- return gen.generate();
- }
-
- /**
- * Convert the output of "tcpdump -d" (human readable BPF program dump) piped in stdin into an
- * APF program and output it via stdout.
- */
- public static void main(String[] args) throws Exception {
- BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
- String line = null;
- StringBuilder responseData = new StringBuilder();
- ApfGenerator gen = new ApfGenerator(3);
- while ((line = in.readLine()) != null) convertLine(line, gen);
- System.out.write(gen.generate());
- }
-}
diff --git a/tests/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java b/tests/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java
deleted file mode 100644
index f948086..0000000
--- a/tests/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2018 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.captiveportal;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.MalformedURLException;
-import java.text.ParseException;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class CaptivePortalProbeSpecTest {
-
- @Test
- public void testGetResult_Regex() throws MalformedURLException, ParseException {
- // 2xx status or 404, with an empty (match everything) location regex
- CaptivePortalProbeSpec statusRegexSpec = CaptivePortalProbeSpec.parseSpec(
- "http://www.google.com@@/@@2[0-9]{2}|404@@/@@");
-
- // 404, or 301/302 redirect to some HTTPS page under google.com
- CaptivePortalProbeSpec redirectSpec = CaptivePortalProbeSpec.parseSpec(
- "http://google.com@@/@@404|30[12]@@/@@https://([0-9a-z]+\\.)*google\\.com.*");
-
- assertSuccess(statusRegexSpec.getResult(200, null));
- assertSuccess(statusRegexSpec.getResult(299, "qwer"));
- assertSuccess(statusRegexSpec.getResult(404, null));
- assertSuccess(statusRegexSpec.getResult(404, ""));
-
- assertPortal(statusRegexSpec.getResult(300, null));
- assertPortal(statusRegexSpec.getResult(399, "qwer"));
- assertPortal(statusRegexSpec.getResult(500, null));
-
- assertSuccess(redirectSpec.getResult(404, null));
- assertSuccess(redirectSpec.getResult(404, ""));
- assertSuccess(redirectSpec.getResult(301, "https://www.google.com"));
- assertSuccess(redirectSpec.getResult(301, "https://www.google.com/test?q=3"));
- assertSuccess(redirectSpec.getResult(302, "https://google.com/test?q=3"));
-
- assertPortal(redirectSpec.getResult(299, "https://google.com/test?q=3"));
- assertPortal(redirectSpec.getResult(299, ""));
- assertPortal(redirectSpec.getResult(499, null));
- assertPortal(redirectSpec.getResult(301, "http://login.portal.example.com/loginpage"));
- assertPortal(redirectSpec.getResult(302, "http://www.google.com/test?q=3"));
- }
-
- @Test(expected = ParseException.class)
- public void testParseSpec_Empty() throws MalformedURLException, ParseException {
- CaptivePortalProbeSpec.parseSpec("");
- }
-
- @Test(expected = ParseException.class)
- public void testParseSpec_Null() throws MalformedURLException, ParseException {
- CaptivePortalProbeSpec.parseSpec(null);
- }
-
- @Test(expected = ParseException.class)
- public void testParseSpec_MissingParts() throws MalformedURLException, ParseException {
- CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123");
- }
-
- @Test(expected = ParseException.class)
- public void testParseSpec_TooManyParts() throws MalformedURLException, ParseException {
- CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123@@/@@456@@/@@extra");
- }
-
- @Test(expected = ParseException.class)
- public void testParseSpec_InvalidStatusRegex() throws MalformedURLException, ParseException {
- CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@unmatched(parenthesis@@/@@456");
- }
-
- @Test(expected = ParseException.class)
- public void testParseSpec_InvalidLocationRegex() throws MalformedURLException, ParseException {
- CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123@@/@@unmatched[[]bracket");
- }
-
- @Test(expected = MalformedURLException.class)
- public void testParseSpec_EmptyURL() throws MalformedURLException, ParseException {
- CaptivePortalProbeSpec.parseSpec("@@/@@123@@/@@123");
- }
-
- @Test(expected = ParseException.class)
- public void testParseSpec_NoParts() throws MalformedURLException, ParseException {
- CaptivePortalProbeSpec.parseSpec("invalid");
- }
-
- @Test(expected = MalformedURLException.class)
- public void testParseSpec_RegexInvalidUrl() throws MalformedURLException, ParseException {
- CaptivePortalProbeSpec.parseSpec("notaurl@@/@@123@@/@@123");
- }
-
- @Test
- public void testParseSpecOrNull_UsesSpec() {
- final String specUrl = "http://google.com/probe";
- final String redirectUrl = "https://google.com/probe";
- CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull(
- specUrl + "@@/@@302@@/@@" + redirectUrl);
- assertEquals(specUrl, spec.getUrl().toString());
-
- assertPortal(spec.getResult(302, "http://portal.example.com"));
- assertSuccess(spec.getResult(302, redirectUrl));
- }
-
- @Test
- public void testParseSpecOrNull_UsesFallback() throws MalformedURLException {
- CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull(null);
- assertNull(spec);
-
- spec = CaptivePortalProbeSpec.parseSpecOrNull("");
- assertNull(spec);
-
- spec = CaptivePortalProbeSpec.parseSpecOrNull("@@/@@ @@/@@ @@/@@");
- assertNull(spec);
-
- spec = CaptivePortalProbeSpec.parseSpecOrNull("invalid@@/@@123@@/@@456");
- assertNull(spec);
- }
-
- @Test
- public void testParseSpecOrUseStatusCodeFallback_EmptySpec() throws MalformedURLException {
- CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull("");
- assertNull(spec);
- }
-
- private void assertIsStatusSpec(CaptivePortalProbeSpec spec) {
- assertSuccess(spec.getResult(204, null));
- assertSuccess(spec.getResult(204, "1234"));
-
- assertPortal(spec.getResult(200, null));
- assertPortal(spec.getResult(301, null));
- assertPortal(spec.getResult(302, "1234"));
- assertPortal(spec.getResult(399, ""));
-
- assertFailed(spec.getResult(404, null));
- assertFailed(spec.getResult(500, "1234"));
- }
-
- private void assertPortal(CaptivePortalProbeResult result) {
- assertTrue(result.isPortal());
- }
-
- private void assertSuccess(CaptivePortalProbeResult result) {
- assertTrue(result.isSuccessful());
- }
-
- private void assertFailed(CaptivePortalProbeResult result) {
- assertTrue(result.isFailed());
- }
-}
diff --git a/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java b/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
deleted file mode 100644
index 27d7255..0000000
--- a/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.dhcp.DhcpLease.HOSTNAME_NONE;
-import static android.net.dhcp.DhcpLeaseRepository.CLIENTID_UNSPEC;
-import static android.net.dhcp.DhcpLeaseRepository.INETADDR_UNSPEC;
-
-import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.IpPrefix;
-import android.net.MacAddress;
-import android.net.dhcp.DhcpServer.Clock;
-import android.net.util.SharedLog;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import static java.lang.String.format;
-
-import java.net.Inet4Address;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DhcpLeaseRepositoryTest {
- private static final Inet4Address TEST_DEF_ROUTER = parseAddr4("192.168.42.247");
- private static final Inet4Address TEST_SERVER_ADDR = parseAddr4("192.168.42.241");
- private static final Inet4Address TEST_RESERVED_ADDR = parseAddr4("192.168.42.243");
- private static final MacAddress TEST_MAC_1 = MacAddress.fromBytes(
- new byte[] { 5, 4, 3, 2, 1, 0 });
- private static final MacAddress TEST_MAC_2 = MacAddress.fromBytes(
- new byte[] { 0, 1, 2, 3, 4, 5 });
- private static final MacAddress TEST_MAC_3 = MacAddress.fromBytes(
- new byte[] { 0, 1, 2, 3, 4, 6 });
- private static final Inet4Address TEST_INETADDR_1 = parseAddr4("192.168.42.248");
- private static final Inet4Address TEST_INETADDR_2 = parseAddr4("192.168.42.249");
- private static final String TEST_HOSTNAME_1 = "hostname1";
- private static final String TEST_HOSTNAME_2 = "hostname2";
- private static final IpPrefix TEST_IP_PREFIX = new IpPrefix(TEST_SERVER_ADDR, 22);
- private static final long TEST_TIME = 100L;
- private static final int TEST_LEASE_TIME_MS = 3_600_000;
- private static final Set<Inet4Address> TEST_EXCL_SET =
- Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
- TEST_SERVER_ADDR, TEST_DEF_ROUTER, TEST_RESERVED_ADDR)));
-
- @NonNull
- private SharedLog mLog;
- @NonNull @Mock
- private Clock mClock;
- @NonNull
- private DhcpLeaseRepository mRepo;
-
- private static Inet4Address parseAddr4(String inet4Addr) {
- return (Inet4Address) parseNumericAddress(inet4Addr);
- }
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mLog = new SharedLog("DhcpLeaseRepositoryTest");
- when(mClock.elapsedRealtime()).thenReturn(TEST_TIME);
- mRepo = new DhcpLeaseRepository(
- TEST_IP_PREFIX, TEST_EXCL_SET, TEST_LEASE_TIME_MS, mLog, mClock);
- }
-
- /**
- * Request a number of addresses through offer/request. Useful to test address exhaustion.
- * @param nAddr Number of addresses to request.
- */
- private void requestAddresses(byte nAddr) throws Exception {
- final HashSet<Inet4Address> addrs = new HashSet<>();
- byte[] hwAddrBytes = new byte[] { 8, 4, 3, 2, 1, 0 };
- for (byte i = 0; i < nAddr; i++) {
- hwAddrBytes[5] = i;
- MacAddress newMac = MacAddress.fromBytes(hwAddrBytes);
- final String hostname = "host_" + i;
- final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, newMac,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, hostname);
-
- assertNotNull(lease);
- assertEquals(newMac, lease.getHwAddr());
- assertEquals(hostname, lease.getHostname());
- assertTrue(format("Duplicate address allocated: %s in %s", lease.getNetAddr(), addrs),
- addrs.add(lease.getNetAddr()));
-
- requestLeaseSelecting(newMac, lease.getNetAddr(), hostname);
- }
- }
-
- @Test
- public void testAddressExhaustion() throws Exception {
- // Use a /28 to quickly run out of addresses
- mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS);
-
- // /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses
- requestAddresses((byte) 11);
-
- try {
- mRepo.getOffer(null, TEST_MAC_2,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
- fail("Should be out of addresses");
- } catch (DhcpLeaseRepository.OutOfAddressesException e) {
- // Expected
- }
- }
-
- @Test
- public void testUpdateParams_LeaseCleanup() throws Exception {
- // Inside /28:
- final Inet4Address reqAddrIn28 = parseAddr4("192.168.42.242");
- final Inet4Address declinedAddrIn28 = parseAddr4("192.168.42.245");
-
- // Inside /28, but not available there (first address of the range)
- final Inet4Address declinedFirstAddrIn28 = parseAddr4("192.168.42.240");
-
- final DhcpLease reqAddrIn28Lease = requestLeaseSelecting(TEST_MAC_1, reqAddrIn28);
- mRepo.markLeaseDeclined(declinedAddrIn28);
- mRepo.markLeaseDeclined(declinedFirstAddrIn28);
-
- // Inside /22, but outside /28:
- final Inet4Address reqAddrIn22 = parseAddr4("192.168.42.3");
- final Inet4Address declinedAddrIn22 = parseAddr4("192.168.42.4");
-
- final DhcpLease reqAddrIn22Lease = requestLeaseSelecting(TEST_MAC_3, reqAddrIn22);
- mRepo.markLeaseDeclined(declinedAddrIn22);
-
- // Address that will be reserved in the updateParams call below
- final Inet4Address reservedAddr = parseAddr4("192.168.42.244");
- final DhcpLease reservedAddrLease = requestLeaseSelecting(TEST_MAC_2, reservedAddr);
-
- // Update from /22 to /28 and add another reserved address
- Set<Inet4Address> newReserved = new HashSet<>(TEST_EXCL_SET);
- newReserved.add(reservedAddr);
- mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), newReserved, TEST_LEASE_TIME_MS);
-
- assertHasLease(reqAddrIn28Lease);
- assertDeclined(declinedAddrIn28);
-
- assertNotDeclined(declinedFirstAddrIn28);
-
- assertNoLease(reqAddrIn22Lease);
- assertNotDeclined(declinedAddrIn22);
-
- assertNoLease(reservedAddrLease);
- }
-
- @Test
- public void testGetOffer_StableAddress() throws Exception {
- for (final MacAddress macAddr : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
- final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-
- // Same lease is offered twice
- final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
- assertEquals(lease, newLease);
- }
- }
-
- @Test
- public void testUpdateParams_UsesNewPrefix() throws Exception {
- final IpPrefix newPrefix = new IpPrefix(parseAddr4("192.168.123.0"), 24);
- mRepo.updateParams(newPrefix, TEST_EXCL_SET, TEST_LEASE_TIME_MS);
-
- DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
- assertTrue(newPrefix.contains(lease.getNetAddr()));
- }
-
- @Test
- public void testGetOffer_ExistingLease() throws Exception {
- requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1, TEST_HOSTNAME_1);
-
- DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
- assertEquals(TEST_INETADDR_1, offer.getNetAddr());
- assertEquals(TEST_HOSTNAME_1, offer.getHostname());
- }
-
- @Test
- public void testGetOffer_ClientIdHasExistingLease() throws Exception {
- final byte[] clientId = new byte[] { 1, 2 };
- mRepo.requestLease(clientId, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
- IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false,
- TEST_HOSTNAME_1);
-
- // Different MAC, but same clientId
- DhcpLease offer = mRepo.getOffer(clientId, TEST_MAC_2,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
- assertEquals(TEST_INETADDR_1, offer.getNetAddr());
- assertEquals(TEST_HOSTNAME_1, offer.getHostname());
- }
-
- @Test
- public void testGetOffer_DifferentClientId() throws Exception {
- final byte[] clientId1 = new byte[] { 1, 2 };
- final byte[] clientId2 = new byte[] { 3, 4 };
- mRepo.requestLease(clientId1, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
- IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false,
- TEST_HOSTNAME_1);
-
- // Same MAC, different client ID
- DhcpLease offer = mRepo.getOffer(clientId2, TEST_MAC_1,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
- // Obtains a different address
- assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
- assertEquals(HOSTNAME_NONE, offer.getHostname());
- assertEquals(TEST_MAC_1, offer.getHwAddr());
- }
-
- @Test
- public void testGetOffer_RequestedAddress() throws Exception {
- DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
- TEST_INETADDR_1 /* reqAddr */, TEST_HOSTNAME_1);
- assertEquals(TEST_INETADDR_1, offer.getNetAddr());
- assertEquals(TEST_HOSTNAME_1, offer.getHostname());
- }
-
- @Test
- public void testGetOffer_RequestedAddressInUse() throws Exception {
- requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
- DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, IPV4_ADDR_ANY /* relayAddr */,
- TEST_INETADDR_1 /* reqAddr */, HOSTNAME_NONE);
- assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
- }
-
- @Test
- public void testGetOffer_RequestedAddressReserved() throws Exception {
- DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
- TEST_RESERVED_ADDR /* reqAddr */, HOSTNAME_NONE);
- assertNotEquals(TEST_RESERVED_ADDR, offer.getNetAddr());
- }
-
- @Test
- public void testGetOffer_RequestedAddressInvalid() throws Exception {
- final Inet4Address invalidAddr = parseAddr4("192.168.42.0");
- DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
- invalidAddr /* reqAddr */, HOSTNAME_NONE);
- assertNotEquals(invalidAddr, offer.getNetAddr());
- }
-
- @Test
- public void testGetOffer_RequestedAddressOutsideSubnet() throws Exception {
- final Inet4Address invalidAddr = parseAddr4("192.168.254.2");
- DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
- invalidAddr /* reqAddr */, HOSTNAME_NONE);
- assertNotEquals(invalidAddr, offer.getNetAddr());
- }
-
- @Test(expected = DhcpLeaseRepository.InvalidSubnetException.class)
- public void testGetOffer_RelayInInvalidSubnet() throws Exception {
- mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, parseAddr4("192.168.254.2") /* relayAddr */,
- INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
- }
-
- @Test
- public void testRequestLease_SelectingTwice() throws Exception {
- final DhcpLease lease1 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1,
- TEST_HOSTNAME_1);
-
- // Second request from same client for a different address
- final DhcpLease lease2 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_2,
- TEST_HOSTNAME_2);
-
- assertEquals(TEST_INETADDR_1, lease1.getNetAddr());
- assertEquals(TEST_HOSTNAME_1, lease1.getHostname());
-
- assertEquals(TEST_INETADDR_2, lease2.getNetAddr());
- assertEquals(TEST_HOSTNAME_2, lease2.getHostname());
-
- // First address freed when client requested a different one: another client can request it
- final DhcpLease lease3 = requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1, HOSTNAME_NONE);
- assertEquals(TEST_INETADDR_1, lease3.getNetAddr());
- }
-
- @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
- public void testRequestLease_SelectingInvalid() throws Exception {
- requestLeaseSelecting(TEST_MAC_1, parseAddr4("192.168.254.5"));
- }
-
- @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
- public void testRequestLease_SelectingInUse() throws Exception {
- requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
- requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
- }
-
- @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
- public void testRequestLease_SelectingReserved() throws Exception {
- requestLeaseSelecting(TEST_MAC_1, TEST_RESERVED_ADDR);
- }
-
- @Test(expected = DhcpLeaseRepository.InvalidSubnetException.class)
- public void testRequestLease_SelectingRelayInInvalidSubnet() throws Exception {
- mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
- parseAddr4("192.168.128.1") /* relayAddr */, TEST_INETADDR_1 /* reqAddr */,
- true /* sidSet */, HOSTNAME_NONE);
- }
-
- @Test
- public void testRequestLease_InitReboot() throws Exception {
- // Request address once
- requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-
- final long newTime = TEST_TIME + 100;
- when(mClock.elapsedRealtime()).thenReturn(newTime);
-
- // init-reboot (sidSet == false): verify configuration
- final DhcpLease lease = requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_1);
- assertEquals(TEST_INETADDR_1, lease.getNetAddr());
- assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
- }
-
- @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
- public void testRequestLease_InitRebootWrongAddr() throws Exception {
- // Request address once
- requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
- // init-reboot with different requested address
- requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_2);
- }
-
- @Test
- public void testRequestLease_InitRebootUnknownAddr() throws Exception {
- // init-reboot with unknown requested address
- final DhcpLease lease = requestLeaseInitReboot(TEST_MAC_1, TEST_INETADDR_2);
- // RFC2131 says we should not reply to accommodate other servers, but since we are
- // authoritative we allow creating the lease to avoid issues with lost lease DB (same as
- // dnsmasq behavior)
- assertEquals(TEST_INETADDR_2, lease.getNetAddr());
- }
-
- @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
- public void testRequestLease_InitRebootWrongSubnet() throws Exception {
- requestLeaseInitReboot(TEST_MAC_1, parseAddr4("192.168.254.2"));
- }
-
- @Test
- public void testRequestLease_Renewing() throws Exception {
- requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-
- final long newTime = TEST_TIME + 100;
- when(mClock.elapsedRealtime()).thenReturn(newTime);
-
- final DhcpLease lease = requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
-
- assertEquals(TEST_INETADDR_1, lease.getNetAddr());
- assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
- }
-
- @Test
- public void testRequestLease_RenewingUnknownAddr() throws Exception {
- final long newTime = TEST_TIME + 100;
- when(mClock.elapsedRealtime()).thenReturn(newTime);
- final DhcpLease lease = requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
- // Allows renewing an unknown address if available
- assertEquals(TEST_INETADDR_1, lease.getNetAddr());
- assertEquals(newTime + TEST_LEASE_TIME_MS, lease.getExpTime());
- }
-
- @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
- public void testRequestLease_RenewingAddrInUse() throws Exception {
- requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
- requestLeaseRenewing(TEST_MAC_1, TEST_INETADDR_1);
- }
-
- @Test(expected = DhcpLeaseRepository.InvalidAddressException.class)
- public void testRequestLease_RenewingInvalidAddr() throws Exception {
- requestLeaseRenewing(TEST_MAC_1, parseAddr4("192.168.254.2"));
- }
-
- @Test
- public void testReleaseLease() throws Exception {
- final DhcpLease lease1 = requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-
- assertHasLease(lease1);
- assertTrue(mRepo.releaseLease(CLIENTID_UNSPEC, TEST_MAC_1, TEST_INETADDR_1));
- assertNoLease(lease1);
-
- final DhcpLease lease2 = requestLeaseSelecting(TEST_MAC_2, TEST_INETADDR_1);
- assertEquals(TEST_INETADDR_1, lease2.getNetAddr());
- }
-
- @Test
- public void testReleaseLease_UnknownLease() {
- assertFalse(mRepo.releaseLease(CLIENTID_UNSPEC, TEST_MAC_1, TEST_INETADDR_1));
- }
-
- @Test
- public void testReleaseLease_StableOffer() throws Exception {
- for (MacAddress mac : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
- final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-
- requestLeaseSelecting(mac, lease.getNetAddr());
- mRepo.releaseLease(CLIENTID_UNSPEC, mac, lease.getNetAddr());
-
- // Same lease is offered after it was released
- final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
- assertEquals(lease.getNetAddr(), newLease.getNetAddr());
- }
- }
-
- @Test
- public void testMarkLeaseDeclined() throws Exception {
- final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
-
- mRepo.markLeaseDeclined(lease.getNetAddr());
-
- // Same lease is not offered again
- final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
- assertNotEquals(lease.getNetAddr(), newLease.getNetAddr());
- }
-
- @Test
- public void testMarkLeaseDeclined_UsedIfOutOfAddresses() throws Exception {
- // Use a /28 to quickly run out of addresses
- mRepo.updateParams(new IpPrefix(TEST_SERVER_ADDR, 28), TEST_EXCL_SET, TEST_LEASE_TIME_MS);
-
- mRepo.markLeaseDeclined(TEST_INETADDR_1);
- mRepo.markLeaseDeclined(TEST_INETADDR_2);
-
- // /28 should have 16 addresses, 14 w/o the first/last, 11 w/o excluded addresses
- requestAddresses((byte) 9);
-
- // Last 2 addresses: addresses marked declined should be used
- final DhcpLease firstLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_1);
- requestLeaseSelecting(TEST_MAC_1, firstLease.getNetAddr());
-
- final DhcpLease secondLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2,
- IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_2);
- requestLeaseSelecting(TEST_MAC_2, secondLease.getNetAddr());
-
- // Now out of addresses
- try {
- mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_3, IPV4_ADDR_ANY /* relayAddr */,
- INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
- fail("Repository should be out of addresses and throw");
- } catch (DhcpLeaseRepository.OutOfAddressesException e) { /* expected */ }
-
- assertEquals(TEST_INETADDR_1, firstLease.getNetAddr());
- assertEquals(TEST_HOSTNAME_1, firstLease.getHostname());
- assertEquals(TEST_INETADDR_2, secondLease.getNetAddr());
- assertEquals(TEST_HOSTNAME_2, secondLease.getHostname());
- }
-
- private DhcpLease requestLease(@NonNull MacAddress macAddr, @NonNull Inet4Address clientAddr,
- @Nullable Inet4Address reqAddr, @Nullable String hostname, boolean sidSet)
- throws DhcpLeaseRepository.DhcpLeaseException {
- return mRepo.requestLease(CLIENTID_UNSPEC, macAddr, clientAddr,
- IPV4_ADDR_ANY /* relayAddr */,
- reqAddr, sidSet, hostname);
- }
-
- /**
- * Request a lease simulating a client in the SELECTING state.
- */
- private DhcpLease requestLeaseSelecting(@NonNull MacAddress macAddr,
- @NonNull Inet4Address reqAddr, @Nullable String hostname)
- throws DhcpLeaseRepository.DhcpLeaseException {
- return requestLease(macAddr, IPV4_ADDR_ANY /* clientAddr */, reqAddr, hostname,
- true /* sidSet */);
- }
-
- /**
- * Request a lease simulating a client in the SELECTING state.
- */
- private DhcpLease requestLeaseSelecting(@NonNull MacAddress macAddr,
- @NonNull Inet4Address reqAddr) throws DhcpLeaseRepository.DhcpLeaseException {
- return requestLeaseSelecting(macAddr, reqAddr, HOSTNAME_NONE);
- }
-
- /**
- * Request a lease simulating a client in the INIT-REBOOT state.
- */
- private DhcpLease requestLeaseInitReboot(@NonNull MacAddress macAddr,
- @NonNull Inet4Address reqAddr) throws DhcpLeaseRepository.DhcpLeaseException {
- return requestLease(macAddr, IPV4_ADDR_ANY /* clientAddr */, reqAddr, HOSTNAME_NONE,
- false /* sidSet */);
- }
-
- /**
- * Request a lease simulating a client in the RENEWING state.
- */
- private DhcpLease requestLeaseRenewing(@NonNull MacAddress macAddr,
- @NonNull Inet4Address clientAddr) throws DhcpLeaseRepository.DhcpLeaseException {
- // Renewing: clientAddr filled in, no reqAddr
- return requestLease(macAddr, clientAddr, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE,
- true /* sidSet */);
- }
-
- private void assertNoLease(DhcpLease lease) {
- assertFalse("Leases contain " + lease, mRepo.getCommittedLeases().contains(lease));
- }
-
- private void assertHasLease(DhcpLease lease) {
- assertTrue("Leases do not contain " + lease, mRepo.getCommittedLeases().contains(lease));
- }
-
- private void assertNotDeclined(Inet4Address addr) {
- assertFalse("Address is declined: " + addr, mRepo.getDeclinedAddresses().contains(addr));
- }
-
- private void assertDeclined(Inet4Address addr) {
- assertTrue("Address is not declined: " + addr, mRepo.getDeclinedAddresses().contains(addr));
- }
-}
diff --git a/tests/src/android/net/dhcp/DhcpPacketTest.java b/tests/src/android/net/dhcp/DhcpPacketTest.java
deleted file mode 100644
index a30d3e4..0000000
--- a/tests/src/android/net/dhcp/DhcpPacketTest.java
+++ /dev/null
@@ -1,1117 +0,0 @@
-/*
- * Copyright (C) 2015 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.dhcp;
-
-import static android.net.dhcp.DhcpPacket.DHCP_BROADCAST_ADDRESS;
-import static android.net.dhcp.DhcpPacket.DHCP_DNS_SERVER;
-import static android.net.dhcp.DhcpPacket.DHCP_DOMAIN_NAME;
-import static android.net.dhcp.DhcpPacket.DHCP_LEASE_TIME;
-import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_ACK;
-import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_OFFER;
-import static android.net.dhcp.DhcpPacket.DHCP_MTU;
-import static android.net.dhcp.DhcpPacket.DHCP_REBINDING_TIME;
-import static android.net.dhcp.DhcpPacket.DHCP_RENEWAL_TIME;
-import static android.net.dhcp.DhcpPacket.DHCP_ROUTER;
-import static android.net.dhcp.DhcpPacket.DHCP_SUBNET_MASK;
-import static android.net.dhcp.DhcpPacket.DHCP_VENDOR_INFO;
-import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
-import static android.net.dhcp.DhcpPacket.ENCAP_L2;
-import static android.net.dhcp.DhcpPacket.ENCAP_L3;
-import static android.net.dhcp.DhcpPacket.INADDR_ANY;
-import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
-import static android.net.dhcp.DhcpPacket.ParseException;
-import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
-import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.annotation.Nullable;
-import android.net.DhcpResults;
-import android.net.LinkAddress;
-import android.net.NetworkUtils;
-import android.net.metrics.DhcpErrorEvent;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.HexDump;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayOutputStream;
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Random;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DhcpPacketTest {
-
- private static final Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
- private static final Inet4Address CLIENT_ADDR = v4Address("192.0.2.234");
- private static final int PREFIX_LENGTH = 22;
- private static final Inet4Address NETMASK = getPrefixMaskAsInet4Address(PREFIX_LENGTH);
- private static final Inet4Address BROADCAST_ADDR = getBroadcastAddress(
- SERVER_ADDR, PREFIX_LENGTH);
- private static final String HOSTNAME = "testhostname";
- private static final short MTU = 1500;
- // Use our own empty address instead of IPV4_ADDR_ANY or INADDR_ANY to ensure that the code
- // doesn't use == instead of equals when comparing addresses.
- private static final Inet4Address ANY = v4Address("0.0.0.0");
-
- private static final byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
-
- private static final Inet4Address v4Address(String addrString) throws IllegalArgumentException {
- return (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
- }
-
- @Before
- public void setUp() {
- DhcpPacket.testOverrideVendorId = "android-dhcp-???";
- DhcpPacket.testOverrideHostname = "android-01234567890abcde";
- }
-
- class TestDhcpPacket extends DhcpPacket {
- private byte mType;
- // TODO: Make this a map of option numbers to bytes instead.
- private byte[] mDomainBytes, mVendorInfoBytes, mLeaseTimeBytes, mNetmaskBytes;
-
- public TestDhcpPacket(byte type, Inet4Address clientIp, Inet4Address yourIp) {
- super(0xdeadbeef, (short) 0, clientIp, yourIp, INADDR_ANY, INADDR_ANY,
- CLIENT_MAC, true);
- mType = type;
- }
-
- public TestDhcpPacket(byte type) {
- this(type, INADDR_ANY, CLIENT_ADDR);
- }
-
- public TestDhcpPacket setDomainBytes(byte[] domainBytes) {
- mDomainBytes = domainBytes;
- return this;
- }
-
- public TestDhcpPacket setVendorInfoBytes(byte[] vendorInfoBytes) {
- mVendorInfoBytes = vendorInfoBytes;
- return this;
- }
-
- public TestDhcpPacket setLeaseTimeBytes(byte[] leaseTimeBytes) {
- mLeaseTimeBytes = leaseTimeBytes;
- return this;
- }
-
- public TestDhcpPacket setNetmaskBytes(byte[] netmaskBytes) {
- mNetmaskBytes = netmaskBytes;
- return this;
- }
-
- public ByteBuffer buildPacket(int encap, short unusedDestUdp, short unusedSrcUdp) {
- ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
- fillInPacket(encap, CLIENT_ADDR, SERVER_ADDR,
- DHCP_CLIENT, DHCP_SERVER, result, DHCP_BOOTREPLY, false);
- return result;
- }
-
- public void finishPacket(ByteBuffer buffer) {
- addTlv(buffer, DHCP_MESSAGE_TYPE, mType);
- if (mDomainBytes != null) {
- addTlv(buffer, DHCP_DOMAIN_NAME, mDomainBytes);
- }
- if (mVendorInfoBytes != null) {
- addTlv(buffer, DHCP_VENDOR_INFO, mVendorInfoBytes);
- }
- if (mLeaseTimeBytes != null) {
- addTlv(buffer, DHCP_LEASE_TIME, mLeaseTimeBytes);
- }
- if (mNetmaskBytes != null) {
- addTlv(buffer, DHCP_SUBNET_MASK, mNetmaskBytes);
- }
- addTlvEnd(buffer);
- }
-
- // Convenience method.
- public ByteBuffer build() {
- // ENCAP_BOOTP packets don't contain ports, so just pass in 0.
- ByteBuffer pkt = buildPacket(ENCAP_BOOTP, (short) 0, (short) 0);
- pkt.flip();
- return pkt;
- }
- }
-
- private void assertDomainAndVendorInfoParses(
- String expectedDomain, byte[] domainBytes,
- String expectedVendorInfo, byte[] vendorInfoBytes) throws Exception {
- ByteBuffer packet = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER)
- .setDomainBytes(domainBytes)
- .setVendorInfoBytes(vendorInfoBytes)
- .build();
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
- assertEquals(expectedDomain, offerPacket.mDomainName);
- assertEquals(expectedVendorInfo, offerPacket.mVendorInfo);
- }
-
- @Test
- public void testDomainName() throws Exception {
- byte[] nullByte = new byte[] { 0x00 };
- byte[] twoNullBytes = new byte[] { 0x00, 0x00 };
- byte[] nonNullDomain = new byte[] {
- (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l'
- };
- byte[] trailingNullDomain = new byte[] {
- (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l', 0x00
- };
- byte[] embeddedNullsDomain = new byte[] {
- (byte) 'g', (byte) 'o', (byte) 'o', 0x00, 0x00, (byte) 'g', (byte) 'l'
- };
- byte[] metered = "ANDROID_METERED".getBytes("US-ASCII");
-
- byte[] meteredEmbeddedNull = metered.clone();
- meteredEmbeddedNull[7] = (char) 0;
-
- byte[] meteredTrailingNull = metered.clone();
- meteredTrailingNull[meteredTrailingNull.length - 1] = (char) 0;
-
- assertDomainAndVendorInfoParses("", nullByte, "\u0000", nullByte);
- assertDomainAndVendorInfoParses("", twoNullBytes, "\u0000\u0000", twoNullBytes);
- assertDomainAndVendorInfoParses("goo.gl", nonNullDomain, "ANDROID_METERED", metered);
- assertDomainAndVendorInfoParses("goo", embeddedNullsDomain,
- "ANDROID\u0000METERED", meteredEmbeddedNull);
- assertDomainAndVendorInfoParses("goo.gl", trailingNullDomain,
- "ANDROID_METERE\u0000", meteredTrailingNull);
- }
-
- private void assertLeaseTimeParses(boolean expectValid, Integer rawLeaseTime,
- long leaseTimeMillis, byte[] leaseTimeBytes) throws Exception {
- TestDhcpPacket testPacket = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER);
- if (leaseTimeBytes != null) {
- testPacket.setLeaseTimeBytes(leaseTimeBytes);
- }
- ByteBuffer packet = testPacket.build();
- DhcpPacket offerPacket = null;
-
- if (!expectValid) {
- try {
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
- fail("Invalid packet parsed successfully: " + offerPacket);
- } catch (ParseException expected) {
- }
- return;
- }
-
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
- assertNotNull(offerPacket);
- assertEquals(rawLeaseTime, offerPacket.mLeaseTime);
- DhcpResults dhcpResults = offerPacket.toDhcpResults(); // Just check this doesn't crash.
- assertEquals(leaseTimeMillis, offerPacket.getLeaseTimeMillis());
- }
-
- @Test
- public void testLeaseTime() throws Exception {
- byte[] noLease = null;
- byte[] tooShortLease = new byte[] { 0x00, 0x00 };
- byte[] tooLongLease = new byte[] { 0x00, 0x00, 0x00, 60, 0x01 };
- byte[] zeroLease = new byte[] { 0x00, 0x00, 0x00, 0x00 };
- byte[] tenSecondLease = new byte[] { 0x00, 0x00, 0x00, 10 };
- byte[] oneMinuteLease = new byte[] { 0x00, 0x00, 0x00, 60 };
- byte[] fiveMinuteLease = new byte[] { 0x00, 0x00, 0x01, 0x2c };
- byte[] oneDayLease = new byte[] { 0x00, 0x01, 0x51, (byte) 0x80 };
- byte[] maxIntPlusOneLease = new byte[] { (byte) 0x80, 0x00, 0x00, 0x01 };
- byte[] infiniteLease = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
-
- assertLeaseTimeParses(true, null, 0, noLease);
- assertLeaseTimeParses(false, null, 0, tooShortLease);
- assertLeaseTimeParses(false, null, 0, tooLongLease);
- assertLeaseTimeParses(true, 0, 60 * 1000, zeroLease);
- assertLeaseTimeParses(true, 10, 60 * 1000, tenSecondLease);
- assertLeaseTimeParses(true, 60, 60 * 1000, oneMinuteLease);
- assertLeaseTimeParses(true, 300, 300 * 1000, fiveMinuteLease);
- assertLeaseTimeParses(true, 86400, 86400 * 1000, oneDayLease);
- assertLeaseTimeParses(true, -2147483647, 2147483649L * 1000, maxIntPlusOneLease);
- assertLeaseTimeParses(true, DhcpPacket.INFINITE_LEASE, 0, infiniteLease);
- }
-
- private void checkIpAddress(String expected, Inet4Address clientIp, Inet4Address yourIp,
- byte[] netmaskBytes) throws Exception {
- checkIpAddress(expected, DHCP_MESSAGE_TYPE_OFFER, clientIp, yourIp, netmaskBytes);
- checkIpAddress(expected, DHCP_MESSAGE_TYPE_ACK, clientIp, yourIp, netmaskBytes);
- }
-
- private void checkIpAddress(String expected, byte type,
- Inet4Address clientIp, Inet4Address yourIp,
- byte[] netmaskBytes) throws Exception {
- ByteBuffer packet = new TestDhcpPacket(type, clientIp, yourIp)
- .setNetmaskBytes(netmaskBytes)
- .build();
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
- DhcpResults results = offerPacket.toDhcpResults();
-
- if (expected != null) {
- LinkAddress expectedAddress = new LinkAddress(expected);
- assertEquals(expectedAddress, results.ipAddress);
- } else {
- assertNull(results);
- }
- }
-
- @Test
- public void testIpAddress() throws Exception {
- byte[] slash11Netmask = new byte[] { (byte) 0xff, (byte) 0xe0, 0x00, 0x00 };
- byte[] slash24Netmask = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00 };
- byte[] invalidNetmask = new byte[] { (byte) 0xff, (byte) 0xfb, (byte) 0xff, 0x00 };
- Inet4Address example1 = v4Address("192.0.2.1");
- Inet4Address example2 = v4Address("192.0.2.43");
-
- // A packet without any addresses is not valid.
- checkIpAddress(null, ANY, ANY, slash24Netmask);
-
- // ClientIP is used iff YourIP is not present.
- checkIpAddress("192.0.2.1/24", example2, example1, slash24Netmask);
- checkIpAddress("192.0.2.43/11", example2, ANY, slash11Netmask);
- checkIpAddress("192.0.2.43/11", ANY, example2, slash11Netmask);
-
- // Invalid netmasks are ignored.
- checkIpAddress(null, example2, ANY, invalidNetmask);
-
- // If there is no netmask, implicit netmasks are used.
- checkIpAddress("192.0.2.43/24", ANY, example2, null);
- }
-
- private void assertDhcpResults(String ipAddress, String gateway, String dnsServersString,
- String domains, String serverAddress, String serverHostName, String vendorInfo,
- int leaseDuration, boolean hasMeteredHint, int mtu, DhcpResults dhcpResults)
- throws Exception {
- assertEquals(new LinkAddress(ipAddress), dhcpResults.ipAddress);
- assertEquals(v4Address(gateway), dhcpResults.gateway);
-
- String[] dnsServerStrings = dnsServersString.split(",");
- ArrayList dnsServers = new ArrayList();
- for (String dnsServerString : dnsServerStrings) {
- dnsServers.add(v4Address(dnsServerString));
- }
- assertEquals(dnsServers, dhcpResults.dnsServers);
-
- assertEquals(domains, dhcpResults.domains);
- assertEquals(v4Address(serverAddress), dhcpResults.serverAddress);
- assertEquals(serverHostName, dhcpResults.serverHostName);
- assertEquals(vendorInfo, dhcpResults.vendorInfo);
- assertEquals(leaseDuration, dhcpResults.leaseDuration);
- assertEquals(hasMeteredHint, dhcpResults.hasMeteredHint());
- assertEquals(mtu, dhcpResults.mtu);
- }
-
- @Test
- public void testOffer1() throws Exception {
- // TODO: Turn all of these into golden files. This will probably require using
- // androidx.test.InstrumentationRegistry for obtaining a Context object
- // to read such golden files, along with an appropriate Android.mk.
- // CHECKSTYLE:OFF Generated code
- final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
- // IP header.
- "451001480000000080118849c0a89003c0a89ff7" +
- // UDP header.
- "004300440134dcfa" +
- // BOOTP header.
- "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
- // MAC address.
- "30766ff2a90c00000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Options
- "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
- "3a0400000e103b040000189cff00000000000000000000"));
- // CHECKSTYLE:ON Generated code
-
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
- assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
- DhcpResults dhcpResults = offerPacket.toDhcpResults();
- assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
- null, "192.168.144.3", "", null, 7200, false, 0, dhcpResults);
- }
-
- @Test
- public void testOffer2() throws Exception {
- // CHECKSTYLE:OFF Generated code
- final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
- // IP header.
- "450001518d0600004011144dc0a82b01c0a82bf7" +
- // UDP header.
- "00430044013d9ac7" +
- // BOOTP header.
- "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
- // MAC address.
- "30766ff2a90c00000000000000000000" +
- // Server name ("dhcp.android.com" plus invalid "AAAA" after null terminator).
- "646863702e616e64726f69642e636f6d00000000000000000000000000000000" +
- "0000000000004141414100000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Options
- "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
- "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
- // CHECKSTYLE:ON Generated code
-
- assertEquals(337, packet.limit());
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
- assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
- DhcpResults dhcpResults = offerPacket.toDhcpResults();
- assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1",
- null, "192.168.43.1", "dhcp.android.com", "ANDROID_METERED", 3600, true, 0,
- dhcpResults);
- assertTrue(dhcpResults.hasMeteredHint());
- }
-
- @Test
- public void testBadIpPacket() throws Exception {
- final byte[] packet = HexDump.hexStringToByteArray(
- // IP header.
- "450001518d0600004011144dc0a82b01c0a82bf7");
-
- try {
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
- } catch (DhcpPacket.ParseException expected) {
- assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
- return;
- }
- fail("Dhcp packet parsing should have failed");
- }
-
- @Test
- public void testBadDhcpPacket() throws Exception {
- final byte[] packet = HexDump.hexStringToByteArray(
- // IP header.
- "450001518d0600004011144dc0a82b01c0a82bf7" +
- // UDP header.
- "00430044013d9ac7" +
- // BOOTP header.
- "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000");
-
- try {
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
- } catch (DhcpPacket.ParseException expected) {
- assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
- return;
- }
- fail("Dhcp packet parsing should have failed");
- }
-
- @Test
- public void testBadTruncatedOffer() throws Exception {
- final byte[] packet = HexDump.hexStringToByteArray(
- // IP header.
- "450001518d0600004011144dc0a82b01c0a82bf7" +
- // UDP header.
- "00430044013d9ac7" +
- // BOOTP header.
- "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
- // MAC address.
- "30766ff2a90c00000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File, missing one byte
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "00000000000000000000000000000000000000000000000000000000000000");
-
- try {
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
- } catch (DhcpPacket.ParseException expected) {
- assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
- return;
- }
- fail("Dhcp packet parsing should have failed");
- }
-
- @Test
- public void testBadOfferWithoutACookie() throws Exception {
- final byte[] packet = HexDump.hexStringToByteArray(
- // IP header.
- "450001518d0600004011144dc0a82b01c0a82bf7" +
- // UDP header.
- "00430044013d9ac7" +
- // BOOTP header.
- "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
- // MAC address.
- "30766ff2a90c00000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000"
- // No options
- );
-
- try {
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
- } catch (DhcpPacket.ParseException expected) {
- assertDhcpErrorCodes(DhcpErrorEvent.DHCP_NO_COOKIE, expected.errorCode);
- return;
- }
- fail("Dhcp packet parsing should have failed");
- }
-
- @Test
- public void testOfferWithBadCookie() throws Exception {
- final byte[] packet = HexDump.hexStringToByteArray(
- // IP header.
- "450001518d0600004011144dc0a82b01c0a82bf7" +
- // UDP header.
- "00430044013d9ac7" +
- // BOOTP header.
- "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
- // MAC address.
- "30766ff2a90c00000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Bad cookie
- "DEADBEEF3501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
- "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
-
- try {
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
- } catch (DhcpPacket.ParseException expected) {
- assertDhcpErrorCodes(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE, expected.errorCode);
- return;
- }
- fail("Dhcp packet parsing should have failed");
- }
-
- private void assertDhcpErrorCodes(int expected, int got) {
- assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
- }
-
- @Test
- public void testTruncatedOfferPackets() throws Exception {
- final byte[] packet = HexDump.hexStringToByteArray(
- // IP header.
- "450001518d0600004011144dc0a82b01c0a82bf7" +
- // UDP header.
- "00430044013d9ac7" +
- // BOOTP header.
- "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
- // MAC address.
- "30766ff2a90c00000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Options
- "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
- "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
-
- for (int len = 0; len < packet.length; len++) {
- try {
- DhcpPacket.decodeFullPacket(packet, len, ENCAP_L3);
- } catch (ParseException e) {
- if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
- fail(String.format("bad truncated packet of length %d", len));
- }
- }
- }
- }
-
- @Test
- public void testRandomPackets() throws Exception {
- final int maxRandomPacketSize = 512;
- final Random r = new Random();
- for (int i = 0; i < 10000; i++) {
- byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
- r.nextBytes(packet);
- try {
- DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
- } catch (ParseException e) {
- if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
- fail("bad packet: " + HexDump.toHexString(packet));
- }
- }
- }
- }
-
- private byte[] mtuBytes(int mtu) {
- // 0x1a02: option 26, length 2. 0xff: no more options.
- if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
- throw new IllegalArgumentException(
- String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
- }
- String hexString = String.format("1a02%04xff", mtu);
- return HexDump.hexStringToByteArray(hexString);
- }
-
- private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
- if (mtuBytes != null) {
- packet.position(packet.capacity() - mtuBytes.length);
- packet.put(mtuBytes);
- packet.clear();
- }
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
- assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
- DhcpResults dhcpResults = offerPacket.toDhcpResults();
- assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
- null, "192.168.144.3", "", null, 7200, false, expectedMtu, dhcpResults);
- }
-
- @Test
- public void testMtu() throws Exception {
- // CHECKSTYLE:OFF Generated code
- final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
- // IP header.
- "451001480000000080118849c0a89003c0a89ff7" +
- // UDP header.
- "004300440134dcfa" +
- // BOOTP header.
- "02010600c997a63b0000000000000000c0a89ff70000000000000000" +
- // MAC address.
- "30766ff2a90c00000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Options
- "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
- "3a0400000e103b040000189cff00000000"));
- // CHECKSTYLE:ON Generated code
-
- checkMtu(packet, 0, null);
- checkMtu(packet, 0, mtuBytes(1501));
- checkMtu(packet, 1500, mtuBytes(1500));
- checkMtu(packet, 1499, mtuBytes(1499));
- checkMtu(packet, 1280, mtuBytes(1280));
- checkMtu(packet, 0, mtuBytes(1279));
- checkMtu(packet, 0, mtuBytes(576));
- checkMtu(packet, 0, mtuBytes(68));
- checkMtu(packet, 0, mtuBytes(Short.MIN_VALUE));
- checkMtu(packet, 0, mtuBytes(Short.MAX_VALUE + 3));
- checkMtu(packet, 0, mtuBytes(-1));
- }
-
- @Test
- public void testBadHwaddrLength() throws Exception {
- // CHECKSTYLE:OFF Generated code
- final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
- // IP header.
- "450001518d0600004011144dc0a82b01c0a82bf7" +
- // UDP header.
- "00430044013d9ac7" +
- // BOOTP header.
- "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
- // MAC address.
- "30766ff2a90c00000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Options
- "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
- "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
- // CHECKSTYLE:ON Generated code
- String expectedClientMac = "30766FF2A90C";
-
- final int hwAddrLenOffset = 20 + 8 + 2;
- assertEquals(6, packet.get(hwAddrLenOffset));
-
- // Expect the expected.
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
- assertNotNull(offerPacket);
- assertEquals(6, offerPacket.getClientMac().length);
- assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
-
- // Reduce the hardware address length and verify that it shortens the client MAC.
- packet.flip();
- packet.put(hwAddrLenOffset, (byte) 5);
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
- assertNotNull(offerPacket);
- assertEquals(5, offerPacket.getClientMac().length);
- assertEquals(expectedClientMac.substring(0, 10),
- HexDump.toHexString(offerPacket.getClientMac()));
-
- packet.flip();
- packet.put(hwAddrLenOffset, (byte) 3);
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
- assertNotNull(offerPacket);
- assertEquals(3, offerPacket.getClientMac().length);
- assertEquals(expectedClientMac.substring(0, 6),
- HexDump.toHexString(offerPacket.getClientMac()));
-
- // Set the the hardware address length to 0xff and verify that we a) don't treat it as -1
- // and crash, and b) hardcode it to 6.
- packet.flip();
- packet.put(hwAddrLenOffset, (byte) -1);
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
- assertNotNull(offerPacket);
- assertEquals(6, offerPacket.getClientMac().length);
- assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
-
- // Set the the hardware address length to a positive invalid value (> 16) and verify that we
- // hardcode it to 6.
- packet.flip();
- packet.put(hwAddrLenOffset, (byte) 17);
- offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
- assertNotNull(offerPacket);
- assertEquals(6, offerPacket.getClientMac().length);
- assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
- }
-
- @Test
- public void testPadAndOverloadedOptionsOffer() throws Exception {
- // A packet observed in the real world that is interesting for two reasons:
- //
- // 1. It uses pad bytes, which we previously didn't support correctly.
- // 2. It uses DHCP option overloading, which we don't currently support (but it doesn't
- // store any information in the overloaded fields).
- //
- // For now, we just check that it parses correctly.
- // CHECKSTYLE:OFF Generated code
- final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
- // Ethernet header.
- "b4cef6000000e80462236e300800" +
- // IP header.
- "4500014c00000000ff11741701010101ac119876" +
- // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
- "004300440138ae5a" +
- // BOOTP header.
- "020106000fa0059f0000000000000000ac1198760000000000000000" +
- // MAC address.
- "b4cef600000000000000000000000000" +
- // Server name.
- "ff00000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "ff00000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Options
- "638253633501023604010101010104ffff000033040000a8c03401030304ac1101010604ac110101" +
- "0000000000000000000000000000000000000000000000ff000000"));
- // CHECKSTYLE:ON Generated code
-
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
- assertTrue(offerPacket instanceof DhcpOfferPacket);
- DhcpResults dhcpResults = offerPacket.toDhcpResults();
- assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
- null, "1.1.1.1", "", null, 43200, false, 0, dhcpResults);
- }
-
- @Test
- public void testBug2111() throws Exception {
- // CHECKSTYLE:OFF Generated code
- final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
- // IP header.
- "4500014c00000000ff119beac3eaf3880a3f5d04" +
- // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
- "0043004401387464" +
- // BOOTP header.
- "0201060002554812000a0000000000000a3f5d040000000000000000" +
- // MAC address.
- "00904c00000000000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Options.
- "638253633501023604c00002fe33040000bfc60104fffff00003040a3f50010608c0000201c0000202" +
- "0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"));
- // CHECKSTYLE:ON Generated code
-
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
- assertTrue(offerPacket instanceof DhcpOfferPacket);
- DhcpResults dhcpResults = offerPacket.toDhcpResults();
- assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
- "domain123.co.uk", "192.0.2.254", "", null, 49094, false, 0, dhcpResults);
- }
-
- @Test
- public void testBug2136() throws Exception {
- // CHECKSTYLE:OFF Generated code
- final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
- // Ethernet header.
- "bcf5ac000000d0c7890000000800" +
- // IP header.
- "4500014c00000000ff119beac3eaf3880a3f5d04" +
- // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
- "0043004401387574" +
- // BOOTP header.
- "0201060163339a3000050000000000000a209ecd0000000000000000" +
- // MAC address.
- "bcf5ac00000000000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Options.
- "6382536335010236040a20ff80330400001c200104fffff00003040a20900106089458413494584135" +
- "0f0b6c616e63732e61632e756b000000000000000000ff00000000"));
- // CHECKSTYLE:ON Generated code
-
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
- assertTrue(offerPacket instanceof DhcpOfferPacket);
- assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
- DhcpResults dhcpResults = offerPacket.toDhcpResults();
- assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
- "lancs.ac.uk", "10.32.255.128", "", null, 7200, false, 0, dhcpResults);
- }
-
- @Test
- public void testUdpServerAnySourcePort() throws Exception {
- // CHECKSTYLE:OFF Generated code
- final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
- // Ethernet header.
- "9cd917000000001c2e0000000800" +
- // IP header.
- "45a00148000040003d115087d18194fb0a0f7af2" +
- // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
- // NOTE: The server source port is not the canonical port 67.
- "C29F004401341268" +
- // BOOTP header.
- "02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
- // MAC address.
- "9cd91700000000000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Options.
- "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
- "d18180060f0777766d2e6564751c040a0fffffff000000"));
- // CHECKSTYLE:ON Generated code
-
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
- assertTrue(offerPacket instanceof DhcpOfferPacket);
- assertEquals("9CD917000000", HexDump.toHexString(offerPacket.getClientMac()));
- DhcpResults dhcpResults = offerPacket.toDhcpResults();
- assertDhcpResults("10.15.122.242/16", "10.15.200.23",
- "209.129.128.3,209.129.148.3,209.129.128.6",
- "wvm.edu", "10.1.105.252", "", null, 86400, false, 0, dhcpResults);
- }
-
- @Test
- public void testUdpInvalidDstPort() throws Exception {
- // CHECKSTYLE:OFF Generated code
- final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
- // Ethernet header.
- "9cd917000000001c2e0000000800" +
- // IP header.
- "45a00148000040003d115087d18194fb0a0f7af2" +
- // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
- // NOTE: The destination port is a non-DHCP port.
- "0043aaaa01341268" +
- // BOOTP header.
- "02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
- // MAC address.
- "9cd91700000000000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Options.
- "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
- "d18180060f0777766d2e6564751c040a0fffffff000000"));
- // CHECKSTYLE:ON Generated code
-
- try {
- DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
- fail("Packet with invalid dst port did not throw ParseException");
- } catch (ParseException expected) {}
- }
-
- @Test
- public void testMultipleRouters() throws Exception {
- // CHECKSTYLE:OFF Generated code
- final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
- // Ethernet header.
- "fc3d93000000" + "081735000000" + "0800" +
- // IP header.
- "45000148c2370000ff117ac2c0a8bd02ffffffff" +
- // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
- "0043004401343beb" +
- // BOOTP header.
- "0201060027f518e20000800000000000c0a8bd310000000000000000" +
- // MAC address.
- "fc3d9300000000000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // File.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- // Options.
- "638253633501023604c0abbd023304000070803a04000038403b04000062700104ffffff00" +
- "0308c0a8bd01ffffff0006080808080808080404ff000000000000"));
- // CHECKSTYLE:ON Generated code
-
- DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
- assertTrue(offerPacket instanceof DhcpOfferPacket);
- assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
- DhcpResults dhcpResults = offerPacket.toDhcpResults();
- assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
- null, "192.171.189.2", "", null, 28800, false, 0, dhcpResults);
- }
-
- @Test
- public void testDiscoverPacket() throws Exception {
- short secs = 7;
- int transactionId = 0xdeadbeef;
- byte[] hwaddr = {
- (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a
- };
-
- ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
- DhcpPacket.ENCAP_L2, transactionId, secs, hwaddr,
- false /* do unicast */, DhcpClient.REQUESTED_PARAMS);
-
- byte[] headers = new byte[] {
- // Ethernet header.
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
- (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a,
- (byte) 0x08, (byte) 0x00,
- // IP header.
- (byte) 0x45, (byte) 0x10, (byte) 0x01, (byte) 0x56,
- (byte) 0x00, (byte) 0x00, (byte) 0x40, (byte) 0x00,
- (byte) 0x40, (byte) 0x11, (byte) 0x39, (byte) 0x88,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
- // UDP header.
- (byte) 0x00, (byte) 0x44, (byte) 0x00, (byte) 0x43,
- (byte) 0x01, (byte) 0x42, (byte) 0x6a, (byte) 0x4a,
- // BOOTP.
- (byte) 0x01, (byte) 0x01, (byte) 0x06, (byte) 0x00,
- (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
- (byte) 0x00, (byte) 0x07, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b,
- (byte) 0xb1, (byte) 0x7a
- };
- byte[] options = new byte[] {
- // Magic cookie 0x63825363.
- (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63,
- // Message type DISCOVER.
- (byte) 0x35, (byte) 0x01, (byte) 0x01,
- // Client identifier Ethernet, da:01:19:5b:b1:7a.
- (byte) 0x3d, (byte) 0x07,
- (byte) 0x01,
- (byte) 0xda, (byte) 0x01, (byte) 0x19, (byte) 0x5b, (byte) 0xb1, (byte) 0x7a,
- // Max message size 1500.
- (byte) 0x39, (byte) 0x02, (byte) 0x05, (byte) 0xdc,
- // Version "android-dhcp-???".
- (byte) 0x3c, (byte) 0x10,
- 'a', 'n', 'd', 'r', 'o', 'i', 'd', '-', 'd', 'h', 'c', 'p', '-', '?', '?', '?',
- // Hostname "android-01234567890abcde"
- (byte) 0x0c, (byte) 0x18,
- 'a', 'n', 'd', 'r', 'o', 'i', 'd', '-',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e',
- // Requested parameter list.
- (byte) 0x37, (byte) 0x0a,
- DHCP_SUBNET_MASK,
- DHCP_ROUTER,
- DHCP_DNS_SERVER,
- DHCP_DOMAIN_NAME,
- DHCP_MTU,
- DHCP_BROADCAST_ADDRESS,
- DHCP_LEASE_TIME,
- DHCP_RENEWAL_TIME,
- DHCP_REBINDING_TIME,
- DHCP_VENDOR_INFO,
- // End options.
- (byte) 0xff,
- // Our packets are always of even length. TODO: find out why and possibly fix it.
- (byte) 0x00
- };
- byte[] expected = new byte[DhcpPacket.MIN_PACKET_LENGTH_L2 + options.length];
- assertTrue((expected.length & 1) == 0);
- System.arraycopy(headers, 0, expected, 0, headers.length);
- System.arraycopy(options, 0, expected, DhcpPacket.MIN_PACKET_LENGTH_L2, options.length);
-
- byte[] actual = new byte[packet.limit()];
- packet.get(actual);
- String msg =
- "Expected:\n " + Arrays.toString(expected) +
- "\nActual:\n " + Arrays.toString(actual);
- assertTrue(msg, Arrays.equals(expected, actual));
- }
-
- public void checkBuildOfferPacket(int leaseTimeSecs, @Nullable String hostname)
- throws Exception {
- final int renewalTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) / 2);
- final int rebindingTime = (int) (Integer.toUnsignedLong(leaseTimeSecs) * 875 / 1000);
- final int transactionId = 0xdeadbeef;
-
- final ByteBuffer packet = DhcpPacket.buildOfferPacket(
- DhcpPacket.ENCAP_BOOTP, transactionId, false /* broadcast */,
- SERVER_ADDR, INADDR_ANY /* relayIp */, CLIENT_ADDR /* yourIp */,
- CLIENT_MAC, leaseTimeSecs, NETMASK /* netMask */,
- BROADCAST_ADDR /* bcAddr */, Collections.singletonList(SERVER_ADDR) /* gateways */,
- Collections.singletonList(SERVER_ADDR) /* dnsServers */,
- SERVER_ADDR /* dhcpServerIdentifier */, null /* domainName */, hostname,
- false /* metered */, MTU);
-
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- // BOOTP headers
- bos.write(new byte[] {
- (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x00,
- (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- // ciaddr
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- });
- // yiaddr
- bos.write(CLIENT_ADDR.getAddress());
- // siaddr
- bos.write(SERVER_ADDR.getAddress());
- // giaddr
- bos.write(INADDR_ANY.getAddress());
- // chaddr
- bos.write(CLIENT_MAC);
-
- // Padding
- bos.write(new byte[202]);
-
- // Options
- bos.write(new byte[]{
- // Magic cookie 0x63825363.
- (byte) 0x63, (byte) 0x82, (byte) 0x53, (byte) 0x63,
- // Message type OFFER.
- (byte) 0x35, (byte) 0x01, (byte) 0x02,
- });
- // Server ID
- bos.write(new byte[] { (byte) 0x36, (byte) 0x04 });
- bos.write(SERVER_ADDR.getAddress());
- // Lease time
- bos.write(new byte[] { (byte) 0x33, (byte) 0x04 });
- bos.write(intToByteArray(leaseTimeSecs));
- if (leaseTimeSecs != INFINITE_LEASE) {
- // Renewal time
- bos.write(new byte[]{(byte) 0x3a, (byte) 0x04});
- bos.write(intToByteArray(renewalTime));
- // Rebinding time
- bos.write(new byte[]{(byte) 0x3b, (byte) 0x04});
- bos.write(intToByteArray(rebindingTime));
- }
- // Subnet mask
- bos.write(new byte[] { (byte) 0x01, (byte) 0x04 });
- bos.write(NETMASK.getAddress());
- // Broadcast address
- bos.write(new byte[] { (byte) 0x1c, (byte) 0x04 });
- bos.write(BROADCAST_ADDR.getAddress());
- // Router
- bos.write(new byte[] { (byte) 0x03, (byte) 0x04 });
- bos.write(SERVER_ADDR.getAddress());
- // Nameserver
- bos.write(new byte[] { (byte) 0x06, (byte) 0x04 });
- bos.write(SERVER_ADDR.getAddress());
- // Hostname
- if (hostname != null) {
- bos.write(new byte[]{(byte) 0x0c, (byte) hostname.length()});
- bos.write(hostname.getBytes(Charset.forName("US-ASCII")));
- }
- // MTU
- bos.write(new byte[] { (byte) 0x1a, (byte) 0x02 });
- bos.write(shortToByteArray(MTU));
- // End options.
- bos.write(0xff);
-
- if ((bos.size() & 1) != 0) {
- bos.write(0x00);
- }
-
- final byte[] expected = bos.toByteArray();
- final byte[] actual = new byte[packet.limit()];
- packet.get(actual);
- final String msg = "Expected:\n " + HexDump.dumpHexString(expected) +
- "\nActual:\n " + HexDump.dumpHexString(actual);
- assertTrue(msg, Arrays.equals(expected, actual));
- }
-
- @Test
- public void testOfferPacket() throws Exception {
- checkBuildOfferPacket(3600, HOSTNAME);
- checkBuildOfferPacket(Integer.MAX_VALUE, HOSTNAME);
- checkBuildOfferPacket(0x80000000, HOSTNAME);
- checkBuildOfferPacket(INFINITE_LEASE, HOSTNAME);
- checkBuildOfferPacket(3600, null);
- }
-
- private static byte[] intToByteArray(int val) {
- return ByteBuffer.allocate(4).putInt(val).array();
- }
-
- private static byte[] shortToByteArray(short val) {
- return ByteBuffer.allocate(2).putShort(val).array();
- }
-}
diff --git a/tests/src/android/net/dhcp/DhcpServerTest.java b/tests/src/android/net/dhcp/DhcpServerTest.java
deleted file mode 100644
index f0e2f1b..0000000
--- a/tests/src/android/net/dhcp/DhcpServerTest.java
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
-import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
-import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
-import static android.net.dhcp.DhcpPacket.INADDR_ANY;
-import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST;
-import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.INetworkStackStatusCallback;
-import android.net.LinkAddress;
-import android.net.MacAddress;
-import android.net.dhcp.DhcpLeaseRepository.InvalidAddressException;
-import android.net.dhcp.DhcpLeaseRepository.OutOfAddressesException;
-import android.net.dhcp.DhcpServer.Clock;
-import android.net.dhcp.DhcpServer.Dependencies;
-import android.net.util.SharedLog;
-import android.os.HandlerThread;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.net.Inet4Address;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(AndroidTestingRunner.class)
-@SmallTest
-@RunWithLooper
-public class DhcpServerTest {
- private static final String TEST_IFACE = "testiface";
-
- private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2");
- private static final LinkAddress TEST_SERVER_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20);
- private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>(
- Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124")));
- private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>(
- Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127")));
- private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>(
- Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
- private static final long TEST_LEASE_TIME_SECS = 3600L;
- private static final int TEST_MTU = 1500;
- private static final String TEST_HOSTNAME = "testhostname";
-
- private static final int TEST_TRANSACTION_ID = 123;
- private static final byte[] TEST_CLIENT_MAC_BYTES = new byte [] { 1, 2, 3, 4, 5, 6 };
- private static final MacAddress TEST_CLIENT_MAC = MacAddress.fromBytes(TEST_CLIENT_MAC_BYTES);
- private static final Inet4Address TEST_CLIENT_ADDR = parseAddr("192.168.0.42");
-
- private static final long TEST_CLOCK_TIME = 1234L;
- private static final int TEST_LEASE_EXPTIME_SECS = 3600;
- private static final DhcpLease TEST_LEASE = new DhcpLease(null, TEST_CLIENT_MAC,
- TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME,
- null /* hostname */);
- private static final DhcpLease TEST_LEASE_WITH_HOSTNAME = new DhcpLease(null, TEST_CLIENT_MAC,
- TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS * 1000L + TEST_CLOCK_TIME, TEST_HOSTNAME);
-
- @NonNull @Mock
- private Dependencies mDeps;
- @NonNull @Mock
- private DhcpLeaseRepository mRepository;
- @NonNull @Mock
- private Clock mClock;
- @NonNull @Mock
- private DhcpPacketListener mPacketListener;
-
- @NonNull @Captor
- private ArgumentCaptor<ByteBuffer> mSentPacketCaptor;
- @NonNull @Captor
- private ArgumentCaptor<Inet4Address> mResponseDstAddrCaptor;
-
- @NonNull
- private HandlerThread mHandlerThread;
- @NonNull
- private TestableLooper mLooper;
- @NonNull
- private DhcpServer mServer;
-
- @Nullable
- private String mPrevShareClassloaderProp;
-
- private final INetworkStackStatusCallback mAssertSuccessCallback =
- new INetworkStackStatusCallback.Stub() {
- @Override
- public void onStatusAvailable(int statusCode) {
- assertEquals(STATUS_SUCCESS, statusCode);
- }
-
- @Override
- public int getInterfaceVersion() {
- return this.VERSION;
- }
- };
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- when(mDeps.makeLeaseRepository(any(), any(), any())).thenReturn(mRepository);
- when(mDeps.makeClock()).thenReturn(mClock);
- when(mDeps.makePacketListener()).thenReturn(mPacketListener);
- doNothing().when(mDeps)
- .sendPacket(any(), mSentPacketCaptor.capture(), mResponseDstAddrCaptor.capture());
- when(mClock.elapsedRealtime()).thenReturn(TEST_CLOCK_TIME);
-
- final DhcpServingParams servingParams = new DhcpServingParams.Builder()
- .setDefaultRouters(TEST_DEFAULT_ROUTERS)
- .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS)
- .setDnsServers(TEST_DNS_SERVERS)
- .setServerAddr(TEST_SERVER_LINKADDR)
- .setLinkMtu(TEST_MTU)
- .setExcludedAddrs(TEST_EXCLUDED_ADDRS)
- .build();
-
- mLooper = TestableLooper.get(this);
- mHandlerThread = spy(new HandlerThread("TestDhcpServer"));
- when(mHandlerThread.getLooper()).thenReturn(mLooper.getLooper());
- mServer = new DhcpServer(mHandlerThread, TEST_IFACE, servingParams,
- new SharedLog(DhcpServerTest.class.getSimpleName()), mDeps);
-
- mServer.start(mAssertSuccessCallback);
- mLooper.processAllMessages();
- }
-
- @After
- public void tearDown() throws Exception {
- mServer.stop(mAssertSuccessCallback);
- mLooper.processMessages(1);
- verify(mPacketListener, times(1)).stop();
- verify(mHandlerThread, times(1)).quitSafely();
- }
-
- @Test
- public void testStart() throws Exception {
- verify(mPacketListener, times(1)).start();
- }
-
- @Test
- public void testDiscover() throws Exception {
- // TODO: refactor packet construction to eliminate unnecessary/confusing/duplicate fields
- when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
- eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */))
- .thenReturn(TEST_LEASE);
-
- final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID,
- (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES,
- false /* broadcast */, INADDR_ANY /* srcIp */);
- mServer.processPacket(discover, DHCP_CLIENT);
-
- assertResponseSentTo(TEST_CLIENT_ADDR);
- final DhcpOfferPacket packet = assertOffer(getPacket());
- assertMatchesTestLease(packet);
- }
-
- @Test
- public void testDiscover_OutOfAddresses() throws Exception {
- when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
- eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */))
- .thenThrow(new OutOfAddressesException("Test exception"));
-
- final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID,
- (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES,
- false /* broadcast */, INADDR_ANY /* srcIp */);
- mServer.processPacket(discover, DHCP_CLIENT);
-
- assertResponseSentTo(INADDR_BROADCAST);
- final DhcpNakPacket packet = assertNak(getPacket());
- assertMatchesClient(packet);
- }
-
- private DhcpRequestPacket makeRequestSelectingPacket() {
- final DhcpRequestPacket request = new DhcpRequestPacket(TEST_TRANSACTION_ID,
- (short) 0 /* secs */, INADDR_ANY /* clientIp */, INADDR_ANY /* relayIp */,
- TEST_CLIENT_MAC_BYTES, false /* broadcast */);
- request.mServerIdentifier = TEST_SERVER_ADDR;
- request.mRequestedIp = TEST_CLIENT_ADDR;
- return request;
- }
-
- @Test
- public void testRequest_Selecting_Ack() throws Exception {
- when(mRepository.requestLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC),
- eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */,
- eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, eq(TEST_HOSTNAME)))
- .thenReturn(TEST_LEASE_WITH_HOSTNAME);
-
- final DhcpRequestPacket request = makeRequestSelectingPacket();
- request.mHostName = TEST_HOSTNAME;
- request.mRequestedParams = new byte[] { DHCP_HOST_NAME };
- mServer.processPacket(request, DHCP_CLIENT);
-
- assertResponseSentTo(TEST_CLIENT_ADDR);
- final DhcpAckPacket packet = assertAck(getPacket());
- assertMatchesTestLease(packet, TEST_HOSTNAME);
- }
-
- @Test
- public void testRequest_Selecting_Nak() throws Exception {
- when(mRepository.requestLease(isNull(), eq(TEST_CLIENT_MAC),
- eq(INADDR_ANY) /* clientAddr */, eq(INADDR_ANY) /* relayAddr */,
- eq(TEST_CLIENT_ADDR) /* reqAddr */, eq(true) /* sidSet */, isNull() /* hostname */))
- .thenThrow(new InvalidAddressException("Test error"));
-
- final DhcpRequestPacket request = makeRequestSelectingPacket();
- mServer.processPacket(request, DHCP_CLIENT);
-
- assertResponseSentTo(INADDR_BROADCAST);
- final DhcpNakPacket packet = assertNak(getPacket());
- assertMatchesClient(packet);
- }
-
- @Test
- public void testRequest_Selecting_WrongClientPort() throws Exception {
- final DhcpRequestPacket request = makeRequestSelectingPacket();
- mServer.processPacket(request, 50000);
-
- verify(mRepository, never())
- .requestLease(any(), any(), any(), any(), any(), anyBoolean(), any());
- verify(mDeps, never()).sendPacket(any(), any(), any());
- }
-
- @Test
- public void testRelease() throws Exception {
- final DhcpReleasePacket release = new DhcpReleasePacket(TEST_TRANSACTION_ID,
- TEST_SERVER_ADDR, TEST_CLIENT_ADDR,
- INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES);
- mServer.processPacket(release, DHCP_CLIENT);
-
- verify(mRepository, times(1))
- .releaseLease(isNull(), eq(TEST_CLIENT_MAC), eq(TEST_CLIENT_ADDR));
- }
-
- /* TODO: add more tests once packet construction is refactored, including:
- * - usage of giaddr
- * - usage of broadcast bit
- * - other request states (init-reboot/renewing/rebinding)
- */
-
- private void assertMatchesTestLease(@NonNull DhcpPacket packet, @Nullable String hostname) {
- assertMatchesClient(packet);
- assertFalse(packet.hasExplicitClientId());
- assertEquals(TEST_SERVER_ADDR, packet.mServerIdentifier);
- assertEquals(TEST_CLIENT_ADDR, packet.mYourIp);
- assertNotNull(packet.mLeaseTime);
- assertEquals(TEST_LEASE_EXPTIME_SECS, (int) packet.mLeaseTime);
- assertEquals(hostname, packet.mHostName);
- }
-
- private void assertMatchesTestLease(@NonNull DhcpPacket packet) {
- assertMatchesTestLease(packet, null);
- }
-
- private void assertMatchesClient(@NonNull DhcpPacket packet) {
- assertEquals(TEST_TRANSACTION_ID, packet.mTransId);
- assertEquals(TEST_CLIENT_MAC, MacAddress.fromBytes(packet.mClientMac));
- }
-
- private void assertResponseSentTo(@NonNull Inet4Address addr) {
- assertEquals(addr, mResponseDstAddrCaptor.getValue());
- }
-
- private static DhcpNakPacket assertNak(@Nullable DhcpPacket packet) {
- assertTrue(packet instanceof DhcpNakPacket);
- return (DhcpNakPacket) packet;
- }
-
- private static DhcpAckPacket assertAck(@Nullable DhcpPacket packet) {
- assertTrue(packet instanceof DhcpAckPacket);
- return (DhcpAckPacket) packet;
- }
-
- private static DhcpOfferPacket assertOffer(@Nullable DhcpPacket packet) {
- assertTrue(packet instanceof DhcpOfferPacket);
- return (DhcpOfferPacket) packet;
- }
-
- private DhcpPacket getPacket() throws Exception {
- verify(mDeps, times(1)).sendPacket(any(), any(), any());
- return DhcpPacket.decodeFullPacket(mSentPacketCaptor.getValue(), ENCAP_BOOTP);
- }
-
- private static Inet4Address parseAddr(@Nullable String inet4Addr) {
- return (Inet4Address) parseNumericAddress(inet4Addr);
- }
-}
diff --git a/tests/src/android/net/dhcp/DhcpServingParamsTest.java b/tests/src/android/net/dhcp/DhcpServingParamsTest.java
deleted file mode 100644
index 57a87a4..0000000
--- a/tests/src/android/net/dhcp/DhcpServingParamsTest.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2018 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.dhcp;
-
-import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.dhcp.DhcpServingParams.MTU_UNSET;
-import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.LinkAddress;
-import android.net.dhcp.DhcpServingParams.InvalidParameterException;
-import android.net.shared.Inet4AddressUtils;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.lang.reflect.Modifier;
-import java.net.Inet4Address;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DhcpServingParamsTest {
- @NonNull
- private DhcpServingParams.Builder mBuilder;
-
- private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>(
- Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124")));
- private static final long TEST_LEASE_TIME_SECS = 3600L;
- private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>(
- Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127")));
- private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2");
- private static final LinkAddress TEST_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20);
- private static final int TEST_MTU = 1500;
- private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>(
- Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201")));
- private static final boolean TEST_METERED = true;
-
- @Before
- public void setUp() {
- mBuilder = new DhcpServingParams.Builder()
- .setDefaultRouters(TEST_DEFAULT_ROUTERS)
- .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS)
- .setDnsServers(TEST_DNS_SERVERS)
- .setServerAddr(TEST_LINKADDR)
- .setLinkMtu(TEST_MTU)
- .setExcludedAddrs(TEST_EXCLUDED_ADDRS)
- .setMetered(TEST_METERED);
- }
-
- @Test
- public void testBuild_Immutable() throws InvalidParameterException {
- final Set<Inet4Address> routers = new HashSet<>(TEST_DEFAULT_ROUTERS);
- final Set<Inet4Address> dnsServers = new HashSet<>(TEST_DNS_SERVERS);
- final Set<Inet4Address> excludedAddrs = new HashSet<>(TEST_EXCLUDED_ADDRS);
-
- final DhcpServingParams params = mBuilder
- .setDefaultRouters(routers)
- .setDnsServers(dnsServers)
- .setExcludedAddrs(excludedAddrs)
- .build();
-
- // Modifications to source objects should not affect builder or final parameters
- final Inet4Address addedAddr = parseAddr("192.168.0.223");
- routers.add(addedAddr);
- dnsServers.add(addedAddr);
- excludedAddrs.add(addedAddr);
-
- assertEquals(TEST_DEFAULT_ROUTERS, params.defaultRouters);
- assertEquals(TEST_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs);
- assertEquals(TEST_DNS_SERVERS, params.dnsServers);
- assertEquals(TEST_LINKADDR, params.serverAddr);
- assertEquals(TEST_MTU, params.linkMtu);
- assertEquals(TEST_METERED, params.metered);
-
- assertContains(params.excludedAddrs, TEST_EXCLUDED_ADDRS);
- assertContains(params.excludedAddrs, TEST_DEFAULT_ROUTERS);
- assertContains(params.excludedAddrs, TEST_DNS_SERVERS);
- assertContains(params.excludedAddrs, TEST_SERVER_ADDR);
-
- assertFalse("excludedAddrs should not contain " + addedAddr,
- params.excludedAddrs.contains(addedAddr));
- }
-
- @Test(expected = InvalidParameterException.class)
- public void testBuild_NegativeLeaseTime() throws InvalidParameterException {
- mBuilder.setDhcpLeaseTimeSecs(-1).build();
- }
-
- @Test(expected = InvalidParameterException.class)
- public void testBuild_LeaseTimeTooLarge() throws InvalidParameterException {
- // Set lease time larger than max value for uint32
- mBuilder.setDhcpLeaseTimeSecs(1L << 32).build();
- }
-
- @Test
- public void testBuild_InfiniteLeaseTime() throws InvalidParameterException {
- final long infiniteLeaseTime = 0xffffffffL;
- final DhcpServingParams params = mBuilder
- .setDhcpLeaseTimeSecs(infiniteLeaseTime).build();
- assertEquals(infiniteLeaseTime, params.dhcpLeaseTimeSecs);
- assertTrue(params.dhcpLeaseTimeSecs > 0L);
- }
-
- @Test
- public void testBuild_UnsetMtu() throws InvalidParameterException {
- final DhcpServingParams params = mBuilder.setLinkMtu(MTU_UNSET).build();
- assertEquals(MTU_UNSET, params.linkMtu);
- }
-
- @Test(expected = InvalidParameterException.class)
- public void testBuild_MtuTooSmall() throws InvalidParameterException {
- mBuilder.setLinkMtu(20).build();
- }
-
- @Test(expected = InvalidParameterException.class)
- public void testBuild_MtuTooLarge() throws InvalidParameterException {
- mBuilder.setLinkMtu(65_536).build();
- }
-
- @Test(expected = InvalidParameterException.class)
- public void testBuild_IPv6Addr() throws InvalidParameterException {
- mBuilder.setServerAddr(new LinkAddress(parseNumericAddress("fe80::1111"), 120)).build();
- }
-
- @Test(expected = InvalidParameterException.class)
- public void testBuild_PrefixTooLarge() throws InvalidParameterException {
- mBuilder.setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 15)).build();
- }
-
- @Test(expected = InvalidParameterException.class)
- public void testBuild_PrefixTooSmall() throws InvalidParameterException {
- mBuilder.setDefaultRouters(parseAddr("192.168.0.254"))
- .setServerAddr(new LinkAddress(TEST_SERVER_ADDR, 31))
- .build();
- }
-
- @Test(expected = InvalidParameterException.class)
- public void testBuild_RouterNotInPrefix() throws InvalidParameterException {
- mBuilder.setDefaultRouters(parseAddr("192.168.254.254")).build();
- }
-
- @Test
- public void testFromParcelableObject() throws InvalidParameterException {
- final DhcpServingParams params = mBuilder.build();
- final DhcpServingParamsParcel parcel = new DhcpServingParamsParcel();
- parcel.defaultRouters = toIntArray(TEST_DEFAULT_ROUTERS);
- parcel.dhcpLeaseTimeSecs = TEST_LEASE_TIME_SECS;
- parcel.dnsServers = toIntArray(TEST_DNS_SERVERS);
- parcel.serverAddr = inet4AddressToIntHTH(TEST_SERVER_ADDR);
- parcel.serverAddrPrefixLength = TEST_LINKADDR.getPrefixLength();
- parcel.linkMtu = TEST_MTU;
- parcel.excludedAddrs = toIntArray(TEST_EXCLUDED_ADDRS);
- parcel.metered = TEST_METERED;
- final DhcpServingParams parceled = DhcpServingParams.fromParcelableObject(parcel);
-
- assertEquals(params.defaultRouters, parceled.defaultRouters);
- assertEquals(params.dhcpLeaseTimeSecs, parceled.dhcpLeaseTimeSecs);
- assertEquals(params.dnsServers, parceled.dnsServers);
- assertEquals(params.serverAddr, parceled.serverAddr);
- assertEquals(params.linkMtu, parceled.linkMtu);
- assertEquals(params.excludedAddrs, parceled.excludedAddrs);
- assertEquals(params.metered, parceled.metered);
-
- // Ensure that we do not miss any field if added in the future
- final long numFields = Arrays.stream(DhcpServingParams.class.getDeclaredFields())
- .filter(f -> !Modifier.isStatic(f.getModifiers()))
- .count();
- assertEquals(7, numFields);
- }
-
- @Test(expected = InvalidParameterException.class)
- public void testFromParcelableObject_NullArgument() throws InvalidParameterException {
- DhcpServingParams.fromParcelableObject(null);
- }
-
- private static int[] toIntArray(Collection<Inet4Address> addrs) {
- return addrs.stream().mapToInt(Inet4AddressUtils::inet4AddressToIntHTH).toArray();
- }
-
- private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) {
- for (final T elem : subset) {
- assertContains(set, elem);
- }
- }
-
- private static <T> void assertContains(@NonNull Set<T> set, @Nullable T elem) {
- assertTrue("Set does not contain " + elem, set.contains(elem));
- }
-
- @NonNull
- private static Inet4Address parseAddr(@NonNull String inet4Addr) {
- return (Inet4Address) parseNumericAddress(inet4Addr);
- }
-}
diff --git a/tests/src/android/net/ip/IpClientTest.java b/tests/src/android/net/ip/IpClientTest.java
deleted file mode 100644
index 5f80006..0000000
--- a/tests/src/android/net/ip/IpClientTest.java
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * Copyright (C) 2017 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.ip;
-
-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.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.app.AlarmManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.INetd;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.MacAddress;
-import android.net.NetworkStackIpMemoryStore;
-import android.net.RouteInfo;
-import android.net.ipmemorystore.NetworkAttributes;
-import android.net.shared.InitialConfiguration;
-import android.net.shared.ProvisioningConfiguration;
-import android.net.util.InterfaceParams;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.R;
-import com.android.server.NetworkObserver;
-import com.android.server.NetworkObserverRegistry;
-import com.android.server.NetworkStackService;
-
-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.net.InetAddress;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Tests for IpClient.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpClientTest {
- private static final int DEFAULT_AVOIDBADWIFI_CONFIG_VALUE = 1;
-
- private static final String VALID = "VALID";
- private static final String INVALID = "INVALID";
- private static final String TEST_IFNAME = "test_wlan0";
- private static final int TEST_IFINDEX = 1001;
- // See RFC 7042#section-2.1.2 for EUI-48 documentation values.
- private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
- private static final int TEST_TIMEOUT_MS = 400;
- private static final String TEST_L2KEY = "some l2key";
- private static final String TEST_GROUPHINT = "some grouphint";
-
- @Mock private Context mContext;
- @Mock private ConnectivityManager mCm;
- @Mock private NetworkObserverRegistry mObserverRegistry;
- @Mock private INetd mNetd;
- @Mock private Resources mResources;
- @Mock private IIpClientCallbacks mCb;
- @Mock private AlarmManager mAlarm;
- @Mock private IpClient.Dependencies mDependencies;
- @Mock private ContentResolver mContentResolver;
- @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
- @Mock private NetworkStackIpMemoryStore mIpMemoryStore;
-
- private NetworkObserver mObserver;
- private InterfaceParams mIfParams;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
- when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm);
- when(mContext.getResources()).thenReturn(mResources);
- when(mDependencies.getNetd(any())).thenReturn(mNetd);
- when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
- .thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
- when(mContext.getContentResolver()).thenReturn(mContentResolver);
-
- mIfParams = null;
- }
-
- private void setTestInterfaceParams(String ifname) {
- mIfParams = (ifname != null)
- ? new InterfaceParams(ifname, TEST_IFINDEX, TEST_MAC)
- : null;
- when(mDependencies.getInterfaceParams(anyString())).thenReturn(mIfParams);
- }
-
- private IpClient makeIpClient(String ifname) throws Exception {
- setTestInterfaceParams(ifname);
- final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry,
- mNetworkStackServiceManager, mDependencies);
- verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
- verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
- ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class);
- verify(mObserverRegistry, times(1)).registerObserverForNonblockingCallback(arg.capture());
- mObserver = arg.getValue();
- reset(mObserverRegistry);
- reset(mNetd);
- // Verify IpClient doesn't call onLinkPropertiesChange() when it starts.
- verify(mCb, never()).onLinkPropertiesChange(any());
- reset(mCb);
- return ipc;
- }
-
- private static LinkProperties makeEmptyLinkProperties(String iface) {
- final LinkProperties empty = new LinkProperties();
- empty.setInterfaceName(iface);
- return empty;
- }
-
- private void verifyNetworkAttributesStored(final String l2Key,
- final NetworkAttributes attributes) {
- // TODO : when storing is implemented, turn this on
- // verify(mIpMemoryStore).storeNetworkAttributes(eq(l2Key), eq(attributes), any());
- }
-
- @Test
- public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
- setTestInterfaceParams(null);
- try {
- final IpClient ipc = new IpClient(mContext, null, mCb, mObserverRegistry,
- mNetworkStackServiceManager, mDependencies);
- ipc.shutdown();
- fail();
- } catch (NullPointerException npe) {
- // Phew; null interface names not allowed.
- }
- }
-
- @Test
- public void testNullCallbackMostDefinitelyThrows() throws Exception {
- final String ifname = "lo";
- setTestInterfaceParams(ifname);
- try {
- final IpClient ipc = new IpClient(mContext, ifname, null, mObserverRegistry,
- mNetworkStackServiceManager, mDependencies);
- ipc.shutdown();
- fail();
- } catch (NullPointerException npe) {
- // Phew; null callbacks not allowed.
- }
- }
-
- @Test
- public void testInvalidInterfaceDoesNotThrow() throws Exception {
- setTestInterfaceParams(TEST_IFNAME);
- final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
- mNetworkStackServiceManager, mDependencies);
- verifyNoMoreInteractions(mIpMemoryStore);
- ipc.shutdown();
- }
-
- @Test
- public void testInterfaceNotFoundFailsImmediately() throws Exception {
- setTestInterfaceParams(null);
- final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
- mNetworkStackServiceManager, mDependencies);
- ipc.startProvisioning(new ProvisioningConfiguration());
- verify(mCb, times(1)).onProvisioningFailure(any());
- verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
- ipc.shutdown();
- }
-
- @Test
- public void testDefaultProvisioningConfiguration() throws Exception {
- final String iface = TEST_IFNAME;
- final IpClient ipc = makeIpClient(iface);
-
- ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
- .withoutIPv4()
- // TODO: mock IpReachabilityMonitor's dependencies (NetworkInterface, PowerManager)
- // and enable it in this test
- .withoutIpReachabilityMonitor()
- .build();
-
- ipc.startProvisioning(config);
- verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
- verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
- verify(mCb, never()).onProvisioningFailure(any());
- verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
-
- ipc.shutdown();
- verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
- verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
- verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
- .onLinkPropertiesChange(makeEmptyLinkProperties(iface));
- }
-
- @Test
- public void testProvisioningWithInitialConfiguration() throws Exception {
- final String iface = TEST_IFNAME;
- final IpClient ipc = makeIpClient(iface);
- final String l2Key = TEST_L2KEY;
- final String groupHint = TEST_GROUPHINT;
-
- String[] addresses = {
- "fe80::a4be:f92:e1f7:22d1/64",
- "fe80::f04a:8f6:6a32:d756/64",
- "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"
- };
- String[] prefixes = { "fe80::/64", "fd2c:4e57:8e3c::/64" };
-
- ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
- .withoutIPv4()
- .withoutIpReachabilityMonitor()
- .withInitialConfiguration(conf(links(addresses), prefixes(prefixes), ips()))
- .build();
-
- ipc.startProvisioning(config);
- verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
- verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
- verify(mCb, never()).onProvisioningFailure(any());
- ipc.setL2KeyAndGroupHint(l2Key, groupHint);
-
- for (String addr : addresses) {
- String[] parts = addr.split("/");
- verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1))
- .interfaceAddAddress(iface, parts[0], Integer.parseInt(parts[1]));
- }
-
- final int lastAddr = addresses.length - 1;
-
- // Add N - 1 addresses
- for (int i = 0; i < lastAddr; i++) {
- mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[i]), iface);
- verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(any());
- reset(mCb);
- }
-
- // Add Nth address
- mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[lastAddr]), iface);
- LinkProperties want = linkproperties(links(addresses), routes(prefixes));
- want.setInterfaceName(iface);
- verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(want);
- verifyNetworkAttributesStored(l2Key, new NetworkAttributes.Builder()
- .setGroupHint(groupHint)
- .build());
-
- ipc.shutdown();
- verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
- verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
- verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
- .onLinkPropertiesChange(makeEmptyLinkProperties(iface));
- verifyNoMoreInteractions(mIpMemoryStore);
- }
-
- @Test
- public void testIsProvisioned() throws Exception {
- InitialConfiguration empty = conf(links(), prefixes());
- IsProvisionedTestCase[] testcases = {
- // nothing
- notProvisionedCase(links(), routes(), dns(), null),
- notProvisionedCase(links(), routes(), dns(), empty),
-
- // IPv4
- provisionedCase(links("192.0.2.12/24"), routes(), dns(), empty),
-
- // IPv6
- notProvisionedCase(
- links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
- routes(), dns(), empty),
- notProvisionedCase(
- links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
- routes("fe80::/64", "fd2c:4e57:8e3c::/64"), dns("fd00:1234:5678::1000"), empty),
- provisionedCase(
- links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
- routes("::/0"),
- dns("2001:db8:dead:beef:f00::02"), empty),
-
- // Initial configuration
- provisionedCase(
- links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
- routes("fe80::/64", "fd2c:4e57:8e3c::/64"),
- dns(),
- conf(links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
- prefixes( "fe80::/64", "fd2c:4e57:8e3c::/64"), ips()))
- };
-
- for (IsProvisionedTestCase testcase : testcases) {
- if (IpClient.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) {
- fail(testcase.errorMessage());
- }
- }
- }
-
- static class IsProvisionedTestCase {
- boolean isProvisioned;
- LinkProperties lp;
- InitialConfiguration config;
-
- String errorMessage() {
- return String.format("expected %s with config %s to be %s, but was %s",
- lp, config, provisioned(isProvisioned), provisioned(!isProvisioned));
- }
-
- static String provisioned(boolean isProvisioned) {
- return isProvisioned ? "provisioned" : "not provisioned";
- }
- }
-
- static IsProvisionedTestCase provisionedCase(Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes,
- Set<InetAddress> lpDns, InitialConfiguration config) {
- return provisioningTest(true, lpAddrs, lpRoutes, lpDns, config);
- }
-
- static IsProvisionedTestCase notProvisionedCase(Set<LinkAddress> lpAddrs,
- Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
- return provisioningTest(false, lpAddrs, lpRoutes, lpDns, config);
- }
-
- static IsProvisionedTestCase provisioningTest(boolean isProvisioned, Set<LinkAddress> lpAddrs,
- Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
- IsProvisionedTestCase testcase = new IsProvisionedTestCase();
- testcase.isProvisioned = isProvisioned;
- testcase.lp = new LinkProperties();
- testcase.lp.setLinkAddresses(lpAddrs);
- for (RouteInfo route : lpRoutes) {
- testcase.lp.addRoute(route);
- }
- for (InetAddress dns : lpDns) {
- testcase.lp.addDnsServer(dns);
- }
- testcase.config = config;
- return testcase;
- }
-
- @Test
- public void testInitialConfigurations() throws Exception {
- InitialConfigurationTestCase[] testcases = {
- validConf("valid IPv4 configuration",
- links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("192.0.2.2")),
- validConf("another valid IPv4 configuration",
- links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns()),
- validConf("valid IPv6 configurations",
- links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
- prefixes("2001:db8:dead:beef::/64", "fe80::/64"),
- dns("2001:db8:dead:beef:f00::02")),
- validConf("valid IPv6 configurations",
- links("fe80::1/64"), prefixes("fe80::/64"), dns()),
- validConf("valid IPv6/v4 configuration",
- links("2001:db8:dead:beef:f00::a0/48", "192.0.2.12/24"),
- prefixes("2001:db8:dead:beef::/64", "192.0.2.0/24"),
- dns("192.0.2.2", "2001:db8:dead:beef:f00::02")),
- validConf("valid IPv6 configuration without any GUA.",
- links("fd00:1234:5678::1/48"),
- prefixes("fd00:1234:5678::/48"),
- dns("fd00:1234:5678::1000")),
-
- invalidConf("empty configuration", links(), prefixes(), dns()),
- invalidConf("v4 addr and dns not in any prefix",
- links("192.0.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
- invalidConf("v4 addr not in any prefix",
- links("198.51.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
- invalidConf("v4 dns addr not in any prefix",
- links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("198.51.100.2")),
- invalidConf("v6 addr not in any prefix",
- links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
- prefixes("2001:db8:dead:beef::/64"),
- dns("2001:db8:dead:beef:f00::02")),
- invalidConf("v6 dns addr not in any prefix",
- links("fe80::1/64"), prefixes("fe80::/64"), dns("2001:db8:dead:beef:f00::02")),
- invalidConf("default ipv6 route and no GUA",
- links("fd01:1111:2222:3333::a0/128"), prefixes("::/0"), dns()),
- invalidConf("invalid v6 prefix length",
- links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/32"),
- dns()),
- invalidConf("another invalid v6 prefix length",
- links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/72"),
- dns())
- };
-
- for (InitialConfigurationTestCase testcase : testcases) {
- if (testcase.config.isValid() != testcase.isValid) {
- fail(testcase.errorMessage());
- }
- }
- }
-
- static class InitialConfigurationTestCase {
- String descr;
- boolean isValid;
- InitialConfiguration config;
- public String errorMessage() {
- return String.format("%s: expected configuration %s to be %s, but was %s",
- descr, config, validString(isValid), validString(!isValid));
- }
- static String validString(boolean isValid) {
- return isValid ? VALID : INVALID;
- }
- }
-
- static InitialConfigurationTestCase validConf(String descr, Set<LinkAddress> links,
- Set<IpPrefix> prefixes, Set<InetAddress> dns) {
- return confTestCase(descr, true, conf(links, prefixes, dns));
- }
-
- static InitialConfigurationTestCase invalidConf(String descr, Set<LinkAddress> links,
- Set<IpPrefix> prefixes, Set<InetAddress> dns) {
- return confTestCase(descr, false, conf(links, prefixes, dns));
- }
-
- static InitialConfigurationTestCase confTestCase(
- String descr, boolean isValid, InitialConfiguration config) {
- InitialConfigurationTestCase testcase = new InitialConfigurationTestCase();
- testcase.descr = descr;
- testcase.isValid = isValid;
- testcase.config = config;
- return testcase;
- }
-
- static LinkProperties linkproperties(Set<LinkAddress> addresses, Set<RouteInfo> routes) {
- LinkProperties lp = new LinkProperties();
- lp.setLinkAddresses(addresses);
- for (RouteInfo route : routes) {
- lp.addRoute(route);
- }
- return lp;
- }
-
- static InitialConfiguration conf(Set<LinkAddress> links, Set<IpPrefix> prefixes) {
- return conf(links, prefixes, new HashSet<>());
- }
-
- static InitialConfiguration conf(
- Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns) {
- InitialConfiguration conf = new InitialConfiguration();
- conf.ipAddresses.addAll(links);
- conf.directlyConnectedRoutes.addAll(prefixes);
- conf.dnsServers.addAll(dns);
- return conf;
- }
-
- static Set<RouteInfo> routes(String... routes) {
- return mapIntoSet(routes, (r) -> new RouteInfo(new IpPrefix(r)));
- }
-
- static Set<IpPrefix> prefixes(String... prefixes) {
- return mapIntoSet(prefixes, IpPrefix::new);
- }
-
- static Set<LinkAddress> links(String... addresses) {
- return mapIntoSet(addresses, LinkAddress::new);
- }
-
- static Set<InetAddress> ips(String... addresses) {
- return mapIntoSet(addresses, InetAddress::getByName);
- }
-
- static Set<InetAddress> dns(String... addresses) {
- return ips(addresses);
- }
-
- static <A, B> Set<B> mapIntoSet(A[] in, Fn<A, B> fn) {
- Set<B> out = new HashSet<>(in.length);
- for (A item : in) {
- try {
- out.add(fn.call(item));
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- return out;
- }
-
- interface Fn<A,B> {
- B call(A a) throws Exception;
- }
-
- @Test
- public void testAll() {
- List<String> list1 = Arrays.asList();
- List<String> list2 = Arrays.asList("foo");
- List<String> list3 = Arrays.asList("bar", "baz");
- List<String> list4 = Arrays.asList("foo", "bar", "baz");
-
- assertTrue(InitialConfiguration.all(list1, (x) -> false));
- assertFalse(InitialConfiguration.all(list2, (x) -> false));
- assertTrue(InitialConfiguration.all(list3, (x) -> true));
- assertTrue(InitialConfiguration.all(list2, (x) -> x.charAt(0) == 'f'));
- assertFalse(InitialConfiguration.all(list4, (x) -> x.charAt(0) == 'f'));
- }
-
- @Test
- public void testAny() {
- List<String> list1 = Arrays.asList();
- List<String> list2 = Arrays.asList("foo");
- List<String> list3 = Arrays.asList("bar", "baz");
- List<String> list4 = Arrays.asList("foo", "bar", "baz");
-
- assertFalse(InitialConfiguration.any(list1, (x) -> true));
- assertTrue(InitialConfiguration.any(list2, (x) -> true));
- assertTrue(InitialConfiguration.any(list2, (x) -> x.charAt(0) == 'f'));
- assertFalse(InitialConfiguration.any(list3, (x) -> x.charAt(0) == 'f'));
- assertTrue(InitialConfiguration.any(list4, (x) -> x.charAt(0) == 'f'));
- }
-
- @Test
- public void testFindAll() {
- List<String> list1 = Arrays.asList();
- List<String> list2 = Arrays.asList("foo");
- List<String> list3 = Arrays.asList("foo", "bar", "baz");
-
- assertEquals(list1, IpClient.findAll(list1, (x) -> true));
- assertEquals(list1, IpClient.findAll(list3, (x) -> false));
- assertEquals(list3, IpClient.findAll(list3, (x) -> true));
- assertEquals(list2, IpClient.findAll(list3, (x) -> x.charAt(0) == 'f'));
- }
-}
diff --git a/tests/src/android/net/ip/IpReachabilityMonitorTest.java b/tests/src/android/net/ip/IpReachabilityMonitorTest.java
deleted file mode 100644
index 64b168a..0000000
--- a/tests/src/android/net/ip/IpReachabilityMonitorTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2017 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.ip;
-
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.util.InterfaceParams;
-import android.net.util.SharedLog;
-import android.os.Handler;
-import android.os.Looper;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for IpReachabilityMonitor.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpReachabilityMonitorTest {
-
- @Mock IpReachabilityMonitor.Callback mCallback;
- @Mock IpReachabilityMonitor.Dependencies mDependencies;
- @Mock SharedLog mLog;
- @Mock Context mContext;
- Handler mHandler;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mLog.forSubComponent(anyString())).thenReturn(mLog);
- mHandler = new Handler(Looper.getMainLooper());
- }
-
- IpReachabilityMonitor makeMonitor() {
- final InterfaceParams ifParams = new InterfaceParams("fake0", 1, null);
- return new IpReachabilityMonitor(
- mContext, ifParams, mHandler, mLog, mCallback, false, mDependencies);
- }
-
- @Test
- public void testNothing() {
- IpReachabilityMonitor monitor = makeMonitor();
- }
-}
diff --git a/tests/src/android/net/util/ConnectivityPacketSummaryTest.java b/tests/src/android/net/util/ConnectivityPacketSummaryTest.java
deleted file mode 100644
index 71be8b3..0000000
--- a/tests/src/android/net/util/ConnectivityPacketSummaryTest.java
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Copyright (C) 2016 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.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.net.MacAddress;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.util.HexEncoding;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for ConnectivityPacketSummary.
- *
- * @hide
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ConnectivityPacketSummaryTest {
- private static final MacAddress MYHWADDR = MacAddress.fromString("80:7a:bf:6f:48:f3");
-
- private String getSummary(String hexBytes) {
- hexBytes = hexBytes.replaceAll("\\s+", "");
- final byte[] bytes = HexEncoding.decode(hexBytes.toCharArray(), false);
- return ConnectivityPacketSummary.summarize(MYHWADDR, bytes);
- }
-
- @Test
- public void testParseICMPv6DADProbe() {
- final String packet =
- // Ethernet
- "3333FF6F48F3 807ABF6F48F3 86DD" +
- // IPv6
- "600000000018 3A FF" +
- "00000000000000000000000000000000" +
- "FF0200000000000000000001FF6F48F3" +
- // ICMPv6
- "87 00 A8E7" +
- "00000000" +
- "FE80000000000000827ABFFFFE6F48F3";
-
- final String expected =
- "TX 80:7a:bf:6f:48:f3 > 33:33:ff:6f:48:f3 ipv6" +
- " :: > ff02::1:ff6f:48f3 icmp6" +
- " ns fe80::827a:bfff:fe6f:48f3";
-
- assertEquals(expected, getSummary(packet));
- }
-
- @Test
- public void testParseICMPv6RS() {
- final String packet =
- // Ethernet
- "333300000002 807ABF6F48F3 86DD" +
- // IPv6
- "600000000010 3A FF" +
- "FE80000000000000827ABFFFFE6F48F3" +
- "FF020000000000000000000000000002" +
- // ICMPv6 RS
- "85 00 6973" +
- "00000000" +
- "01 01 807ABF6F48F3";
-
- final String expected =
- "TX 80:7a:bf:6f:48:f3 > 33:33:00:00:00:02 ipv6" +
- " fe80::827a:bfff:fe6f:48f3 > ff02::2 icmp6" +
- " rs slla 80:7a:bf:6f:48:f3";
-
- assertEquals(expected, getSummary(packet));
- }
-
- @Test
- public void testParseICMPv6RA() {
- final String packet =
- // Ethernet
- "807ABF6F48F3 100E7E263FC1 86DD" +
- // IPv6
- "600000000068 3A FF" +
- "FE80000000000000FA000004FD000001" +
- "FE80000000000000827ABFFFFE6F48F3" +
- // ICMPv6 RA
- "86 00 8141" +
- "40 00 0E10" +
- "00000000" +
- "00000000" +
- "01 01 00005E000265" +
- "05 01 0000000005DC" +
- "19 05 000000000E10" +
- " 20014860486000000000000000008844" +
- " 20014860486000000000000000008888" +
- "03 04 40 C0" +
- " 00278D00" +
- " 00093A80" +
- " 00000000" +
- " 2401FA000004FD000000000000000000";
-
- final String expected =
- "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
- " fe80::fa00:4:fd00:1 > fe80::827a:bfff:fe6f:48f3 icmp6" +
- " ra slla 00:00:5e:00:02:65 mtu 1500";
-
- assertEquals(expected, getSummary(packet));
- }
-
- @Test
- public void testParseICMPv6NS() {
- final String packet =
- // Ethernet
- "807ABF6F48F3 100E7E263FC1 86DD" +
- // IPv6
- "6C0000000020 3A FF" +
- "FE80000000000000FA000004FD000001" +
- "FF0200000000000000000001FF01C146" +
- // ICMPv6 NS
- "87 00 8AD4" +
- "00000000" +
- "2401FA000004FD0015EA6A5C7B01C146" +
- "01 01 00005E000265";
-
- final String expected =
- "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
- " fe80::fa00:4:fd00:1 > ff02::1:ff01:c146 icmp6" +
- " ns 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 slla 00:00:5e:00:02:65";
-
- assertEquals(expected, getSummary(packet));
- }
-
- @Test
- public void testInvalidICMPv6NDLength() {
- final String packet =
- // Ethernet
- "807ABF6F48F3 100E7E263FC1 86DD" +
- // IPv6
- "600000000068 3A FF" +
- "FE80000000000000FA000004FD000001" +
- "FE80000000000000827ABFFFFE6F48F3" +
- // ICMPv6 RA
- "86 00 8141" +
- "40 00 0E10" +
- "00000000" +
- "00000000" +
- "01 01 00005E000265" +
- "00 00 0102030405D6";
-
- final String expected =
- "RX 10:0e:7e:26:3f:c1 > 80:7a:bf:6f:48:f3 ipv6" +
- " fe80::fa00:4:fd00:1 > fe80::827a:bfff:fe6f:48f3 icmp6" +
- " ra slla 00:00:5e:00:02:65 <malformed>";
-
- assertEquals(expected, getSummary(packet));
- }
-
- @Test
- public void testParseICMPv6NA() {
- final String packet =
- // Ethernet
- "00005E000265 807ABF6F48F3 86DD" +
- "600000000020 3A FF" +
- "2401FA000004FD0015EA6A5C7B01C146" +
- "FE80000000000000FA000004FD000001" +
- "88 00 E8126" +
- "0000000" +
- "2401FA000004FD0015EA6A5C7B01C146" +
- "02 01 807ABF6F48F3";
-
- final String expected =
- "TX 80:7a:bf:6f:48:f3 > 00:00:5e:00:02:65 ipv6" +
- " 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 > fe80::fa00:4:fd00:1 icmp6" +
- " na 2401:fa00:4:fd00:15ea:6a5c:7b01:c146 tlla 80:7a:bf:6f:48:f3";
-
- assertEquals(expected, getSummary(packet));
- }
-
- @Test
- public void testParseARPRequest() {
- final String packet =
- // Ethernet
- "FFFFFFFFFFFF 807ABF6F48F3 0806" +
- // ARP
- "0001 0800 06 04" +
- // Request
- "0001" +
- "807ABF6F48F3 64706ADB" +
- "000000000000 64706FFD";
-
- final String expected =
- "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff arp" +
- " who-has 100.112.111.253";
-
- assertEquals(expected, getSummary(packet));
- }
-
- @Test
- public void testParseARPReply() {
- final String packet =
- // Ethernet
- "807ABF6F48F3 288A1CA8DFC1 0806" +
- // ARP
- "0001 0800 06 04" +
- // Reply
- "0002" +
- "288A1CA8DFC1 64706FFD"+
- "807ABF6F48F3 64706ADB" +
- // Ethernet padding to packet min size.
- "0000000000000000000000000000";
-
- final String expected =
- "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 arp" +
- " reply 100.112.111.253 28:8a:1c:a8:df:c1";
-
- assertEquals(expected, getSummary(packet));
- }
-
- @Test
- public void testParseDHCPv4Discover() {
- final String packet =
- // Ethernet
- "FFFFFFFFFFFF 807ABF6F48F3 0800" +
- // IPv4
- "451001580000400040113986" +
- "00000000" +
- "FFFFFFFF" +
- // UDP
- "0044 0043" +
- "0144 5559" +
- // DHCPv4
- "01 01 06 00" +
- "79F7ACA4" +
- "0000 0000" +
- "00000000" +
- "00000000" +
- "00000000" +
- "00000000" +
- "807ABF6F48F300000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "63 82 53 63" +
- "35 01 01" +
- "3D 07 01807ABF6F48F3" +
- "39 02 05DC" +
- "3C 12 616E64726F69642D646863702D372E312E32" +
- "0C 18 616E64726F69642D36623030366333313333393835343139" +
- "37 0A 01 03 06 0F 1A 1C 33 3A 3B 2B" +
- "FF" +
- "00";
-
- final String expectedPrefix =
- "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff ipv4" +
- " 0.0.0.0 > 255.255.255.255 udp" +
- " 68 > 67 dhcp4" +
- " 80:7a:bf:6f:48:f3 DISCOVER";
-
- assertTrue(getSummary(packet).startsWith(expectedPrefix));
- }
-
- @Test
- public void testParseDHCPv4Offer() {
- final String packet =
- // Ethernet
- "807ABF6F48F3 288A1CA8DFC1 0800" +
- // IPv4
- "4500013D4D2C0000401188CB" +
- "64706FFD" +
- "64706ADB" +
- // UDP
- "0043 0044" +
- "0129 371D" +
- // DHCPv4
- "02 01 06 01" +
- "79F7ACA4" +
- "0000 0000" +
- "00000000" +
- "64706ADB" +
- "00000000" +
- "00000000" +
- "807ABF6F48F300000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "63 82 53 63" +
- "35 01 02" +
- "36 04 AC188A0B" +
- "33 04 00000708" +
- "01 04 FFFFF000" +
- "03 04 64706FFE" +
- "06 08 08080808" +
- " 08080404" +
- "FF0001076165313A363636FF";
-
- final String expectedPrefix =
- "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 ipv4" +
- " 100.112.111.253 > 100.112.106.219 udp" +
- " 67 > 68 dhcp4" +
- " 80:7a:bf:6f:48:f3 OFFER";
-
- assertTrue(getSummary(packet).startsWith(expectedPrefix));
- }
-
- @Test
- public void testParseDHCPv4Request() {
- final String packet =
- // Ethernet
- "FFFFFFFFFFFF 807ABF6F48F3 0800" +
- // IPv4
- "45100164000040004011397A" +
- "00000000" +
- "FFFFFFFF" +
- // UDP
- "0044 0043" +
- "0150 E5C7" +
- // DHCPv4
- "01 01 06 00" +
- "79F7ACA4" +
- "0001 0000" +
- "00000000" +
- "00000000" +
- "00000000" +
- "00000000" +
- "807ABF6F48F300000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "63 82 53 63" +
- "35 01 03" +
- "3D 07 01807ABF6F48F3" +
- "32 04 64706ADB" +
- "36 04 AC188A0B" +
- "39 02 05DC" +
- "3C 12 616E64726F69642D646863702D372E312E32" +
- "0C 18 616E64726F69642D36623030366333313333393835343139" +
- "37 0A 01 03 06 0F 1A 1C 33 3A 3B 2B" +
- "FF" +
- "00";
-
- final String expectedPrefix =
- "TX 80:7a:bf:6f:48:f3 > ff:ff:ff:ff:ff:ff ipv4" +
- " 0.0.0.0 > 255.255.255.255 udp" +
- " 68 > 67 dhcp4" +
- " 80:7a:bf:6f:48:f3 REQUEST";
-
- assertTrue(getSummary(packet).startsWith(expectedPrefix));
- }
-
- @Test
- public void testParseDHCPv4Ack() {
- final String packet =
- // Ethernet
- "807ABF6F48F3 288A1CA8DFC1 0800" +
- // IPv4
- "4500013D4D3B0000401188BC" +
- "64706FFD" +
- "64706ADB" +
- // UDP
- "0043 0044" +
- "0129 341C" +
- // DHCPv4
- "02 01 06 01" +
- "79F7ACA4" +
- "0001 0000" +
- "00000000" +
- "64706ADB" +
- "00000000" +
- "00000000" +
- "807ABF6F48F300000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "63 82 53 63" +
- "35 01 05" +
- "36 04 AC188A0B" +
- "33 04 00000708" +
- "01 04 FFFFF000" +
- "03 04 64706FFE" +
- "06 08 08080808" +
- " 08080404" +
- "FF0001076165313A363636FF";
-
- final String expectedPrefix =
- "RX 28:8a:1c:a8:df:c1 > 80:7a:bf:6f:48:f3 ipv4" +
- " 100.112.111.253 > 100.112.106.219 udp" +
- " 67 > 68 dhcp4" +
- " 80:7a:bf:6f:48:f3 ACK";
-
- assertTrue(getSummary(packet).startsWith(expectedPrefix));
- }
-}
diff --git a/tests/src/android/net/util/PacketReaderTest.java b/tests/src/android/net/util/PacketReaderTest.java
deleted file mode 100644
index 289dcad..0000000
--- a/tests/src/android/net/util/PacketReaderTest.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2016 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.util;
-
-import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_NONBLOCK;
-import static android.system.OsConstants.SOL_SOCKET;
-import static android.system.OsConstants.SO_SNDTIMEO;
-
-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 android.os.Handler;
-import android.os.HandlerThread;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructTimeval;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.FileDescriptor;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketException;
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Tests for PacketReader.
- *
- * @hide
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class PacketReaderTest {
- static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress();
- static final StructTimeval TIMEO = StructTimeval.fromMillis(500);
-
- protected CountDownLatch mLatch;
- protected FileDescriptor mLocalSocket;
- protected InetSocketAddress mLocalSockName;
- protected byte[] mLastRecvBuf;
- protected boolean mStopped;
- protected HandlerThread mHandlerThread;
- protected PacketReader mReceiver;
-
- class UdpLoopbackReader extends PacketReader {
- public UdpLoopbackReader(Handler h) {
- super(h);
- }
-
- @Override
- protected FileDescriptor createFd() {
- FileDescriptor s = null;
- try {
- s = Os.socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
- Os.bind(s, LOOPBACK6, 0);
- mLocalSockName = (InetSocketAddress) Os.getsockname(s);
- Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO);
- } catch (ErrnoException|SocketException e) {
- closeFd(s);
- fail();
- return null;
- }
-
- mLocalSocket = s;
- return s;
- }
-
- @Override
- protected void handlePacket(byte[] recvbuf, int length) {
- mLastRecvBuf = Arrays.copyOf(recvbuf, length);
- mLatch.countDown();
- }
-
- @Override
- protected void onStart() {
- mStopped = false;
- mLatch.countDown();
- }
-
- @Override
- protected void onStop() {
- mStopped = true;
- mLatch.countDown();
- }
- };
-
- @Before
- public void setUp() {
- resetLatch();
- mLocalSocket = null;
- mLocalSockName = null;
- mLastRecvBuf = null;
- mStopped = false;
-
- mHandlerThread = new HandlerThread(PacketReaderTest.class.getSimpleName());
- mHandlerThread.start();
- }
-
- @After
- public void tearDown() throws Exception {
- if (mReceiver != null) {
- mHandlerThread.getThreadHandler().post(() -> { mReceiver.stop(); });
- waitForActivity();
- }
- mReceiver = null;
- mHandlerThread.quit();
- mHandlerThread = null;
- }
-
- void resetLatch() { mLatch = new CountDownLatch(1); }
-
- void waitForActivity() throws Exception {
- try {
- mLatch.await(1000, TimeUnit.MILLISECONDS);
- } finally {
- resetLatch();
- }
- }
-
- void sendPacket(byte[] contents) throws Exception {
- final DatagramSocket sender = new DatagramSocket();
- sender.connect(mLocalSockName);
- sender.send(new DatagramPacket(contents, contents.length));
- sender.close();
- }
-
- @Test
- public void testBasicWorking() throws Exception {
- final Handler h = mHandlerThread.getThreadHandler();
- mReceiver = new UdpLoopbackReader(h);
-
- h.post(() -> { mReceiver.start(); });
- waitForActivity();
- assertTrue(mLocalSockName != null);
- assertEquals(LOOPBACK6, mLocalSockName.getAddress());
- assertTrue(0 < mLocalSockName.getPort());
- assertTrue(mLocalSocket != null);
- assertFalse(mStopped);
-
- final byte[] one = "one 1".getBytes("UTF-8");
- sendPacket(one);
- waitForActivity();
- assertEquals(1, mReceiver.numPacketsReceived());
- assertTrue(Arrays.equals(one, mLastRecvBuf));
- assertFalse(mStopped);
-
- final byte[] two = "two 2".getBytes("UTF-8");
- sendPacket(two);
- waitForActivity();
- assertEquals(2, mReceiver.numPacketsReceived());
- assertTrue(Arrays.equals(two, mLastRecvBuf));
- assertFalse(mStopped);
-
- mReceiver.stop();
- waitForActivity();
- assertEquals(2, mReceiver.numPacketsReceived());
- assertTrue(Arrays.equals(two, mLastRecvBuf));
- assertTrue(mStopped);
- mReceiver = null;
- }
-
- class NullPacketReader extends PacketReader {
- public NullPacketReader(Handler h, int recvbufsize) {
- super(h, recvbufsize);
- }
-
- @Override
- public FileDescriptor createFd() { return null; }
- }
-
- @Test
- public void testMinimalRecvBufSize() throws Exception {
- final Handler h = mHandlerThread.getThreadHandler();
-
- for (int i : new int[]{-1, 0, 1, DEFAULT_RECV_BUF_SIZE-1}) {
- final PacketReader b = new NullPacketReader(h, i);
- assertEquals(DEFAULT_RECV_BUF_SIZE, b.recvBufSize());
- }
- }
-}
diff --git a/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
deleted file mode 100644
index 832b712..0000000
--- a/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ /dev/null
@@ -1,1022 +0,0 @@
-/*
- * Copyright (C) 2017 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 com.android.server.connectivity;
-
-import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
-import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_INVALID;
-import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
-import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
-import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.DnsResolver;
-import android.net.INetworkMonitorCallbacks;
-import android.net.InetAddresses;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.captiveportal.CaptivePortalProbeResult;
-import android.net.metrics.IpConnectivityLog;
-import android.net.shared.PrivateDnsConfig;
-import android.net.util.SharedLog;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.telephony.CellSignalStrength;
-import android.telephony.TelephonyManager;
-import android.util.ArrayMap;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.networkstack.R;
-import com.android.networkstack.metrics.DataStallDetectionStats;
-import com.android.networkstack.metrics.DataStallStatsUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
-
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.Executor;
-
-import javax.net.ssl.SSLHandshakeException;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkMonitorTest {
- private static final String LOCATION_HEADER = "location";
-
- private @Mock Context mContext;
- private @Mock Resources mResources;
- private @Mock IpConnectivityLog mLogger;
- private @Mock SharedLog mValidationLogger;
- private @Mock NetworkInfo mNetworkInfo;
- private @Mock DnsResolver mDnsResolver;
- private @Mock ConnectivityManager mCm;
- private @Mock TelephonyManager mTelephony;
- private @Mock WifiManager mWifi;
- private @Mock HttpURLConnection mHttpConnection;
- private @Mock HttpURLConnection mHttpsConnection;
- private @Mock HttpURLConnection mFallbackConnection;
- private @Mock HttpURLConnection mOtherFallbackConnection;
- private @Mock Random mRandom;
- private @Mock NetworkMonitor.Dependencies mDependencies;
- private @Mock INetworkMonitorCallbacks mCallbacks;
- private @Spy Network mCleartextDnsNetwork = new Network(TEST_NETID);
- private @Mock Network mNetwork;
- private @Mock DataStallStatsUtils mDataStallStatsUtils;
- private @Mock WifiInfo mWifiInfo;
- private @Captor ArgumentCaptor<String> mNetworkTestedRedirectUrlCaptor;
-
- private HashSet<WrappedNetworkMonitor> mCreatedNetworkMonitors;
- private HashSet<BroadcastReceiver> mRegisteredReceivers;
-
- private static final int TEST_NETID = 4242;
- private static final String TEST_HTTP_URL = "http://www.google.com/gen_204";
- private static final String TEST_HTTPS_URL = "https://www.google.com/gen_204";
- private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204";
- private static final String TEST_OTHER_FALLBACK_URL = "http://otherfallback.google.com/gen_204";
- private static final String TEST_MCCMNC = "123456";
-
- private static final int RETURN_CODE_DNS_SUCCESS = 0;
- private static final int RETURN_CODE_DNS_TIMEOUT = 255;
- private static final int DEFAULT_DNS_TIMEOUT_THRESHOLD = 5;
-
- private static final int HANDLER_TIMEOUT_MS = 1000;
-
- private static final LinkProperties TEST_LINK_PROPERTIES = new LinkProperties();
-
- private static final NetworkCapabilities METERED_CAPABILITIES = new NetworkCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET);
-
- private static final NetworkCapabilities NOT_METERED_CAPABILITIES = new NetworkCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
-
- private static final NetworkCapabilities NO_INTERNET_CAPABILITIES = new NetworkCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-
- /**
- * Fakes DNS responses.
- *
- * Allows test methods to configure the IP addresses that will be resolved by
- * Network#getAllByName and by DnsResolver#query.
- */
- class FakeDns {
- private final ArrayMap<String, List<InetAddress>> mAnswers = new ArrayMap<>();
- private boolean mNonBypassPrivateDnsWorking = true;
-
- /** Whether DNS queries on mNonBypassPrivateDnsWorking should succeed. */
- private void setNonBypassPrivateDnsWorking(boolean working) {
- mNonBypassPrivateDnsWorking = working;
- }
-
- /** Clears all DNS entries. */
- private synchronized void clearAll() {
- mAnswers.clear();
- }
-
- /** Returns the answer for a given name on the given mock network. */
- private synchronized List<InetAddress> getAnswer(Object mock, String hostname) {
- if (mock == mNetwork && !mNonBypassPrivateDnsWorking) {
- return null;
- }
- if (mAnswers.containsKey(hostname)) {
- return mAnswers.get(hostname);
- }
- return mAnswers.get("*");
- }
-
- /** Sets the answer for a given name. */
- private synchronized void setAnswer(String hostname, String[] answer)
- throws UnknownHostException {
- if (answer == null) {
- mAnswers.remove(hostname);
- } else {
- List<InetAddress> answerList = new ArrayList<>();
- for (String addr : answer) {
- answerList.add(InetAddresses.parseNumericAddress(addr));
- }
- mAnswers.put(hostname, answerList);
- }
- }
-
- /** Simulates a getAllByName call for the specified name on the specified mock network. */
- private InetAddress[] getAllByName(Object mock, String hostname)
- throws UnknownHostException {
- List<InetAddress> answer = getAnswer(mock, hostname);
- if (answer == null || answer.size() == 0) {
- throw new UnknownHostException(hostname);
- }
- return answer.toArray(new InetAddress[0]);
- }
-
- /** Starts mocking DNS queries. */
- private void startMocking() throws UnknownHostException {
- // Queries on mNetwork using getAllByName.
- doAnswer(invocation -> {
- return getAllByName(invocation.getMock(), invocation.getArgument(0));
- }).when(mNetwork).getAllByName(any());
-
- // Queries on mCleartextDnsNetwork using DnsResolver#query.
- doAnswer(invocation -> {
- String hostname = (String) invocation.getArgument(1);
- Executor executor = (Executor) invocation.getArgument(3);
- DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(5);
-
- List<InetAddress> answer = getAnswer(invocation.getMock(), hostname);
- if (answer != null && answer.size() > 0) {
- new Handler(Looper.getMainLooper()).post(() -> {
- executor.execute(() -> callback.onAnswer(answer, 0));
- });
- }
- // If no answers, do nothing. sendDnsProbeWithTimeout will time out and throw UHE.
- return null;
- }).when(mDnsResolver).query(any(), any(), anyInt(), any(), any(), any());
-
- // Queries on mCleartextDnsNetwork using using DnsResolver#query with QueryType.
- doAnswer(invocation -> {
- String hostname = (String) invocation.getArgument(1);
- Executor executor = (Executor) invocation.getArgument(4);
- DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(6);
-
- List<InetAddress> answer = getAnswer(invocation.getMock(), hostname);
- if (answer != null && answer.size() > 0) {
- new Handler(Looper.getMainLooper()).post(() -> {
- executor.execute(() -> callback.onAnswer(answer, 0));
- });
- }
- // If no answers, do nothing. sendDnsProbeWithTimeout will time out and throw UHE.
- return null;
- }).when(mDnsResolver).query(any(), any(), anyInt(), anyInt(), any(), any(), any());
- }
- }
-
- private FakeDns mFakeDns;
-
- @Before
- public void setUp() throws IOException {
- MockitoAnnotations.initMocks(this);
- when(mDependencies.getPrivateDnsBypassNetwork(any())).thenReturn(mCleartextDnsNetwork);
- when(mDependencies.getDnsResolver()).thenReturn(mDnsResolver);
- when(mDependencies.getRandom()).thenReturn(mRandom);
- when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt()))
- .thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
- when(mDependencies.getDeviceConfigPropertyInt(any(), eq(CAPTIVE_PORTAL_USE_HTTPS),
- anyInt())).thenReturn(1);
- when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL), any()))
- .thenReturn(TEST_HTTP_URL);
- when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL), any()))
- .thenReturn(TEST_HTTPS_URL);
-
- doReturn(mCleartextDnsNetwork).when(mNetwork).getPrivateDnsBypassingCopy();
-
- when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm);
- when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephony);
- when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifi);
- when(mContext.getResources()).thenReturn(mResources);
-
- when(mResources.getString(anyInt())).thenReturn("");
- when(mResources.getStringArray(anyInt())).thenReturn(new String[0]);
-
- when(mNetworkInfo.getType()).thenReturn(ConnectivityManager.TYPE_WIFI);
- setFallbackUrl(TEST_FALLBACK_URL);
- setOtherFallbackUrls(TEST_OTHER_FALLBACK_URL);
- setFallbackSpecs(null); // Test with no fallback spec by default
- when(mRandom.nextInt()).thenReturn(0);
-
- // DNS probe timeout should not be defined more than half of HANDLER_TIMEOUT_MS. Otherwise,
- // it will fail the test because of timeout expired for querying AAAA and A sequentially.
- when(mResources.getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout)))
- .thenReturn(200);
-
- doAnswer((invocation) -> {
- URL url = invocation.getArgument(0);
- switch(url.toString()) {
- case TEST_HTTP_URL:
- return mHttpConnection;
- case TEST_HTTPS_URL:
- return mHttpsConnection;
- case TEST_FALLBACK_URL:
- return mFallbackConnection;
- case TEST_OTHER_FALLBACK_URL:
- return mOtherFallbackConnection;
- default:
- fail("URL not mocked: " + url.toString());
- return null;
- }
- }).when(mCleartextDnsNetwork).openConnection(any());
- when(mHttpConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
- when(mHttpsConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
-
- mFakeDns = new FakeDns();
- mFakeDns.startMocking();
- mFakeDns.setAnswer("*", new String[]{"2001:db8::1", "192.0.2.2"});
-
- when(mContext.registerReceiver(any(BroadcastReceiver.class), any())).then((invocation) -> {
- mRegisteredReceivers.add(invocation.getArgument(0));
- return new Intent();
- });
-
- doAnswer((invocation) -> {
- mRegisteredReceivers.remove(invocation.getArgument(0));
- return null;
- }).when(mContext).unregisterReceiver(any());
-
- setMinDataStallEvaluateInterval(500);
- setDataStallEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS);
- setValidDataStallDnsTimeThreshold(500);
- setConsecutiveDnsTimeoutThreshold(5);
-
- mCreatedNetworkMonitors = new HashSet<>();
- mRegisteredReceivers = new HashSet<>();
- }
-
- @After
- public void tearDown() {
- mFakeDns.clearAll();
- assertTrue(mCreatedNetworkMonitors.size() > 0);
- // Make a local copy of mCreatedNetworkMonitors because during the iteration below,
- // WrappedNetworkMonitor#onQuitting will delete elements from it on the handler threads.
- WrappedNetworkMonitor[] networkMonitors = mCreatedNetworkMonitors.toArray(
- new WrappedNetworkMonitor[0]);
- for (WrappedNetworkMonitor nm : networkMonitors) {
- nm.notifyNetworkDisconnected();
- nm.awaitQuit();
- }
- assertEquals("NetworkMonitor still running after disconnect",
- 0, mCreatedNetworkMonitors.size());
- assertEquals("BroadcastReceiver still registered after disconnect",
- 0, mRegisteredReceivers.size());
- }
-
- private class WrappedNetworkMonitor extends NetworkMonitor {
- private long mProbeTime = 0;
- private final ConditionVariable mQuitCv = new ConditionVariable(false);
-
- WrappedNetworkMonitor() {
- super(mContext, mCallbacks, mNetwork, mLogger, mValidationLogger,
- mDependencies, mDataStallStatsUtils);
- }
-
- @Override
- protected long getLastProbeTime() {
- return mProbeTime;
- }
-
- protected void setLastProbeTime(long time) {
- mProbeTime = time;
- }
-
- @Override
- protected void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
- generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
- }
-
- @Override
- protected void onQuitting() {
- assertTrue(mCreatedNetworkMonitors.remove(this));
- mQuitCv.open();
- }
-
- protected void awaitQuit() {
- assertTrue("NetworkMonitor did not quit after " + HANDLER_TIMEOUT_MS + "ms",
- mQuitCv.block(HANDLER_TIMEOUT_MS));
- }
- }
-
- private WrappedNetworkMonitor makeMonitor(NetworkCapabilities nc) {
- final WrappedNetworkMonitor nm = new WrappedNetworkMonitor();
- nm.start();
- setNetworkCapabilities(nm, nc);
- waitForIdle(nm.getHandler());
- mCreatedNetworkMonitors.add(nm);
- return nm;
- }
-
- private WrappedNetworkMonitor makeMeteredNetworkMonitor() {
- final WrappedNetworkMonitor nm = makeMonitor(METERED_CAPABILITIES);
- return nm;
- }
-
- private WrappedNetworkMonitor makeNotMeteredNetworkMonitor() {
- final WrappedNetworkMonitor nm = makeMonitor(NOT_METERED_CAPABILITIES);
- return nm;
- }
-
- private void setNetworkCapabilities(NetworkMonitor nm, NetworkCapabilities nc) {
- nm.notifyNetworkCapabilitiesChanged(nc);
- waitForIdle(nm.getHandler());
- }
-
- private void waitForIdle(Handler handler) {
- final ConditionVariable cv = new ConditionVariable(false);
- handler.post(cv::open);
- if (!cv.block(HANDLER_TIMEOUT_MS)) {
- fail("Timed out waiting for handler");
- }
- }
-
- @Test
- public void testGetIntSetting() throws Exception {
- WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
-
- // No config resource, no device config. Expect to get default resource.
- doThrow(new Resources.NotFoundException())
- .when(mResources).getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout));
- doAnswer(invocation -> {
- int defaultValue = invocation.getArgument(2);
- return defaultValue;
- }).when(mDependencies).getDeviceConfigPropertyInt(any(),
- eq(NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT),
- anyInt());
- when(mResources.getInteger(eq(R.integer.default_captive_portal_dns_probe_timeout)))
- .thenReturn(42);
- assertEquals(42, wnm.getIntSetting(mContext,
- R.integer.config_captive_portal_dns_probe_timeout,
- NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
- R.integer.default_captive_portal_dns_probe_timeout));
-
- // Set device config. Expect to get device config.
- when(mDependencies.getDeviceConfigPropertyInt(any(),
- eq(NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT), anyInt()))
- .thenReturn(1234);
- assertEquals(1234, wnm.getIntSetting(mContext,
- R.integer.config_captive_portal_dns_probe_timeout,
- NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
- R.integer.default_captive_portal_dns_probe_timeout));
-
- // Set config resource. Expect to get config resource.
- when(mResources.getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout)))
- .thenReturn(5678);
- assertEquals(5678, wnm.getIntSetting(mContext,
- R.integer.config_captive_portal_dns_probe_timeout,
- NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
- R.integer.default_captive_portal_dns_probe_timeout));
- }
-
- @Test
- public void testIsCaptivePortal_HttpProbeIsPortal() throws IOException {
- setSslException(mHttpsConnection);
- setPortal302(mHttpConnection);
-
- runPortalNetworkTest();
- }
-
- @Test
- public void testIsCaptivePortal_HttpsProbeIsNotPortal() throws IOException {
- setStatus(mHttpsConnection, 204);
- setStatus(mHttpConnection, 500);
-
- runNotPortalNetworkTest();
- }
-
- @Test
- public void testIsCaptivePortal_FallbackProbeIsPortal() throws IOException {
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setPortal302(mFallbackConnection);
-
- runPortalNetworkTest();
- }
-
- @Test
- public void testIsCaptivePortal_FallbackProbeIsNotPortal() throws IOException {
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 500);
-
- // Fallback probe did not see portal, HTTPS failed -> inconclusive
- runFailedNetworkTest();
- }
-
- @Test
- public void testIsCaptivePortal_OtherFallbackProbeIsPortal() throws IOException {
- // Set all fallback probes but one to invalid URLs to verify they are being skipped
- setFallbackUrl(TEST_FALLBACK_URL);
- setOtherFallbackUrls(TEST_FALLBACK_URL + "," + TEST_OTHER_FALLBACK_URL);
-
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 500);
- setPortal302(mOtherFallbackConnection);
-
- // TEST_OTHER_FALLBACK_URL is third
- when(mRandom.nextInt()).thenReturn(2);
-
- // First check always uses the first fallback URL: inconclusive
- final NetworkMonitor monitor = runNetworkTest(NETWORK_TEST_RESULT_INVALID);
- assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
- verify(mFallbackConnection, times(1)).getResponseCode();
- verify(mOtherFallbackConnection, never()).getResponseCode();
-
- // Second check uses the URL chosen by Random
- final CaptivePortalProbeResult result = monitor.isCaptivePortal();
- assertTrue(result.isPortal());
- verify(mOtherFallbackConnection, times(1)).getResponseCode();
- }
-
- @Test
- public void testIsCaptivePortal_AllProbesFailed() throws IOException {
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 404);
-
- runFailedNetworkTest();
- verify(mFallbackConnection, times(1)).getResponseCode();
- verify(mOtherFallbackConnection, never()).getResponseCode();
- }
-
- @Test
- public void testIsCaptivePortal_InvalidUrlSkipped() throws IOException {
- setFallbackUrl("invalid");
- setOtherFallbackUrls("otherinvalid," + TEST_OTHER_FALLBACK_URL + ",yetanotherinvalid");
-
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setPortal302(mOtherFallbackConnection);
-
- runPortalNetworkTest();
- verify(mOtherFallbackConnection, times(1)).getResponseCode();
- verify(mFallbackConnection, never()).getResponseCode();
- }
-
- private void setupFallbackSpec() throws IOException {
- setFallbackSpecs("http://example.com@@/@@204@@/@@"
- + "@@,@@"
- + TEST_OTHER_FALLBACK_URL + "@@/@@30[12]@@/@@https://(www\\.)?google.com/?.*");
-
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
-
- // Use the 2nd fallback spec
- when(mRandom.nextInt()).thenReturn(1);
- }
-
- @Test
- public void testIsCaptivePortal_FallbackSpecIsPartial() throws IOException {
- setupFallbackSpec();
- set302(mOtherFallbackConnection, "https://www.google.com/test?q=3");
-
- // HTTPS failed, fallback spec went through -> partial connectivity
- runPartialConnectivityNetworkTest();
- verify(mOtherFallbackConnection, times(1)).getResponseCode();
- verify(mFallbackConnection, never()).getResponseCode();
- }
-
- @Test
- public void testIsCaptivePortal_FallbackSpecIsPortal() throws IOException {
- setupFallbackSpec();
- set302(mOtherFallbackConnection, "http://login.portal.example.com");
-
- runPortalNetworkTest();
- }
-
- @Test
- public void testIsCaptivePortal_IgnorePortals() throws IOException {
- setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
- setSslException(mHttpsConnection);
- setPortal302(mHttpConnection);
-
- runNotPortalNetworkTest();
- }
-
- @Test
- public void testIsDataStall_EvaluationDisabled() {
- setDataStallEvaluationType(0);
- WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- assertFalse(wrappedMonitor.isDataStall());
- }
-
- @Test
- public void testIsDataStall_EvaluationDnsOnNotMeteredNetwork() {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
- assertTrue(wrappedMonitor.isDataStall());
- }
-
- @Test
- public void testIsDataStall_EvaluationDnsOnMeteredNetwork() {
- WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- assertFalse(wrappedMonitor.isDataStall());
-
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
- assertTrue(wrappedMonitor.isDataStall());
- }
-
- @Test
- public void testIsDataStall_EvaluationDnsWithDnsTimeoutCount() {
- WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- makeDnsTimeoutEvent(wrappedMonitor, 3);
- assertFalse(wrappedMonitor.isDataStall());
- // Reset consecutive timeout counts.
- makeDnsSuccessEvent(wrappedMonitor, 1);
- makeDnsTimeoutEvent(wrappedMonitor, 2);
- assertFalse(wrappedMonitor.isDataStall());
-
- makeDnsTimeoutEvent(wrappedMonitor, 3);
- assertTrue(wrappedMonitor.isDataStall());
-
- // Set the value to larger than the default dns log size.
- setConsecutiveDnsTimeoutThreshold(51);
- wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- makeDnsTimeoutEvent(wrappedMonitor, 50);
- assertFalse(wrappedMonitor.isDataStall());
-
- makeDnsTimeoutEvent(wrappedMonitor, 1);
- assertTrue(wrappedMonitor.isDataStall());
- }
-
- @Test
- public void testIsDataStall_EvaluationDnsWithDnsTimeThreshold() {
- // Test dns events happened in valid dns time threshold.
- WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
- assertFalse(wrappedMonitor.isDataStall());
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- assertTrue(wrappedMonitor.isDataStall());
-
- // Test dns events happened before valid dns time threshold.
- setValidDataStallDnsTimeThreshold(0);
- wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
- assertFalse(wrappedMonitor.isDataStall());
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- assertFalse(wrappedMonitor.isDataStall());
- }
-
- @Test
- public void testBrokenNetworkNotValidated() throws Exception {
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 404);
-
- runFailedNetworkTest();
- }
-
- @Test
- public void testNoInternetCapabilityValidated() throws Exception {
- runNetworkTest(NO_INTERNET_CAPABILITIES, NETWORK_TEST_RESULT_VALID);
- verify(mCleartextDnsNetwork, never()).openConnection(any());
- }
-
- @Test
- public void testLaunchCaptivePortalApp() throws Exception {
- setSslException(mHttpsConnection);
- setPortal302(mHttpConnection);
-
- final NetworkMonitor nm = makeMonitor(METERED_CAPABILITIES);
- nm.notifyNetworkConnected(TEST_LINK_PROPERTIES, METERED_CAPABILITIES);
-
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .showProvisioningNotification(any(), any());
-
- assertEquals(1, mRegisteredReceivers.size());
-
- // Check that startCaptivePortalApp sends the expected intent.
- nm.launchCaptivePortalApp();
-
- final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
- final ArgumentCaptor<Network> networkCaptor = ArgumentCaptor.forClass(Network.class);
- verify(mCm, timeout(HANDLER_TIMEOUT_MS).times(1))
- .startCaptivePortalApp(networkCaptor.capture(), bundleCaptor.capture());
- final Bundle bundle = bundleCaptor.getValue();
- final Network bundleNetwork = bundle.getParcelable(ConnectivityManager.EXTRA_NETWORK);
- assertEquals(TEST_NETID, bundleNetwork.netId);
- // network is passed both in bundle and as parameter, as the bundle is opaque to the
- // framework and only intended for the captive portal app, but the framework needs
- // the network to identify the right NetworkMonitor.
- assertEquals(TEST_NETID, networkCaptor.getValue().netId);
-
- // Have the app report that the captive portal is dismissed, and check that we revalidate.
- setStatus(mHttpsConnection, 204);
- setStatus(mHttpConnection, 204);
-
- nm.notifyCaptivePortalAppFinished(APP_RETURN_DISMISSED);
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
-
- assertEquals(0, mRegisteredReceivers.size());
- }
-
- @Test
- public void testPrivateDnsSuccess() throws Exception {
- setStatus(mHttpsConnection, 204);
- setStatus(mHttpConnection, 204);
- mFakeDns.setAnswer("dns.google", new String[]{"2001:db8::53"});
-
- WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
- wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google", new InetAddress[0]));
- wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(eq(NETWORK_TEST_RESULT_VALID), eq(null));
- }
-
- @Test
- public void testPrivateDnsResolutionRetryUpdate() throws Exception {
- // Set a private DNS hostname that doesn't resolve and expect validation to fail.
- mFakeDns.setAnswer("dns.google", new String[0]);
- setStatus(mHttpsConnection, 204);
- setStatus(mHttpConnection, 204);
-
- WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
- wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google", new InetAddress[0]));
- wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(eq(NETWORK_TEST_RESULT_INVALID), eq(null));
-
- // Fix DNS and retry, expect validation to succeed.
- reset(mCallbacks);
- mFakeDns.setAnswer("dns.google", new String[]{"2001:db8::1"});
-
- wnm.forceReevaluation(Process.myUid());
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(eq(NETWORK_TEST_RESULT_VALID), eq(null));
-
- // Change configuration to an invalid DNS name, expect validation to fail.
- reset(mCallbacks);
- mFakeDns.setAnswer("dns.bad", new String[0]);
- wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.bad", new InetAddress[0]));
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(eq(NETWORK_TEST_RESULT_INVALID), eq(null));
-
- // Change configuration back to working again, but make private DNS not work.
- // Expect validation to fail.
- reset(mCallbacks);
- mFakeDns.setNonBypassPrivateDnsWorking(false);
- wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google", new InetAddress[0]));
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(eq(NETWORK_TEST_RESULT_INVALID), eq(null));
-
- // Make private DNS work again. Expect validation to succeed.
- reset(mCallbacks);
- mFakeDns.setNonBypassPrivateDnsWorking(true);
- wnm.forceReevaluation(Process.myUid());
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(eq(NETWORK_TEST_RESULT_VALID), eq(null));
- }
-
- @Test
- public void testDataStall_StallSuspectedAndSendMetrics() throws IOException {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- makeDnsTimeoutEvent(wrappedMonitor, 5);
- assertTrue(wrappedMonitor.isDataStall());
- verify(mDataStallStatsUtils, times(1)).write(makeEmptyDataStallDetectionStats(), any());
- }
-
- @Test
- public void testDataStall_NoStallSuspectedAndSendMetrics() throws IOException {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- makeDnsTimeoutEvent(wrappedMonitor, 3);
- assertFalse(wrappedMonitor.isDataStall());
- verify(mDataStallStatsUtils, never()).write(makeEmptyDataStallDetectionStats(), any());
- }
-
- @Test
- public void testCollectDataStallMetrics() {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
-
- when(mTelephony.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
- when(mTelephony.getNetworkOperator()).thenReturn(TEST_MCCMNC);
- when(mTelephony.getSimOperator()).thenReturn(TEST_MCCMNC);
-
- DataStallDetectionStats.Builder stats =
- new DataStallDetectionStats.Builder()
- .setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS)
- .setNetworkType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .setCellData(TelephonyManager.NETWORK_TYPE_LTE /* radioType */,
- true /* roaming */,
- TEST_MCCMNC /* networkMccmnc */,
- TEST_MCCMNC /* simMccmnc */,
- CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN /* signalStrength */);
- generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
-
- assertEquals(wrappedMonitor.buildDataStallDetectionStats(
- NetworkCapabilities.TRANSPORT_CELLULAR), stats.build());
-
- when(mWifi.getConnectionInfo()).thenReturn(mWifiInfo);
-
- stats = new DataStallDetectionStats.Builder()
- .setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS)
- .setNetworkType(NetworkCapabilities.TRANSPORT_WIFI)
- .setWiFiData(mWifiInfo);
- generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
-
- assertEquals(
- wrappedMonitor.buildDataStallDetectionStats(NetworkCapabilities.TRANSPORT_WIFI),
- stats.build());
- }
-
- @Test
- public void testIgnoreHttpsProbe() throws Exception {
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 204);
-
- final NetworkMonitor nm = runNetworkTest(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY);
-
- nm.setAcceptPartialConnectivity();
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(eq(NETWORK_TEST_RESULT_VALID), any());
- }
-
- @Test
- public void testIsPartialConnectivity() throws IOException {
- setStatus(mHttpsConnection, 500);
- setStatus(mHttpConnection, 204);
- setStatus(mFallbackConnection, 500);
- runPartialConnectivityNetworkTest();
-
- setStatus(mHttpsConnection, 500);
- setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 204);
- runPartialConnectivityNetworkTest();
- }
-
- private void assertIpAddressArrayEquals(String[] expected, InetAddress[] actual) {
- String[] actualStrings = new String[actual.length];
- for (int i = 0; i < actual.length; i++) {
- actualStrings[i] = actual[i].getHostAddress();
- }
- assertArrayEquals("Array of IP addresses differs", expected, actualStrings);
- }
-
- @Test
- public void testSendDnsProbeWithTimeout() throws Exception {
- WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
- final int shortTimeoutMs = 200;
-
- // Clear the wildcard DNS response created in setUp.
- mFakeDns.setAnswer("*", null);
-
- String[] expected = new String[]{"2001:db8::"};
- mFakeDns.setAnswer("www.google.com", expected);
- InetAddress[] actual = wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
- assertIpAddressArrayEquals(expected, actual);
-
- expected = new String[]{"2001:db8::", "192.0.2.1"};
- mFakeDns.setAnswer("www.googleapis.com", expected);
- actual = wnm.sendDnsProbeWithTimeout("www.googleapis.com", shortTimeoutMs);
- assertIpAddressArrayEquals(expected, actual);
-
- mFakeDns.setAnswer("www.google.com", new String[0]);
- try {
- wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
- fail("No DNS results, expected UnknownHostException");
- } catch (UnknownHostException e) {
- }
-
- mFakeDns.setAnswer("www.google.com", null);
- try {
- wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
- fail("DNS query timed out, expected UnknownHostException");
- } catch (UnknownHostException e) {
- }
- }
-
- private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
- for (int i = 0; i < count; i++) {
- wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
- RETURN_CODE_DNS_TIMEOUT);
- }
- }
-
- private void makeDnsSuccessEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
- for (int i = 0; i < count; i++) {
- wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
- RETURN_CODE_DNS_SUCCESS);
- }
- }
-
- private DataStallDetectionStats makeEmptyDataStallDetectionStats() {
- return new DataStallDetectionStats.Builder().build();
- }
-
- private void setDataStallEvaluationType(int type) {
- when(mDependencies.getDeviceConfigPropertyInt(any(),
- eq(CONFIG_DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type);
- }
-
- private void setMinDataStallEvaluateInterval(int time) {
- when(mDependencies.getDeviceConfigPropertyInt(any(),
- eq(CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time);
- }
-
- private void setValidDataStallDnsTimeThreshold(int time) {
- when(mDependencies.getDeviceConfigPropertyInt(any(),
- eq(CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time);
- }
-
- private void setConsecutiveDnsTimeoutThreshold(int num) {
- when(mDependencies.getDeviceConfigPropertyInt(any(),
- eq(CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt())).thenReturn(num);
- }
-
- private void setFallbackUrl(String url) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL), any())).thenReturn(url);
- }
-
- private void setOtherFallbackUrls(String urls) {
- when(mDependencies.getDeviceConfigProperty(any(),
- eq(CAPTIVE_PORTAL_OTHER_FALLBACK_URLS), any())).thenReturn(urls);
- }
-
- private void setFallbackSpecs(String specs) {
- when(mDependencies.getDeviceConfigProperty(any(),
- eq(CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
- }
-
- private void setCaptivePortalMode(int mode) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt())).thenReturn(mode);
- }
-
- private void runPortalNetworkTest() {
- runNetworkTest(NETWORK_TEST_RESULT_INVALID);
- assertEquals(1, mRegisteredReceivers.size());
- assertNotNull(mNetworkTestedRedirectUrlCaptor.getValue());
- }
-
- private void runNotPortalNetworkTest() {
- runNetworkTest(NETWORK_TEST_RESULT_VALID);
- assertEquals(0, mRegisteredReceivers.size());
- assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
- }
-
- private void runFailedNetworkTest() {
- runNetworkTest(NETWORK_TEST_RESULT_INVALID);
- assertEquals(0, mRegisteredReceivers.size());
- assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
- }
-
- private void runPartialConnectivityNetworkTest() {
- runNetworkTest(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY);
- assertEquals(0, mRegisteredReceivers.size());
- assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
- }
-
- private NetworkMonitor runNetworkTest(int testResult) {
- return runNetworkTest(METERED_CAPABILITIES, testResult);
- }
-
- private NetworkMonitor runNetworkTest(NetworkCapabilities nc, int testResult) {
- final NetworkMonitor monitor = makeMonitor(nc);
- monitor.notifyNetworkConnected(TEST_LINK_PROPERTIES, nc);
- try {
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(eq(testResult), mNetworkTestedRedirectUrlCaptor.capture());
- } catch (RemoteException e) {
- fail("Unexpected exception: " + e);
- }
- waitForIdle(monitor.getHandler());
-
- return monitor;
- }
-
- private void setSslException(HttpURLConnection connection) throws IOException {
- doThrow(new SSLHandshakeException("Invalid cert")).when(connection).getResponseCode();
- }
-
- private void set302(HttpURLConnection connection, String location) throws IOException {
- setStatus(connection, 302);
- doReturn(location).when(connection).getHeaderField(LOCATION_HEADER);
- }
-
- private void setPortal302(HttpURLConnection connection) throws IOException {
- set302(connection, "http://login.example.com");
- }
-
- private void setStatus(HttpURLConnection connection, int status) throws IOException {
- doReturn(status).when(connection).getResponseCode();
- }
-
- private void generateTimeoutDnsEvent(DataStallDetectionStats.Builder stats, int num) {
- for (int i = 0; i < num; i++) {
- stats.addDnsEvent(RETURN_CODE_DNS_TIMEOUT, 123456789 /* timeMs */);
- }
- }
-}
-
diff --git a/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java b/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
deleted file mode 100644
index 87346e5..0000000
--- a/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.android.server.connectivity.ipmemorystore;
-
-import static com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService.InterruptMaintenance;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doReturn;
-
-import android.app.job.JobScheduler;
-import android.content.Context;
-import android.net.ipmemorystore.Blob;
-import android.net.ipmemorystore.IOnBlobRetrievedListener;
-import android.net.ipmemorystore.IOnL2KeyResponseListener;
-import android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener;
-import android.net.ipmemorystore.IOnSameL3NetworkResponseListener;
-import android.net.ipmemorystore.IOnStatusListener;
-import android.net.ipmemorystore.NetworkAttributes;
-import android.net.ipmemorystore.NetworkAttributesParcelable;
-import android.net.ipmemorystore.SameL3NetworkResponse;
-import android.net.ipmemorystore.SameL3NetworkResponseParcelable;
-import android.net.ipmemorystore.Status;
-import android.net.ipmemorystore.StatusParcelable;
-import android.os.ConditionVariable;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.File;
-import java.lang.reflect.Modifier;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-
-/** Unit tests for {@link IpMemoryStoreService}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class IpMemoryStoreServiceTest {
- private static final String TEST_CLIENT_ID = "testClientId";
- private static final String TEST_DATA_NAME = "testData";
-
- private static final int TEST_DATABASE_SIZE_THRESHOLD = 100 * 1024; //100KB
- private static final int DEFAULT_TIMEOUT_MS = 5000;
- private static final int LONG_TIMEOUT_MS = 30000;
- private static final int FAKE_KEY_COUNT = 20;
- private static final String[] FAKE_KEYS;
- static {
- FAKE_KEYS = new String[FAKE_KEY_COUNT];
- for (int i = 0; i < FAKE_KEYS.length; ++i) {
- FAKE_KEYS[i] = "fakeKey" + i;
- }
- }
-
- @Mock
- private Context mMockContext;
- @Mock
- private JobScheduler mMockJobScheduler;
- private File mDbFile;
-
- private IpMemoryStoreService mService;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- final Context context = InstrumentationRegistry.getContext();
- final File dir = context.getFilesDir();
- mDbFile = new File(dir, "test.db");
- doReturn(mDbFile).when(mMockContext).getDatabasePath(anyString());
- doReturn(mMockJobScheduler).when(mMockContext)
- .getSystemService(Context.JOB_SCHEDULER_SERVICE);
- mService = new IpMemoryStoreService(mMockContext) {
- @Override
- protected int getDbSizeThreshold() {
- return TEST_DATABASE_SIZE_THRESHOLD;
- }
-
- @Override
- boolean isDbSizeOverThreshold() {
- // Add a 100ms delay here for pausing maintenance job a while. Interrupted flag can
- // be set at this time.
- waitForMs(100);
- return super.isDbSizeOverThreshold();
- }
- };
- }
-
- @After
- public void tearDown() {
- mService.shutdown();
- mDbFile.delete();
- }
-
- /** Helper method to make a vanilla IOnStatusListener */
- private IOnStatusListener onStatus(Consumer<Status> functor) {
- return new IOnStatusListener() {
- @Override
- public void onComplete(final StatusParcelable statusParcelable) throws RemoteException {
- functor.accept(new Status(statusParcelable));
- }
-
- @Override
- public IBinder asBinder() {
- return null;
- }
-
- @Override
- public int getInterfaceVersion() {
- return this.VERSION;
- }
- };
- }
-
- /** Helper method to make an IOnBlobRetrievedListener */
- private interface OnBlobRetrievedListener {
- void onBlobRetrieved(Status status, String l2Key, String name, byte[] data);
- }
- private IOnBlobRetrievedListener onBlobRetrieved(final OnBlobRetrievedListener functor) {
- return new IOnBlobRetrievedListener() {
- @Override
- public void onBlobRetrieved(final StatusParcelable statusParcelable,
- final String l2Key, final String name, final Blob blob) throws RemoteException {
- functor.onBlobRetrieved(new Status(statusParcelable), l2Key, name,
- null == blob ? null : blob.data);
- }
-
- @Override
- public IBinder asBinder() {
- return null;
- }
-
- @Override
- public int getInterfaceVersion() {
- return this.VERSION;
- }
- };
- }
-
- /** Helper method to make an IOnNetworkAttributesRetrievedListener */
- private interface OnNetworkAttributesRetrievedListener {
- void onNetworkAttributesRetrieved(Status status, String l2Key, NetworkAttributes attr);
- }
- private IOnNetworkAttributesRetrievedListener onNetworkAttributesRetrieved(
- final OnNetworkAttributesRetrievedListener functor) {
- return new IOnNetworkAttributesRetrievedListener() {
- @Override
- public void onNetworkAttributesRetrieved(final StatusParcelable status,
- final String l2Key, final NetworkAttributesParcelable attributes)
- throws RemoteException {
- functor.onNetworkAttributesRetrieved(new Status(status), l2Key,
- null == attributes ? null : new NetworkAttributes(attributes));
- }
-
- @Override
- public IBinder asBinder() {
- return null;
- }
-
- @Override
- public int getInterfaceVersion() {
- return this.VERSION;
- }
- };
- }
-
- /** Helper method to make an IOnSameNetworkResponseListener */
- private interface OnSameL3NetworkResponseListener {
- void onSameL3NetworkResponse(Status status, SameL3NetworkResponse answer);
- }
- private IOnSameL3NetworkResponseListener onSameResponse(
- final OnSameL3NetworkResponseListener functor) {
- return new IOnSameL3NetworkResponseListener() {
- @Override
- public void onSameL3NetworkResponse(final StatusParcelable status,
- final SameL3NetworkResponseParcelable sameL3Network)
- throws RemoteException {
- functor.onSameL3NetworkResponse(new Status(status),
- null == sameL3Network ? null : new SameL3NetworkResponse(sameL3Network));
- }
-
- @Override
- public IBinder asBinder() {
- return null;
- }
-
- @Override
- public int getInterfaceVersion() {
- return this.VERSION;
- }
- };
- }
-
- /** Helper method to make an IOnL2KeyResponseListener */
- private interface OnL2KeyResponseListener {
- void onL2KeyResponse(Status status, String key);
- }
- private IOnL2KeyResponseListener onL2KeyResponse(final OnL2KeyResponseListener functor) {
- return new IOnL2KeyResponseListener() {
- @Override
- public void onL2KeyResponse(final StatusParcelable status, final String key)
- throws RemoteException {
- functor.onL2KeyResponse(new Status(status), key);
- }
-
- @Override
- public IBinder asBinder() {
- return null;
- }
-
- @Override
- public int getInterfaceVersion() {
- return this.VERSION;
- }
- };
- }
-
- // Helper method to factorize some boilerplate
- private void doLatched(final String timeoutMessage, final Consumer<CountDownLatch> functor) {
- doLatched(timeoutMessage, functor, DEFAULT_TIMEOUT_MS);
- }
-
- private void doLatched(final String timeoutMessage, final Consumer<CountDownLatch> functor,
- final int timeout) {
- final CountDownLatch latch = new CountDownLatch(1);
- functor.accept(latch);
- try {
- if (!latch.await(timeout, TimeUnit.MILLISECONDS)) {
- fail(timeoutMessage);
- }
- } catch (InterruptedException e) {
- fail("Thread was interrupted");
- }
- }
-
- // Helper methods to factorize more boilerplate
- private void storeAttributes(final String l2Key, final NetworkAttributes na) {
- storeAttributes("Did not complete storing attributes", l2Key, na);
- }
- private void storeAttributes(final String timeoutMessage, final String l2Key,
- final NetworkAttributes na) {
- doLatched(timeoutMessage, latch -> mService.storeNetworkAttributes(l2Key, na.toParcelable(),
- onStatus(status -> {
- assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
- latch.countDown();
- })));
- }
-
- /** Insert large data that db size will be over threshold for maintenance test usage. */
- private void insertFakeDataAndOverThreshold() {
- try {
- final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
- na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
- na.setGroupHint("hint1");
- na.setMtu(219);
- na.setDnsAddresses(Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")));
- final byte[] data = new byte[]{-3, 6, 8, -9, 12, -128, 0, 89, 112, 91, -34};
- final long time = System.currentTimeMillis() - 1;
- for (int i = 0; i < 1000; i++) {
- int errorCode = IpMemoryStoreDatabase.storeNetworkAttributes(
- mService.mDb,
- "fakeKey" + i,
- // Let first 100 records get expiry.
- i < 100 ? time : time + TimeUnit.HOURS.toMillis(i),
- na.build());
- assertEquals(errorCode, Status.SUCCESS);
-
- errorCode = IpMemoryStoreDatabase.storeBlob(
- mService.mDb, "fakeKey" + i, TEST_CLIENT_ID, TEST_DATA_NAME, data);
- assertEquals(errorCode, Status.SUCCESS);
- }
-
- // After added 5000 records, db size is larger than fake threshold(100KB).
- assertTrue(mService.isDbSizeOverThreshold());
- } catch (final UnknownHostException e) {
- fail("Insert fake data fail");
- }
- }
-
- /** Wait for assigned time. */
- private void waitForMs(long ms) {
- try {
- Thread.sleep(ms);
- } catch (final InterruptedException e) {
- fail("Thread was interrupted");
- }
- }
-
- @Test
- public void testNetworkAttributes() throws UnknownHostException {
- final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
- na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
- na.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
- na.setGroupHint("hint1");
- na.setMtu(219);
- final String l2Key = FAKE_KEYS[0];
- NetworkAttributes attributes = na.build();
- storeAttributes(l2Key, attributes);
-
- doLatched("Did not complete retrieving attributes", latch ->
- mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
- (status, key, attr) -> {
- assertTrue("Retrieve network attributes not successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(attributes, attr);
- latch.countDown();
- })));
-
- final NetworkAttributes.Builder na2 = new NetworkAttributes.Builder();
- na.setDnsAddresses(Arrays.asList(
- new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
- final NetworkAttributes attributes2 = na2.build();
- storeAttributes("Did not complete storing attributes 2", l2Key, attributes2);
-
- doLatched("Did not complete retrieving attributes 2", latch ->
- mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
- (status, key, attr) -> {
- assertTrue("Retrieve network attributes not successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(attributes.assignedV4Address, attr.assignedV4Address);
- assertEquals(attributes.assignedV4AddressExpiry,
- attr.assignedV4AddressExpiry);
- assertEquals(attributes.groupHint, attr.groupHint);
- assertEquals(attributes.mtu, attr.mtu);
- assertEquals(attributes2.dnsAddresses, attr.dnsAddresses);
- latch.countDown();
- })));
-
- doLatched("Did not complete retrieving attributes 3", latch ->
- mService.retrieveNetworkAttributes(l2Key + "nonexistent",
- onNetworkAttributesRetrieved(
- (status, key, attr) -> {
- assertTrue("Retrieve network attributes not successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(l2Key + "nonexistent", key);
- assertNull("Retrieved data not stored", attr);
- latch.countDown();
- }
- )));
-
- // Verify that this test does not miss any new field added later.
- // If any field is added to NetworkAttributes it must be tested here for storing
- // and retrieving.
- assertEquals(5, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
- .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
- }
-
- @Test
- public void testInvalidAttributes() {
- doLatched("Did not complete storing bad attributes", latch ->
- mService.storeNetworkAttributes("key", null, onStatus(status -> {
- assertFalse("Success storing on a null key",
- status.isSuccess());
- assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
- latch.countDown();
- })));
-
- final NetworkAttributes na = new NetworkAttributes.Builder().setMtu(2).build();
- doLatched("Did not complete storing bad attributes", latch ->
- mService.storeNetworkAttributes(null, na.toParcelable(), onStatus(status -> {
- assertFalse("Success storing null attributes on a null key",
- status.isSuccess());
- assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
- latch.countDown();
- })));
-
- doLatched("Did not complete storing bad attributes", latch ->
- mService.storeNetworkAttributes(null, null, onStatus(status -> {
- assertFalse("Success storing null attributes on a null key",
- status.isSuccess());
- assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
- latch.countDown();
- })));
-
- doLatched("Did not complete retrieving bad attributes", latch ->
- mService.retrieveNetworkAttributes(null, onNetworkAttributesRetrieved(
- (status, key, attr) -> {
- assertFalse("Success retrieving attributes for a null key",
- status.isSuccess());
- assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
- assertNull(key);
- assertNull(attr);
- latch.countDown();
- })));
- }
-
- @Test
- public void testPrivateData() {
- final Blob b = new Blob();
- b.data = new byte[] { -3, 6, 8, -9, 12, -128, 0, 89, 112, 91, -34 };
- final String l2Key = FAKE_KEYS[0];
- doLatched("Did not complete storing private data", latch ->
- mService.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
- onStatus(status -> {
- assertTrue("Store status not successful : " + status.resultCode,
- status.isSuccess());
- latch.countDown();
- })));
-
- doLatched("Did not complete retrieving private data", latch ->
- mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, onBlobRetrieved(
- (status, key, name, data) -> {
- assertTrue("Retrieve blob status not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(name, TEST_DATA_NAME);
- assertTrue(Arrays.equals(b.data, data));
- latch.countDown();
- })));
-
- // Most puzzling error message ever
- doLatched("Did not complete retrieving nothing", latch ->
- mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME + "2", onBlobRetrieved(
- (status, key, name, data) -> {
- assertTrue("Retrieve blob status not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(name, TEST_DATA_NAME + "2");
- assertNull(data);
- latch.countDown();
- })));
- }
-
- @Test
- public void testFindL2Key() throws UnknownHostException {
- final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
- na.setGroupHint("hint0");
- storeAttributes(FAKE_KEYS[0], na.build());
-
- na.setDnsAddresses(Arrays.asList(
- new InetAddress[] {Inet6Address.getByName("8D56:9AF1::08EE:20F1")}));
- na.setMtu(219);
- storeAttributes(FAKE_KEYS[1], na.build());
- na.setMtu(null);
- na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
- na.setDnsAddresses(Arrays.asList(
- new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
- na.setGroupHint("hint1");
- storeAttributes(FAKE_KEYS[2], na.build());
- na.setMtu(219);
- storeAttributes(FAKE_KEYS[3], na.build());
- na.setMtu(240);
- storeAttributes(FAKE_KEYS[4], na.build());
- na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("5.6.7.8"));
- storeAttributes(FAKE_KEYS[5], na.build());
-
- // Matches key 5 exactly
- doLatched("Did not finish finding L2Key", latch ->
- mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
- assertTrue("Retrieve network sameness not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(FAKE_KEYS[5], key);
- latch.countDown();
- })));
-
- // MTU matches key 4 but v4 address matches key 5. The latter is stronger.
- na.setMtu(240);
- doLatched("Did not finish finding L2Key", latch ->
- mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
- assertTrue("Retrieve network sameness not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(FAKE_KEYS[5], key);
- latch.countDown();
- })));
-
- // Closest to key 3 (indeed, identical)
- na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
- na.setMtu(219);
- doLatched("Did not finish finding L2Key", latch ->
- mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
- assertTrue("Retrieve network sameness not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(FAKE_KEYS[3], key);
- latch.countDown();
- })));
-
- // Group hint alone must not be strong enough to override the rest
- na.setGroupHint("hint0");
- doLatched("Did not finish finding L2Key", latch ->
- mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
- assertTrue("Retrieve network sameness not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(FAKE_KEYS[3], key);
- latch.countDown();
- })));
-
- // Still closest to key 3, though confidence is lower
- na.setGroupHint("hint1");
- na.setDnsAddresses(null);
- doLatched("Did not finish finding L2Key", latch ->
- mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
- assertTrue("Retrieve network sameness not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(FAKE_KEYS[3], key);
- latch.countDown();
- })));
-
- // But changing the MTU makes this closer to key 4
- na.setMtu(240);
- doLatched("Did not finish finding L2Key", latch ->
- mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
- assertTrue("Retrieve network sameness not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(FAKE_KEYS[4], key);
- latch.countDown();
- })));
-
- // MTU alone not strong enough to make this group-close
- na.setGroupHint(null);
- na.setDnsAddresses(null);
- na.setAssignedV4Address(null);
- doLatched("Did not finish finding L2Key", latch ->
- mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
- assertTrue("Retrieve network sameness not successful : " + status.resultCode,
- status.isSuccess());
- assertNull(key);
- latch.countDown();
- })));
- }
-
- private void assertNetworksSameness(final String key1, final String key2, final int sameness) {
- doLatched("Did not finish evaluating sameness", latch ->
- mService.isSameNetwork(key1, key2, onSameResponse((status, answer) -> {
- assertTrue("Retrieve network sameness not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(sameness, answer.getNetworkSameness());
- latch.countDown();
- })));
- }
-
- @Test
- public void testIsSameNetwork() throws UnknownHostException {
- final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
- na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
- na.setGroupHint("hint1");
- na.setMtu(219);
- na.setDnsAddresses(Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")));
-
- storeAttributes(FAKE_KEYS[0], na.build());
- // 0 and 1 have identical attributes
- storeAttributes(FAKE_KEYS[1], na.build());
-
- // Hopefully only the MTU being different still means it's the same network
- na.setMtu(200);
- storeAttributes(FAKE_KEYS[2], na.build());
-
- // Hopefully different MTU, assigned V4 address and grouphint make a different network,
- // even with identical DNS addresses
- na.setAssignedV4Address(null);
- na.setGroupHint("hint2");
- storeAttributes(FAKE_KEYS[3], na.build());
-
- assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[1], SameL3NetworkResponse.NETWORK_SAME);
- assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[2], SameL3NetworkResponse.NETWORK_SAME);
- assertNetworksSameness(FAKE_KEYS[1], FAKE_KEYS[2], SameL3NetworkResponse.NETWORK_SAME);
- assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[3], SameL3NetworkResponse.NETWORK_DIFFERENT);
- assertNetworksSameness(FAKE_KEYS[0], "neverInsertedKey",
- SameL3NetworkResponse.NETWORK_NEVER_CONNECTED);
-
- doLatched("Did not finish evaluating sameness", latch ->
- mService.isSameNetwork(null, null, onSameResponse((status, answer) -> {
- assertFalse("Retrieve network sameness suspiciously successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
- assertNull(answer);
- latch.countDown();
- })));
- }
-
-
- @Test
- public void testFullMaintenance() {
- insertFakeDataAndOverThreshold();
-
- final InterruptMaintenance im = new InterruptMaintenance(0/* Fake JobId */);
- // Do full maintenance and then db size should go down and meet the threshold.
- doLatched("Maintenance unexpectedly completed successfully", latch ->
- mService.fullMaintenance(onStatus((status) -> {
- assertTrue("Execute full maintenance failed: "
- + status.resultCode, status.isSuccess());
- latch.countDown();
- }), im), LONG_TIMEOUT_MS);
-
- // Assume that maintenance is successful, db size shall meet the threshold.
- assertFalse(mService.isDbSizeOverThreshold());
- }
-
- @Test
- public void testInterruptMaintenance() {
- insertFakeDataAndOverThreshold();
-
- final InterruptMaintenance im = new InterruptMaintenance(0/* Fake JobId */);
-
- // Test interruption immediately.
- im.setInterrupted(true);
- // Do full maintenance and the expectation is not completed by interruption.
- doLatched("Maintenance unexpectedly completed successfully", latch ->
- mService.fullMaintenance(onStatus((status) -> {
- assertFalse(status.isSuccess());
- latch.countDown();
- }), im), LONG_TIMEOUT_MS);
-
- // Assume that no data are removed, db size shall be over the threshold.
- assertTrue(mService.isDbSizeOverThreshold());
-
- // Reset the flag and test interruption during maintenance.
- im.setInterrupted(false);
-
- final ConditionVariable latch = new ConditionVariable();
- // Do full maintenance and the expectation is not completed by interruption.
- mService.fullMaintenance(onStatus((status) -> {
- assertFalse(status.isSuccess());
- latch.open();
- }), im);
-
- // Give a little bit of time for maintenance to start up for realism
- waitForMs(50);
- // Interrupt maintenance job.
- im.setInterrupted(true);
-
- if (!latch.block(LONG_TIMEOUT_MS)) {
- fail("Maintenance unexpectedly completed successfully");
- }
-
- // Assume that only do dropAllExpiredRecords method in previous maintenance, db size shall
- // still be over the threshold.
- assertTrue(mService.isDbSizeOverThreshold());
- }
-}
diff --git a/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java b/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
deleted file mode 100644
index 3d3aabc..0000000
--- a/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.android.server.connectivity.ipmemorystore;
-
-import static com.android.server.connectivity.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Unit tests for {@link RelevanceUtils}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RelevanceUtilsTests {
- @Test
- public void testComputeRelevanceForTargetDate() {
- final long dayInMillis = 24L * 60 * 60 * 1000;
- final long base = 1_000_000L; // any given point in time
- // Relevance when the network expires in 1000 years must be capped
- assertEquals(CAPPED_RELEVANCE, RelevanceUtils.computeRelevanceForTargetDate(
- base + 1000L * dayInMillis, base));
- // Relevance when expiry is before the date must be 0
- assertEquals(0, RelevanceUtils.computeRelevanceForTargetDate(base - 1, base));
- // Make sure the relevance for a given target date is higher if the expiry is further
- // in the future
- assertTrue(RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base)
- < RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base));
-
- // Make sure the relevance falls slower as the expiry is closing in. This is to ensure
- // the decay is indeed logarithmic.
- final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(base, base);
- final int relevance50DaysBeforeExpiry =
- RelevanceUtils.computeRelevanceForTargetDate(base + 50 * dayInMillis, base);
- final int relevance100DaysBeforeExpiry =
- RelevanceUtils.computeRelevanceForTargetDate(base + 100 * dayInMillis, base);
- final int relevance150DaysBeforeExpiry =
- RelevanceUtils.computeRelevanceForTargetDate(base + 150 * dayInMillis, base);
- assertEquals(0, relevanceAtExpiry);
- assertTrue(relevance50DaysBeforeExpiry - relevanceAtExpiry
- < relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry);
- assertTrue(relevance100DaysBeforeExpiry - relevance50DaysBeforeExpiry
- < relevance150DaysBeforeExpiry - relevance100DaysBeforeExpiry);
- }
-
- @Test
- public void testIncreaseRelevance() {
- long expiry = System.currentTimeMillis();
-
- final long firstBump = RelevanceUtils.bumpExpiryDate(expiry);
- // Though a few milliseconds might have elapsed, the first bump should push the duration
- // to days in the future, so unless this test takes literal days between these two lines,
- // this should always pass.
- assertTrue(firstBump > expiry);
-
- expiry = 0;
- long lastDifference = Long.MAX_VALUE;
- // The relevance should be capped in at most this many steps. Otherwise, fail.
- final int steps = 1000;
- for (int i = 0; i < steps; ++i) {
- final long newExpiry = RelevanceUtils.bumpExpiryDuration(expiry);
- if (newExpiry == expiry) {
- // The relevance should be capped. Make sure it is, then exit without failure.
- assertEquals(newExpiry, RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
- return;
- }
- // Make sure the new expiry is further in the future than last time.
- assertTrue(newExpiry > expiry);
- // Also check that it was not bumped as much as the last bump, because the
- // decay must be exponential.
- assertTrue(newExpiry - expiry < lastDifference);
- lastDifference = newExpiry - expiry;
- expiry = newExpiry;
- }
- fail("Relevance failed to go to the maximum value after " + steps + " bumps");
- }
-
- @Test
- public void testContinuity() {
- final long expiry = System.currentTimeMillis();
-
- // Relevance at expiry and after expiry should be the cap.
- final int relevanceBeforeMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
- expiry - (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1_000_000));
- assertEquals(relevanceBeforeMaxLifetime, CAPPED_RELEVANCE);
- final int relevanceForMaxLifetime = RelevanceUtils.computeRelevanceForTargetDate(expiry,
- expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS);
- assertEquals(relevanceForMaxLifetime, CAPPED_RELEVANCE);
-
- // If the max relevance is reached at the cap lifetime, one millisecond less than this
- // should be very close. Strictly speaking this is a bit brittle, but it should be
- // good enough for the purposes of the memory store.
- final int relevanceForOneMillisecLessThanCap = RelevanceUtils.computeRelevanceForTargetDate(
- expiry, expiry - RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS + 1);
- assertTrue(relevanceForOneMillisecLessThanCap <= CAPPED_RELEVANCE);
- assertTrue(relevanceForOneMillisecLessThanCap >= CAPPED_RELEVANCE - 10);
-
- // Likewise the relevance one millisecond before expiry should be very close to 0. It's
- // fine if it rounds down to 0.
- final int relevanceOneMillisecBeforeExpiry = RelevanceUtils.computeRelevanceForTargetDate(
- expiry, expiry - 1);
- assertTrue(relevanceOneMillisecBeforeExpiry <= 10);
- assertTrue(relevanceOneMillisecBeforeExpiry >= 0);
-
- final int relevanceAtExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry, expiry);
- assertEquals(relevanceAtExpiry, 0);
- final int relevanceAfterExpiry = RelevanceUtils.computeRelevanceForTargetDate(expiry,
- expiry + 1_000_000);
- assertEquals(relevanceAfterExpiry, 0);
- }
-
- // testIncreaseRelevance makes sure bumping the expiry continuously always yields a
- // monotonically increasing date as a side effect, but this tests that the relevance (as
- // opposed to the expiry date) increases monotonically with increasing periods.
- @Test
- public void testMonotonicity() {
- // Hopefully the relevance is granular enough to give a different value for every one
- // of this number of steps.
- final int steps = 40;
- final long expiry = System.currentTimeMillis();
-
- int lastRelevance = -1;
- for (int i = 0; i < steps; ++i) {
- final long date = expiry - i * (RelevanceUtils.CAPPED_RELEVANCE_LIFETIME_MS / steps);
- final int relevance = RelevanceUtils.computeRelevanceForTargetDate(expiry, date);
- assertTrue(relevance > lastRelevance);
- lastRelevance = relevance;
- }
- }
-}
diff --git a/tests/src/com/android/server/util/SharedLogTest.java b/tests/src/com/android/server/util/SharedLogTest.java
deleted file mode 100644
index b1db051..0000000
--- a/tests/src/com/android/server/util/SharedLogTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2017 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 com.android.server.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.net.util.SharedLog;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintWriter;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class SharedLogTest {
- private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}";
- private static final String TIMESTAMP = "HH:MM:SS";
-
- @Test
- public void testBasicOperation() {
- final SharedLog logTop = new SharedLog("top");
- logTop.mark("first post!");
-
- final SharedLog logLevel2a = logTop.forSubComponent("twoA");
- final SharedLog logLevel2b = logTop.forSubComponent("twoB");
- logLevel2b.e("2b or not 2b");
- logLevel2b.e("No exception", null);
- logLevel2b.e("Wait, here's one", new Exception("Test"));
- logLevel2a.w("second post?");
-
- final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
- logTop.log("still logging");
- logLevel3.log("3 >> 2");
- logLevel2a.mark("ok: last post");
-
- final String[] expected = {
- " - MARK first post!",
- " - [twoB] ERROR 2b or not 2b",
- " - [twoB] ERROR No exception",
- // No stacktrace in shared log, only in logcat
- " - [twoB] ERROR Wait, here's one: Test",
- " - [twoA] WARN second post?",
- " - still logging",
- " - [twoA.three] 3 >> 2",
- " - [twoA] MARK ok: last post",
- };
- // Verify the logs are all there and in the correct order.
- verifyLogLines(expected, logTop);
-
- // In fact, because they all share the same underlying LocalLog,
- // every subcomponent SharedLog's dump() is identical.
- verifyLogLines(expected, logLevel2a);
- verifyLogLines(expected, logLevel2b);
- verifyLogLines(expected, logLevel3);
- }
-
- private static void verifyLogLines(String[] expected, SharedLog log) {
- final ByteArrayOutputStream ostream = new ByteArrayOutputStream();
- final PrintWriter pw = new PrintWriter(ostream, true);
- log.dump(null, pw, null);
-
- final String dumpOutput = ostream.toString();
- assertTrue(dumpOutput != null);
- assertTrue(!"".equals(dumpOutput));
-
- final String[] lines = dumpOutput.split("\n");
- assertEquals(expected.length, lines.length);
-
- for (int i = 0; i < expected.length; i++) {
- String got = lines[i];
- String want = expected[i];
- assertTrue(String.format("'%s' did not contain '%s'", got, want), got.endsWith(want));
- assertTrue(String.format("'%s' did not contain a %s timestamp", got, TIMESTAMP),
- got.replaceFirst(TIMESTAMP_PATTERN, TIMESTAMP).contains(TIMESTAMP));
- }
- }
-}