diff options
| -rw-r--r-- | services/net/java/android/net/apf/ApfFilter.java | 53 | ||||
| -rw-r--r-- | services/tests/servicestests/src/android/net/apf/ApfTest.java | 53 |
2 files changed, 59 insertions, 47 deletions
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index 538e8f879a3d..485f2f5318f4 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -597,12 +597,13 @@ public class ApfFilter { private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException { // Here's a basic summary of what the IPv4 filter program does: // - // if it's multicast and we're dropping multicast: - // drop - // if it's not broadcast: - // pass - // if it's not DHCP destined to our MAC: - // drop + // if filtering multicast (i.e. multicast lock not held): + // if it's multicast: + // drop + // if it's not broadcast: + // pass + // if it's not DHCP destined to our MAC: + // drop // pass if (mMulticastFilter) { @@ -610,27 +611,27 @@ public class ApfFilter { gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET); gen.addAnd(0xf0); gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL); - } - // Drop all broadcasts besides DHCP addressed to us - // If not a broadcast packet, pass - gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); - gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL); - // If not UDP, drop - gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET); - gen.addJumpIfR0NotEquals(IPPROTO_UDP, gen.DROP_LABEL); - // If fragment, drop. This matches the BPF filter installed by the DHCP client. - gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET); - gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, gen.DROP_LABEL); - // If not to DHCP client port, drop - gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); - gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET); - gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, gen.DROP_LABEL); - // If not DHCP to our MAC address, drop - gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET); - // NOTE: Relies on R1 containing IPv4 header offset. - gen.addAddR1(); - gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, gen.DROP_LABEL); + // Drop all broadcasts besides DHCP addressed to us + // If not a broadcast packet, pass + gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); + gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL); + // If not UDP, drop + gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET); + gen.addJumpIfR0NotEquals(IPPROTO_UDP, gen.DROP_LABEL); + // If fragment, drop. This matches the BPF filter installed by the DHCP client. + gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET); + gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, gen.DROP_LABEL); + // If not to DHCP client port, drop + gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); + gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET); + gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, gen.DROP_LABEL); + // If not DHCP to our MAC address, drop + gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET); + // NOTE: Relies on R1 containing IPv4 header offset. + gen.addAddR1(); + gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, gen.DROP_LABEL); + } // Otherwise, pass gen.addJump(gen.PASS_LABEL); diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java index 9e04d2301ad9..fae82ca4e7a3 100644 --- a/services/tests/servicestests/src/android/net/apf/ApfTest.java +++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java @@ -663,7 +663,7 @@ public class ApfTest extends AndroidTestCase { @LargeTest public void testApfFilterIPv4() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); - ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, false /* multicastFilter */); + ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */); byte[] program = ipManagerCallback.getApfProgram(); // Verify empty packet of 100 zero bytes is passed @@ -726,46 +726,57 @@ public class ApfTest extends AndroidTestCase { byte[] program = ipManagerCallback.getApfProgram(); // Construct IPv4 and IPv6 multicast packets. - ByteBuffer v4packet = ByteBuffer.wrap(new byte[100]); - v4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); - v4packet.position(IPV4_DEST_ADDR_OFFSET); - v4packet.put(new byte[]{(byte)224,0,0,1}); - - ByteBuffer v6packet = ByteBuffer.wrap(new byte[100]); - v6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6); - v6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP); - v6packet.position(IPV6_DEST_ADDR_OFFSET); - v6packet.put(new byte[]{(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb}); + ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]); + mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); + mcastv4packet.position(IPV4_DEST_ADDR_OFFSET); + mcastv4packet.put(new byte[]{(byte)224,0,0,1}); + + 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); + mcastv6packet.position(IPV6_DEST_ADDR_OFFSET); + 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. + ByteBuffer bcastv4packet = ByteBuffer.wrap(new byte[100]); + bcastv4packet.put(ETH_BROADCAST_MAC_ADDRESS); + bcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); + bcastv4packet.position(IPV4_DEST_ADDR_OFFSET); + bcastv4packet.put(new byte[]{(byte)192,(byte)0,(byte)2,(byte)63}); // Verify initially disabled multicast filter is off - assertPass(program, v4packet.array(), 0); - assertPass(program, v6packet.array(), 0); + assertPass(program, bcastv4packet.array(), 0); + assertPass(program, mcastv4packet.array(), 0); + assertPass(program, mcastv6packet.array(), 0); // Turn on multicast filter and verify it works ipManagerCallback.resetApfProgramWait(); apfFilter.setMulticastFilter(true); program = ipManagerCallback.getApfProgram(); - assertDrop(program, v4packet.array(), 0); - assertDrop(program, v6packet.array(), 0); + assertDrop(program, bcastv4packet.array(), 0); + assertDrop(program, mcastv4packet.array(), 0); + assertDrop(program, mcastv6packet.array(), 0); // Turn off multicast filter and verify it's off ipManagerCallback.resetApfProgramWait(); apfFilter.setMulticastFilter(false); program = ipManagerCallback.getApfProgram(); - assertPass(program, v4packet.array(), 0); - assertPass(program, v6packet.array(), 0); + assertPass(program, bcastv4packet.array(), 0); + assertPass(program, mcastv4packet.array(), 0); + assertPass(program, mcastv6packet.array(), 0); // Verify it can be initialized to on ipManagerCallback.resetApfProgramWait(); apfFilter.shutdown(); apfFilter = new TestApfFilter(ipManagerCallback, true /* multicastFilter */); program = ipManagerCallback.getApfProgram(); - assertDrop(program, v4packet.array(), 0); - assertDrop(program, v6packet.array(), 0); + assertDrop(program, bcastv4packet.array(), 0); + assertDrop(program, mcastv4packet.array(), 0); + assertDrop(program, mcastv6packet.array(), 0); // Verify that ICMPv6 multicast is not dropped. - v6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); - assertPass(program, v6packet.array(), 0); + mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); + assertPass(program, mcastv6packet.array(), 0); apfFilter.shutdown(); } |