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 
43 namespace android
44 {
45 
46 static int inet4 = -1;
47 static int inet6 = -1;
48 
as_in_addr(sockaddr * sa)49 static 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 
create_interface(int mtu)58 static int create_interface(int mtu)
59 {
60     int tun = open("/dev/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC);
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 
88 error:
89     close(tun);
90     return SYSTEM_ERROR;
91 }
92 
get_interface_name(char * name,int tun)93 static 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 
get_interface_index(const char * name)104 static 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 
set_addresses(const char * name,const char * addresses)115 static 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 
reset_interface(const char * name)192 static 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 
check_interface(const char * name)205 static 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 
modifyAddress(JNIEnv * env,jobject thiz,jstring jName,jstring jAddress,jint jPrefixLength,bool add)217 static 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 
throwException(JNIEnv * env,int error,const char * message)253 static 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 
create(JNIEnv * env,jobject,jint mtu)262 static 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 
getName(JNIEnv * env,jobject,jint tun)272 static 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 
setAddresses(JNIEnv * env,jobject,jstring jName,jstring jAddresses)282 static 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 
305 error:
306     if (name) {
307         env->ReleaseStringUTFChars(jName, name);
308     }
309     if (addresses) {
310         env->ReleaseStringUTFChars(jAddresses, addresses);
311     }
312     return count;
313 }
314 
reset(JNIEnv * env,jobject,jstring jName)315 static 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 
check(JNIEnv * env,jobject,jstring jName)328 static 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 
addAddress(JNIEnv * env,jobject thiz,jstring jName,jstring jAddress,jint jPrefixLength)340 static 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 
delAddress(JNIEnv * env,jobject thiz,jstring jName,jstring jAddress,jint jPrefixLength)346 static 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 
354 static 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 
register_android_server_connectivity_Vpn(JNIEnv * env)364 int 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