Merge "Fix captive portal app can be launched w/o MAINLINE_NETWORK_STACK permission"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..45884c4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/.idea
+*.iml
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
index 359c859..2e1e96e 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
@@ -155,7 +155,9 @@
DROPPED_ETHERTYPE_BLACKLISTED,
DROPPED_ARP_REPLY_SPA_NO_HOST,
DROPPED_IPV4_KEEPALIVE_ACK,
- DROPPED_IPV6_KEEPALIVE_ACK;
+ DROPPED_IPV6_KEEPALIVE_ACK,
+ DROPPED_IPV4_NATT_KEEPALIVE,
+ DROPPED_IPV6_NATT_KEEPALIVE;
// Returns the negative byte offset from the end of the APF data segment for
// a given counter.
@@ -857,12 +859,129 @@
}
}
- // A class to hold keepalive ack information.
- private abstract static class TcpKeepaliveAck {
+ // TODO: Refactor these subclasses to avoid so much repetition.
+ private abstract static class KeepalivePacket {
// Note that the offset starts from IP header.
// These must be added ether header length when generating program.
static final int IP_HEADER_OFFSET = 0;
+ static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
+ // Append a filter for this keepalive ack to {@code gen}.
+ // Jump to drop if it matches the keepalive ack.
+ // Jump to the next filter if packet doesn't match the keepalive ack.
+ abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException;
+ }
+
+ // A class to hold NAT-T keepalive ack information.
+ private abstract static class NattKeepaliveAck extends KeepalivePacket {
+ static final int UDP_LENGTH_OFFSET = 4;
+ static final int UDP_HEADER_LEN = 8;
+
+ protected static class NattKeepaliveAckData {
+ public final byte[] srcAddress;
+ public final int srcPort;
+ public final byte[] dstAddress;
+ public final int dstPort;
+
+ NattKeepaliveAckData(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
+ srcAddress = sentKeepalivePacket.dstAddress;
+ srcPort = sentKeepalivePacket.dstPort;
+ dstAddress = sentKeepalivePacket.srcAddress;
+ dstPort = sentKeepalivePacket.srcPort;
+ }
+ }
+
+ protected final NattKeepaliveAckData mPacket;
+ protected final byte[] mSrcDstAddr;
+ protected final byte[] mPortFingerprint;
+ // NAT-T keepalive packet
+ protected final byte[] mPayload = {(byte) 0xff};
+
+ NattKeepaliveAck(final NattKeepaliveAckData packet, final byte[] srcDstAddr) {
+ mPacket = packet;
+ mSrcDstAddr = srcDstAddr;
+ mPortFingerprint = generatePortFingerprint(mPacket.srcPort, mPacket.dstPort);
+ }
+
+ static byte[] generatePortFingerprint(int srcPort, int dstPort) {
+ final ByteBuffer fp = ByteBuffer.allocate(4);
+ fp.order(ByteOrder.BIG_ENDIAN);
+ fp.putShort((short) srcPort);
+ fp.putShort((short) dstPort);
+ return fp.array();
+ }
+
+ public String toString() {
+ try {
+ return String.format("%s -> %s",
+ NetworkStackUtils.addressAndPortToString(
+ InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
+ NetworkStackUtils.addressAndPortToString(
+ InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort));
+ } catch (UnknownHostException e) {
+ return "Unknown host";
+ }
+ }
+ }
+
+ private class NattKeepaliveAckV4 extends NattKeepaliveAck {
+ NattKeepaliveAckV4(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
+ this(new NattKeepaliveAckData(sentKeepalivePacket));
+ }
+ NattKeepaliveAckV4(final NattKeepaliveAckData packet) {
+ super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
+ }
+
+ @Override
+ void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+ final String nextFilterLabel = "natt_keepalive_filter" + getUniqueNumberLocked();
+
+ gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
+ gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
+
+ // A NAT-T keepalive packet contains 1 byte payload with the value 0xff
+ // Check payload length is 1
+ gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
+ gen.addAdd(UDP_HEADER_LEN);
+ gen.addSwap();
+ gen.addLoad16(Register.R0, IPV4_TOTAL_LENGTH_OFFSET);
+ gen.addNeg(Register.R1);
+ gen.addAddR1();
+ gen.addJumpIfR0NotEquals(1, nextFilterLabel);
+
+ // R0 = R0 + R1 -> R0 contains IP header
+ gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
+ gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN);
+ gen.addAddR1();
+ gen.addJumpIfBytesNotEqual(Register.R0, mPortFingerprint, nextFilterLabel);
+
+ // Payload offset = R0 + UDP header length
+ gen.addAdd(UDP_HEADER_LEN);
+ gen.addJumpIfBytesNotEqual(Register.R0, mPayload, nextFilterLabel);
+
+ maybeSetupCounter(gen, Counter.DROPPED_IPV4_NATT_KEEPALIVE);
+ gen.addJump(mCountAndDropLabel);
+ gen.defineLabel(nextFilterLabel);
+ }
+ }
+
+ private class NattKeepaliveAckV6 extends NattKeepaliveAck {
+ NattKeepaliveAckV6(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
+ this(new NattKeepaliveAckData(sentKeepalivePacket));
+ }
+
+ NattKeepaliveAckV6(final NattKeepaliveAckData packet) {
+ super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
+ }
+
+ @Override
+ void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+ throw new UnsupportedOperationException("IPv6 NAT-T Keepalive is not supported yet");
+ }
+ }
+
+ // A class to hold TCP keepalive ack information.
+ private abstract static class TcpKeepaliveAck extends KeepalivePacket {
protected static class TcpKeepaliveAckData {
public final byte[] srcAddress;
public final int srcPort;
@@ -870,6 +989,7 @@
public final int dstPort;
public final int seq;
public final int ack;
+
// Create the characteristics of the ack packet from the sent keepalive packet.
TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
srcAddress = sentKeepalivePacket.dstAddress;
@@ -902,28 +1022,18 @@
return fp.array();
}
- static byte[] concatArrays(final byte[]... arr) {
- int size = 0;
- for (byte[] a : arr) {
- size += a.length;
- }
- final byte[] result = new byte[size];
- int offset = 0;
- for (byte[] a : arr) {
- System.arraycopy(a, 0, result, offset, a.length);
- offset += a.length;
- }
- return result;
- }
-
public String toString() {
- return String.format("%s(%d) -> %s(%d), seq=%d, ack=%d",
- mPacket.srcAddress,
- mPacket.srcPort,
- mPacket.dstAddress,
- mPacket.dstPort,
- mPacket.seq,
- mPacket.ack);
+ try {
+ return String.format("%s -> %s , seq=%d, ack=%d",
+ NetworkStackUtils.addressAndPortToString(
+ InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
+ NetworkStackUtils.addressAndPortToString(
+ InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort),
+ Integer.toUnsignedLong(mPacket.seq),
+ Integer.toUnsignedLong(mPacket.ack));
+ } catch (UnknownHostException e) {
+ return "Unknown host";
+ }
}
// Append a filter for this keepalive ack to {@code gen}.
@@ -933,7 +1043,6 @@
}
private class TcpKeepaliveAckV4 extends TcpKeepaliveAck {
- private static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
this(new TcpKeepaliveAckData(sentKeepalivePacket));
@@ -987,7 +1096,7 @@
@Override
void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
- throw new UnsupportedOperationException("IPv6 Keepalive is not supported yet");
+ throw new UnsupportedOperationException("IPv6 TCP Keepalive is not supported yet");
}
}
@@ -997,7 +1106,7 @@
@GuardedBy("this")
private ArrayList<Ra> mRas = new ArrayList<>();
@GuardedBy("this")
- private SparseArray<TcpKeepaliveAck> mKeepaliveAcks = new SparseArray<>();
+ private SparseArray<KeepalivePacket> mKeepalivePackets = new SparseArray<>();
// There is always some marginal benefit to updating the installed APF program when an RA is
// seen because we can extend the program's lifetime slightly, but there is some cost to
@@ -1171,9 +1280,12 @@
gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
}
- // If any keepalive filter matches, drop
+ // If any TCP keepalive filter matches, drop
generateV4KeepaliveFilters(gen);
+ // If any NAT-T keepalive filter matches, drop
+ generateV4NattKeepaliveFilters(gen);
+
// Otherwise, this is an IPv4 unicast, pass
// If L2 broadcast packet, drop.
// TODO: can we invert this condition to fall through to the common pass case below?
@@ -1191,25 +1303,36 @@
gen.addJump(mCountAndPassLabel);
}
- private void generateV4KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
- final String skipV4KeepaliveFilter = "skip_v4_keepalive_filter";
- final boolean haveV4KeepaliveAcks = NetworkStackUtils.any(mKeepaliveAcks,
- ack -> ack instanceof TcpKeepaliveAckV4);
+ private void generateFilters(ApfGenerator gen, Class<?> filterType, int proto, int offset,
+ String label) throws IllegalInstructionException {
+ final boolean haveKeepaliveAcks = NetworkStackUtils.any(mKeepalivePackets,
+ ack -> filterType.isInstance(ack));
- // If no keepalive acks
- if (!haveV4KeepaliveAcks) return;
+ // If no keepalive packets of this type
+ if (!haveKeepaliveAcks) return;
- // If not tcp, skip keepalive filters
- gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
- gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipV4KeepaliveFilter);
+ // If not the right proto, skip keepalive filters
+ gen.addLoad8(Register.R0, offset);
+ gen.addJumpIfR0NotEquals(proto, label);
- // Drop IPv4 Keepalive acks
- for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
- final TcpKeepaliveAck ack = mKeepaliveAcks.valueAt(i);
- if (ack instanceof TcpKeepaliveAckV4) ack.generateFilterLocked(gen);
+ // Drop Keepalive packets
+ for (int i = 0; i < mKeepalivePackets.size(); ++i) {
+ final KeepalivePacket ack = mKeepalivePackets.valueAt(i);
+ if (filterType.isInstance(ack)) ack.generateFilterLocked(gen);
}
- gen.defineLabel(skipV4KeepaliveFilter);
+ gen.defineLabel(label);
+ }
+
+ private void generateV4KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
+ generateFilters(gen, TcpKeepaliveAckV4.class, IPPROTO_TCP, IPV4_PROTOCOL_OFFSET,
+ "skip_v4_keepalive_filter");
+ }
+
+ private void generateV4NattKeepaliveFilters(ApfGenerator gen)
+ throws IllegalInstructionException {
+ generateFilters(gen, NattKeepaliveAckV4.class, IPPROTO_UDP, IPV4_PROTOCOL_OFFSET,
+ "skip_v4_nattkeepalive_filter");
}
/**
@@ -1294,24 +1417,8 @@
}
private void generateV6KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
- final String skipV6KeepaliveFilter = "skip_v6_keepalive_filter";
- final boolean haveV6KeepaliveAcks = NetworkStackUtils.any(mKeepaliveAcks,
- ack -> ack instanceof TcpKeepaliveAckV6);
-
- // If no keepalive acks
- if (!haveV6KeepaliveAcks) return;
-
- // If not tcp, skip keepalive filters
- gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
- gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipV6KeepaliveFilter);
-
- // Drop IPv6 Keepalive acks
- for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
- final TcpKeepaliveAck ack = mKeepaliveAcks.valueAt(i);
- if (ack instanceof TcpKeepaliveAckV6) ack.generateFilterLocked(gen);
- }
-
- gen.defineLabel(skipV6KeepaliveFilter);
+ generateFilters(gen, TcpKeepaliveAckV6.class, IPPROTO_TCP, IPV6_NEXT_HEADER_OFFSET,
+ "skip_v6_keepalive_filter");
}
/**
@@ -1701,11 +1808,11 @@
public synchronized void addTcpKeepalivePacketFilter(final int slot,
final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
log("Adding keepalive ack(" + slot + ")");
- if (null != mKeepaliveAcks.get(slot)) {
+ if (null != mKeepalivePackets.get(slot)) {
throw new IllegalArgumentException("Keepalive slot " + slot + " is occupied");
}
final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6;
- mKeepaliveAcks.put(slot, (ipVersion == 4)
+ mKeepalivePackets.put(slot, (ipVersion == 4)
? new TcpKeepaliveAckV4(sentKeepalivePacket)
: new TcpKeepaliveAckV6(sentKeepalivePacket));
installNewProgramLocked();
@@ -1720,7 +1827,15 @@
*/
public synchronized void addNattKeepalivePacketFilter(final int slot,
final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
- Log.e(TAG, "APF add NATT keepalive filter is not implemented");
+ log("Adding NAT-T keepalive packet(" + slot + ")");
+ if (null != mKeepalivePackets.get(slot)) {
+ throw new IllegalArgumentException("Natt Keepalive slot " + slot + " is occupied");
+ }
+ final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6;
+ mKeepalivePackets.put(slot, (ipVersion == 4)
+ ? new NattKeepaliveAckV4(sentKeepalivePacket)
+ : new NattKeepaliveAckV6(sentKeepalivePacket));
+ installNewProgramLocked();
}
/**
@@ -1729,7 +1844,8 @@
* @param slot The index used to access the filter.
*/
public synchronized void removeKeepalivePacketFilter(int slot) {
- mKeepaliveAcks.remove(slot);
+ log("Removing keepalive packet(" + slot + ")");
+ mKeepalivePackets.remove(slot);
installNewProgramLocked();
}
@@ -1785,14 +1901,29 @@
}
pw.decreaseIndent();
- pw.println("Keepalive filters:");
+ pw.println("TCP Keepalive filters:");
pw.increaseIndent();
- for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
- final TcpKeepaliveAck keepaliveAck = mKeepaliveAcks.valueAt(i);
- pw.print("Slot ");
- pw.print(mKeepaliveAcks.keyAt(i));
- pw.print(" : ");
- pw.println(keepaliveAck);
+ for (int i = 0; i < mKeepalivePackets.size(); ++i) {
+ final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
+ if (keepalivePacket instanceof TcpKeepaliveAck) {
+ pw.print("Slot ");
+ pw.print(mKeepalivePackets.keyAt(i));
+ pw.print(" : ");
+ pw.println(keepalivePacket);
+ }
+ }
+ pw.decreaseIndent();
+
+ pw.println("NAT-T Keepalive filters:");
+ pw.increaseIndent();
+ for (int i = 0; i < mKeepalivePackets.size(); ++i) {
+ final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
+ if (keepalivePacket instanceof NattKeepaliveAck) {
+ pw.print("Slot ");
+ pw.print(mKeepalivePackets.keyAt(i));
+ pw.print(" : ");
+ pw.println(keepalivePacket);
+ }
}
pw.decreaseIndent();
@@ -1858,4 +1989,18 @@
+ (uint8(bytes[2]) << 8)
+ (uint8(bytes[3]));
}
+
+ private static byte[] concatArrays(final byte[]... arr) {
+ int size = 0;
+ for (byte[] a : arr) {
+ size += a.length;
+ }
+ final byte[] result = new byte[size];
+ int offset = 0;
+ for (byte[] a : arr) {
+ System.arraycopy(a, 0, result, offset, a.length);
+ offset += a.length;
+ }
+ return result;
+ }
}
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index abfed3e..541f9d8 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -23,6 +23,8 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
import java.net.SocketException;
import java.util.List;
import java.util.function.Predicate;
@@ -227,4 +229,13 @@
private static native void addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname,
FileDescriptor fd) throws IOException;
+
+ /**
+ * Return IP address and port in a string format.
+ */
+ public static String addressAndPortToString(InetAddress address, int port) {
+ return String.format(
+ (address instanceof Inet6Address) ? "[%s]:%d" : "%s:%d",
+ address.getHostAddress(), port);
+ }
}
diff --git a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
index 93ab3be..41c3fab 100644
--- a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
+++ b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
@@ -40,6 +40,7 @@
import android.content.Context;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NattKeepalivePacketDataParcelable;
import android.net.TcpKeepalivePacketDataParcelable;
import android.net.apf.ApfFilter.ApfConfiguration;
import android.net.apf.ApfGenerator.IllegalInstructionException;
@@ -998,47 +999,54 @@
}
}
- private static final int ETH_HEADER_LEN = 14;
- private static final int ETH_DEST_ADDR_OFFSET = 0;
- private static final int ETH_ETHERTYPE_OFFSET = 12;
+ private static final int ETH_HEADER_LEN = 14;
+ private static final int ETH_DEST_ADDR_OFFSET = 0;
+ private static final int ETH_ETHERTYPE_OFFSET = 12;
private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
- private static final int IPV4_HEADER_LEN = 20;
- private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
+ private static final int IPV4_HEADER_LEN = 20;
+ private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
- private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
- private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12;
- private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
- private static final int IPV4_TCP_HEADER_LEN = 20;
- private static final int IPV4_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;
- private static final int IPV4_TCP_SRC_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 0;
- private static final int IPV4_TCP_DEST_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 2;
- private static final int IPV4_TCP_SEQ_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 4;
- private static final int IPV4_TCP_ACK_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 8;
+ private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
+ private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12;
+ private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
+
+ private static final int IPV4_TCP_HEADER_LEN = 20;
+ private static final int IPV4_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;
+ private static final int IPV4_TCP_SRC_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 0;
+ private static final int IPV4_TCP_DEST_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 2;
+ private static final int IPV4_TCP_SEQ_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 4;
+ private static final int IPV4_TCP_ACK_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 8;
private static final int IPV4_TCP_HEADER_LENGTH_OFFSET = IPV4_TCP_HEADER_OFFSET + 12;
- private static final int IPV4_TCP_HEADER_FLAG_OFFSET = IPV4_TCP_HEADER_OFFSET + 13;
+ private static final int IPV4_TCP_HEADER_FLAG_OFFSET = IPV4_TCP_HEADER_OFFSET + 13;
+
+ private static final int IPV4_UDP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;;
+ private static final int IPV4_UDP_SRC_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 0;
+ private static final int IPV4_UDP_DEST_PORT_OFFSET = IPV4_UDP_HEADER_OFFSET + 2;
+ private static final int IPV4_UDP_LENGTH_OFFSET = IPV4_UDP_HEADER_OFFSET + 4;
+ private static final int IPV4_UDP_PAYLOAD_OFFSET = IPV4_UDP_HEADER_OFFSET + 8;
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_HEADER_LEN = 40;
- private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
- private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
- private static final int IPV6_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
- private static final int IPV6_TCP_SRC_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 0;
- private static final int IPV6_TCP_DEST_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 2;
- private static final int IPV6_TCP_SEQ_NUM_OFFSET = IPV6_TCP_HEADER_OFFSET + 4;
- private static final int IPV6_TCP_ACK_NUM_OFFSET = IPV6_TCP_HEADER_OFFSET + 8;
+ private static final int IPV6_HEADER_LEN = 40;
+ private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
+ private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
+ private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
+ private static final int IPV6_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+ private static final int IPV6_TCP_SRC_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 0;
+ private static final int IPV6_TCP_DEST_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 2;
+ private static final int IPV6_TCP_SEQ_NUM_OFFSET = IPV6_TCP_HEADER_OFFSET + 4;
+ private static final int IPV6_TCP_ACK_NUM_OFFSET = IPV6_TCP_HEADER_OFFSET + 8;
// The IPv6 all nodes address ff02::1
- private static final byte[] IPV6_ALL_NODES_ADDRESS =
+ private static final byte[] IPV6_ALL_NODES_ADDRESS =
{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
private static final byte[] IPV6_ALL_ROUTERS_ADDRESS =
{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
- 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_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;
@@ -1050,9 +1058,9 @@
private static final int ICMP6_RA_OPTION_OFFSET =
ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
- private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
- private static final int ICMP6_PREFIX_OPTION_LEN = 32;
- private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
+ private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
+ private static final int ICMP6_PREFIX_OPTION_LEN = 32;
+ private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
// From RFC6106: Recursive DNS Server option
@@ -1063,17 +1071,17 @@
// From RFC4191: Route Information option
private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
// Above three options all have the same format:
- private static final int ICMP6_4_BYTE_OPTION_LEN = 8;
+ private static final int ICMP6_4_BYTE_OPTION_LEN = 8;
private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
- private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
+ private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
- private static final int UDP_HEADER_LEN = 8;
+ private static final int UDP_HEADER_LEN = 8;
private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 22;
- private static final int DHCP_CLIENT_PORT = 68;
+ private static final int DHCP_CLIENT_PORT = 68;
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 = {
0, 1, // Hardware type: Ethernet (1)
8, 0, // Protocol type: IP (0x0800)
@@ -1714,6 +1722,76 @@
return packet.array();
}
+ @Test
+ public void testApfFilterNattKeepalivePacket() throws Exception {
+ final MockIpClientCallback cb = new MockIpClientCallback();
+ final ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
+ byte[] program;
+ final int srcPort = 1024;
+ final int dstPort = 4500;
+ final int slot1 = 1;
+ // NAT-T keepalive
+ final byte[] payload = {(byte) 0xff};
+
+ // src: 10.0.0.5, port: 1024
+ // dst: 10.0.0.6, port: 4500
+ InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR);
+ InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR);
+
+ final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable();
+ parcel.srcAddress = srcAddr.getAddress();
+ parcel.srcPort = srcPort;
+ parcel.dstAddress = dstAddr.getAddress();
+ parcel.dstPort = dstPort;
+
+ apfFilter.addNattKeepalivePacketFilter(slot1, parcel);
+ program = cb.getApfProgram();
+
+ // Verify IPv4 keepalive packet is dropped
+ // src: 10.0.0.6, port: 4500
+ // dst: 10.0.0.5, port: 1024
+ final byte[] nattKaPkt = ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR,
+ IPV4_KEEPALIVE_SRC_ADDR, dstPort, srcPort, 1 /* dataLength */);
+ System.arraycopy(payload, 0, nattKaPkt, IPV4_UDP_PAYLOAD_OFFSET, payload.length);
+ assertDrop(program, nattKaPkt);
+ // Verify IPv4 non-keepalive packet from the same source address is passed
+ assertPass(program,
+ ipv4UdpPacket(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+ dstPort, srcPort, 10 /* dataLength */));
+ // Verify IPv4 non-keepalive packet from other source address is passed
+ assertPass(program,
+ ipv4UdpPacket(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+ dstPort, srcPort, 10 /* dataLength */));
+
+ apfFilter.removeKeepalivePacketFilter(slot1);
+ apfFilter.shutdown();
+ }
+
+ private static byte[] ipv4UdpPacket(byte[] sip, byte[] dip, int sport,
+ int dport, int dataLength) {
+ final int totalLength = dataLength + IPV4_HEADER_LEN + UDP_HEADER_LEN;
+ final int udpLength = UDP_HEADER_LEN + dataLength;
+ ByteBuffer packet = ByteBuffer.wrap(new byte[totalLength + ETH_HEADER_LEN]);
+
+ // ether type
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
+
+ // IPv4 header
+ packet.put(IPV4_VERSION_IHL_OFFSET, (byte) 0x45);
+ packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
+ packet.put(IPV4_PROTOCOL_OFFSET, (byte) IPPROTO_UDP);
+ put(packet, IPV4_SRC_ADDR_OFFSET, sip);
+ put(packet, IPV4_DEST_ADDR_OFFSET, dip);
+ packet.putShort(IPV4_UDP_SRC_PORT_OFFSET, (short) sport);
+ packet.putShort(IPV4_UDP_DEST_PORT_OFFSET, (short) dport);
+ packet.putShort(IPV4_UDP_LENGTH_OFFSET, (short) udpLength);
+
+ return packet.array();
+ }
+
// Verify that the last program pushed to the IpClient.Callback properly filters the
// given packet for the given lifetime.
private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 526b4ff..e10d737 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -462,9 +462,10 @@
}
public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) {
- HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
+ final HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
if (networkKeepalives != null) {
- for (KeepaliveInfo ki : networkKeepalives.values()) {
+ final ArrayList<KeepaliveInfo> kalist = new ArrayList(networkKeepalives.values());
+ for (KeepaliveInfo ki : kalist) {
ki.stop(reason);
// Clean up keepalives since the network agent is disconnected and unable to pass
// back asynchronous result of stop().
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index f8582cd..d05369e9 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -650,7 +650,7 @@
case INetd.PERMISSION_UPDATE_DEVICE_STATS:
updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
- case INetd.NO_PERMISSIONS:
+ case INetd.PERMISSION_NONE:
noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
case INetd.PERMISSION_UNINSTALLED:
@@ -676,7 +676,7 @@
ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
}
if (noPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.NO_PERMISSIONS,
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
ArrayUtils.convertToIntArray(noPermissionAppIds));
}
if (uninstalledAppIds.size() != 0) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 79b2081..5731646 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3783,10 +3783,12 @@
}
/**
- * Return the set of subscriber IDs that should be considered as "merged
- * together" for data usage purposes. This is commonly {@code null} to
- * indicate no merging is required. Any returned subscribers are sorted in a
- * deterministic order.
+ * Return the set of subscriber IDs that should be considered "merged together" for data usage
+ * purposes. This is commonly {@code null} to indicate no merging is required. Any returned
+ * subscribers are sorted in a deterministic order.
+ * <p>
+ * The returned set of subscriber IDs will include the subscriber ID corresponding to this
+ * TelephonyManager's subId.
*
* @hide
*/
@@ -3795,7 +3797,7 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.getMergedSubscriberIds(getOpPackageName());
+ return telephony.getMergedSubscriberIds(getSubId(), getOpPackageName());
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 7bbb0ab..6b927bb 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1051,7 +1051,17 @@
*/
String getLine1AlphaTagForDisplay(int subId, String callingPackage);
- String[] getMergedSubscriberIds(String callingPackage);
+ /**
+ * Return the set of subscriber IDs that should be considered "merged together" for data usage
+ * purposes. This is commonly {@code null} to indicate no merging is required. Any returned
+ * subscribers are sorted in a deterministic order.
+ * <p>
+ * The returned set of subscriber IDs will include the subscriber ID corresponding to this
+ * TelephonyManager's subId.
+ *
+ * @hide
+ */
+ String[] getMergedSubscriberIds(int subId, String callingPackage);
/**
* Override the operator branding for the current ICCID.
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 62a4718..df1f57f 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -524,7 +524,7 @@
SparseIntArray netdPermissionsAppIds = new SparseIntArray();
netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET);
- netdPermissionsAppIds.put(MOCK_UID2, INetd.NO_PERMISSIONS);
+ netdPermissionsAppIds.put(MOCK_UID2, INetd.PERMISSION_NONE);
netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS);
netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS);
@@ -534,7 +534,7 @@
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
new int[]{MOCK_UID1});
- mNetdServiceMonitor.expectPermission(INetd.NO_PERMISSIONS, new int[]{MOCK_UID2});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID2});
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS,
@@ -553,8 +553,8 @@
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
// Revoke permission from SYSTEM_UID1, expect no permission stored.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.NO_PERMISSIONS);
- mNetdServiceMonitor.expectPermission(INetd.NO_PERMISSIONS, new int[]{SYSTEM_UID1});
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.PERMISSION_NONE);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1});
}
private PackageInfo addPackage(String packageName, int uid, String[] permissions)
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index 269b6c5..550edd3 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -106,7 +106,7 @@
}
void* cookie = nullptr;
- result = StartIteration(collection->handle_, &cookie, nullptr, nullptr);
+ result = StartIteration(collection->handle_, &cookie);
if (result != 0) {
if (out_error) *out_error = ErrorCodeString(result);
return {};