1 /*
2 * Copyright (C) 2022 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 #define LOG_TAG "jniClatCoordinator"
17
18 #include <arpa/inet.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <inttypes.h>
22 #include <linux/if_packet.h>
23 #include <linux/if_tun.h>
24 #include <linux/ioctl.h>
25 #include <log/log.h>
26 #include <nativehelper/JNIHelp.h>
27 #include <net/if.h>
28 #include <spawn.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <sys/xattr.h>
33 #include <string>
34 #include <unistd.h>
35
36 #include <android-modules-utils/sdk_level.h>
37 #include <bpf/BpfMap.h>
38 #include <bpf/BpfUtils.h>
39 #include <netjniutils/netjniutils.h>
40 #include <private/android_filesystem_config.h>
41
42 #include "libclat/clatutils.h"
43 #include "nativehelper/scoped_utf_chars.h"
44
45 // Sync from system/netd/server/NetdConstants.h
46 #define __INT_STRLEN(i) sizeof(#i)
47 #define _INT_STRLEN(i) __INT_STRLEN(i)
48 #define INT32_STRLEN _INT_STRLEN(INT32_MIN)
49
50 #define DEVICEPREFIX "v4-"
51
52 namespace android {
53
54 static bool fatal = false;
55
56 #define ALOGF(s ...) do { ALOGE(s); fatal = true; } while(0)
57
58 enum verify { VERIFY_DIR, VERIFY_BIN, VERIFY_PROG, VERIFY_MAP_RO, VERIFY_MAP_RW };
59
verifyPerms(const char * const path,const mode_t mode,const uid_t uid,const gid_t gid,const char * const ctxt,const verify vtype)60 static void verifyPerms(const char * const path,
61 const mode_t mode, const uid_t uid, const gid_t gid,
62 const char * const ctxt,
63 const verify vtype) {
64 struct stat s = {};
65
66 if (lstat(path, &s)) ALOGF("lstat '%s' errno=%d", path, errno);
67 if (s.st_mode != mode) ALOGF("'%s' mode is 0%o != 0%o", path, s.st_mode, mode);
68 if (s.st_uid != uid) ALOGF("'%s' uid is %d != %d", path, s.st_uid, uid);
69 if (s.st_gid != gid) ALOGF("'%s' gid is %d != %d", path, s.st_gid, gid);
70
71 char b[255] = {};
72 int v = lgetxattr(path, "security.selinux", &b, sizeof(b));
73 if (v < 0) ALOGF("lgetxattr '%s' errno=%d", path, errno);
74 if (strncmp(ctxt, b, sizeof(b))) ALOGF("context of '%s' is '%s' != '%s'", path, b, ctxt);
75
76 int fd = -1;
77
78 switch (vtype) {
79 case VERIFY_DIR: return;
80 case VERIFY_BIN: return;
81 case VERIFY_PROG: fd = bpf::retrieveProgram(path); break;
82 case VERIFY_MAP_RO: fd = bpf::mapRetrieveRO(path); break;
83 case VERIFY_MAP_RW: fd = bpf::mapRetrieveRW(path); break;
84 }
85
86 if (fd < 0) ALOGF("bpf_obj_get '%s' failed, errno=%d", path, errno);
87
88 if (fd >= 0) close(fd);
89 }
90
91 #undef ALOGF
92
isGsiImage()93 bool isGsiImage() {
94 // this implementation matches 2 other places in the codebase (same function name too)
95 return !access("/system/system_ext/etc/init/init.gsi.rc", F_OK);
96 }
97
98 static const char* kClatdDir = "/apex/com.android.tethering/bin/for-system";
99 static const char* kClatdBin = "/apex/com.android.tethering/bin/for-system/clatd";
100
101 #define V(path, md, uid, gid, ctx, vtype) \
102 verifyPerms((path), (md), AID_ ## uid, AID_ ## gid, "u:object_r:" ctx ":s0", VERIFY_ ## vtype)
103
verifyClatPerms()104 static void verifyClatPerms() {
105 // We might run as part of tests instead of as part of system server
106 if (getuid() != AID_SYSTEM) return;
107
108 // First verify the clatd directory and binary,
109 // since this is built into the apex file system image,
110 // failures here are 99% likely to be build problems.
111 V(kClatdDir, S_IFDIR|0750, ROOT, SYSTEM, "system_file", DIR);
112 V(kClatdBin, S_IFREG|S_ISUID|S_ISGID|0755, CLAT, CLAT, "clatd_exec", BIN);
113
114 // Move on to verifying that the bpf programs and maps are as expected.
115 // This relies on the kernel and bpfloader.
116
117 // Clat BPF was only mainlined during T.
118 if (!modules::sdklevel::IsAtLeastT()) return;
119
120 V("/sys/fs/bpf", S_IFDIR|S_ISVTX|0777, ROOT, ROOT, "fs_bpf", DIR);
121 V("/sys/fs/bpf/net_shared", S_IFDIR|S_ISVTX|0777, ROOT, ROOT, "fs_bpf_net_shared", DIR);
122
123 // pre-U we do not have selinux privs to getattr on bpf maps/progs
124 // so while the below *should* be as listed, we have no way to actually verify
125 if (!modules::sdklevel::IsAtLeastU()) return;
126
127 #define V2(path, md, vtype) \
128 V("/sys/fs/bpf/net_shared/" path, (md), ROOT, SYSTEM, "fs_bpf_net_shared", vtype)
129
130 V2("prog_clatd_schedcls_egress4_clat_rawip", S_IFREG|0440, PROG);
131 V2("prog_clatd_schedcls_ingress6_clat_rawip", S_IFREG|0440, PROG);
132 V2("prog_clatd_schedcls_ingress6_clat_ether", S_IFREG|0440, PROG);
133 V2("map_clatd_clat_egress4_map", S_IFREG|0660, MAP_RW);
134 V2("map_clatd_clat_ingress6_map", S_IFREG|0660, MAP_RW);
135
136 #undef V2
137
138 // HACK: Some old vendor kernels lack ~5.10 backport of 'bpffs selinux genfscon' support.
139 // This is *NOT* supported, but let's allow, at least for now, U+ GSI to boot on them.
140 // (without this hack pixel5 R vendor + U gsi breaks)
141 if (isGsiImage() && !bpf::isAtLeastKernelVersion(5, 10, 0)) {
142 ALOGE("GSI with *BAD* pre-5.10 kernel lacking bpffs selinux genfscon support.");
143 return;
144 }
145
146 if (fatal) abort();
147 }
148
149 #undef V
150
throwIOException(JNIEnv * env,const char * msg,int error)151 static void throwIOException(JNIEnv* env, const char* msg, int error) {
152 jniThrowExceptionFmt(env, "java/io/IOException", "%s: %s", msg, strerror(error));
153 }
154
com_android_server_connectivity_ClatCoordinator_selectIpv4Address(JNIEnv * env,jclass clazz,jstring v4addr,jint prefixlen)155 jstring com_android_server_connectivity_ClatCoordinator_selectIpv4Address(JNIEnv* env,
156 jclass clazz,
157 jstring v4addr,
158 jint prefixlen) {
159 ScopedUtfChars address(env, v4addr);
160 in_addr ip;
161 if (inet_pton(AF_INET, address.c_str(), &ip) != 1) {
162 throwIOException(env, "invalid address", EINVAL);
163 return nullptr;
164 }
165
166 // Pick an IPv4 address.
167 // TODO: this picks the address based on other addresses that are assigned to interfaces, but
168 // the address is only actually assigned to an interface once clatd starts up. So we could end
169 // up with two clatd instances with the same IPv4 address.
170 // Stop doing this and instead pick a free one from the kV4Addr pool.
171 in_addr v4 = {net::clat::selectIpv4Address(ip, prefixlen)};
172 if (v4.s_addr == INADDR_NONE) {
173 jniThrowExceptionFmt(env, "java/io/IOException", "No free IPv4 address in %s/%d",
174 address.c_str(), prefixlen);
175 return nullptr;
176 }
177
178 char addrstr[INET_ADDRSTRLEN];
179 if (!inet_ntop(AF_INET, (void*)&v4, addrstr, sizeof(addrstr))) {
180 throwIOException(env, "invalid address", EADDRNOTAVAIL);
181 return nullptr;
182 }
183 return env->NewStringUTF(addrstr);
184 }
185
186 // Picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix.
com_android_server_connectivity_ClatCoordinator_generateIpv6Address(JNIEnv * env,jclass clazz,jstring ifaceStr,jstring v4Str,jstring prefix64Str,jint mark)187 jstring com_android_server_connectivity_ClatCoordinator_generateIpv6Address(
188 JNIEnv* env, jclass clazz, jstring ifaceStr, jstring v4Str, jstring prefix64Str,
189 jint mark) {
190 ScopedUtfChars iface(env, ifaceStr);
191 ScopedUtfChars addr4(env, v4Str);
192 ScopedUtfChars prefix64(env, prefix64Str);
193
194 if (iface.c_str() == nullptr) {
195 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid null interface name");
196 return nullptr;
197 }
198
199 in_addr v4;
200 if (inet_pton(AF_INET, addr4.c_str(), &v4) != 1) {
201 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid clat v4 address %s",
202 addr4.c_str());
203 return nullptr;
204 }
205
206 in6_addr nat64Prefix;
207 if (inet_pton(AF_INET6, prefix64.c_str(), &nat64Prefix) != 1) {
208 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid prefix %s", prefix64.c_str());
209 return nullptr;
210 }
211
212 in6_addr v6;
213 if (net::clat::generateIpv6Address(iface.c_str(), v4, nat64Prefix, &v6, mark)) {
214 jniThrowExceptionFmt(env, "java/io/IOException",
215 "Unable to find global source address on %s for %s", iface.c_str(),
216 prefix64.c_str());
217 return nullptr;
218 }
219
220 char addrstr[INET6_ADDRSTRLEN];
221 if (!inet_ntop(AF_INET6, (void*)&v6, addrstr, sizeof(addrstr))) {
222 throwIOException(env, "invalid address", EADDRNOTAVAIL);
223 return nullptr;
224 }
225 return env->NewStringUTF(addrstr);
226 }
227
com_android_server_connectivity_ClatCoordinator_createTunInterface(JNIEnv * env,jclass clazz,jstring tuniface)228 static jint com_android_server_connectivity_ClatCoordinator_createTunInterface(JNIEnv* env,
229 jclass clazz,
230 jstring tuniface) {
231 ScopedUtfChars v4interface(env, tuniface);
232
233 // open the tun device in non blocking mode as required by clatd
234 jint fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC);
235 if (fd == -1) {
236 jniThrowExceptionFmt(env, "java/io/IOException", "open tun device failed (%s)",
237 strerror(errno));
238 return -1;
239 }
240
241 struct ifreq ifr = {
242 .ifr_flags = static_cast<short>(IFF_TUN | IFF_TUN_EXCL),
243 };
244 strlcpy(ifr.ifr_name, v4interface.c_str(), sizeof(ifr.ifr_name));
245
246 if (ioctl(fd, TUNSETIFF, &ifr, sizeof(ifr))) {
247 close(fd);
248 jniThrowExceptionFmt(env, "java/io/IOException", "ioctl(TUNSETIFF) failed (%s)",
249 strerror(errno));
250 return -1;
251 }
252
253 return fd;
254 }
255
com_android_server_connectivity_ClatCoordinator_detectMtu(JNIEnv * env,jclass clazz,jstring platSubnet,jint plat_suffix,jint mark)256 static jint com_android_server_connectivity_ClatCoordinator_detectMtu(JNIEnv* env, jclass clazz,
257 jstring platSubnet,
258 jint plat_suffix, jint mark) {
259 ScopedUtfChars platSubnetStr(env, platSubnet);
260
261 in6_addr plat_subnet;
262 if (inet_pton(AF_INET6, platSubnetStr.c_str(), &plat_subnet) != 1) {
263 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid plat prefix address %s",
264 platSubnetStr.c_str());
265 return -1;
266 }
267
268 int ret = net::clat::detect_mtu(&plat_subnet, plat_suffix, mark);
269 if (ret < 0) {
270 jniThrowExceptionFmt(env, "java/io/IOException", "detect mtu failed: %s", strerror(-ret));
271 return -1;
272 }
273
274 return ret;
275 }
276
com_android_server_connectivity_ClatCoordinator_openPacketSocket(JNIEnv * env,jclass clazz)277 static jint com_android_server_connectivity_ClatCoordinator_openPacketSocket(JNIEnv* env,
278 jclass clazz) {
279 // Will eventually be bound to htons(ETH_P_IPV6) protocol,
280 // but only after appropriate bpf filter is attached.
281 const int sock = socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC, 0);
282 if (sock < 0) {
283 throwIOException(env, "packet socket failed", errno);
284 return -1;
285 }
286 const int on = 1;
287 // enable tpacket_auxdata cmsg delivery, which includes L2 header length
288 if (setsockopt(sock, SOL_PACKET, PACKET_AUXDATA, &on, sizeof(on))) {
289 throwIOException(env, "packet socket auxdata enablement failed", errno);
290 close(sock);
291 return -1;
292 }
293 // needed for virtio_net_hdr prepending, which includes checksum metadata
294 if (setsockopt(sock, SOL_PACKET, PACKET_VNET_HDR, &on, sizeof(on))) {
295 throwIOException(env, "packet socket vnet_hdr enablement failed", errno);
296 close(sock);
297 return -1;
298 }
299 return sock;
300 }
301
com_android_server_connectivity_ClatCoordinator_openRawSocket6(JNIEnv * env,jclass clazz,jint mark)302 static jint com_android_server_connectivity_ClatCoordinator_openRawSocket6(JNIEnv* env,
303 jclass clazz,
304 jint mark) {
305 int sock = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_RAW);
306 if (sock < 0) {
307 throwIOException(env, "raw socket failed", errno);
308 return -1;
309 }
310
311 // TODO: check the mark validation
312 if (setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
313 throwIOException(env, "could not set mark on raw socket", errno);
314 close(sock);
315 return -1;
316 }
317
318 return sock;
319 }
320
com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt(JNIEnv * env,jclass clazz,jobject javaFd,jstring addr6,jint ifindex)321 static void com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt(
322 JNIEnv* env, jclass clazz, jobject javaFd, jstring addr6, jint ifindex) {
323 int sock = netjniutils::GetNativeFileDescriptor(env, javaFd);
324 if (sock < 0) {
325 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
326 return;
327 }
328
329 ScopedUtfChars addrStr(env, addr6);
330
331 in6_addr addr;
332 if (inet_pton(AF_INET6, addrStr.c_str(), &addr) != 1) {
333 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid IPv6 address %s",
334 addrStr.c_str());
335 return;
336 }
337
338 struct ipv6_mreq mreq = {addr, ifindex};
339 int ret = setsockopt(sock, SOL_IPV6, IPV6_JOIN_ANYCAST, &mreq, sizeof(mreq));
340 if (ret) {
341 jniThrowExceptionFmt(env, "java/io/IOException", "setsockopt IPV6_JOIN_ANYCAST failed: %s",
342 strerror(errno));
343 return;
344 }
345 }
346
com_android_server_connectivity_ClatCoordinator_configurePacketSocket(JNIEnv * env,jclass clazz,jobject javaFd,jstring addr6,jint ifindex)347 static void com_android_server_connectivity_ClatCoordinator_configurePacketSocket(
348 JNIEnv* env, jclass clazz, jobject javaFd, jstring addr6, jint ifindex) {
349 ScopedUtfChars addrStr(env, addr6);
350
351 int sock = netjniutils::GetNativeFileDescriptor(env, javaFd);
352 if (sock < 0) {
353 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
354 return;
355 }
356
357 in6_addr addr;
358 if (inet_pton(AF_INET6, addrStr.c_str(), &addr) != 1) {
359 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid IPv6 address %s",
360 addrStr.c_str());
361 return;
362 }
363
364 int ret = net::clat::configure_packet_socket(sock, &addr, ifindex);
365 if (ret < 0) {
366 throwIOException(env, "configure packet socket failed", -ret);
367 return;
368 }
369 }
370
com_android_server_connectivity_ClatCoordinator_startClatd(JNIEnv * env,jclass clazz,jobject tunJavaFd,jobject readSockJavaFd,jobject writeSockJavaFd,jstring iface,jstring pfx96,jstring v4,jstring v6)371 static jint com_android_server_connectivity_ClatCoordinator_startClatd(
372 JNIEnv* env, jclass clazz, jobject tunJavaFd, jobject readSockJavaFd,
373 jobject writeSockJavaFd, jstring iface, jstring pfx96, jstring v4, jstring v6) {
374 ScopedUtfChars ifaceStr(env, iface);
375 ScopedUtfChars pfx96Str(env, pfx96);
376 ScopedUtfChars v4Str(env, v4);
377 ScopedUtfChars v6Str(env, v6);
378
379 int tunFd = netjniutils::GetNativeFileDescriptor(env, tunJavaFd);
380 if (tunFd < 0) {
381 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid tun file descriptor");
382 return -1;
383 }
384
385 int readSock = netjniutils::GetNativeFileDescriptor(env, readSockJavaFd);
386 if (readSock < 0) {
387 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid read socket");
388 return -1;
389 }
390
391 int writeSock = netjniutils::GetNativeFileDescriptor(env, writeSockJavaFd);
392 if (writeSock < 0) {
393 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid write socket");
394 return -1;
395 }
396
397 // 1. these are the FD we'll pass to clatd on the cli, so need it as a string
398 char tunFdStr[INT32_STRLEN];
399 char sockReadStr[INT32_STRLEN];
400 char sockWriteStr[INT32_STRLEN];
401 snprintf(tunFdStr, sizeof(tunFdStr), "%d", tunFd);
402 snprintf(sockReadStr, sizeof(sockReadStr), "%d", readSock);
403 snprintf(sockWriteStr, sizeof(sockWriteStr), "%d", writeSock);
404
405 // 2. we're going to use this as argv[0] to clatd to make ps output more useful
406 std::string progname("clatd-");
407 progname += ifaceStr.c_str();
408
409 // clang-format off
410 const char* args[] = {progname.c_str(),
411 "-i", ifaceStr.c_str(),
412 "-p", pfx96Str.c_str(),
413 "-4", v4Str.c_str(),
414 "-6", v6Str.c_str(),
415 "-t", tunFdStr,
416 "-r", sockReadStr,
417 "-w", sockWriteStr,
418 nullptr};
419 // clang-format on
420
421 // 3. register vfork requirement
422 posix_spawnattr_t attr;
423 if (int ret = posix_spawnattr_init(&attr)) {
424 throwIOException(env, "posix_spawnattr_init failed", ret);
425 return -1;
426 }
427
428 // TODO: use android::base::ScopeGuard.
429 if (int ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_USEVFORK
430 | POSIX_SPAWN_CLOEXEC_DEFAULT)) {
431 posix_spawnattr_destroy(&attr);
432 throwIOException(env, "posix_spawnattr_setflags failed", ret);
433 return -1;
434 }
435
436 // 4. register dup2() action: this is what 'clears' the CLOEXEC flag
437 // on the tun fd that we want the child clatd process to inherit
438 // (this will happen after the vfork, and before the execve).
439 // Note that even though dup2(2) is a no-op if fd == new_fd but O_CLOEXEC flag will be removed.
440 // See implementation of bionic's posix_spawn_file_actions_adddup2().
441 posix_spawn_file_actions_t fa;
442 if (int ret = posix_spawn_file_actions_init(&fa)) {
443 posix_spawnattr_destroy(&attr);
444 throwIOException(env, "posix_spawn_file_actions_init failed", ret);
445 return -1;
446 }
447
448 if (int ret = posix_spawn_file_actions_adddup2(&fa, tunFd, tunFd)) {
449 posix_spawnattr_destroy(&attr);
450 posix_spawn_file_actions_destroy(&fa);
451 throwIOException(env, "posix_spawn_file_actions_adddup2 for tun fd failed", ret);
452 return -1;
453 }
454 if (int ret = posix_spawn_file_actions_adddup2(&fa, readSock, readSock)) {
455 posix_spawnattr_destroy(&attr);
456 posix_spawn_file_actions_destroy(&fa);
457 throwIOException(env, "posix_spawn_file_actions_adddup2 for read socket failed", ret);
458 return -1;
459 }
460 if (int ret = posix_spawn_file_actions_adddup2(&fa, writeSock, writeSock)) {
461 posix_spawnattr_destroy(&attr);
462 posix_spawn_file_actions_destroy(&fa);
463 throwIOException(env, "posix_spawn_file_actions_adddup2 for write socket failed", ret);
464 return -1;
465 }
466
467 // 5. actually perform vfork/dup2/execve
468 pid_t pid;
469 if (int ret = posix_spawn(&pid, kClatdBin, &fa, &attr, (char* const*)args, nullptr)) {
470 posix_spawnattr_destroy(&attr);
471 posix_spawn_file_actions_destroy(&fa);
472 throwIOException(env, "posix_spawn failed", ret);
473 return -1;
474 }
475
476 posix_spawnattr_destroy(&attr);
477 posix_spawn_file_actions_destroy(&fa);
478
479 return pid;
480 }
481
482 // Stop clatd process. SIGTERM with timeout first, if fail, SIGKILL.
483 // See stopProcess() in system/netd/server/NetdConstants.cpp.
484 // TODO: have a function stopProcess(int pid, const char *name) in common location and call it.
485 static constexpr int WAITPID_ATTEMPTS = 50;
486 static constexpr int WAITPID_RETRY_INTERVAL_US = 100000;
487
stopClatdProcess(int pid)488 static void stopClatdProcess(int pid) {
489 int err = kill(pid, SIGTERM);
490 if (err) {
491 err = errno;
492 }
493 if (err == ESRCH) {
494 ALOGE("clatd child process %d unexpectedly disappeared", pid);
495 return;
496 }
497 if (err) {
498 ALOGE("Error killing clatd child process %d: %s", pid, strerror(err));
499 }
500 int status = 0;
501 int ret = 0;
502 for (int count = 0; ret == 0 && count < WAITPID_ATTEMPTS; count++) {
503 usleep(WAITPID_RETRY_INTERVAL_US);
504 ret = waitpid(pid, &status, WNOHANG);
505 }
506 if (ret == 0) {
507 ALOGE("Failed to SIGTERM clatd pid=%d, try SIGKILL", pid);
508 // TODO: fix that kill failed or waitpid doesn't return.
509 if (kill(pid, SIGKILL)) {
510 ALOGE("Failed to SIGKILL clatd pid=%d: %s", pid, strerror(errno));
511 }
512 ret = waitpid(pid, &status, 0);
513 }
514 if (ret == -1) {
515 ALOGE("Error waiting for clatd child process %d: %s", pid, strerror(errno));
516 } else {
517 ALOGD("clatd process %d terminated status=%d", pid, status);
518 }
519 }
520
com_android_server_connectivity_ClatCoordinator_stopClatd(JNIEnv * env,jclass clazz,jstring iface,jstring pfx96,jstring v4,jstring v6,jint pid)521 static void com_android_server_connectivity_ClatCoordinator_stopClatd(JNIEnv* env, jclass clazz,
522 jstring iface, jstring pfx96,
523 jstring v4, jstring v6,
524 jint pid) {
525 ScopedUtfChars ifaceStr(env, iface);
526 ScopedUtfChars pfx96Str(env, pfx96);
527 ScopedUtfChars v4Str(env, v4);
528 ScopedUtfChars v6Str(env, v6);
529
530 if (pid <= 0) {
531 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid pid");
532 return;
533 }
534
535 stopClatdProcess(pid);
536 }
537
com_android_server_connectivity_ClatCoordinator_getSocketCookie(JNIEnv * env,jclass clazz,jobject sockJavaFd)538 static jlong com_android_server_connectivity_ClatCoordinator_getSocketCookie(
539 JNIEnv* env, jclass clazz, jobject sockJavaFd) {
540 int sockFd = netjniutils::GetNativeFileDescriptor(env, sockJavaFd);
541 if (sockFd < 0) {
542 jniThrowExceptionFmt(env, "java/io/IOException", "Invalid socket file descriptor");
543 return -1;
544 }
545
546 uint64_t sock_cookie = bpf::getSocketCookie(sockFd);
547 if (!sock_cookie) {
548 throwIOException(env, "get socket cookie failed", errno);
549 return -1;
550 }
551
552 ALOGI("Get cookie %" PRIu64 " for socket fd %d", sock_cookie, sockFd);
553 return static_cast<jlong>(sock_cookie);
554 }
555
556 /*
557 * JNI registration.
558 */
559 static const JNINativeMethod gMethods[] = {
560 /* name, signature, funcPtr */
561 {"native_selectIpv4Address", "(Ljava/lang/String;I)Ljava/lang/String;",
562 (void*)com_android_server_connectivity_ClatCoordinator_selectIpv4Address},
563 {"native_generateIpv6Address",
564 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;",
565 (void*)com_android_server_connectivity_ClatCoordinator_generateIpv6Address},
566 {"native_createTunInterface", "(Ljava/lang/String;)I",
567 (void*)com_android_server_connectivity_ClatCoordinator_createTunInterface},
568 {"native_detectMtu", "(Ljava/lang/String;II)I",
569 (void*)com_android_server_connectivity_ClatCoordinator_detectMtu},
570 {"native_openPacketSocket", "()I",
571 (void*)com_android_server_connectivity_ClatCoordinator_openPacketSocket},
572 {"native_openRawSocket6", "(I)I",
573 (void*)com_android_server_connectivity_ClatCoordinator_openRawSocket6},
574 {"native_addAnycastSetsockopt", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
575 (void*)com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt},
576 {"native_configurePacketSocket", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
577 (void*)com_android_server_connectivity_ClatCoordinator_configurePacketSocket},
578 {"native_startClatd",
579 "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/lang/"
580 "String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
581 (void*)com_android_server_connectivity_ClatCoordinator_startClatd},
582 {"native_stopClatd",
583 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V",
584 (void*)com_android_server_connectivity_ClatCoordinator_stopClatd},
585 {"native_getSocketCookie", "(Ljava/io/FileDescriptor;)J",
586 (void*)com_android_server_connectivity_ClatCoordinator_getSocketCookie},
587 };
588
register_com_android_server_connectivity_ClatCoordinator(JNIEnv * env)589 int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env) {
590 verifyClatPerms();
591 return jniRegisterNativeMethods(env,
592 "android/net/connectivity/com/android/server/connectivity/ClatCoordinator",
593 gMethods, NELEM(gMethods));
594 }
595
596 }; // namespace android
597