• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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_TAG "jniThreadTun"
18 
19 #include <arpa/inet.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <inttypes.h>
23 #include <linux/if_arp.h>
24 #include <linux/if_tun.h>
25 #include <linux/ioctl.h>
26 #include <log/log.h>
27 #include <net/if.h>
28 #include <spawn.h>
29 #include <sys/wait.h>
30 #include <string>
31 
32 #include <private/android_filesystem_config.h>
33 
34 #include "jni.h"
35 #include "nativehelper/JNIHelp.h"
36 #include "nativehelper/scoped_utf_chars.h"
37 
38 namespace android {
com_android_server_thread_TunInterfaceController_createTunInterface(JNIEnv * env,jobject clazz,jstring interfaceName,jint mtu)39 static jint com_android_server_thread_TunInterfaceController_createTunInterface(
40         JNIEnv* env, jobject clazz, jstring interfaceName, jint mtu) {
41     ScopedUtfChars ifName(env, interfaceName);
42 
43     int fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC);
44     if (fd == -1) {
45         jniThrowExceptionFmt(env, "java/io/IOException", "open tun device failed (%s)",
46                              strerror(errno));
47         return -1;
48     }
49 
50     struct ifreq ifr = {
51             .ifr_flags = IFF_TUN | IFF_NO_PI | static_cast<short>(IFF_TUN_EXCL),
52     };
53     strlcpy(ifr.ifr_name, ifName.c_str(), sizeof(ifr.ifr_name));
54 
55     if (ioctl(fd, TUNSETIFF, &ifr, sizeof(ifr)) != 0) {
56         jniThrowExceptionFmt(env, "java/io/IOException", "ioctl(TUNSETIFF) failed (%s)",
57                              strerror(errno));
58         close(fd);
59         return -1;
60     }
61 
62     int inet6 = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_IP);
63     if (inet6 == -1) {
64         jniThrowExceptionFmt(env, "java/io/IOException", "create inet6 socket failed (%s)",
65                              strerror(errno));
66         close(fd);
67         return -1;
68     }
69     ifr.ifr_mtu = mtu;
70     if (ioctl(inet6, SIOCSIFMTU, &ifr) != 0) {
71         jniThrowExceptionFmt(env, "java/io/IOException", "ioctl(SIOCSIFMTU) failed (%s)",
72                              strerror(errno));
73         close(fd);
74         close(inet6);
75         return -1;
76     }
77 
78     close(inet6);
79     return fd;
80 }
81 
com_android_server_thread_TunInterfaceController_setInterfaceUp(JNIEnv * env,jobject clazz,jstring interfaceName,jboolean isUp)82 static void com_android_server_thread_TunInterfaceController_setInterfaceUp(
83         JNIEnv* env, jobject clazz, jstring interfaceName, jboolean isUp) {
84     struct ifreq ifr;
85     ScopedUtfChars ifName(env, interfaceName);
86 
87     ifr.ifr_flags = isUp ? IFF_UP : 0;
88     strlcpy(ifr.ifr_name, ifName.c_str(), sizeof(ifr.ifr_name));
89 
90     int inet6 = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_IP);
91     if (inet6 == -1) {
92         jniThrowExceptionFmt(env, "java/io/IOException", "create inet6 socket failed (%s)",
93                              strerror(errno));
94     }
95 
96     if (ioctl(inet6, SIOCSIFFLAGS, &ifr) != 0) {
97         jniThrowExceptionFmt(env, "java/io/IOException", "ioctl(SIOCSIFFLAGS) failed (%s)",
98                              strerror(errno));
99     }
100 
101     close(inet6);
102 }
103 
104 /*
105  * JNI registration.
106  */
107 
108 static const JNINativeMethod gMethods[] = {
109         /* name, signature, funcPtr */
nativeCreateTunInterface(Ljava/lang/String;I)110         {"nativeCreateTunInterface",
111          "(Ljava/lang/String;I)I",
112          (void*)com_android_server_thread_TunInterfaceController_createTunInterface},
nativeSetInterfaceUp(Ljava/lang/String;Z)113         {"nativeSetInterfaceUp",
114          "(Ljava/lang/String;Z)V",
115          (void*)com_android_server_thread_TunInterfaceController_setInterfaceUp},
116 };
117 
register_com_android_server_thread_TunInterfaceController(JNIEnv * env)118 int register_com_android_server_thread_TunInterfaceController(JNIEnv* env) {
119     return jniRegisterNativeMethods(env, "com/android/server/thread/TunInterfaceController",
120                                     gMethods, NELEM(gMethods));
121 }
122 
123 };  // namespace android
124