Have ConnectivityService install packet filters when possible
Listen for ICMP6 router advertisements on networks that support packet filters. Construct packet filters and install them to ignore redundant future ICMP6 router advertisements. Bug: 26238573 Change-Id: If78300b9fda257c21f3ee6533e1da7de9f897cb4
This commit is contained in:
committed by
Lorenzo Colitti
parent
6a6903553b
commit
9eca1f6072
@@ -200,6 +200,14 @@ public abstract class NetworkAgent extends Handler {
|
||||
*/
|
||||
public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
|
||||
|
||||
/**
|
||||
* Sent by ConnectivityService to the NetworkAgent to install an APF program in the network
|
||||
* chipset for use to filter packets.
|
||||
*
|
||||
* obj = byte[] containing the APF program bytecode.
|
||||
*/
|
||||
public static final int CMD_PUSH_APF_PROGRAM = BASE + 16;
|
||||
|
||||
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
|
||||
NetworkCapabilities nc, LinkProperties lp, int score) {
|
||||
this(looper, context, logTag, ni, nc, lp, score, null);
|
||||
@@ -319,6 +327,10 @@ public abstract class NetworkAgent extends Handler {
|
||||
preventAutomaticReconnect();
|
||||
break;
|
||||
}
|
||||
case CMD_PUSH_APF_PROGRAM: {
|
||||
installPacketFilter((byte[]) msg.obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,6 +506,15 @@ public abstract class NetworkAgent extends Handler {
|
||||
protected void preventAutomaticReconnect() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a packet filter.
|
||||
* @param filter an APF program to filter incoming packets.
|
||||
* @return {@code true} if filter successfully installed, {@code false} otherwise.
|
||||
*/
|
||||
protected boolean installPacketFilter(byte[] filter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void log(String s) {
|
||||
Log.d(LOG_TAG, "NetworkAgent: " + s);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,22 @@ public class NetworkMisc implements Parcelable {
|
||||
*/
|
||||
public String subscriberId;
|
||||
|
||||
/**
|
||||
* Version of APF instruction set supported for packet filtering. 0 indicates no support for
|
||||
* packet filtering using APF programs.
|
||||
*/
|
||||
public int apfVersionSupported;
|
||||
|
||||
/**
|
||||
* Maximum size of APF program allowed.
|
||||
*/
|
||||
public int maximumApfProgramSize;
|
||||
|
||||
/**
|
||||
* Format of packets passed to APF filter. Should be one of ARPHRD_*
|
||||
*/
|
||||
public int apfPacketFormat;
|
||||
|
||||
public NetworkMisc() {
|
||||
}
|
||||
|
||||
@@ -65,6 +81,9 @@ public class NetworkMisc implements Parcelable {
|
||||
explicitlySelected = nm.explicitlySelected;
|
||||
acceptUnvalidated = nm.acceptUnvalidated;
|
||||
subscriberId = nm.subscriberId;
|
||||
apfVersionSupported = nm.apfVersionSupported;
|
||||
maximumApfProgramSize = nm.maximumApfProgramSize;
|
||||
apfPacketFormat = nm.apfPacketFormat;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +98,9 @@ public class NetworkMisc implements Parcelable {
|
||||
out.writeInt(explicitlySelected ? 1 : 0);
|
||||
out.writeInt(acceptUnvalidated ? 1 : 0);
|
||||
out.writeString(subscriberId);
|
||||
out.writeInt(apfVersionSupported);
|
||||
out.writeInt(maximumApfProgramSize);
|
||||
out.writeInt(apfPacketFormat);
|
||||
}
|
||||
|
||||
public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
|
||||
@@ -89,6 +111,9 @@ public class NetworkMisc implements Parcelable {
|
||||
networkMisc.explicitlySelected = in.readInt() != 0;
|
||||
networkMisc.acceptUnvalidated = in.readInt() != 0;
|
||||
networkMisc.subscriberId = in.readString();
|
||||
networkMisc.apfVersionSupported = in.readInt();
|
||||
networkMisc.maximumApfProgramSize = in.readInt();
|
||||
networkMisc.apfPacketFormat = in.readInt();
|
||||
return networkMisc;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,13 @@ public class NetworkUtils {
|
||||
*/
|
||||
public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
|
||||
|
||||
/**
|
||||
* Attaches a socket filter that accepts ICMP6 router advertisement packets to the given socket.
|
||||
* @param fd the socket's {@link FileDescriptor}.
|
||||
* @param packetType the hardware address type, one of ARPHRD_*.
|
||||
*/
|
||||
public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException;
|
||||
|
||||
/**
|
||||
* Binds the current process to the network designated by {@code netId}. All sockets created
|
||||
* in the future (and not explicitly bound via a bound {@link SocketFactory} (see
|
||||
|
||||
@@ -26,10 +26,13 @@
|
||||
#include <net/if.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <net/if_ether.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <cutils/properties.h>
|
||||
|
||||
@@ -64,7 +67,6 @@ static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
|
||||
|
||||
static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
|
||||
{
|
||||
int fd = jniGetFDFromFileDescriptor(env, javaFd);
|
||||
uint32_t ip_offset = sizeof(ether_header);
|
||||
uint32_t proto_offset = ip_offset + offsetof(iphdr, protocol);
|
||||
uint32_t flags_offset = ip_offset + offsetof(iphdr, frag_off);
|
||||
@@ -94,6 +96,45 @@ static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobje
|
||||
filter_code,
|
||||
};
|
||||
|
||||
int fd = jniGetFDFromFileDescriptor(env, javaFd);
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
|
||||
jniThrowExceptionFmt(env, "java/net/SocketException",
|
||||
"setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void android_net_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobject javaFd,
|
||||
jint hardwareAddressType)
|
||||
{
|
||||
if (hardwareAddressType != ARPHRD_ETHER) {
|
||||
jniThrowExceptionFmt(env, "java/net/SocketException",
|
||||
"attachRaFilter only supports ARPHRD_ETHER");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t ipv6_offset = sizeof(ether_header);
|
||||
uint32_t ipv6_next_header_offset = ipv6_offset + offsetof(ip6_hdr, ip6_nxt);
|
||||
uint32_t icmp6_offset = ipv6_offset + sizeof(ip6_hdr);
|
||||
uint32_t icmp6_type_offset = icmp6_offset + offsetof(icmp6_hdr, icmp6_type);
|
||||
struct sock_filter filter_code[] = {
|
||||
// Check IPv6 Next Header is ICMPv6.
|
||||
BPF_STMT(BPF_LD | BPF_B | BPF_ABS, ipv6_next_header_offset),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
|
||||
|
||||
// Check ICMPv6 type is Router Advertisement.
|
||||
BPF_STMT(BPF_LD | BPF_B | BPF_ABS, icmp6_type_offset),
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_ROUTER_ADVERT, 0, 1),
|
||||
|
||||
// Accept or reject.
|
||||
BPF_STMT(BPF_RET | BPF_K, 0xffff),
|
||||
BPF_STMT(BPF_RET | BPF_K, 0)
|
||||
};
|
||||
struct sock_fprog filter = {
|
||||
sizeof(filter_code) / sizeof(filter_code[0]),
|
||||
filter_code,
|
||||
};
|
||||
|
||||
int fd = jniGetFDFromFileDescriptor(env, javaFd);
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
|
||||
jniThrowExceptionFmt(env, "java/net/SocketException",
|
||||
"setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
|
||||
@@ -148,6 +189,7 @@ static const JNINativeMethod gNetworkUtilMethods[] = {
|
||||
{ "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
|
||||
{ "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
|
||||
{ "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
|
||||
{ "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter },
|
||||
};
|
||||
|
||||
int register_android_net_NetworkUtils(JNIEnv* env)
|
||||
|
||||
@@ -125,6 +125,7 @@ import com.android.server.connectivity.NetworkAgentInfo;
|
||||
import com.android.server.connectivity.NetworkMonitor;
|
||||
import com.android.server.connectivity.PacManager;
|
||||
import com.android.server.connectivity.PermissionMonitor;
|
||||
import com.android.server.connectivity.ApfFilter;
|
||||
import com.android.server.connectivity.Tethering;
|
||||
import com.android.server.connectivity.Vpn;
|
||||
import com.android.server.net.BaseNetworkObserver;
|
||||
@@ -359,6 +360,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
*/
|
||||
private static final int EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT = 31;
|
||||
|
||||
/**
|
||||
* used to push APF program to NetworkAgent
|
||||
* replyTo = NetworkAgent message handler
|
||||
* obj = byte[] of APF program
|
||||
*/
|
||||
private static final int EVENT_PUSH_APF_PROGRAM_TO_NETWORK = 32;
|
||||
|
||||
/** Handler thread used for both of the handlers below. */
|
||||
@VisibleForTesting
|
||||
protected final HandlerThread mHandlerThread;
|
||||
@@ -2188,6 +2196,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
mKeepaliveTracker.handleStopAllKeepalives(nai,
|
||||
ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
|
||||
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
|
||||
if (nai.apfFilter != null) nai.apfFilter.shutdown();
|
||||
mNetworkAgentInfos.remove(msg.replyTo);
|
||||
updateClat(null, nai.linkProperties, nai);
|
||||
synchronized (mNetworkForNetId) {
|
||||
@@ -2402,6 +2411,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
accept ? 1 : 0, always ? 1: 0, network));
|
||||
}
|
||||
|
||||
public void pushApfProgramToNetwork(NetworkAgentInfo nai, byte[] program) {
|
||||
enforceConnectivityInternalPermission();
|
||||
Message msg = mHandler.obtainMessage(EVENT_PUSH_APF_PROGRAM_TO_NETWORK, program);
|
||||
msg.replyTo = nai.messenger;
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) {
|
||||
if (DBG) log("handleSetAcceptUnvalidated network=" + network +
|
||||
" accept=" + accept + " always=" + always);
|
||||
@@ -2556,6 +2572,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
handleMobileDataAlwaysOn();
|
||||
break;
|
||||
}
|
||||
case EVENT_PUSH_APF_PROGRAM_TO_NETWORK: {
|
||||
NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
|
||||
if (nai == null) {
|
||||
loge("EVENT_PUSH_APF_PROGRAM_TO_NETWORK from unknown NetworkAgent");
|
||||
} else {
|
||||
nai.asyncChannel.sendMessage(NetworkAgent.CMD_PUSH_APF_PROGRAM,
|
||||
(byte[]) msg.obj);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Sent by KeepaliveTracker to process an app request on the state machine thread.
|
||||
case NetworkAgent.CMD_START_PACKET_KEEPALIVE: {
|
||||
mKeepaliveTracker.handleStartKeepalive(msg);
|
||||
@@ -3944,6 +3970,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
if (networkAgent.clatd != null) {
|
||||
networkAgent.clatd.fixupLinkProperties(oldLp);
|
||||
}
|
||||
if (networkAgent.apfFilter != null) {
|
||||
networkAgent.apfFilter.updateFilter();
|
||||
}
|
||||
|
||||
updateInterfaces(newLp, oldLp, netId);
|
||||
updateMtu(newLp, oldLp);
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.util.SparseArray;
|
||||
import com.android.internal.util.AsyncChannel;
|
||||
import com.android.server.ConnectivityService;
|
||||
import com.android.server.connectivity.NetworkMonitor;
|
||||
import com.android.server.connectivity.ApfFilter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
@@ -163,6 +164,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
||||
// Used by ConnectivityService to keep track of 464xlat.
|
||||
public Nat464Xlat clatd;
|
||||
|
||||
public ApfFilter apfFilter;
|
||||
|
||||
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
|
||||
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
|
||||
NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService) {
|
||||
@@ -175,6 +178,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
||||
currentScore = score;
|
||||
networkMonitor = connService.createNetworkMonitor(context, handler, this, defaultRequest);
|
||||
networkMisc = misc;
|
||||
apfFilter.maybeInstall(connService, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user