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 
     21 #include <arpa/inet.h>
     22 #include <errno.h>
     23 #include <fcntl.h>
     24 #include <linux/if.h>
     25 #include <linux/if_tun.h>
     26 #include <linux/route.h>
     27 #include <linux/ipv6_route.h>
     28 #include <netinet/in.h>
     29 #include <stdio.h>
     30 #include <string.h>
     31 #include <sys/ioctl.h>
     32 #include <sys/socket.h>
     33 #include <sys/stat.h>
     34 #include <sys/types.h>
     35 
     36 #include <log/log.h>
     37 
     38 #include "netutils/ifc.h"
     39 
     40 #include "jni.h"
     41 #include <nativehelper/JNIHelp.h>
     42 
     43 namespace android
     44 {
     45 
     46 static int inet4 = -1;
     47 static int inet6 = -1;
     48 
     49 static inline in_addr_t *as_in_addr(sockaddr *sa) {
     50     return &((sockaddr_in *)sa)->sin_addr.s_addr;
     51 }
     52 
     53 //------------------------------------------------------------------------------
     54 
     55 #define SYSTEM_ERROR (-1)
     56 #define BAD_ARGUMENT (-2)
     57 
     58 static int create_interface(int mtu)
     59 {
     60     int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
     61 
     62     ifreq ifr4;
     63     memset(&ifr4, 0, sizeof(ifr4));
     64 
     65     // Allocate interface.
     66     ifr4.ifr_flags = IFF_TUN | IFF_NO_PI;
     67     if (ioctl(tun, TUNSETIFF, &ifr4)) {
     68         ALOGE("Cannot allocate TUN: %s", strerror(errno));
     69         goto error;
     70     }
     71 
     72     // Activate interface.
     73     ifr4.ifr_flags = IFF_UP;
     74     if (ioctl(inet4, SIOCSIFFLAGS, &ifr4)) {
     75         ALOGE("Cannot activate %s: %s", ifr4.ifr_name, strerror(errno));
     76         goto error;
     77     }
     78 
     79     // Set MTU if it is specified.
     80     ifr4.ifr_mtu = mtu;
     81     if (mtu > 0 && ioctl(inet4, SIOCSIFMTU, &ifr4)) {
     82         ALOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno));
     83         goto error;
     84     }
     85 
     86     return tun;
     87 
     88 error:
     89     close(tun);
     90     return SYSTEM_ERROR;
     91 }
     92 
     93 static int get_interface_name(char *name, int tun)
     94 {
     95     ifreq ifr4;
     96     if (ioctl(tun, TUNGETIFF, &ifr4)) {
     97         ALOGE("Cannot get interface name: %s", strerror(errno));
     98         return SYSTEM_ERROR;
     99     }
    100     strncpy(name, ifr4.ifr_name, IFNAMSIZ);
    101     return 0;
    102 }
    103 
    104 static int get_interface_index(const char *name)
    105 {
    106     ifreq ifr4;
    107     strncpy(ifr4.ifr_name, name, IFNAMSIZ);
    108     if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
    109         ALOGE("Cannot get index of %s: %s", name, strerror(errno));
    110         return SYSTEM_ERROR;
    111     }
    112     return ifr4.ifr_ifindex;
    113 }
    114 
    115 static int set_addresses(const char *name, const char *addresses)
    116 {
    117     int index = get_interface_index(name);
    118     if (index < 0) {
    119         return index;
    120     }
    121 
    122     ifreq ifr4;
    123     memset(&ifr4, 0, sizeof(ifr4));
    124     strncpy(ifr4.ifr_name, name, IFNAMSIZ);
    125     ifr4.ifr_addr.sa_family = AF_INET;
    126     ifr4.ifr_netmask.sa_family = AF_INET;
    127 
    128     in6_ifreq ifr6;
    129     memset(&ifr6, 0, sizeof(ifr6));
    130     ifr6.ifr6_ifindex = index;
    131 
    132     char address[65];
    133     int prefix;
    134     int chars;
    135     int count = 0;
    136 
    137     while (sscanf(addresses, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
    138         addresses += chars;
    139 
    140         if (strchr(address, ':')) {
    141             // Add an IPv6 address.
    142             if (inet_pton(AF_INET6, address, &ifr6.ifr6_addr) != 1 ||
    143                     prefix < 0 || prefix > 128) {
    144                 count = BAD_ARGUMENT;
    145                 break;
    146             }
    147 
    148             ifr6.ifr6_prefixlen = prefix;
    149             if (ioctl(inet6, SIOCSIFADDR, &ifr6)) {
    150                 count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
    151                 break;
    152             }
    153         } else {
    154             // Add an IPv4 address.
    155             if (inet_pton(AF_INET, address, as_in_addr(&ifr4.ifr_addr)) != 1 ||
    156                     prefix < 0 || prefix > 32) {
    157                 count = BAD_ARGUMENT;
    158                 break;
    159             }
    160 
    161             if (count) {
    162                 snprintf(ifr4.ifr_name, sizeof(ifr4.ifr_name), "%s:%d", name, count);
    163             }
    164             if (ioctl(inet4, SIOCSIFADDR, &ifr4)) {
    165                 count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
    166                 break;
    167             }
    168 
    169             in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
    170             *as_in_addr(&ifr4.ifr_netmask) = htonl(mask);
    171             if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) {
    172                 count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
    173                 break;
    174             }
    175         }
    176         ALOGD("Address added on %s: %s/%d", name, address, prefix);
    177         ++count;
    178     }
    179 
    180     if (count == BAD_ARGUMENT) {
    181         ALOGE("Invalid address: %s/%d", address, prefix);
    182     } else if (count == SYSTEM_ERROR) {
    183         ALOGE("Cannot add address: %s/%d: %s", address, prefix, strerror(errno));
    184     } else if (*addresses) {
    185         ALOGE("Invalid address: %s", addresses);
    186         count = BAD_ARGUMENT;
    187     }
    188 
    189     return count;
    190 }
    191 
    192 static int reset_interface(const char *name)
    193 {
    194     ifreq ifr4;
    195     strncpy(ifr4.ifr_name, name, IFNAMSIZ);
    196     ifr4.ifr_flags = 0;
    197 
    198     if (ioctl(inet4, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) {
    199         ALOGE("Cannot reset %s: %s", name, strerror(errno));
    200         return SYSTEM_ERROR;
    201     }
    202     return 0;
    203 }
    204 
    205 static int check_interface(const char *name)
    206 {
    207     ifreq ifr4;
    208     strncpy(ifr4.ifr_name, name, IFNAMSIZ);
    209     ifr4.ifr_flags = 0;
    210 
    211     if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
    212         ALOGE("Cannot check %s: %s", name, strerror(errno));
    213     }
    214     return ifr4.ifr_flags;
    215 }
    216 
    217 static bool modifyAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress,
    218                           jint jPrefixLength, bool add)
    219 {
    220     int error = SYSTEM_ERROR;
    221     const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
    222     const char *address = jAddress ? env->GetStringUTFChars(jAddress, NULL) : NULL;
    223 
    224     if (!name) {
    225         jniThrowNullPointerException(env, "name");
    226     } else if (!address) {
    227         jniThrowNullPointerException(env, "address");
    228     } else {
    229         if (add) {
    230             if ((error = ifc_add_address(name, address, jPrefixLength)) != 0) {
    231                 ALOGE("Cannot add address %s/%d on interface %s (%s)", address, jPrefixLength, name,
    232                       strerror(-error));
    233             }
    234         } else {
    235             if ((error = ifc_del_address(name, address, jPrefixLength)) != 0) {
    236                 ALOGE("Cannot del address %s/%d on interface %s (%s)", address, jPrefixLength, name,
    237                       strerror(-error));
    238             }
    239         }
    240     }
    241 
    242     if (name) {
    243         env->ReleaseStringUTFChars(jName, name);
    244     }
    245     if (address) {
    246         env->ReleaseStringUTFChars(jAddress, address);
    247     }
    248     return !error;
    249 }
    250 
    251 //------------------------------------------------------------------------------
    252 
    253 static void throwException(JNIEnv *env, int error, const char *message)
    254 {
    255     if (error == SYSTEM_ERROR) {
    256         jniThrowException(env, "java/lang/IllegalStateException", message);
    257     } else {
    258         jniThrowException(env, "java/lang/IllegalArgumentException", message);
    259     }
    260 }
    261 
    262 static jint create(JNIEnv *env, jobject /* thiz */, jint mtu)
    263 {
    264     int tun = create_interface(mtu);
    265     if (tun < 0) {
    266         throwException(env, tun, "Cannot create interface");
    267         return -1;
    268     }
    269     return tun;
    270 }
    271 
    272 static jstring getName(JNIEnv *env, jobject /* thiz */, jint tun)
    273 {
    274     char name[IFNAMSIZ];
    275     if (get_interface_name(name, tun) < 0) {
    276         throwException(env, SYSTEM_ERROR, "Cannot get interface name");
    277         return NULL;
    278     }
    279     return env->NewStringUTF(name);
    280 }
    281 
    282 static jint setAddresses(JNIEnv *env, jobject /* thiz */, jstring jName,
    283         jstring jAddresses)
    284 {
    285     const char *name = NULL;
    286     const char *addresses = NULL;
    287     int count = -1;
    288 
    289     name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
    290     if (!name) {
    291         jniThrowNullPointerException(env, "name");
    292         goto error;
    293     }
    294     addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
    295     if (!addresses) {
    296         jniThrowNullPointerException(env, "addresses");
    297         goto error;
    298     }
    299     count = set_addresses(name, addresses);
    300     if (count < 0) {
    301         throwException(env, count, "Cannot set address");
    302         count = -1;
    303     }
    304 
    305 error:
    306     if (name) {
    307         env->ReleaseStringUTFChars(jName, name);
    308     }
    309     if (addresses) {
    310         env->ReleaseStringUTFChars(jAddresses, addresses);
    311     }
    312     return count;
    313 }
    314 
    315 static void reset(JNIEnv *env, jobject /* thiz */, jstring jName)
    316 {
    317     const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
    318     if (!name) {
    319         jniThrowNullPointerException(env, "name");
    320         return;
    321     }
    322     if (reset_interface(name) < 0) {
    323         throwException(env, SYSTEM_ERROR, "Cannot reset interface");
    324     }
    325     env->ReleaseStringUTFChars(jName, name);
    326 }
    327 
    328 static jint check(JNIEnv *env, jobject /* thiz */, jstring jName)
    329 {
    330     const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
    331     if (!name) {
    332         jniThrowNullPointerException(env, "name");
    333         return 0;
    334     }
    335     int flags = check_interface(name);
    336     env->ReleaseStringUTFChars(jName, name);
    337     return flags;
    338 }
    339 
    340 static bool addAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress,
    341                        jint jPrefixLength)
    342 {
    343     return modifyAddress(env, thiz, jName, jAddress, jPrefixLength, true);
    344 }
    345 
    346 static bool delAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress,
    347                        jint jPrefixLength)
    348 {
    349     return modifyAddress(env, thiz, jName, jAddress, jPrefixLength, false);
    350 }
    351 
    352 //------------------------------------------------------------------------------
    353 
    354 static const JNINativeMethod gMethods[] = {
    355     {"jniCreate", "(I)I", (void *)create},
    356     {"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
    357     {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
    358     {"jniReset", "(Ljava/lang/String;)V", (void *)reset},
    359     {"jniCheck", "(Ljava/lang/String;)I", (void *)check},
    360     {"jniAddAddress", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)addAddress},
    361     {"jniDelAddress", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)delAddress},
    362 };
    363 
    364 int register_android_server_connectivity_Vpn(JNIEnv *env)
    365 {
    366     if (inet4 == -1) {
    367         inet4 = socket(AF_INET, SOCK_DGRAM, 0);
    368     }
    369     if (inet6 == -1) {
    370         inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
    371     }
    372     return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn",
    373             gMethods, NELEM(gMethods));
    374 }
    375 
    376 };
    377