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
21#include <arpa/inet.h>
22#include <errno.h>
23#include <fcntl.h>
24#include <linux/if.h>
25#include <linux/if_tun.h>
26#include <linux/route.h>
27#include <linux/ipv6_route.h>
28#include <netinet/in.h>
29#include <stdio.h>
30#include <string.h>
31#include <sys/ioctl.h>
32#include <sys/socket.h>
33#include <sys/stat.h>
34#include <sys/types.h>
35
36#include <log/log.h>
37
38#include "netutils/ifc.h"
39
40#include "jni.h"
41#include <nativehelper/JNIHelp.h>
42
43namespace android
44{
45
46static int inet4 = -1;
47static int inet6 = -1;
48
49static inline in_addr_t *as_in_addr(sockaddr *sa) {
50    return &((sockaddr_in *)sa)->sin_addr.s_addr;
51}
52
53//------------------------------------------------------------------------------
54
55#define SYSTEM_ERROR (-1)
56#define BAD_ARGUMENT (-2)
57
58static int create_interface(int mtu)
59{
60    int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
61
62    ifreq ifr4;
63    memset(&ifr4, 0, sizeof(ifr4));
64
65    // Allocate interface.
66    ifr4.ifr_flags = IFF_TUN | IFF_NO_PI;
67    if (ioctl(tun, TUNSETIFF, &ifr4)) {
68        ALOGE("Cannot allocate TUN: %s", strerror(errno));
69        goto error;
70    }
71
72    // Activate interface.
73    ifr4.ifr_flags = IFF_UP;
74    if (ioctl(inet4, SIOCSIFFLAGS, &ifr4)) {
75        ALOGE("Cannot activate %s: %s", ifr4.ifr_name, strerror(errno));
76        goto error;
77    }
78
79    // Set MTU if it is specified.
80    ifr4.ifr_mtu = mtu;
81    if (mtu > 0 && ioctl(inet4, SIOCSIFMTU, &ifr4)) {
82        ALOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno));
83        goto error;
84    }
85
86    return tun;
87
88error:
89    close(tun);
90    return SYSTEM_ERROR;
91}
92
93static int get_interface_name(char *name, int tun)
94{
95    ifreq ifr4;
96    if (ioctl(tun, TUNGETIFF, &ifr4)) {
97        ALOGE("Cannot get interface name: %s", strerror(errno));
98        return SYSTEM_ERROR;
99    }
100    strncpy(name, ifr4.ifr_name, IFNAMSIZ);
101    return 0;
102}
103
104static int get_interface_index(const char *name)
105{
106    ifreq ifr4;
107    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
108    if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
109        ALOGE("Cannot get index of %s: %s", name, strerror(errno));
110        return SYSTEM_ERROR;
111    }
112    return ifr4.ifr_ifindex;
113}
114
115static int set_addresses(const char *name, const char *addresses)
116{
117    int index = get_interface_index(name);
118    if (index < 0) {
119        return index;
120    }
121
122    ifreq ifr4;
123    memset(&ifr4, 0, sizeof(ifr4));
124    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
125    ifr4.ifr_addr.sa_family = AF_INET;
126    ifr4.ifr_netmask.sa_family = AF_INET;
127
128    in6_ifreq ifr6;
129    memset(&ifr6, 0, sizeof(ifr6));
130    ifr6.ifr6_ifindex = index;
131
132    char address[65];
133    int prefix;
134    int chars;
135    int count = 0;
136
137    while (sscanf(addresses, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
138        addresses += chars;
139
140        if (strchr(address, ':')) {
141            // Add an IPv6 address.
142            if (inet_pton(AF_INET6, address, &ifr6.ifr6_addr) != 1 ||
143                    prefix < 0 || prefix > 128) {
144                count = BAD_ARGUMENT;
145                break;
146            }
147
148            ifr6.ifr6_prefixlen = prefix;
149            if (ioctl(inet6, SIOCSIFADDR, &ifr6)) {
150                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
151                break;
152            }
153        } else {
154            // Add an IPv4 address.
155            if (inet_pton(AF_INET, address, as_in_addr(&ifr4.ifr_addr)) != 1 ||
156                    prefix < 0 || prefix > 32) {
157                count = BAD_ARGUMENT;
158                break;
159            }
160
161            if (count) {
162                snprintf(ifr4.ifr_name, sizeof(ifr4.ifr_name), "%s:%d", name, count);
163            }
164            if (ioctl(inet4, SIOCSIFADDR, &ifr4)) {
165                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
166                break;
167            }
168
169            in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
170            *as_in_addr(&ifr4.ifr_netmask) = htonl(mask);
171            if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) {
172                count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
173                break;
174            }
175        }
176        ALOGD("Address added on %s: %s/%d", name, address, prefix);
177        ++count;
178    }
179
180    if (count == BAD_ARGUMENT) {
181        ALOGE("Invalid address: %s/%d", address, prefix);
182    } else if (count == SYSTEM_ERROR) {
183        ALOGE("Cannot add address: %s/%d: %s", address, prefix, strerror(errno));
184    } else if (*addresses) {
185        ALOGE("Invalid address: %s", addresses);
186        count = BAD_ARGUMENT;
187    }
188
189    return count;
190}
191
192static int reset_interface(const char *name)
193{
194    ifreq ifr4;
195    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
196    ifr4.ifr_flags = 0;
197
198    if (ioctl(inet4, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) {
199        ALOGE("Cannot reset %s: %s", name, strerror(errno));
200        return SYSTEM_ERROR;
201    }
202    return 0;
203}
204
205static int check_interface(const char *name)
206{
207    ifreq ifr4;
208    strncpy(ifr4.ifr_name, name, IFNAMSIZ);
209    ifr4.ifr_flags = 0;
210
211    if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
212        ALOGE("Cannot check %s: %s", name, strerror(errno));
213    }
214    return ifr4.ifr_flags;
215}
216
217static bool modifyAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress,
218                          jint jPrefixLength, bool add)
219{
220    int error = SYSTEM_ERROR;
221    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
222    const char *address = jAddress ? env->GetStringUTFChars(jAddress, NULL) : NULL;
223
224    if (!name) {
225        jniThrowNullPointerException(env, "name");
226    } else if (!address) {
227        jniThrowNullPointerException(env, "address");
228    } else {
229        if (add) {
230            if ((error = ifc_add_address(name, address, jPrefixLength)) != 0) {
231                ALOGE("Cannot add address %s/%d on interface %s (%s)", address, jPrefixLength, name,
232                      strerror(-error));
233            }
234        } else {
235            if ((error = ifc_del_address(name, address, jPrefixLength)) != 0) {
236                ALOGE("Cannot del address %s/%d on interface %s (%s)", address, jPrefixLength, name,
237                      strerror(-error));
238            }
239        }
240    }
241
242    if (name) {
243        env->ReleaseStringUTFChars(jName, name);
244    }
245    if (address) {
246        env->ReleaseStringUTFChars(jAddress, address);
247    }
248    return !error;
249}
250
251//------------------------------------------------------------------------------
252
253static void throwException(JNIEnv *env, int error, const char *message)
254{
255    if (error == SYSTEM_ERROR) {
256        jniThrowException(env, "java/lang/IllegalStateException", message);
257    } else {
258        jniThrowException(env, "java/lang/IllegalArgumentException", message);
259    }
260}
261
262static jint create(JNIEnv *env, jobject /* thiz */, jint mtu)
263{
264    int tun = create_interface(mtu);
265    if (tun < 0) {
266        throwException(env, tun, "Cannot create interface");
267        return -1;
268    }
269    return tun;
270}
271
272static jstring getName(JNIEnv *env, jobject /* thiz */, jint tun)
273{
274    char name[IFNAMSIZ];
275    if (get_interface_name(name, tun) < 0) {
276        throwException(env, SYSTEM_ERROR, "Cannot get interface name");
277        return NULL;
278    }
279    return env->NewStringUTF(name);
280}
281
282static jint setAddresses(JNIEnv *env, jobject /* thiz */, jstring jName,
283        jstring jAddresses)
284{
285    const char *name = NULL;
286    const char *addresses = NULL;
287    int count = -1;
288
289    name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
290    if (!name) {
291        jniThrowNullPointerException(env, "name");
292        goto error;
293    }
294    addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
295    if (!addresses) {
296        jniThrowNullPointerException(env, "addresses");
297        goto error;
298    }
299    count = set_addresses(name, addresses);
300    if (count < 0) {
301        throwException(env, count, "Cannot set address");
302        count = -1;
303    }
304
305error:
306    if (name) {
307        env->ReleaseStringUTFChars(jName, name);
308    }
309    if (addresses) {
310        env->ReleaseStringUTFChars(jAddresses, addresses);
311    }
312    return count;
313}
314
315static void reset(JNIEnv *env, jobject /* thiz */, jstring jName)
316{
317    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
318    if (!name) {
319        jniThrowNullPointerException(env, "name");
320        return;
321    }
322    if (reset_interface(name) < 0) {
323        throwException(env, SYSTEM_ERROR, "Cannot reset interface");
324    }
325    env->ReleaseStringUTFChars(jName, name);
326}
327
328static jint check(JNIEnv *env, jobject /* thiz */, jstring jName)
329{
330    const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
331    if (!name) {
332        jniThrowNullPointerException(env, "name");
333        return 0;
334    }
335    int flags = check_interface(name);
336    env->ReleaseStringUTFChars(jName, name);
337    return flags;
338}
339
340static bool addAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress,
341                       jint jPrefixLength)
342{
343    return modifyAddress(env, thiz, jName, jAddress, jPrefixLength, true);
344}
345
346static bool delAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress,
347                       jint jPrefixLength)
348{
349    return modifyAddress(env, thiz, jName, jAddress, jPrefixLength, false);
350}
351
352//------------------------------------------------------------------------------
353
354static const JNINativeMethod gMethods[] = {
355    {"jniCreate", "(I)I", (void *)create},
356    {"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
357    {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
358    {"jniReset", "(Ljava/lang/String;)V", (void *)reset},
359    {"jniCheck", "(Ljava/lang/String;)I", (void *)check},
360    {"jniAddAddress", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)addAddress},
361    {"jniDelAddress", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)delAddress},
362};
363
364int register_android_server_connectivity_Vpn(JNIEnv *env)
365{
366    if (inet4 == -1) {
367        inet4 = socket(AF_INET, SOCK_DGRAM, 0);
368    }
369    if (inet6 == -1) {
370        inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
371    }
372    return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn",
373            gMethods, NELEM(gMethods));
374}
375
376};
377