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