com_android_server_connectivity_Vpn.cpp revision c2b8aa0b4c822b0e307f62131650f4a6ee89bb66
1/* 2 * Copyright (C) 2011 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_NDEBUG 0 18 19#define LOG_TAG "VpnJni" 20#include <cutils/log.h> 21#include <cutils/properties.h> 22 23#include <stdio.h> 24#include <string.h> 25#include <sys/ioctl.h> 26#include <sys/types.h> 27#include <sys/stat.h> 28#include <sys/socket.h> 29#include <netinet/in.h> 30#include <arpa/inet.h> 31#include <errno.h> 32#include <fcntl.h> 33 34#include <linux/if.h> 35#include <linux/if_tun.h> 36#include <linux/route.h> 37#include <linux/ipv6_route.h> 38 39#include "jni.h" 40#include "JNIHelp.h" 41 42namespace android 43{ 44 45static int inet4 = -1; 46static int inet6 = -1; 47 48static inline in_addr_t *as_in_addr(sockaddr *sa) { 49 return &((sockaddr_in *)sa)->sin_addr.s_addr; 50} 51 52//------------------------------------------------------------------------------ 53 54#define SYSTEM_ERROR -1 55#define BAD_ARGUMENT -2 56 57static int create_interface(char *name, int *index, int mtu) 58{ 59 int tun = open("/dev/tun", O_RDWR | O_NONBLOCK); 60 61 ifreq ifr4; 62 memset(&ifr4, 0, sizeof(ifr4)); 63 64 // Allocate interface. 65 ifr4.ifr_flags = IFF_TUN | IFF_NO_PI; 66 if (ioctl(tun, TUNSETIFF, &ifr4)) { 67 LOGE("Cannot allocate TUN: %s", strerror(errno)); 68 goto error; 69 } 70 71 // Activate interface. 72 ifr4.ifr_flags = IFF_UP; 73 if (ioctl(inet4, SIOCSIFFLAGS, &ifr4)) { 74 LOGE("Cannot activate %s: %s", ifr4.ifr_name, strerror(errno)); 75 goto error; 76 } 77 78 // Set MTU if it is specified. 79 ifr4.ifr_mtu = mtu; 80 if (mtu > 0 && ioctl(inet4, SIOCSIFMTU, &ifr4)) { 81 LOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno)); 82 goto error; 83 } 84 85 // Get interface index. 86 if (ioctl(inet4, SIOGIFINDEX, &ifr4)) { 87 LOGE("Cannot get index of %s: %s", ifr4.ifr_name, strerror(errno)); 88 goto error; 89 } 90 91 strncpy(name, ifr4.ifr_name, IFNAMSIZ); 92 *index = ifr4.ifr_ifindex; 93 return tun; 94 95error: 96 close(tun); 97 return SYSTEM_ERROR; 98} 99 100static int set_addresses(const char *name, int index, const char *addresses) 101{ 102 ifreq ifr4; 103 memset(&ifr4, 0, sizeof(ifr4)); 104 strncpy(ifr4.ifr_name, name, IFNAMSIZ); 105 ifr4.ifr_addr.sa_family = AF_INET; 106 107 in6_ifreq ifr6; 108 memset(&ifr6, 0, sizeof(ifr6)); 109 ifr6.ifr6_ifindex = index; 110 111 char address[65]; 112 int prefix; 113 int chars; 114 int count = 0; 115 116 while (sscanf(addresses, " %64[^/]/%d %n", address, &prefix, &chars) == 2) { 117 addresses += chars; 118 119 if (strchr(address, ':')) { 120 // Add an IPv6 address. 121 if (inet_pton(AF_INET6, address, &ifr6.ifr6_addr) != 1 || 122 prefix < 0 || prefix > 128) { 123 count = BAD_ARGUMENT; 124 break; 125 } 126 127 ifr6.ifr6_prefixlen = prefix; 128 if (ioctl(inet6, SIOCSIFADDR, &ifr6)) { 129 count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; 130 break; 131 } 132 } else { 133 // Add an IPv4 address. 134 if (inet_pton(AF_INET, address, as_in_addr(&ifr4.ifr_addr)) != 1 || 135 prefix < 0 || prefix > 32) { 136 count = BAD_ARGUMENT; 137 break; 138 } 139 140 if (count) { 141 sprintf(ifr4.ifr_name, "%s:%d", name, count); 142 } 143 if (ioctl(inet4, SIOCSIFADDR, &ifr4)) { 144 count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; 145 break; 146 } 147 148 in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0; 149 *as_in_addr(&ifr4.ifr_addr) = htonl(mask); 150 if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) { 151 count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; 152 break; 153 } 154 } 155 LOGD("Address added on %s: %s/%d", name, address, prefix); 156 ++count; 157 } 158 159 if (count == BAD_ARGUMENT) { 160 LOGE("Invalid address: %s/%d", address, prefix); 161 } else if (count == SYSTEM_ERROR) { 162 LOGE("Cannot add address: %s/%d: %s", address, prefix, strerror(errno)); 163 } else if (*addresses) { 164 LOGE("Invalid address: %s", addresses); 165 count = BAD_ARGUMENT; 166 } 167 168 return count; 169} 170 171static int set_routes(const char *name, int index, const char *routes) 172{ 173 rtentry rt4; 174 memset(&rt4, 0, sizeof(rt4)); 175 rt4.rt_dev = (char *)name; 176 rt4.rt_flags = RTF_UP; 177 rt4.rt_dst.sa_family = AF_INET; 178 rt4.rt_genmask.sa_family = AF_INET; 179 180 in6_rtmsg rt6; 181 memset(&rt6, 0, sizeof(rt6)); 182 rt6.rtmsg_ifindex = index; 183 rt6.rtmsg_flags = RTF_UP; 184 185 char address[65]; 186 int prefix; 187 int chars; 188 int count = 0; 189 190 while (sscanf(routes, " %64[^/]/%d %n", address, &prefix, &chars) == 2) { 191 routes += chars; 192 193 if (strchr(address, ':')) { 194 // Add an IPv6 route. 195 if (inet_pton(AF_INET6, address, &rt6.rtmsg_dst) != 1 || 196 prefix < 0 || prefix > 128) { 197 count = BAD_ARGUMENT; 198 break; 199 } 200 201 rt6.rtmsg_dst_len = prefix ? prefix : 1; 202 if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) { 203 count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; 204 break; 205 } 206 207 if (!prefix) { 208 // Split the route instead of replacing the default route. 209 rt6.rtmsg_dst.s6_addr[0] ^= 0x80; 210 if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) { 211 count = SYSTEM_ERROR; 212 break; 213 } 214 } 215 } else { 216 // Add an IPv4 route. 217 if (inet_pton(AF_INET, address, as_in_addr(&rt4.rt_dst)) != 1 || 218 prefix < 0 || prefix > 32) { 219 count = BAD_ARGUMENT; 220 break; 221 } 222 223 in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0x80000000; 224 *as_in_addr(&rt4.rt_genmask) = htonl(mask); 225 if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) { 226 count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; 227 break; 228 } 229 230 if (!prefix) { 231 // Split the route instead of replacing the default route. 232 *as_in_addr(&rt4.rt_dst) ^= htonl(0x80000000); 233 if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) { 234 count = SYSTEM_ERROR; 235 break; 236 } 237 } 238 } 239 LOGD("Route added on %s: %s/%d", name, address, prefix); 240 ++count; 241 } 242 243 if (count == BAD_ARGUMENT) { 244 LOGE("Invalid route: %s/%d", address, prefix); 245 } else if (count == SYSTEM_ERROR) { 246 LOGE("Cannot add route: %s/%d: %s", 247 address, prefix, strerror(errno)); 248 } else if (*routes) { 249 LOGE("Invalid route: %s", routes); 250 count = BAD_ARGUMENT; 251 } 252 253 return count; 254} 255 256static int get_interface_name(char *name, int tun) 257{ 258 ifreq ifr4; 259 if (ioctl(tun, TUNGETIFF, &ifr4)) { 260 LOGE("Cannot get interface name: %s", strerror(errno)); 261 return SYSTEM_ERROR; 262 } 263 strncpy(name, ifr4.ifr_name, IFNAMSIZ); 264 return 0; 265} 266 267static int reset_interface(const char *name) 268{ 269 ifreq ifr4; 270 strncpy(ifr4.ifr_name, name, IFNAMSIZ); 271 ifr4.ifr_flags = 0; 272 273 if (ioctl(inet4, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) { 274 LOGE("Cannot reset %s: %s", name, strerror(errno)); 275 return SYSTEM_ERROR; 276 } 277 return 0; 278} 279 280static int check_interface(const char *name) 281{ 282 ifreq ifr4; 283 strncpy(ifr4.ifr_name, name, IFNAMSIZ); 284 ifr4.ifr_flags = 0; 285 286 if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) { 287 LOGE("Cannot check %s: %s", name, strerror(errno)); 288 } 289 return ifr4.ifr_flags; 290} 291 292static int bind_to_interface(int socket, const char *name) 293{ 294 if (setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name))) { 295 LOGE("Cannot bind socket to %s: %s", name, strerror(errno)); 296 return SYSTEM_ERROR; 297 } 298 return 0; 299} 300 301//------------------------------------------------------------------------------ 302 303static void throwException(JNIEnv *env, int error, const char *message) 304{ 305 if (error == SYSTEM_ERROR) { 306 jniThrowException(env, "java/lang/IllegalStateException", message); 307 } else { 308 jniThrowException(env, "java/lang/IllegalArgumentException", message); 309 } 310} 311 312static jint configure(JNIEnv *env, jobject thiz, 313 jint mtu, jstring jAddresses, jstring jRoutes) 314{ 315 char name[IFNAMSIZ]; 316 int index; 317 int tun = create_interface(name, &index, mtu); 318 if (tun < 0) { 319 throwException(env, tun, "Cannot create interface"); 320 return -1; 321 } 322 323 const char *addresses = NULL; 324 const char *routes = NULL; 325 int count; 326 327 // At least one address must be set. 328 addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL; 329 if (!addresses) { 330 jniThrowNullPointerException(env, "address"); 331 goto error; 332 } 333 count = set_addresses(name, index, addresses); 334 env->ReleaseStringUTFChars(jAddresses, addresses); 335 if (count <= 0) { 336 throwException(env, count, "Cannot set address"); 337 goto error; 338 } 339 LOGD("Configured %d address(es) on %s", count, name); 340 341 // On the contrary, routes are optional. 342 routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL; 343 if (routes) { 344 count = set_routes(name, index, routes); 345 env->ReleaseStringUTFChars(jRoutes, routes); 346 if (count < 0) { 347 throwException(env, count, "Cannot set route"); 348 goto error; 349 } 350 LOGD("Configured %d route(s) on %s", count, name); 351 } 352 353 return tun; 354 355error: 356 close(tun); 357 LOGD("%s is destroyed", name); 358 return -1; 359} 360 361static jstring getName(JNIEnv *env, jobject thiz, jint tun) 362{ 363 char name[IFNAMSIZ]; 364 if (get_interface_name(name, tun) < 0) { 365 throwException(env, SYSTEM_ERROR, "Cannot get interface name"); 366 return NULL; 367 } 368 return env->NewStringUTF(name); 369} 370 371static void reset(JNIEnv *env, jobject thiz, jstring jName) 372{ 373 const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL; 374 if (!name) { 375 jniThrowNullPointerException(env, "name"); 376 return; 377 } 378 if (reset_interface(name) < 0) { 379 throwException(env, SYSTEM_ERROR, "Cannot reset interface"); 380 } 381 env->ReleaseStringUTFChars(jName, name); 382} 383 384static jint check(JNIEnv *env, jobject thiz, jstring jName) 385{ 386 const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL; 387 if (!name) { 388 jniThrowNullPointerException(env, "name"); 389 return 0; 390 } 391 int flags = check_interface(name); 392 env->ReleaseStringUTFChars(jName, name); 393 return flags; 394} 395 396static void protect(JNIEnv *env, jobject thiz, jint socket, jstring jName) 397{ 398 const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL; 399 if (!name) { 400 jniThrowNullPointerException(env, "name"); 401 return; 402 } 403 if (bind_to_interface(socket, name) < 0) { 404 throwException(env, SYSTEM_ERROR, "Cannot protect socket"); 405 } 406 env->ReleaseStringUTFChars(jName, name); 407} 408 409//------------------------------------------------------------------------------ 410 411static JNINativeMethod gMethods[] = { 412 {"jniConfigure", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)configure}, 413 {"jniGetName", "(I)Ljava/lang/String;", (void *)getName}, 414 {"jniReset", "(Ljava/lang/String;)V", (void *)reset}, 415 {"jniCheck", "(Ljava/lang/String;)I", (void *)check}, 416 {"jniProtect", "(ILjava/lang/String;)V", (void *)protect}, 417}; 418 419int register_android_server_connectivity_Vpn(JNIEnv *env) 420{ 421 if (inet4 == -1) { 422 inet4 = socket(AF_INET, SOCK_DGRAM, 0); 423 } 424 if (inet6 == -1) { 425 inet6 = socket(AF_INET6, SOCK_DGRAM, 0); 426 } 427 return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn", 428 gMethods, NELEM(gMethods)); 429} 430 431}; 432