android_net_NetUtils.cpp revision cbe4f7c225f87ef1e8cb496bce434f334774bc88
1/* 2 * Copyright 2008, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "NetUtils" 18 19#include "jni.h" 20#include "JNIHelp.h" 21#include "NetdClient.h" 22#include <utils/misc.h> 23#include <android_runtime/AndroidRuntime.h> 24#include <utils/Log.h> 25#include <arpa/inet.h> 26#include <net/if.h> 27#include <linux/filter.h> 28#include <linux/if.h> 29#include <linux/if_ether.h> 30#include <linux/if_packet.h> 31#include <net/if_ether.h> 32#include <netinet/ip.h> 33#include <netinet/udp.h> 34#include <cutils/properties.h> 35 36#include "core_jni_helpers.h" 37 38extern "C" { 39int ifc_enable(const char *ifname); 40int ifc_disable(const char *ifname); 41int ifc_reset_connections(const char *ifname, int reset_mask); 42 43int dhcp_start(const char * const ifname); 44int dhcp_start_renew(const char * const ifname); 45int dhcp_get_results(const char * const ifname, 46 const char *ipaddr, 47 const char *gateway, 48 uint32_t *prefixLength, 49 const char *dns[], 50 const char *server, 51 uint32_t *lease, 52 const char *vendorInfo, 53 const char *domains, 54 const char *mtu); 55 56int dhcp_stop(const char *ifname); 57int dhcp_release_lease(const char *ifname); 58char *dhcp_get_errmsg(); 59} 60 61#define NETUTILS_PKG_NAME "android/net/NetworkUtils" 62 63namespace android { 64 65static const uint16_t kDhcpClientPort = 68; 66 67/* 68 * The following remembers the jfieldID's of the fields 69 * of the DhcpInfo Java object, so that we don't have 70 * to look them up every time. 71 */ 72static struct fieldIds { 73 jmethodID clear; 74 jmethodID setIpAddress; 75 jmethodID setGateway; 76 jmethodID addDns; 77 jmethodID setDomains; 78 jmethodID setServerAddress; 79 jmethodID setLeaseDuration; 80 jmethodID setVendorInfo; 81} dhcpResultsFieldIds; 82 83static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, 84 jstring ifname, jint mask) 85{ 86 int result; 87 88 const char *nameStr = env->GetStringUTFChars(ifname, NULL); 89 90 ALOGD("android_net_utils_resetConnections in env=%p clazz=%p iface=%s mask=0x%x\n", 91 env, clazz, nameStr, mask); 92 93 result = ::ifc_reset_connections(nameStr, mask); 94 env->ReleaseStringUTFChars(ifname, nameStr); 95 return (jint)result; 96} 97 98static jboolean android_net_utils_getDhcpResults(JNIEnv* env, jobject clazz, jstring ifname, 99 jobject dhcpResults) 100{ 101 int result; 102 char ipaddr[PROPERTY_VALUE_MAX]; 103 uint32_t prefixLength; 104 char gateway[PROPERTY_VALUE_MAX]; 105 char dns1[PROPERTY_VALUE_MAX]; 106 char dns2[PROPERTY_VALUE_MAX]; 107 char dns3[PROPERTY_VALUE_MAX]; 108 char dns4[PROPERTY_VALUE_MAX]; 109 const char *dns[5] = {dns1, dns2, dns3, dns4, NULL}; 110 char server[PROPERTY_VALUE_MAX]; 111 uint32_t lease; 112 char vendorInfo[PROPERTY_VALUE_MAX]; 113 char domains[PROPERTY_VALUE_MAX]; 114 char mtu[PROPERTY_VALUE_MAX]; 115 116 const char *nameStr = env->GetStringUTFChars(ifname, NULL); 117 if (nameStr == NULL) return (jboolean)false; 118 119 result = ::dhcp_get_results(nameStr, ipaddr, gateway, &prefixLength, 120 dns, server, &lease, vendorInfo, domains, mtu); 121 if (result != 0) { 122 ALOGD("dhcp_get_results failed : %s (%s)", nameStr, ::dhcp_get_errmsg()); 123 } 124 125 env->ReleaseStringUTFChars(ifname, nameStr); 126 if (result == 0) { 127 env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear); 128 129 // set the linkAddress 130 // dhcpResults->addLinkAddress(inetAddress, prefixLength) 131 result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setIpAddress, 132 env->NewStringUTF(ipaddr), prefixLength); 133 } 134 135 if (result == 0) { 136 // set the gateway 137 result = env->CallBooleanMethod(dhcpResults, 138 dhcpResultsFieldIds.setGateway, env->NewStringUTF(gateway)); 139 } 140 141 if (result == 0) { 142 // dhcpResults->addDns(new InetAddress(dns1)) 143 result = env->CallBooleanMethod(dhcpResults, 144 dhcpResultsFieldIds.addDns, env->NewStringUTF(dns1)); 145 } 146 147 if (result == 0) { 148 env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setDomains, 149 env->NewStringUTF(domains)); 150 151 result = env->CallBooleanMethod(dhcpResults, 152 dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2)); 153 154 if (result == 0) { 155 result = env->CallBooleanMethod(dhcpResults, 156 dhcpResultsFieldIds.addDns, env->NewStringUTF(dns3)); 157 if (result == 0) { 158 result = env->CallBooleanMethod(dhcpResults, 159 dhcpResultsFieldIds.addDns, env->NewStringUTF(dns4)); 160 } 161 } 162 } 163 164 if (result == 0) { 165 // dhcpResults->setServerAddress(new InetAddress(server)) 166 result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setServerAddress, 167 env->NewStringUTF(server)); 168 } 169 170 if (result == 0) { 171 // dhcpResults->setLeaseDuration(lease) 172 env->CallVoidMethod(dhcpResults, 173 dhcpResultsFieldIds.setLeaseDuration, lease); 174 175 // dhcpResults->setVendorInfo(vendorInfo) 176 env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setVendorInfo, 177 env->NewStringUTF(vendorInfo)); 178 } 179 return (jboolean)(result == 0); 180} 181 182static jboolean android_net_utils_startDhcp(JNIEnv* env, jobject clazz, jstring ifname) 183{ 184 const char *nameStr = env->GetStringUTFChars(ifname, NULL); 185 if (nameStr == NULL) return (jboolean)false; 186 if (::dhcp_start(nameStr) != 0) { 187 ALOGD("dhcp_start failed : %s", nameStr); 188 return (jboolean)false; 189 } 190 return (jboolean)true; 191} 192 193static jboolean android_net_utils_startDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname) 194{ 195 const char *nameStr = env->GetStringUTFChars(ifname, NULL); 196 if (nameStr == NULL) return (jboolean)false; 197 if (::dhcp_start_renew(nameStr) != 0) { 198 ALOGD("dhcp_start_renew failed : %s", nameStr); 199 return (jboolean)false; 200 } 201 return (jboolean)true; 202} 203 204static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname) 205{ 206 int result; 207 208 const char *nameStr = env->GetStringUTFChars(ifname, NULL); 209 result = ::dhcp_stop(nameStr); 210 env->ReleaseStringUTFChars(ifname, nameStr); 211 return (jboolean)(result == 0); 212} 213 214static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname) 215{ 216 int result; 217 218 const char *nameStr = env->GetStringUTFChars(ifname, NULL); 219 result = ::dhcp_release_lease(nameStr); 220 env->ReleaseStringUTFChars(ifname, nameStr); 221 return (jboolean)(result == 0); 222} 223 224static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz) 225{ 226 return env->NewStringUTF(::dhcp_get_errmsg()); 227} 228 229static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd) 230{ 231 int fd = jniGetFDFromFileDescriptor(env, javaFd); 232 uint32_t ip_offset = sizeof(ether_header); 233 uint32_t proto_offset = ip_offset + offsetof(iphdr, protocol); 234 uint32_t flags_offset = ip_offset + offsetof(iphdr, frag_off); 235 uint32_t dport_indirect_offset = ip_offset + offsetof(udphdr, dest); 236 struct sock_filter filter_code[] = { 237 // Check the protocol is UDP. 238 BPF_STMT(BPF_LD | BPF_B | BPF_ABS, proto_offset), 239 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 6), 240 241 // Check this is not a fragment. 242 BPF_STMT(BPF_LD | BPF_H | BPF_ABS, flags_offset), 243 BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, 0x1fff, 4, 0), 244 245 // Get the IP header length. 246 BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, ip_offset), 247 248 // Check the destination port. 249 BPF_STMT(BPF_LD | BPF_H | BPF_IND, dport_indirect_offset), 250 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 0, 1), 251 252 // Accept or reject. 253 BPF_STMT(BPF_RET | BPF_K, 0xffff), 254 BPF_STMT(BPF_RET | BPF_K, 0) 255 }; 256 struct sock_fprog filter = { 257 sizeof(filter_code) / sizeof(filter_code[0]), 258 filter_code, 259 }; 260 261 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) { 262 jniThrowExceptionFmt(env, "java/net/SocketException", 263 "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno)); 264 } 265} 266 267static jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId) 268{ 269 return (jboolean) !setNetworkForProcess(netId); 270} 271 272static jint android_net_utils_getNetworkBoundToProcess(JNIEnv *env, jobject thiz) 273{ 274 return getNetworkForProcess(); 275} 276 277static jboolean android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz, 278 jint netId) 279{ 280 return (jboolean) !setNetworkForResolv(netId); 281} 282 283static jint android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket, 284 jint netId) 285{ 286 return setNetworkForSocket(netId, socket); 287} 288 289static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket) 290{ 291 return (jboolean) !protectFromVpn(socket); 292} 293 294 295// ---------------------------------------------------------------------------- 296 297/* 298 * JNI registration. 299 */ 300static JNINativeMethod gNetworkUtilMethods[] = { 301 /* name, signature, funcPtr */ 302 { "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections }, 303 { "startDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_startDhcp }, 304 { "startDhcpRenew", "(Ljava/lang/String;)Z", (void *)android_net_utils_startDhcpRenew }, 305 { "getDhcpResults", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z", (void *)android_net_utils_getDhcpResults }, 306 { "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp }, 307 { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease }, 308 { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError }, 309 { "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork }, 310 { "getNetworkBoundToProcess", "()I", (void*) android_net_utils_getNetworkBoundToProcess }, 311 { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution }, 312 { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork }, 313 { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn }, 314 { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter }, 315}; 316 317int register_android_net_NetworkUtils(JNIEnv* env) 318{ 319 jclass dhcpResultsClass = FindClassOrDie(env, "android/net/DhcpResults"); 320 321 dhcpResultsFieldIds.clear = GetMethodIDOrDie(env, dhcpResultsClass, "clear", "()V"); 322 dhcpResultsFieldIds.setIpAddress =GetMethodIDOrDie(env, dhcpResultsClass, "setIpAddress", 323 "(Ljava/lang/String;I)Z"); 324 dhcpResultsFieldIds.setGateway = GetMethodIDOrDie(env, dhcpResultsClass, "setGateway", 325 "(Ljava/lang/String;)Z"); 326 dhcpResultsFieldIds.addDns = GetMethodIDOrDie(env, dhcpResultsClass, "addDns", 327 "(Ljava/lang/String;)Z"); 328 dhcpResultsFieldIds.setDomains = GetMethodIDOrDie(env, dhcpResultsClass, "setDomains", 329 "(Ljava/lang/String;)V"); 330 dhcpResultsFieldIds.setServerAddress = GetMethodIDOrDie(env, dhcpResultsClass, 331 "setServerAddress", "(Ljava/lang/String;)Z"); 332 dhcpResultsFieldIds.setLeaseDuration = GetMethodIDOrDie(env, dhcpResultsClass, 333 "setLeaseDuration", "(I)V"); 334 dhcpResultsFieldIds.setVendorInfo = GetMethodIDOrDie(env, dhcpResultsClass, "setVendorInfo", 335 "(Ljava/lang/String;)V"); 336 337 return RegisterMethodsOrDie(env, NETUTILS_PKG_NAME, gNetworkUtilMethods, 338 NELEM(gNetworkUtilMethods)); 339} 340 341}; // namespace android 342