diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2015-03-06 19:57:39 +0900 |
---|---|---|
committer | Lorenzo Colitti <lorenzo@google.com> | 2015-03-16 20:08:45 +0900 |
commit | 566e0cb692ef8be5ba01c874ebd9d2576be99fe4 (patch) | |
tree | 4ce4fe9cd8e0e025b351e64a8a6ab7d0fc89b8df /core | |
parent | 5671eedda0e8e5acf63697bd9f4d8c3027440184 (diff) | |
download | frameworks_base-566e0cb692ef8be5ba01c874ebd9d2576be99fe4.zip frameworks_base-566e0cb692ef8be5ba01c874ebd9d2576be99fe4.tar.gz frameworks_base-566e0cb692ef8be5ba01c874ebd9d2576be99fe4.tar.bz2 |
DHCP: Add a native method for making a DHCP socket.
Bug: 19704592
Change-Id: Iadd60d39c93aaabd2917e76791101a7d313b34be
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/net/NetworkUtils.java | 7 | ||||
-rw-r--r-- | core/jni/android_net_NetUtils.cpp | 50 |
2 files changed, 57 insertions, 0 deletions
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 4f35a22..01704e5 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -16,9 +16,11 @@ package android.net; +import java.io.FileDescriptor; import java.net.InetAddress; import java.net.Inet4Address; import java.net.Inet6Address; +import java.net.SocketException; import java.net.UnknownHostException; import java.util.Collection; import java.util.Locale; @@ -139,6 +141,11 @@ public class NetworkUtils { public native static String getDhcpError(); /** + * Attaches a socket filter that accepts DHCP packets to the given socket. + */ + public native static void attachDhcpFilter(FileDescriptor fd) 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 * {@link Network#getSocketFactory}) will be bound to this network. Note that if this diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index e64f1de..2ba8e8c 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -24,6 +24,14 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/Log.h> #include <arpa/inet.h> +#include <net/if.h> +#include <linux/filter.h> +#include <linux/if.h> +#include <linux/if_ether.h> +#include <linux/if_packet.h> +#include <net/if_ether.h> +#include <netinet/ip.h> +#include <netinet/udp.h> #include <cutils/properties.h> extern "C" { @@ -53,6 +61,8 @@ char *dhcp_get_errmsg(); namespace android { +static const uint16_t kDhcpClientPort = 68; + /* * The following remembers the jfieldID's of the fields * of the DhcpInfo Java object, so that we don't have @@ -215,6 +225,44 @@ static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz) return env->NewStringUTF(::dhcp_get_errmsg()); } +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); + uint32_t dport_indirect_offset = ip_offset + offsetof(udphdr, dest); + struct sock_filter filter_code[] = { + // Check the protocol is UDP. + BPF_STMT(BPF_LD | BPF_B | BPF_ABS, proto_offset), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 6), + + // Check this is not a fragment. + BPF_STMT(BPF_LD | BPF_H | BPF_ABS, flags_offset), + BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, 0x1fff, 4, 0), + + // Get the IP header length. + BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, ip_offset), + + // Check the destination port. + BPF_STMT(BPF_LD | BPF_H | BPF_IND, dport_indirect_offset), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 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, + }; + + 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 jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId) { return (jboolean) !setNetworkForProcess(netId); @@ -242,6 +290,7 @@ static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint return (jboolean) !protectFromVpn(socket); } + // ---------------------------------------------------------------------------- /* @@ -261,6 +310,7 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution }, { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork }, { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn }, + { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter }, }; int register_android_net_NetworkUtils(JNIEnv* env) |