Merge "APF: drop multicast ICMPv6 while in doze mode"
This commit is contained in:
@@ -16,21 +16,21 @@
|
|||||||
|
|
||||||
package android.net.apf;
|
package android.net.apf;
|
||||||
|
|
||||||
|
import static android.net.util.NetworkConstants.*;
|
||||||
import static android.system.OsConstants.*;
|
import static android.system.OsConstants.*;
|
||||||
|
|
||||||
import static com.android.internal.util.BitUtils.bytesToBEInt;
|
import static com.android.internal.util.BitUtils.bytesToBEInt;
|
||||||
import static com.android.internal.util.BitUtils.getUint16;
|
import static com.android.internal.util.BitUtils.getUint16;
|
||||||
import static com.android.internal.util.BitUtils.getUint32;
|
import static com.android.internal.util.BitUtils.getUint32;
|
||||||
import static com.android.internal.util.BitUtils.getUint8;
|
import static com.android.internal.util.BitUtils.getUint8;
|
||||||
import static com.android.internal.util.BitUtils.uint16;
|
|
||||||
import static com.android.internal.util.BitUtils.uint32;
|
import static com.android.internal.util.BitUtils.uint32;
|
||||||
import static com.android.internal.util.BitUtils.uint8;
|
|
||||||
|
|
||||||
import android.os.SystemClock;
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.NetworkUtils;
|
import android.net.NetworkUtils;
|
||||||
import android.net.apf.ApfGenerator;
|
|
||||||
import android.net.apf.ApfGenerator.IllegalInstructionException;
|
import android.net.apf.ApfGenerator.IllegalInstructionException;
|
||||||
import android.net.apf.ApfGenerator.Register;
|
import android.net.apf.ApfGenerator.Register;
|
||||||
import android.net.ip.IpClient;
|
import android.net.ip.IpClient;
|
||||||
@@ -39,31 +39,29 @@ import android.net.metrics.ApfStats;
|
|||||||
import android.net.metrics.IpConnectivityLog;
|
import android.net.metrics.IpConnectivityLog;
|
||||||
import android.net.metrics.RaEvent;
|
import android.net.metrics.RaEvent;
|
||||||
import android.net.util.InterfaceParams;
|
import android.net.util.InterfaceParams;
|
||||||
|
import android.os.PowerManager;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.system.PacketSocketAddress;
|
import android.system.PacketSocketAddress;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.util.HexDump;
|
import com.android.internal.util.HexDump;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.Thread;
|
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.BufferUnderflowException;
|
import java.nio.BufferUnderflowException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import libcore.io.IoBridge;
|
import libcore.io.IoBridge;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,10 +213,6 @@ public class ApfFilter {
|
|||||||
{ (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_SOLICITATION = 133;
|
|
||||||
private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
|
|
||||||
private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
|
|
||||||
private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
|
|
||||||
|
|
||||||
// NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
|
// NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
|
||||||
private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
|
private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
|
||||||
@@ -258,9 +252,26 @@ public class ApfFilter {
|
|||||||
private long mUniqueCounter;
|
private long mUniqueCounter;
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private boolean mMulticastFilter;
|
private boolean mMulticastFilter;
|
||||||
|
@GuardedBy("this")
|
||||||
|
private boolean mInDozeMode;
|
||||||
private final boolean mDrop802_3Frames;
|
private final boolean mDrop802_3Frames;
|
||||||
private final int[] mEthTypeBlackList;
|
private final int[] mEthTypeBlackList;
|
||||||
|
|
||||||
|
// Detects doze mode state transitions.
|
||||||
|
private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
|
||||||
|
PowerManager powerManager =
|
||||||
|
(PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||||
|
final boolean deviceIdle = powerManager.isDeviceIdleMode();
|
||||||
|
setDozeMode(deviceIdle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
// Our IPv4 address, if we have just one, otherwise null.
|
// Our IPv4 address, if we have just one, otherwise null.
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private byte[] mIPv4Address;
|
private byte[] mIPv4Address;
|
||||||
@@ -269,13 +280,14 @@ public class ApfFilter {
|
|||||||
private int mIPv4PrefixLength;
|
private int mIPv4PrefixLength;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
ApfFilter(ApfConfiguration config, InterfaceParams ifParams,
|
ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
|
||||||
IpClient.Callback ipClientCallback, IpConnectivityLog log) {
|
IpClient.Callback ipClientCallback, IpConnectivityLog log) {
|
||||||
mApfCapabilities = config.apfCapabilities;
|
mApfCapabilities = config.apfCapabilities;
|
||||||
mIpClientCallback = ipClientCallback;
|
mIpClientCallback = ipClientCallback;
|
||||||
mInterfaceParams = ifParams;
|
mInterfaceParams = ifParams;
|
||||||
mMulticastFilter = config.multicastFilter;
|
mMulticastFilter = config.multicastFilter;
|
||||||
mDrop802_3Frames = config.ieee802_3Filter;
|
mDrop802_3Frames = config.ieee802_3Filter;
|
||||||
|
mContext = context;
|
||||||
|
|
||||||
// Now fill the black list from the passed array
|
// Now fill the black list from the passed array
|
||||||
mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
|
mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
|
||||||
@@ -284,6 +296,10 @@ public class ApfFilter {
|
|||||||
|
|
||||||
// TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
|
// TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
|
||||||
maybeStartFilter();
|
maybeStartFilter();
|
||||||
|
|
||||||
|
// Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
|
||||||
|
mContext.registerReceiver(mDeviceIdleReceiver,
|
||||||
|
new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void log(String s) {
|
private void log(String s) {
|
||||||
@@ -522,7 +538,7 @@ public class ApfFilter {
|
|||||||
// to our packet socket. b/29586253
|
// to our packet socket. b/29586253
|
||||||
if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
|
if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
|
||||||
getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
|
getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
|
||||||
getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMP6_ROUTER_ADVERTISEMENT) {
|
getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
|
||||||
throw new InvalidRaException("Not an ICMP6 router advertisement");
|
throw new InvalidRaException("Not an ICMP6 router advertisement");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -889,10 +905,11 @@ public class ApfFilter {
|
|||||||
private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
|
private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
|
||||||
// Here's a basic summary of what the IPv6 filter program does:
|
// Here's a basic summary of what the IPv6 filter program does:
|
||||||
//
|
//
|
||||||
// if it's not ICMPv6:
|
// if we're dropping multicast
|
||||||
// if it's multicast and we're dropping multicast:
|
// if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
|
||||||
// drop
|
// if it's multicast:
|
||||||
// pass
|
// drop
|
||||||
|
// pass
|
||||||
// if it's ICMPv6 RS to any:
|
// if it's ICMPv6 RS to any:
|
||||||
// drop
|
// drop
|
||||||
// if it's ICMPv6 NA to ff02::1:
|
// if it's ICMPv6 NA to ff02::1:
|
||||||
@@ -902,28 +919,44 @@ public class ApfFilter {
|
|||||||
|
|
||||||
// Drop multicast if the multicast filter is enabled.
|
// Drop multicast if the multicast filter is enabled.
|
||||||
if (mMulticastFilter) {
|
if (mMulticastFilter) {
|
||||||
// Don't touch ICMPv6 multicast here, we deal with it in more detail later.
|
final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter";
|
||||||
String skipIpv6MulticastFilterLabel = "skipIPv6MulticastFilter";
|
final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast";
|
||||||
gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIpv6MulticastFilterLabel);
|
|
||||||
|
|
||||||
// Drop all other packets sent to ff00::/8.
|
// While in doze mode, drop ICMPv6 multicast pings, let the others pass.
|
||||||
|
// While awake, let all ICMPv6 multicasts through.
|
||||||
|
if (mInDozeMode) {
|
||||||
|
// Not ICMPv6? -> Proceed to multicast filtering
|
||||||
|
gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
|
||||||
|
|
||||||
|
// ICMPv6 but not ECHO? -> Skip the multicast filter.
|
||||||
|
// (ICMPv6 ECHO requests will go through the multicast filter below).
|
||||||
|
gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
|
||||||
|
gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
|
||||||
|
} else {
|
||||||
|
gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop all other packets sent to ff00::/8 (multicast prefix).
|
||||||
|
gen.defineLabel(dropAllIPv6MulticastsLabel);
|
||||||
gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
|
gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
|
||||||
gen.addJumpIfR0Equals(0xff, gen.DROP_LABEL);
|
gen.addJumpIfR0Equals(0xff, gen.DROP_LABEL);
|
||||||
// Not multicast and not ICMPv6. Pass.
|
// Not multicast. Pass.
|
||||||
gen.addJump(gen.PASS_LABEL);
|
gen.addJump(gen.PASS_LABEL);
|
||||||
gen.defineLabel(skipIpv6MulticastFilterLabel);
|
gen.defineLabel(skipIPv6MulticastFilterLabel);
|
||||||
} else {
|
} else {
|
||||||
// If not ICMPv6, pass.
|
// If not ICMPv6, pass.
|
||||||
gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL);
|
gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we got this far, the packet is ICMPv6. Drop some specific types.
|
||||||
|
|
||||||
// Add unsolicited multicast neighbor announcements filter
|
// Add unsolicited multicast neighbor announcements filter
|
||||||
String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
|
String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
|
||||||
gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
|
gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
|
||||||
// Drop all router solicitations (b/32833400)
|
// Drop all router solicitations (b/32833400)
|
||||||
gen.addJumpIfR0Equals(ICMP6_ROUTER_SOLICITATION, gen.DROP_LABEL);
|
gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, gen.DROP_LABEL);
|
||||||
// If not neighbor announcements, skip filter.
|
// If not neighbor announcements, skip filter.
|
||||||
gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel);
|
gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
|
||||||
// If to ff02::1, drop.
|
// If to ff02::1, drop.
|
||||||
// TODO: Drop only if they don't contain the address of on-link neighbours.
|
// TODO: Drop only if they don't contain the address of on-link neighbours.
|
||||||
gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
|
gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
|
||||||
@@ -1167,9 +1200,9 @@ public class ApfFilter {
|
|||||||
* Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
|
* Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
|
||||||
* filtering using APF programs.
|
* filtering using APF programs.
|
||||||
*/
|
*/
|
||||||
public static ApfFilter maybeCreate(ApfConfiguration config,
|
public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
|
||||||
InterfaceParams ifParams, IpClient.Callback ipClientCallback) {
|
InterfaceParams ifParams, IpClient.Callback ipClientCallback) {
|
||||||
if (config == null || ifParams == null) return null;
|
if (context == null || config == null || ifParams == null) return null;
|
||||||
ApfCapabilities apfCapabilities = config.apfCapabilities;
|
ApfCapabilities apfCapabilities = config.apfCapabilities;
|
||||||
if (apfCapabilities == null) return null;
|
if (apfCapabilities == null) return null;
|
||||||
if (apfCapabilities.apfVersionSupported == 0) return null;
|
if (apfCapabilities.apfVersionSupported == 0) return null;
|
||||||
@@ -1186,7 +1219,8 @@ public class ApfFilter {
|
|||||||
Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
|
Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new ApfFilter(config, ifParams, ipClientCallback, new IpConnectivityLog());
|
|
||||||
|
return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog());
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void shutdown() {
|
public synchronized void shutdown() {
|
||||||
@@ -1196,12 +1230,11 @@ public class ApfFilter {
|
|||||||
mReceiveThread = null;
|
mReceiveThread = null;
|
||||||
}
|
}
|
||||||
mRas.clear();
|
mRas.clear();
|
||||||
|
mContext.unregisterReceiver(mDeviceIdleReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void setMulticastFilter(boolean isEnabled) {
|
public synchronized void setMulticastFilter(boolean isEnabled) {
|
||||||
if (mMulticastFilter == isEnabled) {
|
if (mMulticastFilter == isEnabled) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
mMulticastFilter = isEnabled;
|
mMulticastFilter = isEnabled;
|
||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
mNumProgramUpdatesAllowingMulticast++;
|
mNumProgramUpdatesAllowingMulticast++;
|
||||||
@@ -1209,6 +1242,13 @@ public class ApfFilter {
|
|||||||
installNewProgramLocked();
|
installNewProgramLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public synchronized void setDozeMode(boolean isEnabled) {
|
||||||
|
if (mInDozeMode == isEnabled) return;
|
||||||
|
mInDozeMode = isEnabled;
|
||||||
|
installNewProgramLocked();
|
||||||
|
}
|
||||||
|
|
||||||
/** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
|
/** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
|
||||||
private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
|
private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
|
||||||
LinkAddress ipv4Address = null;
|
LinkAddress ipv4Address = null;
|
||||||
|
|||||||
@@ -1490,7 +1490,7 @@ public class IpClient extends StateMachine {
|
|||||||
mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
|
mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
|
||||||
apfConfig.ethTypeBlackList =
|
apfConfig.ethTypeBlackList =
|
||||||
mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
|
mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
|
||||||
mApfFilter = ApfFilter.maybeCreate(apfConfig, mInterfaceParams, mCallback);
|
mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
|
||||||
// TODO: investigate the effects of any multicast filtering racing/interfering with the
|
// TODO: investigate the effects of any multicast filtering racing/interfering with the
|
||||||
// rest of this IP configuration startup.
|
// rest of this IP configuration startup.
|
||||||
if (mApfFilter == null) {
|
if (mApfFilter == null) {
|
||||||
|
|||||||
@@ -136,6 +136,8 @@ public final class NetworkConstants {
|
|||||||
* - https://tools.ietf.org/html/rfc4861
|
* - https://tools.ietf.org/html/rfc4861
|
||||||
*/
|
*/
|
||||||
public static final int ICMPV6_HEADER_MIN_LEN = 4;
|
public static final int ICMPV6_HEADER_MIN_LEN = 4;
|
||||||
|
public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
|
||||||
|
public static final int ICMPV6_ECHO_REPLY_TYPE = 129;
|
||||||
public static final int ICMPV6_ROUTER_SOLICITATION = 133;
|
public static final int ICMPV6_ROUTER_SOLICITATION = 133;
|
||||||
public static final int ICMPV6_ROUTER_ADVERTISEMENT = 134;
|
public static final int ICMPV6_ROUTER_ADVERTISEMENT = 134;
|
||||||
public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135;
|
public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135;
|
||||||
@@ -147,7 +149,6 @@ public final class NetworkConstants {
|
|||||||
public static final int ICMPV6_ND_OPTION_TLLA = 2;
|
public static final int ICMPV6_ND_OPTION_TLLA = 2;
|
||||||
public static final int ICMPV6_ND_OPTION_MTU = 5;
|
public static final int ICMPV6_ND_OPTION_MTU = 5;
|
||||||
|
|
||||||
public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UDP constants.
|
* UDP constants.
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package android.net.apf;
|
package android.net.apf;
|
||||||
|
|
||||||
|
import static android.net.util.NetworkConstants.*;
|
||||||
import static android.system.OsConstants.*;
|
import static android.system.OsConstants.*;
|
||||||
import static com.android.internal.util.BitUtils.bytesToBEInt;
|
import static com.android.internal.util.BitUtils.bytesToBEInt;
|
||||||
import static com.android.internal.util.BitUtils.put;
|
import static com.android.internal.util.BitUtils.put;
|
||||||
@@ -26,6 +27,7 @@ import static org.junit.Assert.fail;
|
|||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.NetworkUtils;
|
import android.net.NetworkUtils;
|
||||||
@@ -82,6 +84,7 @@ public class ApfTest {
|
|||||||
private static final int TIMEOUT_MS = 500;
|
private static final int TIMEOUT_MS = 500;
|
||||||
|
|
||||||
@Mock IpConnectivityLog mLog;
|
@Mock IpConnectivityLog mLog;
|
||||||
|
@Mock Context mContext;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -633,9 +636,9 @@ public class ApfTest {
|
|||||||
private FileDescriptor mWriteSocket;
|
private FileDescriptor mWriteSocket;
|
||||||
private final long mFixedTimeMs = SystemClock.elapsedRealtime();
|
private final long mFixedTimeMs = SystemClock.elapsedRealtime();
|
||||||
|
|
||||||
public TestApfFilter(ApfConfiguration config, IpManager.Callback ipManagerCallback,
|
public TestApfFilter(Context context, ApfConfiguration config,
|
||||||
IpConnectivityLog log) throws Exception {
|
IpManager.Callback ipManagerCallback, IpConnectivityLog log) throws Exception {
|
||||||
super(config, InterfaceParams.getByName("lo"), ipManagerCallback, log);
|
super(context, config, InterfaceParams.getByName("lo"), ipManagerCallback, log);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pretend an RA packet has been received and show it to ApfFilter.
|
// Pretend an RA packet has been received and show it to ApfFilter.
|
||||||
@@ -757,6 +760,17 @@ public class ApfTest {
|
|||||||
private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2};
|
private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2};
|
||||||
private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0};
|
private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
// Helper to initialize a default apfFilter.
|
||||||
|
private ApfFilter setupApfFilter(IpManager.Callback ipManagerCallback, ApfConfiguration config)
|
||||||
|
throws Exception {
|
||||||
|
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
|
||||||
|
LinkProperties lp = new LinkProperties();
|
||||||
|
lp.addLinkAddress(link);
|
||||||
|
TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
|
||||||
|
apfFilter.setLinkProperties(lp);
|
||||||
|
return apfFilter;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApfFilterIPv4() throws Exception {
|
public void testApfFilterIPv4() throws Exception {
|
||||||
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
|
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
|
||||||
@@ -766,7 +780,7 @@ public class ApfTest {
|
|||||||
|
|
||||||
ApfConfiguration config = getDefaultConfig();
|
ApfConfiguration config = getDefaultConfig();
|
||||||
config.multicastFilter = DROP_MULTICAST;
|
config.multicastFilter = DROP_MULTICAST;
|
||||||
TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
|
TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
|
||||||
apfFilter.setLinkProperties(lp);
|
apfFilter.setLinkProperties(lp);
|
||||||
|
|
||||||
byte[] program = ipManagerCallback.getApfProgram();
|
byte[] program = ipManagerCallback.getApfProgram();
|
||||||
@@ -818,7 +832,7 @@ public class ApfTest {
|
|||||||
public void testApfFilterIPv6() throws Exception {
|
public void testApfFilterIPv6() throws Exception {
|
||||||
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
|
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
|
||||||
ApfConfiguration config = getDefaultConfig();
|
ApfConfiguration config = getDefaultConfig();
|
||||||
TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
|
TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
|
||||||
byte[] program = ipManagerCallback.getApfProgram();
|
byte[] program = ipManagerCallback.getApfProgram();
|
||||||
|
|
||||||
// Verify empty IPv6 packet is passed
|
// Verify empty IPv6 packet is passed
|
||||||
@@ -861,7 +875,7 @@ public class ApfTest {
|
|||||||
|
|
||||||
ApfConfiguration config = getDefaultConfig();
|
ApfConfiguration config = getDefaultConfig();
|
||||||
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
||||||
TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
|
TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
|
||||||
apfFilter.setLinkProperties(lp);
|
apfFilter.setLinkProperties(lp);
|
||||||
|
|
||||||
byte[] program = ipManagerCallback.getApfProgram();
|
byte[] program = ipManagerCallback.getApfProgram();
|
||||||
@@ -925,7 +939,7 @@ public class ApfTest {
|
|||||||
apfFilter.shutdown();
|
apfFilter.shutdown();
|
||||||
config.multicastFilter = DROP_MULTICAST;
|
config.multicastFilter = DROP_MULTICAST;
|
||||||
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
||||||
apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
|
apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
|
||||||
apfFilter.setLinkProperties(lp);
|
apfFilter.setLinkProperties(lp);
|
||||||
program = ipManagerCallback.getApfProgram();
|
program = ipManagerCallback.getApfProgram();
|
||||||
assertDrop(program, mcastv4packet.array());
|
assertDrop(program, mcastv4packet.array());
|
||||||
@@ -940,17 +954,48 @@ public class ApfTest {
|
|||||||
apfFilter.shutdown();
|
apfFilter.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApfFilterMulticastPingWhileDozing() throws Exception {
|
||||||
|
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
|
||||||
|
ApfFilter apfFilter = setupApfFilter(ipManagerCallback, getDefaultConfig());
|
||||||
|
|
||||||
|
// Construct a multicast ICMPv6 ECHO request.
|
||||||
|
final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
|
||||||
|
ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
|
||||||
|
packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
|
||||||
|
packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
|
||||||
|
packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
|
||||||
|
put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
|
||||||
|
|
||||||
|
// Normally, we let multicast pings alone...
|
||||||
|
assertPass(ipManagerCallback.getApfProgram(), packet.array());
|
||||||
|
|
||||||
|
// ...and even while dozing...
|
||||||
|
apfFilter.setDozeMode(true);
|
||||||
|
assertPass(ipManagerCallback.getApfProgram(), packet.array());
|
||||||
|
|
||||||
|
// ...but when the multicast filter is also enabled, drop the multicast pings to save power.
|
||||||
|
apfFilter.setMulticastFilter(true);
|
||||||
|
assertDrop(ipManagerCallback.getApfProgram(), packet.array());
|
||||||
|
|
||||||
|
// However, we should still let through all other ICMPv6 types.
|
||||||
|
ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
|
||||||
|
raPacket.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ROUTER_ADVERTISEMENT);
|
||||||
|
assertPass(ipManagerCallback.getApfProgram(), raPacket.array());
|
||||||
|
|
||||||
|
// Now wake up from doze mode to ensure that we no longer drop the packets.
|
||||||
|
// (The multicast filter is still enabled at this point).
|
||||||
|
apfFilter.setDozeMode(false);
|
||||||
|
assertPass(ipManagerCallback.getApfProgram(), packet.array());
|
||||||
|
|
||||||
|
apfFilter.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApfFilter802_3() throws Exception {
|
public void testApfFilter802_3() throws Exception {
|
||||||
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
|
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
|
||||||
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
|
|
||||||
LinkProperties lp = new LinkProperties();
|
|
||||||
lp.addLinkAddress(link);
|
|
||||||
|
|
||||||
ApfConfiguration config = getDefaultConfig();
|
ApfConfiguration config = getDefaultConfig();
|
||||||
TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
|
ApfFilter apfFilter = setupApfFilter(ipManagerCallback, config);
|
||||||
apfFilter.setLinkProperties(lp);
|
|
||||||
|
|
||||||
byte[] program = ipManagerCallback.getApfProgram();
|
byte[] program = ipManagerCallback.getApfProgram();
|
||||||
|
|
||||||
// Verify empty packet of 100 zero bytes is passed
|
// Verify empty packet of 100 zero bytes is passed
|
||||||
@@ -970,8 +1015,7 @@ public class ApfTest {
|
|||||||
ipManagerCallback.resetApfProgramWait();
|
ipManagerCallback.resetApfProgramWait();
|
||||||
apfFilter.shutdown();
|
apfFilter.shutdown();
|
||||||
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
||||||
apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
|
apfFilter = setupApfFilter(ipManagerCallback, config);
|
||||||
apfFilter.setLinkProperties(lp);
|
|
||||||
program = ipManagerCallback.getApfProgram();
|
program = ipManagerCallback.getApfProgram();
|
||||||
|
|
||||||
// Verify that IEEE802.3 frame is dropped
|
// Verify that IEEE802.3 frame is dropped
|
||||||
@@ -992,18 +1036,13 @@ public class ApfTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApfFilterEthTypeBL() throws Exception {
|
public void testApfFilterEthTypeBL() throws Exception {
|
||||||
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
|
|
||||||
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
|
|
||||||
LinkProperties lp = new LinkProperties();
|
|
||||||
lp.addLinkAddress(link);
|
|
||||||
final int[] emptyBlackList = {};
|
final int[] emptyBlackList = {};
|
||||||
final int[] ipv4BlackList = {ETH_P_IP};
|
final int[] ipv4BlackList = {ETH_P_IP};
|
||||||
final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
|
final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
|
||||||
|
|
||||||
|
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
|
||||||
ApfConfiguration config = getDefaultConfig();
|
ApfConfiguration config = getDefaultConfig();
|
||||||
TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
|
ApfFilter apfFilter = setupApfFilter(ipManagerCallback, config);
|
||||||
apfFilter.setLinkProperties(lp);
|
|
||||||
|
|
||||||
byte[] program = ipManagerCallback.getApfProgram();
|
byte[] program = ipManagerCallback.getApfProgram();
|
||||||
|
|
||||||
// Verify empty packet of 100 zero bytes is passed
|
// Verify empty packet of 100 zero bytes is passed
|
||||||
@@ -1023,8 +1062,7 @@ public class ApfTest {
|
|||||||
ipManagerCallback.resetApfProgramWait();
|
ipManagerCallback.resetApfProgramWait();
|
||||||
apfFilter.shutdown();
|
apfFilter.shutdown();
|
||||||
config.ethTypeBlackList = ipv4BlackList;
|
config.ethTypeBlackList = ipv4BlackList;
|
||||||
apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
|
apfFilter = setupApfFilter(ipManagerCallback, config);
|
||||||
apfFilter.setLinkProperties(lp);
|
|
||||||
program = ipManagerCallback.getApfProgram();
|
program = ipManagerCallback.getApfProgram();
|
||||||
|
|
||||||
// Verify that IPv4 frame will be dropped
|
// Verify that IPv4 frame will be dropped
|
||||||
@@ -1039,8 +1077,7 @@ public class ApfTest {
|
|||||||
ipManagerCallback.resetApfProgramWait();
|
ipManagerCallback.resetApfProgramWait();
|
||||||
apfFilter.shutdown();
|
apfFilter.shutdown();
|
||||||
config.ethTypeBlackList = ipv4Ipv6BlackList;
|
config.ethTypeBlackList = ipv4Ipv6BlackList;
|
||||||
apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
|
apfFilter = setupApfFilter(ipManagerCallback, config);
|
||||||
apfFilter.setLinkProperties(lp);
|
|
||||||
program = ipManagerCallback.getApfProgram();
|
program = ipManagerCallback.getApfProgram();
|
||||||
|
|
||||||
// Verify that IPv4 frame will be dropped
|
// Verify that IPv4 frame will be dropped
|
||||||
@@ -1081,7 +1118,7 @@ public class ApfTest {
|
|||||||
ApfConfiguration config = getDefaultConfig();
|
ApfConfiguration config = getDefaultConfig();
|
||||||
config.multicastFilter = DROP_MULTICAST;
|
config.multicastFilter = DROP_MULTICAST;
|
||||||
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
||||||
TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
|
TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
|
||||||
|
|
||||||
// Verify initially ARP request filter is off, and GARP filter is on.
|
// Verify initially ARP request filter is off, and GARP filter is on.
|
||||||
verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
|
verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
|
||||||
@@ -1205,7 +1242,7 @@ public class ApfTest {
|
|||||||
ApfConfiguration config = getDefaultConfig();
|
ApfConfiguration config = getDefaultConfig();
|
||||||
config.multicastFilter = DROP_MULTICAST;
|
config.multicastFilter = DROP_MULTICAST;
|
||||||
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
||||||
TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
|
TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
|
||||||
byte[] program = ipManagerCallback.getApfProgram();
|
byte[] program = ipManagerCallback.getApfProgram();
|
||||||
|
|
||||||
final int ROUTER_LIFETIME = 1000;
|
final int ROUTER_LIFETIME = 1000;
|
||||||
@@ -1351,7 +1388,7 @@ public class ApfTest {
|
|||||||
ApfConfiguration config = getDefaultConfig();
|
ApfConfiguration config = getDefaultConfig();
|
||||||
config.multicastFilter = DROP_MULTICAST;
|
config.multicastFilter = DROP_MULTICAST;
|
||||||
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
||||||
TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
|
TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
|
||||||
for (int i = 0; i < 1000; i++) {
|
for (int i = 0; i < 1000; i++) {
|
||||||
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
|
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
|
||||||
r.nextBytes(packet);
|
r.nextBytes(packet);
|
||||||
@@ -1372,7 +1409,7 @@ public class ApfTest {
|
|||||||
ApfConfiguration config = getDefaultConfig();
|
ApfConfiguration config = getDefaultConfig();
|
||||||
config.multicastFilter = DROP_MULTICAST;
|
config.multicastFilter = DROP_MULTICAST;
|
||||||
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
config.ieee802_3Filter = DROP_802_3_FRAMES;
|
||||||
TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
|
TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
|
||||||
for (int i = 0; i < 1000; i++) {
|
for (int i = 0; i < 1000; i++) {
|
||||||
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
|
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
|
||||||
r.nextBytes(packet);
|
r.nextBytes(packet);
|
||||||
|
|||||||
Reference in New Issue
Block a user