Merge "ApfFilter: take into account IPv4 subnet prefix" into nyc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
886a45acfe
@@ -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]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user