• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
41 namespace android
42 {
43 
44 static int inet4 = -1;
45 static int inet6 = -1;
46 
as_in_addr(sockaddr * sa)47 static 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 
create_interface(int mtu)56 static 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 
86 error:
87     close(tun);
88     return SYSTEM_ERROR;
89 }
90 
get_interface_name(char * name,int tun)91 static 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 
get_interface_index(const char * name)102 static 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 
set_addresses(const char * name,const char * addresses)113 static 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 
set_routes(const char * name,const char * routes)190 static 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 
reset_interface(const char * name)280 static 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 
check_interface(const char * name)293 static 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 
305 //------------------------------------------------------------------------------
306 
throwException(JNIEnv * env,int error,const char * message)307 static void throwException(JNIEnv *env, int error, const char *message)
308 {
309     if (error == SYSTEM_ERROR) {
310         jniThrowException(env, "java/lang/IllegalStateException", message);
311     } else {
312         jniThrowException(env, "java/lang/IllegalArgumentException", message);
313     }
314 }
315 
create(JNIEnv * env,jobject thiz,jint mtu)316 static jint create(JNIEnv *env, jobject thiz, jint mtu)
317 {
318     int tun = create_interface(mtu);
319     if (tun < 0) {
320         throwException(env, tun, "Cannot create interface");
321         return -1;
322     }
323     return tun;
324 }
325 
getName(JNIEnv * env,jobject thiz,jint tun)326 static jstring getName(JNIEnv *env, jobject thiz, jint tun)
327 {
328     char name[IFNAMSIZ];
329     if (get_interface_name(name, tun) < 0) {
330         throwException(env, SYSTEM_ERROR, "Cannot get interface name");
331         return NULL;
332     }
333     return env->NewStringUTF(name);
334 }
335 
setAddresses(JNIEnv * env,jobject thiz,jstring jName,jstring jAddresses)336 static jint setAddresses(JNIEnv *env, jobject thiz, jstring jName,
337         jstring jAddresses)
338 {
339     const char *name = NULL;
340     const char *addresses = NULL;
341     int count = -1;
342 
343     name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
344     if (!name) {
345         jniThrowNullPointerException(env, "name");
346         goto error;
347     }
348     addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
349     if (!addresses) {
350         jniThrowNullPointerException(env, "addresses");
351         goto error;
352     }
353     count = set_addresses(name, addresses);
354     if (count < 0) {
355         throwException(env, count, "Cannot set address");
356         count = -1;
357     }
358 
359 error:
360     if (name) {
361         env->ReleaseStringUTFChars(jName, name);
362     }
363     if (addresses) {
364         env->ReleaseStringUTFChars(jAddresses, addresses);
365     }
366     return count;
367 }
368 
setRoutes(JNIEnv * env,jobject thiz,jstring jName,jstring jRoutes)369 static jint setRoutes(JNIEnv *env, jobject thiz, jstring jName,
370         jstring jRoutes)
371 {
372     const char *name = NULL;
373     const char *routes = NULL;
374     int count = -1;
375 
376     name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
377     if (!name) {
378         jniThrowNullPointerException(env, "name");
379         goto error;
380     }
381     routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
382     if (!routes) {
383         jniThrowNullPointerException(env, "routes");
384         goto error;
385     }
386     count = set_routes(name, routes);
387     if (count < 0) {
388         throwException(env, count, "Cannot set route");
389         count = -1;
390     }
391 
392 error:
393     if (name) {
394         env->ReleaseStringUTFChars(jName, name);
395     }
396     if (routes) {
397         env->ReleaseStringUTFChars(jRoutes, routes);
398     }
399     return count;
400 }
401 
reset(JNIEnv * env,jobject thiz,jstring jName)402 static void reset(JNIEnv *env, jobject thiz, jstring jName)
403 {
404     const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
405     if (!name) {
406         jniThrowNullPointerException(env, "name");
407         return;
408     }
409     if (reset_interface(name) < 0) {
410         throwException(env, SYSTEM_ERROR, "Cannot reset interface");
411     }
412     env->ReleaseStringUTFChars(jName, name);
413 }
414 
check(JNIEnv * env,jobject thiz,jstring jName)415 static jint check(JNIEnv *env, jobject thiz, jstring jName)
416 {
417     const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
418     if (!name) {
419         jniThrowNullPointerException(env, "name");
420         return 0;
421     }
422     int flags = check_interface(name);
423     env->ReleaseStringUTFChars(jName, name);
424     return flags;
425 }
426 
427 //------------------------------------------------------------------------------
428 
429 static JNINativeMethod gMethods[] = {
430     {"jniCreate", "(I)I", (void *)create},
431     {"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
432     {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
433     {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes},
434     {"jniReset", "(Ljava/lang/String;)V", (void *)reset},
435     {"jniCheck", "(Ljava/lang/String;)I", (void *)check},
436 };
437 
register_android_server_connectivity_Vpn(JNIEnv * env)438 int register_android_server_connectivity_Vpn(JNIEnv *env)
439 {
440     if (inet4 == -1) {
441         inet4 = socket(AF_INET, SOCK_DGRAM, 0);
442     }
443     if (inet6 == -1) {
444         inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
445     }
446     return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn",
447             gMethods, NELEM(gMethods));
448 }
449 
450 };
451