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