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