1 /*
2 * Copyright (C) 2018 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 "TestNetworkServiceJni"
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/ipv6_route.h>
27 #include <linux/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 "jni.h"
39 #include <android-base/stringprintf.h>
40 #include <android-base/unique_fd.h>
41 #include <bpf/KernelUtils.h>
42 #include <nativehelper/JNIHelp.h>
43 #include <nativehelper/ScopedUtfChars.h>
44
45 #ifndef IFF_NO_CARRIER
46 #define IFF_NO_CARRIER 0x0040
47 #endif
48
49 namespace android {
50
51 //------------------------------------------------------------------------------
52
throwException(JNIEnv * env,int error,const char * action,const char * iface)53 static void throwException(JNIEnv* env, int error, const char* action, const char* iface) {
54 const std::string& msg = "Error: " + std::string(action) + " " + std::string(iface) + ": "
55 + std::string(strerror(error));
56 jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
57 }
58
59 // enable or disable carrier on tun / tap interface.
setTunTapCarrierEnabledImpl(JNIEnv * env,const char * iface,int tunFd,bool enabled)60 static void setTunTapCarrierEnabledImpl(JNIEnv* env, const char* iface, int tunFd, bool enabled) {
61 uint32_t carrierOn = enabled;
62 if (ioctl(tunFd, TUNSETCARRIER, &carrierOn)) {
63 throwException(env, errno, "set carrier", iface);
64 }
65 }
66
createTunTapImpl(JNIEnv * env,bool isTun,bool hasCarrier,bool setIffMulticast,const char * iface)67 static int createTunTapImpl(JNIEnv* env, bool isTun, bool hasCarrier, bool setIffMulticast,
68 const char* iface) {
69 base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
70 ifreq ifr{};
71
72 // Allocate interface.
73 ifr.ifr_flags = (isTun ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
74 if (!hasCarrier) {
75 // Using IFF_NO_CARRIER is supported starting in kernel version >= 6.0
76 // Up until then, unsupported flags are ignored.
77 if (!bpf::isAtLeastKernelVersion(6, 0, 0)) {
78 throwException(env, EOPNOTSUPP, "IFF_NO_CARRIER not supported", ifr.ifr_name);
79 return -1;
80 }
81 ifr.ifr_flags |= IFF_NO_CARRIER;
82 }
83 strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
84 if (ioctl(tun.get(), TUNSETIFF, &ifr)) {
85 throwException(env, errno, "allocating", ifr.ifr_name);
86 return -1;
87 }
88
89 // Mark some TAP interfaces as supporting multicast
90 if (setIffMulticast && !isTun) {
91 base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
92 ifr.ifr_flags = IFF_MULTICAST;
93
94 if (ioctl(inet6CtrlSock.get(), SIOCSIFFLAGS, &ifr)) {
95 throwException(env, errno, "set IFF_MULTICAST", ifr.ifr_name);
96 return -1;
97 }
98 }
99
100 return tun.release();
101 }
102
bringUpInterfaceImpl(JNIEnv * env,const char * iface)103 static void bringUpInterfaceImpl(JNIEnv* env, const char* iface) {
104 // Activate interface using an unconnected datagram socket.
105 base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
106
107 ifreq ifr{};
108 strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
109 if (ioctl(inet6CtrlSock.get(), SIOCGIFFLAGS, &ifr)) {
110 throwException(env, errno, "read flags", iface);
111 return;
112 }
113 ifr.ifr_flags |= IFF_UP;
114 if (ioctl(inet6CtrlSock.get(), SIOCSIFFLAGS, &ifr)) {
115 throwException(env, errno, "set IFF_UP", iface);
116 return;
117 }
118 }
119
120 //------------------------------------------------------------------------------
121
122
123
setTunTapCarrierEnabled(JNIEnv * env,jclass,jstring jIface,jint tunFd,jboolean enabled)124 static void setTunTapCarrierEnabled(JNIEnv* env, jclass /* clazz */, jstring
125 jIface, jint tunFd, jboolean enabled) {
126 ScopedUtfChars iface(env, jIface);
127 if (!iface.c_str()) {
128 jniThrowNullPointerException(env, "iface");
129 return;
130 }
131 setTunTapCarrierEnabledImpl(env, iface.c_str(), tunFd, enabled);
132 }
133
createTunTap(JNIEnv * env,jclass,jboolean isTun,jboolean hasCarrier,jboolean setIffMulticast,jstring jIface)134 static jint createTunTap(JNIEnv* env, jclass /* clazz */, jboolean isTun,
135 jboolean hasCarrier, jboolean setIffMulticast, jstring jIface) {
136 ScopedUtfChars iface(env, jIface);
137 if (!iface.c_str()) {
138 jniThrowNullPointerException(env, "iface");
139 return -1;
140 }
141
142 return createTunTapImpl(env, isTun, hasCarrier, setIffMulticast, iface.c_str());
143 }
144
bringUpInterface(JNIEnv * env,jclass,jstring jIface)145 static void bringUpInterface(JNIEnv* env, jclass /* clazz */, jstring jIface) {
146 ScopedUtfChars iface(env, jIface);
147 if (!iface.c_str()) {
148 jniThrowNullPointerException(env, "iface");
149 return;
150 }
151 bringUpInterfaceImpl(env, iface.c_str());
152 }
153
154 //------------------------------------------------------------------------------
155
156 static const JNINativeMethod gMethods[] = {
157 {"nativeSetTunTapCarrierEnabled", "(Ljava/lang/String;IZ)V", (void*)setTunTapCarrierEnabled},
158 {"nativeCreateTunTap", "(ZZZLjava/lang/String;)I", (void*)createTunTap},
159 {"nativeBringUpInterface", "(Ljava/lang/String;)V", (void*)bringUpInterface},
160 };
161
register_com_android_server_TestNetworkService(JNIEnv * env)162 int register_com_android_server_TestNetworkService(JNIEnv* env) {
163 return jniRegisterNativeMethods(env,
164 "android/net/connectivity/com/android/server/TestNetworkService", gMethods,
165 NELEM(gMethods));
166 }
167
168 }; // namespace android
169