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