Merge "Better IPv4 multicast coverage in ApfTest" into nyc-mr1-dev

This commit is contained in:
Hugo Benichi
2016-09-12 03:29:13 +00:00
committed by Android (Google) Code Review
2 changed files with 149 additions and 86 deletions

View File

@@ -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

View File

@@ -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.