summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/net/java/android/net/apf/ApfFilter.java98
-rw-r--r--services/tests/servicestests/src/android/net/apf/ApfTest.java60
2 files changed, 112 insertions, 46 deletions
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 1e2c92caa250..4c7545240c23 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -19,6 +19,7 @@ package android.net.apf;
import static android.system.OsConstants.*;
import android.os.SystemClock;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
import android.net.apf.ApfGenerator;
@@ -44,6 +45,7 @@ import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.Thread;
+import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
@@ -230,6 +232,9 @@ public class ApfFilter {
// Our IPv4 address, if we have just one, otherwise null.
@GuardedBy("this")
private byte[] mIPv4Address;
+ // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
+ @GuardedBy("this")
+ private int mIPv4PrefixLength;
@VisibleForTesting
ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
@@ -365,26 +370,6 @@ public class ApfFilter {
// Can't be static because it's in a non-static inner class.
// TODO: Make this static once RA is its own class.
- private int uint8(byte b) {
- return b & 0xff;
- }
-
- private int uint16(short s) {
- return s & 0xffff;
- }
-
- private long uint32(int i) {
- return i & 0xffffffffL;
- }
-
- private long getUint16(ByteBuffer buffer, int position) {
- return uint16(buffer.getShort(position));
- }
-
- private long getUint32(ByteBuffer buffer, int position) {
- return uint32(buffer.getInt(position));
- }
-
private void prefixOptionToString(StringBuffer sb, int offset) {
String prefix = IPv6AddresstoString(offset + 16);
int length = uint8(mPacket.get(offset + 2));
@@ -780,7 +765,10 @@ public class ApfFilter {
// If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, gen.DROP_LABEL);
- // TODO: also filter subnet broadcast address.
+ if (mIPv4Address != null && mIPv4PrefixLength < 31) {
+ int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
+ gen.addJumpIfR0Equals(broadcastAddr, gen.DROP_LABEL);
+ }
// If L2 broadcast packet, drop.
gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
@@ -1078,26 +1066,32 @@ public class ApfFilter {
}
}
- // Find the single IPv4 address if there is one, otherwise return null.
- private static byte[] findIPv4Address(LinkProperties lp) {
- byte[] ipv4Address = null;
- for (InetAddress inetAddr : lp.getAddresses()) {
- byte[] addr = inetAddr.getAddress();
- if (addr.length != 4) continue;
- // More than one IPv4 address, abort
- if (ipv4Address != null && !Arrays.equals(ipv4Address, addr)) return null;
- ipv4Address = addr;
+ /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
+ private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
+ LinkAddress ipv4Address = null;
+ for (LinkAddress address : lp.getLinkAddresses()) {
+ if (!(address.getAddress() instanceof Inet4Address)) {
+ continue;
+ }
+ if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
+ // More than one IPv4 address, abort.
+ return null;
+ }
+ ipv4Address = address;
}
return ipv4Address;
}
public synchronized void setLinkProperties(LinkProperties lp) {
// NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
- byte[] ipv4Address = findIPv4Address(lp);
- // If ipv4Address is the same as mIPv4Address, then there's no change, just return.
- if (Arrays.equals(ipv4Address, mIPv4Address)) return;
- // Otherwise update mIPv4Address and install new program.
- mIPv4Address = ipv4Address;
+ final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
+ final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
+ final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
+ if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
+ return;
+ }
+ mIPv4Address = addr;
+ mIPv4PrefixLength = prefix;
installNewProgramLocked();
}
@@ -1143,4 +1137,38 @@ public class ApfFilter {
pw.decreaseIndent();
}
}
+
+ private static int uint8(byte b) {
+ return b & 0xff;
+ }
+
+ private static int uint16(short s) {
+ return s & 0xffff;
+ }
+
+ private static long uint32(int i) {
+ return i & 0xffffffffL;
+ }
+
+ private static long getUint16(ByteBuffer buffer, int position) {
+ return uint16(buffer.getShort(position));
+ }
+
+ private static long getUint32(ByteBuffer buffer, int position) {
+ return uint32(buffer.getInt(position));
+ }
+
+ // TODO: move to android.net.NetworkUtils
+ @VisibleForTesting
+ public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
+ return bytesToInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
+ }
+
+ @VisibleForTesting
+ public static int bytesToInt(byte[] addrBytes) {
+ return (uint8(addrBytes[0]) << 24)
+ + (uint8(addrBytes[1]) << 16)
+ + (uint8(addrBytes[2]) << 8)
+ + (uint8(addrBytes[3]));
+ }
}
diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
index 5c712ea7bdae..f7c61d15bb5f 100644
--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
+++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java
@@ -20,6 +20,9 @@ import static android.system.OsConstants.*;
import com.android.frameworks.servicestests.R;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkUtils;
import android.net.apf.ApfCapabilities;
import android.net.apf.ApfFilter;
import android.net.apf.ApfGenerator;
@@ -28,8 +31,6 @@ import android.net.apf.ApfGenerator.Register;
import android.net.ip.IpManager;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.RaEvent;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
import android.os.ConditionVariable;
import android.os.Parcelable;
import android.system.ErrnoException;
@@ -713,7 +714,7 @@ public class ApfTest extends AndroidTestCase {
private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24;
private static final byte[] MOCK_IPV4_ADDR = {10, 0, 0, 1};
- private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, (byte) 255, (byte) 255};
+ 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_ANY_HOST_ADDR = {0, 0, 0, 0};
@@ -721,8 +722,12 @@ public class ApfTest extends AndroidTestCase {
@LargeTest
public void testApfFilterIPv4() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
+ LinkProperties lp = new LinkProperties();
+ lp.addLinkAddress(link);
ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
+ apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -740,7 +745,7 @@ public class ApfTest extends AndroidTestCase {
put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS);
assertDrop(program, packet.array());
put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR);
- assertPass(program, packet.array());
+ assertDrop(program, packet.array());
// Verify multicast/broadcast IPv4, not DHCP to us, is dropped
put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS);
@@ -797,15 +802,21 @@ public class ApfTest extends AndroidTestCase {
@LargeTest
public void testApfFilterMulticast() throws Exception {
- MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
- byte[] program = ipManagerCallback.getApfProgram();
-
final byte[] unicastIpv4Addr = {(byte)192,0,2,63};
- final byte[] broadcastIpv4Addr = {(byte)192,0,(byte)255,(byte)255};
+ 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};
+ MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
+ LinkProperties lp = new LinkProperties();
+ lp.addLinkAddress(link);
+
+ ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog);
+ apfFilter.setLinkProperties(lp);
+
+ byte[] program = ipManagerCallback.getApfProgram();
+
// Construct IPv4 and IPv6 multicast packets.
ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]);
mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP);
@@ -848,7 +859,7 @@ public class ApfTest extends AndroidTestCase {
assertDrop(program, mcastv6packet.array());
assertDrop(program, bcastv4packet1.array());
assertDrop(program, bcastv4packet2.array());
- assertPass(program, bcastv4unicastl2packet.array());
+ assertDrop(program, bcastv4unicastl2packet.array());
// Turn off multicast filter and verify it's off
ipManagerCallback.resetApfProgramWait();
@@ -864,11 +875,12 @@ public class ApfTest extends AndroidTestCase {
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog);
+ apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
assertDrop(program, mcastv4packet.array());
assertDrop(program, mcastv6packet.array());
assertDrop(program, bcastv4packet1.array());
- assertPass(program, bcastv4unicastl2packet.array());
+ assertDrop(program, bcastv4unicastl2packet.array());
// Verify that ICMPv6 multicast is not dropped.
mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
@@ -1154,4 +1166,30 @@ public class ApfTest extends AndroidTestCase {
*/
private native static boolean compareBpfApf(String filter, String pcap_filename,
byte[] apf_program);
+
+ public void testBytesToInt() {
+ assertEquals(0x00000000, ApfFilter.bytesToInt(IPV4_ANY_HOST_ADDR));
+ assertEquals(0xffffffff, ApfFilter.bytesToInt(IPV4_BROADCAST_ADDRESS));
+ assertEquals(0x0a000001, ApfFilter.bytesToInt(MOCK_IPV4_ADDR));
+ assertEquals(0x0a000002, ApfFilter.bytesToInt(ANOTHER_IPV4_ADDR));
+ assertEquals(0x0a001fff, ApfFilter.bytesToInt(MOCK_BROADCAST_IPV4_ADDR));
+ assertEquals(0xe0000001, ApfFilter.bytesToInt(MOCK_MULTICAST_IPV4_ADDR));
+ }
+
+ 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 = ApfFilter.bytesToInt(InetAddress.getByName(expected).getAddress());
+ assertEquals(want, got);
+ }
}