com_android_server_connectivity_Vpn.cpp revision 84bf7390ea6b9a82bbd036b64c41d7c120b7f159
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    int flags;
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    // Get interface index.
85    if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
86        LOGE("Cannot get index of %s: %s", ifr4.ifr_name, strerror(errno));
87        goto error;
88    }
89
90    // Make it non-blocking.
91    flags = fcntl(tun, F_GETFL, 0);
92    if (flags == -1 || fcntl(tun, F_SETFL, flags | O_NONBLOCK)) {
93        LOGE("Cannot set non-blocking on %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
197    in6_rtmsg rt6;
198    memset(&rt6, 0, sizeof(rt6));
199    rt6.rtmsg_ifindex = index;
200    rt6.rtmsg_flags = RTF_UP;
201
202    char address[65];
203    int prefix;
204
205    int chars;
206    int count = 0;
207
208    while (sscanf(routes, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
209        routes += chars;
210
211        if (strchr(address, ':')) {
212            // Add an IPv6 route.
213            if (inet_pton(AF_INET6, address, &rt6.rtmsg_dst) != 1 ||
214                    prefix < 1 || prefix > 128) {
215                count = BAD_ARGUMENT;
216                break;
217            }
218
219            rt6.rtmsg_dst_len = prefix;
220            if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
221                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
222                break;
223            }
224        } else {
225            // Add an IPv4 route.
226            if (inet_pton(AF_INET, address, as_in_addr(&rt4.rt_dst)) != 1 ||
227                    prefix < 1 || prefix > 32) {
228                count = BAD_ARGUMENT;
229                break;
230            }
231
232            in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
233            *as_in_addr(&rt4.rt_genmask) = htonl(mask);
234            if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
235                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
236                break;
237            }
238        }
239        LOGV("Route added on %s: %s/%d", name, address, prefix);
240        ++count;
241    }
242
243    if (count == BAD_ARGUMENT) {
244        LOGE("Invalid route: %s/%d", address, prefix);
245    } else if (count == SYSTEM_ERROR) {
246        LOGE("Cannot add route: %s/%d: %s",
247                address, prefix, strerror(errno));
248    } else if (*routes) {
249        LOGE("Invalid route: %s", routes);
250        count = BAD_ARGUMENT;
251    }
252
253    close(inet4);
254    close(inet6);
255    return count;
256}
257
258static int get_interface_name(char *name, int tun)
259{
260    ifreq ifr4;
261    if (ioctl(tun, TUNGETIFF, &ifr4)) {
262        LOGE("Cannot get interface name: %s", strerror(errno));
263        return SYSTEM_ERROR;
264    }
265    strcpy(name, ifr4.ifr_name);
266    return 0;
267}
268
269static int reset_interface(const char *name)
270{
271    int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
272
273    ifreq ifr4;
274    ifr4.ifr_flags = 0;
275    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
276
277    if (ioctl(inet4, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) {
278        LOGE("Cannot reset %s: %s", name, strerror(errno));
279        close(inet4);
280        return SYSTEM_ERROR;
281    }
282    close(inet4);
283    return 0;
284}
285
286static int check_interface(const char *name)
287{
288    int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
289
290    ifreq ifr4;
291    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
292    ifr4.ifr_flags = 0;
293
294    if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
295        LOGE("Cannot check %s: %s", name, strerror(errno));
296    }
297    close(inet4);
298    return ifr4.ifr_flags;
299}
300
301static int bind_to_interface(int fd, const char *name)
302{
303    if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name))) {
304        LOGE("Cannot bind socket to %s: %s", name, strerror(errno));
305        return SYSTEM_ERROR;
306    }
307    return 0;
308}
309
310//------------------------------------------------------------------------------
311
312static void throwException(JNIEnv *env, int error, const char *message)
313{
314    if (error == SYSTEM_ERROR) {
315        jniThrowException(env, "java/lang/IllegalStateException", message);
316    } else {
317        jniThrowException(env, "java/lang/IllegalArgumentException", message);
318    }
319}
320
321static jint establish(JNIEnv *env, jobject thiz,
322        jint mtu, jstring jAddresses, jstring jRoutes)
323{
324    char name[IFNAMSIZ];
325    int index;
326    int tun = create_interface(mtu, name, &index);
327    if (tun < 0) {
328        throwException(env, tun, "Cannot create interface");
329        return -1;
330    }
331    LOGD("%s is created", name);
332
333    const char *addresses;
334    const char *routes;
335    int count;
336
337    // Addresses are required.
338    addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
339    if (!addresses) {
340        jniThrowNullPointerException(env, "address");
341        goto error;
342    }
343    count = set_addresses(name, index, addresses);
344    env->ReleaseStringUTFChars(jAddresses, addresses);
345    if (count <= 0) {
346        throwException(env, count, "Cannot set address");
347        goto error;
348    }
349    LOGD("Configured %d address(es) on %s", count, name);
350
351    // Routes are optional.
352    routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
353    if (routes) {
354        count = set_routes(name, index, routes);
355        env->ReleaseStringUTFChars(jRoutes, routes);
356        if (count < 0) {
357            throwException(env, count, "Cannot set route");
358            goto error;
359        }
360        LOGD("Configured %d route(s) on %s", count, name);
361    }
362
363    return tun;
364
365error:
366    close(tun);
367    LOGD("%s is destroyed", name);
368    return -1;
369}
370
371static jstring getName(JNIEnv *env, jobject thiz, jint fd)
372{
373    char name[IFNAMSIZ];
374    if (get_interface_name(name, fd) < 0) {
375        throwException(env, SYSTEM_ERROR, "Cannot get interface name");
376        return NULL;
377    }
378    return env->NewStringUTF(name);
379}
380
381static void reset(JNIEnv *env, jobject thiz, jstring jName)
382{
383    const char *name = jName ?
384            env->GetStringUTFChars(jName, NULL) : NULL;
385    if (!name) {
386        jniThrowNullPointerException(env, "name");
387        return;
388    }
389    if (reset_interface(name) < 0) {
390        throwException(env, SYSTEM_ERROR, "Cannot reset interface");
391    } else {
392        LOGD("%s is deactivated", name);
393    }
394    env->ReleaseStringUTFChars(jName, name);
395}
396
397static jint check(JNIEnv *env, jobject thiz, jstring jName)
398{
399    const char *name = jName ?
400            env->GetStringUTFChars(jName, NULL) : NULL;
401    if (!name) {
402        jniThrowNullPointerException(env, "name");
403        return 0;
404    }
405    int flags = check_interface(name);
406    env->ReleaseStringUTFChars(jName, name);
407    return flags;
408}
409
410static void protect(JNIEnv *env, jobject thiz, jint fd, jstring jName)
411{
412    const char *name = jName ?
413            env->GetStringUTFChars(jName, NULL) : NULL;
414    if (!name) {
415        jniThrowNullPointerException(env, "name");
416        return;
417    }
418    if (bind_to_interface(fd, name) < 0) {
419        throwException(env, SYSTEM_ERROR, "Cannot protect socket");
420    }
421    env->ReleaseStringUTFChars(jName, name);
422}
423
424//------------------------------------------------------------------------------
425
426static JNINativeMethod gMethods[] = {
427    {"nativeEstablish", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)establish},
428    {"nativeGetName", "(I)Ljava/lang/String;", (void *)getName},
429    {"nativeReset", "(Ljava/lang/String;)V", (void *)reset},
430    {"nativeCheck", "(Ljava/lang/String;)I", (void *)check},
431    {"nativeProtect", "(ILjava/lang/String;)V", (void *)protect},
432};
433
434int register_android_server_connectivity_Vpn(JNIEnv *env)
435{
436    return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn",
437            gMethods, NELEM(gMethods));
438}
439
440};
441