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