From 4e5831aeccf98a14b7894537ccbbe4cef77f5bfc Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Fri, 4 Jan 2019 19:46:47 +0800 Subject: [PATCH] Add jni method for DnsResolver Test: built, flashed, booted atest DnsResolverTest Change-Id: Iff730ec918f4db1ba0216f90a12550fe26e271d0 --- core/java/android/net/NetworkUtils.java | 28 ++++++++ core/jni/android_net_NetUtils.cpp | 88 +++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index c0aa4a6faf..7f4d8cd1cf 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -34,6 +34,8 @@ import java.util.Collection; import java.util.Locale; import java.util.TreeSet; +import android.system.ErrnoException; + /** * Native methods for managing network interfaces. * @@ -132,6 +134,32 @@ public class NetworkUtils { */ public native static boolean queryUserAccess(int uid, int netId); + /** + * DNS resolver series jni method. + * Issue the query {@code msg} on the network designated by {@code netId}. + * {@code flags} is an additional config to control actual querying behavior. + * @return a file descriptor to watch for read events + */ + public static native FileDescriptor resNetworkSend( + int netId, byte[] msg, int msglen, int flags) throws ErrnoException; + + /** + * DNS resolver series jni method. + * Look up the {@code nsClass} {@code nsType} Resource Record (RR) associated + * with Domain Name {@code dname} on the network designated by {@code netId}. + * {@code flags} is an additional config to control actual querying behavior. + * @return a file descriptor to watch for read events + */ + public static native FileDescriptor resNetworkQuery( + int netId, String dname, int nsClass, int nsType, int flags) throws ErrnoException; + + /** + * DNS resolver series jni method. + * Read a result for the query associated with the {@code fd}. + * @return a byte array containing blob answer + */ + public static native byte[] resNetworkResult(FileDescriptor fd) throws ErrnoException; + /** * Add an entry into the ARP cache. */ diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 9b138ebb76..7eddcfe425 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -16,8 +16,11 @@ #define LOG_TAG "NetUtils" +#include + #include "jni.h" #include +#include #include "NetdClient.h" #include #include @@ -55,6 +58,31 @@ static const uint32_t kUDPSrcPortIndirectOffset = kEtherHeaderLen + offsetof(udp static const uint32_t kUDPDstPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, dest); static const uint16_t kDhcpClientPort = 68; +constexpr int MAXPACKETSIZE = 8 * 1024; +// FrameworkListener limits the size of commands to 1024 bytes. TODO: fix this. +constexpr int MAXCMDSIZE = 1024; + +static void throwErrnoException(JNIEnv* env, const char* functionName, int error) { + ScopedLocalRef detailMessage(env, env->NewStringUTF(functionName)); + if (detailMessage.get() == NULL) { + // Not really much we can do here. We're probably dead in the water, + // but let's try to stumble on... + env->ExceptionClear(); + } + static jclass errnoExceptionClass = + MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/system/ErrnoException")); + + static jmethodID errnoExceptionCtor = + GetMethodIDOrDie(env, errnoExceptionClass, + "", "(Ljava/lang/String;I)V"); + + jobject exception = env->NewObject(errnoExceptionClass, + errnoExceptionCtor, + detailMessage.get(), + error); + env->Throw(reinterpret_cast(exception)); +} + static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd) { struct sock_filter filter_code[] = { @@ -372,6 +400,63 @@ static void android_net_utils_addArpEntry(JNIEnv *env, jobject thiz, jbyteArray } } +static jobject android_net_utils_resNetworkQuery(JNIEnv *env, jobject thiz, jint netId, + jstring dname, jint ns_class, jint ns_type, jint flags) { + const jsize javaCharsCount = env->GetStringLength(dname); + const jsize byteCountUTF8 = env->GetStringUTFLength(dname); + + // Only allow dname which could be simply formatted to UTF8. + // In native layer, res_mkquery would re-format the input char array to packet. + std::vector queryname(byteCountUTF8 + 1, 0); + + env->GetStringUTFRegion(dname, 0, javaCharsCount, queryname.data()); + int fd = resNetworkQuery(netId, queryname.data(), ns_class, ns_type, flags); + + if (fd < 0) { + throwErrnoException(env, "resNetworkQuery", -fd); + return nullptr; + } + + return jniCreateFileDescriptor(env, fd); +} + +static jobject android_net_utils_resNetworkSend(JNIEnv *env, jobject thiz, jint netId, + jbyteArray msg, jint msgLen, jint flags) { + uint8_t data[MAXCMDSIZE]; + + checkLenAndCopy(env, msg, msgLen, data); + int fd = resNetworkSend(netId, data, msgLen, flags); + + if (fd < 0) { + throwErrnoException(env, "resNetworkSend", -fd); + return nullptr; + } + + return jniCreateFileDescriptor(env, fd); +} + +static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) { + int fd = jniGetFDFromFileDescriptor(env, javaFd); + int rcode; + std::vector buf(MAXPACKETSIZE, 0); + + int res = resNetworkResult(fd, &rcode, buf.data(), MAXPACKETSIZE); + if (res < 0) { + throwErrnoException(env, "resNetworkResult", -res); + return nullptr; + } + + jbyteArray answer = env->NewByteArray(res); + if (answer == nullptr) { + throwErrnoException(env, "resNetworkResult", ENOMEM); + return nullptr; + } else { + env->SetByteArrayRegion(answer, 0, res, + reinterpret_cast(buf.data())); + } + + return answer; +} // ---------------------------------------------------------------------------- @@ -391,6 +476,9 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter }, { "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachControlPacketFilter }, { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_setupRaSocket }, + { "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend }, + { "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery }, + { "resNetworkResult", "(Ljava/io/FileDescriptor;)[B", (void*) android_net_utils_resNetworkResult }, }; int register_android_net_NetworkUtils(JNIEnv* env)