Merge changes Id5f5bdfc,I67b9f30b
* changes: [CLATJ#32] ClatCoordinator: untag clat raw socket [CLATJ#31] ClatCoordinator: tag raw socket to uid AID_CLAT
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <log/log.h>
|
||||
@@ -27,7 +28,11 @@
|
||||
#include <sys/wait.h>
|
||||
#include <string>
|
||||
|
||||
#include <bpf/BpfMap.h>
|
||||
#include <bpf/BpfUtils.h>
|
||||
#include <bpf_shared.h>
|
||||
#include <netjniutils/netjniutils.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
|
||||
#include "libclat/bpfhelper.h"
|
||||
#include "libclat/clatutils.h"
|
||||
@@ -473,6 +478,72 @@ static void com_android_server_connectivity_ClatCoordinator_stopClatd(JNIEnv* en
|
||||
stopClatdProcess(pid);
|
||||
}
|
||||
|
||||
static jlong com_android_server_connectivity_ClatCoordinator_tagSocketAsClat(
|
||||
JNIEnv* env, jobject clazz, jobject sockJavaFd) {
|
||||
int sockFd = netjniutils::GetNativeFileDescriptor(env, sockJavaFd);
|
||||
if (sockFd < 0) {
|
||||
jniThrowExceptionFmt(env, "java/io/IOException", "Invalid socket file descriptor");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t sock_cookie = bpf::getSocketCookie(sockFd);
|
||||
if (sock_cookie == bpf::NONEXISTENT_COOKIE) {
|
||||
throwIOException(env, "get socket cookie failed", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpf::BpfMap<uint64_t, UidTagValue> cookieTagMap;
|
||||
auto res = cookieTagMap.init(COOKIE_TAG_MAP_PATH);
|
||||
if (!res.ok()) {
|
||||
throwIOException(env, "failed to init the cookieTagMap", res.error().code());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Tag raw socket with uid AID_CLAT and set tag as zero because tag is unused in bpf
|
||||
// program for counting data usage in netd.c. Tagging socket is used to avoid counting
|
||||
// duplicated clat traffic in bpf stat.
|
||||
UidTagValue newKey = {.uid = (uint32_t)AID_CLAT, .tag = 0 /* unused */};
|
||||
res = cookieTagMap.writeValue(sock_cookie, newKey, BPF_ANY);
|
||||
if (!res.ok()) {
|
||||
jniThrowExceptionFmt(env, "java/io/IOException", "Failed to tag the socket: %s, fd: %d",
|
||||
strerror(res.error().code()), cookieTagMap.getMap().get());
|
||||
return -1;
|
||||
}
|
||||
|
||||
ALOGI("tag uid AID_CLAT to socket fd %d, cookie %" PRIu64 "", sockFd, sock_cookie);
|
||||
return static_cast<jlong>(sock_cookie);
|
||||
}
|
||||
|
||||
static void com_android_server_connectivity_ClatCoordinator_untagSocket(JNIEnv* env, jobject clazz,
|
||||
jlong cookie) {
|
||||
uint64_t sock_cookie = static_cast<uint64_t>(cookie);
|
||||
if (sock_cookie == bpf::NONEXISTENT_COOKIE) {
|
||||
jniThrowExceptionFmt(env, "java/io/IOException", "Invalid socket cookie");
|
||||
return;
|
||||
}
|
||||
|
||||
// The reason that deleting entry from cookie tag map directly is that the tag socket destroy
|
||||
// listener only monitors on group INET_TCP, INET_UDP, INET6_TCP, INET6_UDP. The other socket
|
||||
// types, ex: raw, are not able to be removed automatically by the listener.
|
||||
// See TrafficController::makeSkDestroyListener.
|
||||
bpf::BpfMap<uint64_t, UidTagValue> cookieTagMap;
|
||||
auto res = cookieTagMap.init(COOKIE_TAG_MAP_PATH);
|
||||
if (!res.ok()) {
|
||||
throwIOException(env, "failed to init the cookieTagMap", res.error().code());
|
||||
return;
|
||||
}
|
||||
|
||||
res = cookieTagMap.deleteValue(sock_cookie);
|
||||
if (!res.ok()) {
|
||||
jniThrowExceptionFmt(env, "java/io/IOException", "Failed to untag the socket: %s",
|
||||
strerror(res.error().code()));
|
||||
return;
|
||||
}
|
||||
|
||||
ALOGI("untag socket cookie %" PRIu64 "", sock_cookie);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* JNI registration.
|
||||
*/
|
||||
@@ -502,6 +573,10 @@ static const JNINativeMethod gMethods[] = {
|
||||
{"native_stopClatd",
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V",
|
||||
(void*)com_android_server_connectivity_ClatCoordinator_stopClatd},
|
||||
{"native_tagSocketAsClat", "(Ljava/io/FileDescriptor;)J",
|
||||
(void*)com_android_server_connectivity_ClatCoordinator_tagSocketAsClat},
|
||||
{"native_untagSocket", "(J)V",
|
||||
(void*)com_android_server_connectivity_ClatCoordinator_untagSocket},
|
||||
};
|
||||
|
||||
int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env) {
|
||||
|
||||
@@ -67,6 +67,7 @@ public class ClatCoordinator {
|
||||
|
||||
private static final int INVALID_IFINDEX = 0;
|
||||
private static final int INVALID_PID = 0;
|
||||
private static final long INVALID_COOKIE = 0;
|
||||
|
||||
@NonNull
|
||||
private final INetd mNetd;
|
||||
@@ -81,6 +82,7 @@ public class ClatCoordinator {
|
||||
@Nullable
|
||||
private String mXlatLocalAddress6 = null;
|
||||
private int mPid = INVALID_PID;
|
||||
private long mCookie = INVALID_COOKIE;
|
||||
|
||||
@VisibleForTesting
|
||||
abstract static class Dependencies {
|
||||
@@ -185,6 +187,20 @@ public class ClatCoordinator {
|
||||
throws IOException {
|
||||
native_stopClatd(iface, pfx96, v4, v6, pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag socket as clat.
|
||||
*/
|
||||
public long tagSocketAsClat(@NonNull FileDescriptor sock) throws IOException {
|
||||
return native_tagSocketAsClat(sock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Untag socket.
|
||||
*/
|
||||
public void untagSocket(long cookie) throws IOException {
|
||||
native_untagSocket(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -335,6 +351,17 @@ public class ClatCoordinator {
|
||||
throw new IOException("add anycast sockopt failed: " + e);
|
||||
}
|
||||
|
||||
// Tag socket as AID_CLAT to avoid duplicated CLAT data usage accounting.
|
||||
long cookie;
|
||||
try {
|
||||
cookie = mDeps.tagSocketAsClat(writeSock6.getFileDescriptor());
|
||||
} catch (IOException e) {
|
||||
tunFd.close();
|
||||
readSock6.close();
|
||||
writeSock6.close();
|
||||
throw new IOException("tag raw socket failed: " + e);
|
||||
}
|
||||
|
||||
// Update our packet socket filter to reflect the new 464xlat IP address.
|
||||
try {
|
||||
mDeps.configurePacketSocket(readSock6.getFileDescriptor(), v6, ifaceIndex);
|
||||
@@ -353,7 +380,9 @@ public class ClatCoordinator {
|
||||
mNat64Prefix = pfx96;
|
||||
mXlatLocalAddress4 = v4;
|
||||
mXlatLocalAddress6 = v6;
|
||||
mCookie = cookie;
|
||||
} catch (IOException e) {
|
||||
mDeps.untagSocket(cookie);
|
||||
throw new IOException("Error start clatd on " + iface + ": " + e);
|
||||
} finally {
|
||||
tunFd.close();
|
||||
@@ -374,7 +403,7 @@ public class ClatCoordinator {
|
||||
Log.i(TAG, "Stopping clatd pid=" + mPid + " on " + mIface);
|
||||
|
||||
mDeps.stopClatd(mIface, mNat64Prefix, mXlatLocalAddress4, mXlatLocalAddress6, mPid);
|
||||
// TODO: remove setIptablesDropRule
|
||||
mDeps.untagSocket(mCookie);
|
||||
|
||||
Log.i(TAG, "clatd on " + mIface + " stopped");
|
||||
|
||||
@@ -383,6 +412,7 @@ public class ClatCoordinator {
|
||||
mXlatLocalAddress4 = null;
|
||||
mXlatLocalAddress6 = null;
|
||||
mPid = INVALID_PID;
|
||||
mCookie = INVALID_COOKIE;
|
||||
}
|
||||
|
||||
private static native String native_selectIpv4Address(String v4addr, int prefixlen)
|
||||
@@ -403,4 +433,6 @@ public class ClatCoordinator {
|
||||
throws IOException;
|
||||
private static native void native_stopClatd(String iface, String pfx96, String v4, String v6,
|
||||
int pid) throws IOException;
|
||||
private static native long native_tagSocketAsClat(FileDescriptor sock) throws IOException;
|
||||
private static native void native_untagSocket(long cookie) throws IOException;
|
||||
}
|
||||
|
||||
@@ -26,13 +26,10 @@ import static com.android.testutils.MiscAsserts.assertThrows;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.anyString;
|
||||
import static org.mockito.Mockito.argThat;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.net.INetd;
|
||||
@@ -82,6 +79,7 @@ public class ClatCoordinatorTest {
|
||||
private static final int TUN_FD = 534;
|
||||
private static final int RAW_SOCK_FD = 535;
|
||||
private static final int PACKET_SOCK_FD = 536;
|
||||
private static final long RAW_SOCK_COOKIE = 27149;
|
||||
private static final ParcelFileDescriptor TUN_PFD = new ParcelFileDescriptor(
|
||||
new FileDescriptor());
|
||||
private static final ParcelFileDescriptor RAW_SOCK_PFD = new ParcelFileDescriptor(
|
||||
@@ -258,12 +256,35 @@ public class ClatCoordinatorTest {
|
||||
/**
|
||||
* Stop clatd.
|
||||
*/
|
||||
@Override
|
||||
public void stopClatd(@NonNull String iface, @NonNull String pfx96, @NonNull String v4,
|
||||
@NonNull String v6, int pid) throws IOException {
|
||||
if (pid == -1) {
|
||||
fail("unsupported arg: " + pid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag socket as clat.
|
||||
*/
|
||||
@Override
|
||||
public long tagSocketAsClat(@NonNull FileDescriptor sock) throws IOException {
|
||||
if (Objects.equals(RAW_SOCK_PFD.getFileDescriptor(), sock)) {
|
||||
return RAW_SOCK_COOKIE;
|
||||
}
|
||||
fail("unsupported arg: " + sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Untag socket.
|
||||
*/
|
||||
@Override
|
||||
public void untagSocket(long cookie) throws IOException {
|
||||
if (cookie != RAW_SOCK_COOKIE) {
|
||||
fail("unsupported arg: " + cookie);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@NonNull
|
||||
@@ -326,6 +347,8 @@ public class ClatCoordinatorTest {
|
||||
inOrder.verify(mDeps).addAnycastSetsockopt(
|
||||
argThat(fd -> Objects.equals(RAW_SOCK_PFD.getFileDescriptor(), fd)),
|
||||
eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(BASE_IFINDEX));
|
||||
inOrder.verify(mDeps).tagSocketAsClat(
|
||||
argThat(fd -> Objects.equals(RAW_SOCK_PFD.getFileDescriptor(), fd)));
|
||||
inOrder.verify(mDeps).configurePacketSocket(
|
||||
argThat(fd -> Objects.equals(PACKET_SOCK_PFD.getFileDescriptor(), fd)),
|
||||
eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(BASE_IFINDEX));
|
||||
@@ -348,13 +371,12 @@ public class ClatCoordinatorTest {
|
||||
coordinator.clatStop();
|
||||
inOrder.verify(mDeps).stopClatd(eq(BASE_IFACE), eq(NAT64_PREFIX_STRING),
|
||||
eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(CLATD_PID));
|
||||
inOrder.verify(mDeps).untagSocket(eq(RAW_SOCK_COOKIE));
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
|
||||
// [4] Expect an IO exception while stopping a clatd that doesn't exist.
|
||||
assertThrows("java.io.IOException: Clatd has not started", IOException.class,
|
||||
() -> coordinator.clatStop());
|
||||
inOrder.verify(mDeps, never()).stopClatd(anyString(), anyString(), anyString(),
|
||||
anyString(), anyInt());
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user