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
22#include <stdio.h>
23#include <string.h>
24#include <sys/ioctl.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/socket.h>
28#include <netinet/in.h>
29#include <arpa/inet.h>
30#include <errno.h>
31#include <fcntl.h>
32
33#include <linux/if.h>
34#include <linux/if_tun.h>
35#include <linux/route.h>
36#include <linux/ipv6_route.h>
37
38#include "jni.h"
39#include "JNIHelp.h"
40
41namespace android
42{
43
44static int inet4 = -1;
45static int inet6 = -1;
46
47static inline in_addr_t *as_in_addr(sockaddr *sa) {
48    return &((sockaddr_in *)sa)->sin_addr.s_addr;
49}
50
51//------------------------------------------------------------------------------
52
53#define SYSTEM_ERROR -1
54#define BAD_ARGUMENT -2
55
56static int create_interface(int mtu)
57{
58    int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
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        ALOGE("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        ALOGE("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        ALOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno));
81        goto error;
82    }
83
84    return tun;
85
86error:
87    close(tun);
88    return SYSTEM_ERROR;
89}
90
91static int get_interface_name(char *name, int tun)
92{
93    ifreq ifr4;
94    if (ioctl(tun, TUNGETIFF, &ifr4)) {
95        ALOGE("Cannot get interface name: %s", strerror(errno));
96        return SYSTEM_ERROR;
97    }
98    strncpy(name, ifr4.ifr_name, IFNAMSIZ);
99    return 0;
100}
101
102static int get_interface_index(const char *name)
103{
104    ifreq ifr4;
105    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
106    if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
107        ALOGE("Cannot get index of %s: %s", name, strerror(errno));
108        return SYSTEM_ERROR;
109    }
110    return ifr4.ifr_ifindex;
111}
112
113static int set_addresses(const char *name, const char *addresses)
114{
115    int index = get_interface_index(name);
116    if (index < 0) {
117        return index;
118    }
119
120    ifreq ifr4;
121    memset(&ifr4, 0, sizeof(ifr4));
122    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
123    ifr4.ifr_addr.sa_family = AF_INET;
124    ifr4.ifr_netmask.sa_family = AF_INET;
125
126    in6_ifreq ifr6;
127    memset(&ifr6, 0, sizeof(ifr6));
128    ifr6.ifr6_ifindex = index;
129
130    char address[65];
131    int prefix;
132    int chars;
133    int count = 0;
134
135    while (sscanf(addresses, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
136        addresses += chars;
137
138        if (strchr(address, ':')) {
139            // Add an IPv6 address.
140            if (inet_pton(AF_INET6, address, &ifr6.ifr6_addr) != 1 ||
141                    prefix < 0 || prefix > 128) {
142                count = BAD_ARGUMENT;
143                break;
144            }
145
146            ifr6.ifr6_prefixlen = prefix;
147            if (ioctl(inet6, SIOCSIFADDR, &ifr6)) {
148                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
149                break;
150            }
151        } else {
152            // Add an IPv4 address.
153            if (inet_pton(AF_INET, address, as_in_addr(&ifr4.ifr_addr)) != 1 ||
154                    prefix < 0 || prefix > 32) {
155                count = BAD_ARGUMENT;
156                break;
157            }
158
159            if (count) {
160                sprintf(ifr4.ifr_name, "%s:%d", name, count);
161            }
162            if (ioctl(inet4, SIOCSIFADDR, &ifr4)) {
163                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
164                break;
165            }
166
167            in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
168            *as_in_addr(&ifr4.ifr_netmask) = htonl(mask);
169            if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) {
170                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
171                break;
172            }
173        }
174        ALOGD("Address added on %s: %s/%d", name, address, prefix);
175        ++count;
176    }
177
178    if (count == BAD_ARGUMENT) {
179        ALOGE("Invalid address: %s/%d", address, prefix);
180    } else if (count == SYSTEM_ERROR) {
181        ALOGE("Cannot add address: %s/%d: %s", address, prefix, strerror(errno));
182    } else if (*addresses) {
183        ALOGE("Invalid address: %s", addresses);
184        count = BAD_ARGUMENT;
185    }
186
187    return count;
188}
189
190static int set_routes(const char *name, const char *routes)
191{
192    int index = get_interface_index(name);
193    if (index < 0) {
194        return index;
195    }
196
197    rtentry rt4;
198    memset(&rt4, 0, sizeof(rt4));
199    rt4.rt_dev = (char *)name;
200    rt4.rt_flags = RTF_UP;
201    rt4.rt_dst.sa_family = AF_INET;
202    rt4.rt_genmask.sa_family = AF_INET;
203
204    in6_rtmsg rt6;
205    memset(&rt6, 0, sizeof(rt6));
206    rt6.rtmsg_ifindex = index;
207    rt6.rtmsg_flags = RTF_UP;
208
209    char address[65];
210    int prefix;
211    int chars;
212    int count = 0;
213
214    while (sscanf(routes, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
215        routes += chars;
216
217        if (strchr(address, ':')) {
218            // Add an IPv6 route.
219            if (inet_pton(AF_INET6, address, &rt6.rtmsg_dst) != 1 ||
220                    prefix < 0 || prefix > 128) {
221                count = BAD_ARGUMENT;
222                break;
223            }
224
225            rt6.rtmsg_dst_len = prefix ? prefix : 1;
226            if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
227                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
228                break;
229            }
230
231            if (!prefix) {
232                // Split the route instead of replacing the default route.
233                rt6.rtmsg_dst.s6_addr[0] ^= 0x80;
234                if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
235                    count = SYSTEM_ERROR;
236                    break;
237                }
238            }
239        } else {
240            // Add an IPv4 route.
241            if (inet_pton(AF_INET, address, as_in_addr(&rt4.rt_dst)) != 1 ||
242                    prefix < 0 || prefix > 32) {
243                count = BAD_ARGUMENT;
244                break;
245            }
246
247            in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0x80000000;
248            *as_in_addr(&rt4.rt_genmask) = htonl(mask);
249            if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
250                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
251                break;
252            }
253
254            if (!prefix) {
255                // Split the route instead of replacing the default route.
256                *as_in_addr(&rt4.rt_dst) ^= htonl(0x80000000);
257                if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
258                    count = SYSTEM_ERROR;
259                    break;
260                }
261            }
262        }
263        ALOGD("Route added on %s: %s/%d", name, address, prefix);
264        ++count;
265    }
266
267    if (count == BAD_ARGUMENT) {
268        ALOGE("Invalid route: %s/%d", address, prefix);
269    } else if (count == SYSTEM_ERROR) {
270        ALOGE("Cannot add route: %s/%d: %s",
271                address, prefix, strerror(errno));
272    } else if (*routes) {
273        ALOGE("Invalid route: %s", routes);
274        count = BAD_ARGUMENT;
275    }
276
277    return count;
278}
279
280static int reset_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, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) {
287        ALOGE("Cannot reset %s: %s", name, strerror(errno));
288        return SYSTEM_ERROR;
289    }
290    return 0;
291}
292
293static int check_interface(const char *name)
294{
295    ifreq ifr4;
296    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
297    ifr4.ifr_flags = 0;
298
299    if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
300        ALOGE("Cannot check %s: %s", name, strerror(errno));
301    }
302    return ifr4.ifr_flags;
303}
304
305static int bind_to_interface(int socket, const char *name)
306{
307    if (setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name))) {
308        ALOGE("Cannot bind socket to %s: %s", name, strerror(errno));
309        return SYSTEM_ERROR;
310    }
311    return 0;
312}
313
314//------------------------------------------------------------------------------
315
316static void throwException(JNIEnv *env, int error, const char *message)
317{
318    if (error == SYSTEM_ERROR) {
319        jniThrowException(env, "java/lang/IllegalStateException", message);
320    } else {
321        jniThrowException(env, "java/lang/IllegalArgumentException", message);
322    }
323}
324
325static jint create(JNIEnv *env, jobject thiz, jint mtu)
326{
327    int tun = create_interface(mtu);
328    if (tun < 0) {
329        throwException(env, tun, "Cannot create interface");
330        return -1;
331    }
332    return tun;
333}
334
335static jstring getName(JNIEnv *env, jobject thiz, jint tun)
336{
337    char name[IFNAMSIZ];
338    if (get_interface_name(name, tun) < 0) {
339        throwException(env, SYSTEM_ERROR, "Cannot get interface name");
340        return NULL;
341    }
342    return env->NewStringUTF(name);
343}
344
345static jint setAddresses(JNIEnv *env, jobject thiz, jstring jName,
346        jstring jAddresses)
347{
348    const char *name = NULL;
349    const char *addresses = NULL;
350    int count = -1;
351
352    name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
353    if (!name) {
354        jniThrowNullPointerException(env, "name");
355        goto error;
356    }
357    addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
358    if (!addresses) {
359        jniThrowNullPointerException(env, "addresses");
360        goto error;
361    }
362    count = set_addresses(name, addresses);
363    if (count < 0) {
364        throwException(env, count, "Cannot set address");
365        count = -1;
366    }
367
368error:
369    if (name) {
370        env->ReleaseStringUTFChars(jName, name);
371    }
372    if (addresses) {
373        env->ReleaseStringUTFChars(jAddresses, addresses);
374    }
375    return count;
376}
377
378static jint setRoutes(JNIEnv *env, jobject thiz, jstring jName,
379        jstring jRoutes)
380{
381    const char *name = NULL;
382    const char *routes = NULL;
383    int count = -1;
384
385    name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
386    if (!name) {
387        jniThrowNullPointerException(env, "name");
388        goto error;
389    }
390    routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
391    if (!routes) {
392        jniThrowNullPointerException(env, "routes");
393        goto error;
394    }
395    count = set_routes(name, routes);
396    if (count < 0) {
397        throwException(env, count, "Cannot set route");
398        count = -1;
399    }
400
401error:
402    if (name) {
403        env->ReleaseStringUTFChars(jName, name);
404    }
405    if (routes) {
406        env->ReleaseStringUTFChars(jRoutes, routes);
407    }
408    return count;
409}
410
411static void reset(JNIEnv *env, jobject thiz, jstring jName)
412{
413    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
414    if (!name) {
415        jniThrowNullPointerException(env, "name");
416        return;
417    }
418    if (reset_interface(name) < 0) {
419        throwException(env, SYSTEM_ERROR, "Cannot reset interface");
420    }
421    env->ReleaseStringUTFChars(jName, name);
422}
423
424static jint check(JNIEnv *env, jobject thiz, jstring jName)
425{
426    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
427    if (!name) {
428        jniThrowNullPointerException(env, "name");
429        return 0;
430    }
431    int flags = check_interface(name);
432    env->ReleaseStringUTFChars(jName, name);
433    return flags;
434}
435
436static void protect(JNIEnv *env, jobject thiz, jint socket, jstring jName)
437{
438    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
439    if (!name) {
440        jniThrowNullPointerException(env, "name");
441        return;
442    }
443    if (bind_to_interface(socket, name) < 0) {
444        throwException(env, SYSTEM_ERROR, "Cannot protect socket");
445    }
446    env->ReleaseStringUTFChars(jName, name);
447}
448
449//------------------------------------------------------------------------------
450
451static JNINativeMethod gMethods[] = {
452    {"jniCreate", "(I)I", (void *)create},
453    {"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
454    {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
455    {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes},
456    {"jniReset", "(Ljava/lang/String;)V", (void *)reset},
457    {"jniCheck", "(Ljava/lang/String;)I", (void *)check},
458    {"jniProtect", "(ILjava/lang/String;)V", (void *)protect},
459};
460
461int register_android_server_connectivity_Vpn(JNIEnv *env)
462{
463    if (inet4 == -1) {
464        inet4 = socket(AF_INET, SOCK_DGRAM, 0);
465    }
466    if (inet6 == -1) {
467        inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
468    }
469    return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn",
470            gMethods, NELEM(gMethods));
471}
472
473};
474