Better IPv4 multicast coverage in ApfTest
This patch improves the test coverage of ApfFilter for IPv4 broadcast and multicast traffic. Bug: 30231088 Change-Id: I2e1d5d5a7cbae17f3d5978a4cf5f10666b5c6104
This commit is contained in:
@@ -171,8 +171,8 @@ public class ApfFilter {
|
|||||||
private static final int ETH_HEADER_LEN = 14;
|
private static final int ETH_HEADER_LEN = 14;
|
||||||
private static final int ETH_DEST_ADDR_OFFSET = 0;
|
private static final int ETH_DEST_ADDR_OFFSET = 0;
|
||||||
private static final int ETH_ETHERTYPE_OFFSET = 12;
|
private static final int ETH_ETHERTYPE_OFFSET = 12;
|
||||||
private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
|
private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
|
||||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
|
{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
|
||||||
// TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
|
// TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
|
||||||
private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
|
private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
|
||||||
// Endianness is not an issue for this constant because the APF interpreter always operates in
|
// Endianness is not an issue for this constant because the APF interpreter always operates in
|
||||||
@@ -188,7 +188,7 @@ public class ApfFilter {
|
|||||||
private static final int IPV6_HEADER_LEN = 40;
|
private static final int IPV6_HEADER_LEN = 40;
|
||||||
// The IPv6 all nodes address ff02::1
|
// The IPv6 all nodes address ff02::1
|
||||||
private static final byte[] IPV6_ALL_NODES_ADDRESS =
|
private static final byte[] IPV6_ALL_NODES_ADDRESS =
|
||||||
new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||||
|
|
||||||
private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
|
private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
|
||||||
private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
|
private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
|
||||||
@@ -206,7 +206,7 @@ public class ApfFilter {
|
|||||||
private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
|
private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
|
||||||
private static final short ARP_OPCODE_REQUEST = 1;
|
private static final short ARP_OPCODE_REQUEST = 1;
|
||||||
private static final short ARP_OPCODE_REPLY = 2;
|
private static final short ARP_OPCODE_REPLY = 2;
|
||||||
private static final byte[] ARP_IPV4_HEADER = new byte[]{
|
private static final byte[] ARP_IPV4_HEADER = {
|
||||||
0, 1, // Hardware type: Ethernet (1)
|
0, 1, // Hardware type: Ethernet (1)
|
||||||
8, 0, // Protocol type: IP (0x0800)
|
8, 0, // Protocol type: IP (0x0800)
|
||||||
6, // Hardware size: 6
|
6, // Hardware size: 6
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ import libcore.io.Streams;
|
|||||||
* Tests for APF program generator and interpreter.
|
* Tests for APF program generator and interpreter.
|
||||||
*
|
*
|
||||||
* Build, install and run with:
|
* Build, install and run with:
|
||||||
* runtest frameworks-services -c com.android.server.ApfTest
|
* runtest frameworks-services -c android.net.apf.ApfTest
|
||||||
*/
|
*/
|
||||||
public class ApfTest extends AndroidTestCase {
|
public class ApfTest extends AndroidTestCase {
|
||||||
private static final int TIMEOUT_MS = 500;
|
private static final int TIMEOUT_MS = 500;
|
||||||
@@ -86,21 +86,45 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
private final static boolean DROP_MULTICAST = true;
|
private final static boolean DROP_MULTICAST = true;
|
||||||
private final static boolean ALLOW_MULTICAST = false;
|
private final static boolean ALLOW_MULTICAST = false;
|
||||||
|
|
||||||
|
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) {
|
private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
|
||||||
assertEquals(expected, apfSimulate(program, packet, filterAge));
|
assertReturnCodesEqual(expected, apfSimulate(program, packet, filterAge));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertVerdict(int expected, byte[] program, byte[] packet) {
|
||||||
|
assertReturnCodesEqual(expected, apfSimulate(program, packet, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertPass(byte[] program, byte[] packet, int filterAge) {
|
private void assertPass(byte[] program, byte[] packet, int filterAge) {
|
||||||
assertVerdict(PASS, program, packet, 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) {
|
private void assertDrop(byte[] program, byte[] packet, int filterAge) {
|
||||||
assertVerdict(DROP, program, packet, filterAge);
|
assertVerdict(DROP, program, packet, filterAge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertDrop(byte[] program, byte[] packet) {
|
||||||
|
assertVerdict(DROP, program, packet);
|
||||||
|
}
|
||||||
|
|
||||||
private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
|
private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
|
||||||
throws IllegalInstructionException {
|
throws IllegalInstructionException {
|
||||||
assertEquals(expected, apfSimulate(gen.generate(), packet, filterAge));
|
assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, filterAge));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
|
private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
|
||||||
@@ -516,7 +540,7 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
gen = new ApfGenerator();
|
gen = new ApfGenerator();
|
||||||
gen.addLoadImmediate(Register.R0, 1);
|
gen.addLoadImmediate(Register.R0, 1);
|
||||||
gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
|
gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
|
||||||
byte[] packet123 = new byte[]{0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||||
assertPass(gen, packet123, 0);
|
assertPass(gen, packet123, 0);
|
||||||
gen = new ApfGenerator();
|
gen = new ApfGenerator();
|
||||||
gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
|
gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
|
||||||
@@ -524,7 +548,7 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
gen = new ApfGenerator();
|
gen = new ApfGenerator();
|
||||||
gen.addLoadImmediate(Register.R0, 1);
|
gen.addLoadImmediate(Register.R0, 1);
|
||||||
gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
|
gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
|
||||||
byte[] packet12345 = new byte[]{0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
|
byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
|
||||||
assertDrop(gen, packet12345, 0);
|
assertDrop(gen, packet12345, 0);
|
||||||
gen = new ApfGenerator();
|
gen = new ApfGenerator();
|
||||||
gen.addLoadImmediate(Register.R0, 1);
|
gen.addLoadImmediate(Register.R0, 1);
|
||||||
@@ -575,7 +599,7 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class TestApfFilter extends ApfFilter {
|
private static class TestApfFilter extends ApfFilter {
|
||||||
public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6};
|
public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
|
||||||
private FileDescriptor mWriteSocket;
|
private FileDescriptor mWriteSocket;
|
||||||
|
|
||||||
public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
|
public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
|
||||||
@@ -620,19 +644,21 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
private static final int ETH_HEADER_LEN = 14;
|
private static final int ETH_HEADER_LEN = 14;
|
||||||
private static final int ETH_DEST_ADDR_OFFSET = 0;
|
private static final int ETH_DEST_ADDR_OFFSET = 0;
|
||||||
private static final int ETH_ETHERTYPE_OFFSET = 12;
|
private static final int ETH_ETHERTYPE_OFFSET = 12;
|
||||||
private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{
|
private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
|
||||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
|
{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
|
||||||
|
|
||||||
private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
|
private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
|
||||||
private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
|
private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
|
||||||
private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
|
private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
|
||||||
|
private static final byte[] IPV4_BROADCAST_ADDRESS =
|
||||||
|
{(byte) 255, (byte) 255, (byte) 255, (byte) 255};
|
||||||
|
|
||||||
private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
|
private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
|
||||||
private static final int IPV6_HEADER_LEN = 40;
|
private static final int IPV6_HEADER_LEN = 40;
|
||||||
private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
|
private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
|
||||||
// The IPv6 all nodes address ff02::1
|
// The IPv6 all nodes address ff02::1
|
||||||
private static final byte[] IPV6_ALL_NODES_ADDRESS =
|
private static final byte[] IPV6_ALL_NODES_ADDRESS =
|
||||||
new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
|
||||||
|
|
||||||
private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
|
private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
|
||||||
private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
|
private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
|
||||||
@@ -670,14 +696,14 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48;
|
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 int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
|
||||||
private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{
|
private static final byte[] ARP_IPV4_REQUEST_HEADER = {
|
||||||
0, 1, // Hardware type: Ethernet (1)
|
0, 1, // Hardware type: Ethernet (1)
|
||||||
8, 0, // Protocol type: IP (0x0800)
|
8, 0, // Protocol type: IP (0x0800)
|
||||||
6, // Hardware size: 6
|
6, // Hardware size: 6
|
||||||
4, // Protocol size: 4
|
4, // Protocol size: 4
|
||||||
0, 1 // Opcode: request (1)
|
0, 1 // Opcode: request (1)
|
||||||
};
|
};
|
||||||
private static final byte[] ARP_IPV4_REPLY_HEADER = new byte[]{
|
private static final byte[] ARP_IPV4_REPLY_HEADER = {
|
||||||
0, 1, // Hardware type: Ethernet (1)
|
0, 1, // Hardware type: Ethernet (1)
|
||||||
8, 0, // Protocol type: IP (0x0800)
|
8, 0, // Protocol type: IP (0x0800)
|
||||||
6, // Hardware size: 6
|
6, // Hardware size: 6
|
||||||
@@ -686,9 +712,11 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
};
|
};
|
||||||
private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
|
private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
|
||||||
|
|
||||||
private static final byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1};
|
private static final byte[] MOCK_IPV4_ADDR = {10, 0, 0, 1};
|
||||||
private static final byte[] ANOTHER_IPV4_ADDR = new byte[]{10, 0, 0, 2};
|
private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, (byte) 255, (byte) 255};
|
||||||
private static final byte[] IPV4_ANY_HOST_ADDR = new byte[]{0, 0, 0, 0};
|
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_ANY_HOST_ADDR = {0, 0, 0, 0};
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
public void testApfFilterIPv4() throws Exception {
|
public void testApfFilterIPv4() throws Exception {
|
||||||
@@ -698,26 +726,43 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
|
|
||||||
// Verify empty packet of 100 zero bytes is passed
|
// Verify empty packet of 100 zero bytes is passed
|
||||||
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
|
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
|
||||||
assertPass(program, packet.array(), 0);
|
assertPass(program, packet.array());
|
||||||
|
|
||||||
// Verify unicast IPv4 packet is passed
|
// 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);
|
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
|
||||||
assertPass(program, packet.array(), 0);
|
put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR);
|
||||||
|
assertPass(program, packet.array());
|
||||||
|
|
||||||
// Verify broadcast IPv4, not DHCP to us, is dropped
|
// Verify L2 unicast to IPv4 broadcast addresses is passed (b/30231088)
|
||||||
packet.put(ETH_BROADCAST_MAC_ADDRESS);
|
put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
|
||||||
assertDrop(program, packet.array(), 0);
|
assertPass(program, packet.array());
|
||||||
|
put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
|
||||||
|
assertPass(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);
|
packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45);
|
||||||
assertDrop(program, packet.array(), 0);
|
assertDrop(program, packet.array());
|
||||||
packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
|
packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP);
|
||||||
assertDrop(program, packet.array(), 0);
|
assertDrop(program, packet.array());
|
||||||
packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
|
packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT);
|
||||||
assertDrop(program, packet.array(), 0);
|
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
|
// Verify broadcast IPv4 DHCP to us is passed
|
||||||
packet.position(DHCP_CLIENT_MAC_OFFSET);
|
put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
|
||||||
packet.put(TestApfFilter.MOCK_MAC_ADDR);
|
assertPass(program, packet.array());
|
||||||
assertPass(program, packet.array(), 0);
|
|
||||||
|
// Verify unicast IPv4 DHCP to us is passed
|
||||||
|
put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR);
|
||||||
|
assertPass(program, packet.array());
|
||||||
|
|
||||||
apfFilter.shutdown();
|
apfFilter.shutdown();
|
||||||
}
|
}
|
||||||
@@ -731,20 +776,19 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
// Verify empty IPv6 packet is passed
|
// Verify empty IPv6 packet is passed
|
||||||
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
|
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
|
||||||
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
|
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
|
||||||
assertPass(program, packet.array(), 0);
|
assertPass(program, packet.array());
|
||||||
|
|
||||||
// Verify empty ICMPv6 packet is passed
|
// Verify empty ICMPv6 packet is passed
|
||||||
packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
|
packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
|
||||||
assertPass(program, packet.array(), 0);
|
assertPass(program, packet.array());
|
||||||
|
|
||||||
// Verify empty ICMPv6 NA packet is passed
|
// Verify empty ICMPv6 NA packet is passed
|
||||||
packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
|
packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT);
|
||||||
assertPass(program, packet.array(), 0);
|
assertPass(program, packet.array());
|
||||||
|
|
||||||
// Verify ICMPv6 NA to ff02::1 is dropped
|
// Verify ICMPv6 NA to ff02::1 is dropped
|
||||||
packet.position(IPV6_DEST_ADDR_OFFSET);
|
put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS);
|
||||||
packet.put(IPV6_ALL_NODES_ADDRESS);
|
assertDrop(program, packet.array());
|
||||||
assertDrop(program, packet.array(), 0);
|
|
||||||
|
|
||||||
apfFilter.shutdown();
|
apfFilter.shutdown();
|
||||||
}
|
}
|
||||||
@@ -755,58 +799,78 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
|
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
|
||||||
byte[] program = ipManagerCallback.getApfProgram();
|
byte[] program = ipManagerCallback.getApfProgram();
|
||||||
|
|
||||||
|
final byte[] unicastIpv4Addr = {(byte)192,0,2,63};
|
||||||
|
final byte[] broadcastIpv4Addr = {(byte)192,0,(byte)255,(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};
|
||||||
|
|
||||||
// Construct IPv4 and IPv6 multicast packets.
|
// Construct IPv4 and IPv6 multicast packets.
|
||||||
ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
|
ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
|
||||||
mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
|
mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
|
||||||
mcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
|
put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
|
||||||
mcastv4packet.put(new byte[]{(byte)224,0,0,1});
|
|
||||||
|
|
||||||
ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
|
ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]);
|
||||||
mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
|
mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
|
||||||
mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
|
mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP);
|
||||||
mcastv6packet.position(IPV6_DEST_ADDR_OFFSET);
|
put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
|
||||||
mcastv6packet.put(new byte[]{(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb});
|
|
||||||
|
|
||||||
// Construct IPv4 broadcast packet.
|
// Construct IPv4 broadcast packet.
|
||||||
ByteBuffer bcastv4packet = ByteBuffer.wrap(new byte[100]);
|
ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]);
|
||||||
bcastv4packet.put(ETH_BROADCAST_MAC_ADDRESS);
|
bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS);
|
||||||
bcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
|
bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
|
||||||
bcastv4packet.position(IPV4_DEST_ADDR_OFFSET);
|
put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr);
|
||||||
bcastv4packet.put(new byte[]{(byte)192,(byte)0,(byte)2,(byte)63});
|
|
||||||
|
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
|
// Verify initially disabled multicast filter is off
|
||||||
assertPass(program, bcastv4packet.array(), 0);
|
assertPass(program, mcastv4packet.array());
|
||||||
assertPass(program, mcastv4packet.array(), 0);
|
assertPass(program, mcastv6packet.array());
|
||||||
assertPass(program, mcastv6packet.array(), 0);
|
assertPass(program, bcastv4packet1.array());
|
||||||
|
assertPass(program, bcastv4packet2.array());
|
||||||
|
assertPass(program, bcastv4unicastl2packet.array());
|
||||||
|
|
||||||
// Turn on multicast filter and verify it works
|
// Turn on multicast filter and verify it works
|
||||||
ipManagerCallback.resetApfProgramWait();
|
ipManagerCallback.resetApfProgramWait();
|
||||||
apfFilter.setMulticastFilter(true);
|
apfFilter.setMulticastFilter(true);
|
||||||
program = ipManagerCallback.getApfProgram();
|
program = ipManagerCallback.getApfProgram();
|
||||||
assertDrop(program, bcastv4packet.array(), 0);
|
assertDrop(program, mcastv4packet.array());
|
||||||
assertDrop(program, mcastv4packet.array(), 0);
|
assertDrop(program, mcastv6packet.array());
|
||||||
assertDrop(program, mcastv6packet.array(), 0);
|
assertDrop(program, bcastv4packet1.array());
|
||||||
|
assertDrop(program, bcastv4packet2.array());
|
||||||
|
assertPass(program, bcastv4unicastl2packet.array());
|
||||||
|
|
||||||
// Turn off multicast filter and verify it's off
|
// Turn off multicast filter and verify it's off
|
||||||
ipManagerCallback.resetApfProgramWait();
|
ipManagerCallback.resetApfProgramWait();
|
||||||
apfFilter.setMulticastFilter(false);
|
apfFilter.setMulticastFilter(false);
|
||||||
program = ipManagerCallback.getApfProgram();
|
program = ipManagerCallback.getApfProgram();
|
||||||
assertPass(program, bcastv4packet.array(), 0);
|
assertPass(program, mcastv4packet.array());
|
||||||
assertPass(program, mcastv4packet.array(), 0);
|
assertPass(program, mcastv6packet.array());
|
||||||
assertPass(program, mcastv6packet.array(), 0);
|
assertPass(program, bcastv4packet1.array());
|
||||||
|
assertPass(program, bcastv4packet2.array());
|
||||||
|
assertPass(program, bcastv4unicastl2packet.array());
|
||||||
|
|
||||||
// Verify it can be initialized to on
|
// Verify it can be initialized to on
|
||||||
ipManagerCallback.resetApfProgramWait();
|
ipManagerCallback.resetApfProgramWait();
|
||||||
apfFilter.shutdown();
|
apfFilter.shutdown();
|
||||||
apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
|
apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
|
||||||
program = ipManagerCallback.getApfProgram();
|
program = ipManagerCallback.getApfProgram();
|
||||||
assertDrop(program, bcastv4packet.array(), 0);
|
assertDrop(program, mcastv4packet.array());
|
||||||
assertDrop(program, mcastv4packet.array(), 0);
|
assertDrop(program, mcastv6packet.array());
|
||||||
assertDrop(program, mcastv6packet.array(), 0);
|
assertDrop(program, bcastv4packet1.array());
|
||||||
|
assertPass(program, bcastv4unicastl2packet.array());
|
||||||
|
|
||||||
// Verify that ICMPv6 multicast is not dropped.
|
// Verify that ICMPv6 multicast is not dropped.
|
||||||
mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
|
mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
|
||||||
assertPass(program, mcastv6packet.array(), 0);
|
assertPass(program, mcastv6packet.array());
|
||||||
|
|
||||||
apfFilter.shutdown();
|
apfFilter.shutdown();
|
||||||
}
|
}
|
||||||
@@ -819,17 +883,17 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
|
|
||||||
private void verifyArpFilter(byte[] program, int filterResult) {
|
private void verifyArpFilter(byte[] program, int filterResult) {
|
||||||
// Verify ARP request packet
|
// Verify ARP request packet
|
||||||
assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR), 0);
|
assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR));
|
||||||
assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR), 0);
|
assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR));
|
||||||
assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR), 0);
|
assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR));
|
||||||
|
|
||||||
// Verify unicast ARP reply packet is always accepted.
|
// Verify unicast ARP reply packet is always accepted.
|
||||||
assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR), 0);
|
assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR));
|
||||||
assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR), 0);
|
assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR));
|
||||||
assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR), 0);
|
assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR));
|
||||||
|
|
||||||
// Verify GARP reply packets are always filtered
|
// Verify GARP reply packets are always filtered
|
||||||
assertDrop(program, garpReply(), 0);
|
assertDrop(program, garpReply());
|
||||||
}
|
}
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@@ -855,34 +919,26 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
private static byte[] arpRequestBroadcast(byte[] tip) {
|
private static byte[] arpRequestBroadcast(byte[] tip) {
|
||||||
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
|
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
|
||||||
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
|
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
|
||||||
packet.position(ETH_DEST_ADDR_OFFSET);
|
put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
|
||||||
packet.put(ETH_BROADCAST_MAC_ADDRESS);
|
put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
|
||||||
packet.position(ARP_HEADER_OFFSET);
|
put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
|
||||||
packet.put(ARP_IPV4_REQUEST_HEADER);
|
|
||||||
packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
|
|
||||||
packet.put(tip);
|
|
||||||
return packet.array();
|
return packet.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] arpReplyUnicast(byte[] tip) {
|
private static byte[] arpReplyUnicast(byte[] tip) {
|
||||||
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
|
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
|
||||||
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
|
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
|
||||||
packet.position(ARP_HEADER_OFFSET);
|
put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
|
||||||
packet.put(ARP_IPV4_REPLY_HEADER);
|
put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip);
|
||||||
packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
|
|
||||||
packet.put(tip);
|
|
||||||
return packet.array();
|
return packet.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] garpReply() {
|
private static byte[] garpReply() {
|
||||||
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
|
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
|
||||||
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
|
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP);
|
||||||
packet.position(ETH_DEST_ADDR_OFFSET);
|
put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
|
||||||
packet.put(ETH_BROADCAST_MAC_ADDRESS);
|
put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER);
|
||||||
packet.position(ARP_HEADER_OFFSET);
|
put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR);
|
||||||
packet.put(ARP_IPV4_REPLY_HEADER);
|
|
||||||
packet.position(ARP_TARGET_IP_ADDRESS_OFFSET);
|
|
||||||
packet.put(IPV4_ANY_HOST_ADDR);
|
|
||||||
return packet.array();
|
return packet.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -893,22 +949,22 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
byte[] program = ipManagerCallback.getApfProgram();
|
byte[] program = ipManagerCallback.getApfProgram();
|
||||||
|
|
||||||
// Verify new program should drop RA for 1/6th its lifetime
|
// Verify new program should drop RA for 1/6th its lifetime
|
||||||
assertDrop(program, packet.array(), 0);
|
assertDrop(program, packet.array());
|
||||||
assertDrop(program, packet.array(), lifetime/6);
|
assertDrop(program, packet.array(), lifetime/6);
|
||||||
assertPass(program, packet.array(), lifetime/6 + 1);
|
assertPass(program, packet.array(), lifetime/6 + 1);
|
||||||
assertPass(program, packet.array(), lifetime);
|
assertPass(program, packet.array(), lifetime);
|
||||||
|
|
||||||
// Verify RA checksum is ignored
|
// Verify RA checksum is ignored
|
||||||
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
|
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345);
|
||||||
assertDrop(program, packet.array(), 0);
|
assertDrop(program, packet.array());
|
||||||
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
|
packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345);
|
||||||
assertDrop(program, packet.array(), 0);
|
assertDrop(program, packet.array());
|
||||||
|
|
||||||
// Verify other changes to RA make it not match filter
|
// Verify other changes to RA make it not match filter
|
||||||
packet.put(0, (byte)-1);
|
packet.put(0, (byte)-1);
|
||||||
assertPass(program, packet.array(), 0);
|
assertPass(program, packet.array());
|
||||||
packet.put(0, (byte)0);
|
packet.put(0, (byte)0);
|
||||||
assertDrop(program, packet.array(), 0);
|
assertDrop(program, packet.array());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that when ApfFilter is shown the given packet, it generates a program to filter it
|
// Test that when ApfFilter is shown the given packet, it generates a program to filter it
|
||||||
@@ -973,7 +1029,7 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000);
|
basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000);
|
||||||
basePacket.position(IPV6_DEST_ADDR_OFFSET);
|
basePacket.position(IPV6_DEST_ADDR_OFFSET);
|
||||||
basePacket.put(IPV6_ALL_NODES_ADDRESS);
|
basePacket.put(IPV6_ALL_NODES_ADDRESS);
|
||||||
assertPass(program, basePacket.array(), 0);
|
assertPass(program, basePacket.array());
|
||||||
|
|
||||||
testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
|
testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000);
|
||||||
verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1));
|
verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1));
|
||||||
@@ -1069,6 +1125,13 @@ public class ApfTest extends AndroidTestCase {
|
|||||||
return file.getAbsolutePath();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call the APF interpreter the run {@code program} on {@code packet} pretending the
|
* Call the APF interpreter the run {@code program} on {@code packet} pretending the
|
||||||
* filter was installed {@code filter_age} seconds ago.
|
* filter was installed {@code filter_age} seconds ago.
|
||||||
|
|||||||
Reference in New Issue
Block a user