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