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