diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp index 562b1a2787..84c4cff90f 100644 --- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp +++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp @@ -183,6 +183,32 @@ static jint com_android_server_connectivity_ClatCoordinator_openRawSocket6(JNIEn return sock; } +static void com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt( + JNIEnv* env, jobject clazz, jobject javaFd, jstring addr6, jint ifindex) { + int sock = netjniutils::GetNativeFileDescriptor(env, javaFd); + if (sock < 0) { + jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor"); + return; + } + + ScopedUtfChars addrStr(env, addr6); + + in6_addr addr; + if (inet_pton(AF_INET6, addrStr.c_str(), &addr) != 1) { + jniThrowExceptionFmt(env, "java/io/IOException", "Invalid IPv6 address %s", + addrStr.c_str()); + return; + } + + struct ipv6_mreq mreq = {addr, ifindex}; + int ret = setsockopt(sock, SOL_IPV6, IPV6_JOIN_ANYCAST, &mreq, sizeof(mreq)); + if (ret) { + jniThrowExceptionFmt(env, "java/io/IOException", "setsockopt IPV6_JOIN_ANYCAST failed: %s", + strerror(errno)); + return; + } +} + /* * JNI registration. */ @@ -201,6 +227,8 @@ static const JNINativeMethod gMethods[] = { (void*)com_android_server_connectivity_ClatCoordinator_openPacketSocket}, {"openRawSocket6", "(I)I", (void*)com_android_server_connectivity_ClatCoordinator_openRawSocket6}, + {"addAnycastSetsockopt", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", + (void*)com_android_server_connectivity_ClatCoordinator_addAnycastSetsockopt}, }; int register_android_server_connectivity_ClatCoordinator(JNIEnv* env) { diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java index cf956c59e3..578379d74e 100644 --- a/service/src/com/android/server/connectivity/ClatCoordinator.java +++ b/service/src/com/android/server/connectivity/ClatCoordinator.java @@ -32,7 +32,9 @@ import android.os.ServiceSpecificException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.InterfaceParams; +import java.io.FileDescriptor; import java.io.IOException; import java.net.InetAddress; import java.nio.ByteBuffer; @@ -63,6 +65,7 @@ public class ClatCoordinator { static final int INIT_V4ADDR_PREFIX_LEN = 29; private static final InetAddress GOOGLE_DNS_4 = InetAddress.parseNumericAddress("8.8.8.8"); + private static final int INVALID_IFINDEX = 0; private static final int INVALID_PID = 0; @NonNull @@ -89,6 +92,14 @@ public class ClatCoordinator { return ParcelFileDescriptor.adoptFd(fd); } + /** + * Get interface index for a given interface. + */ + public int getInterfaceIndex(String ifName) { + final InterfaceParams params = InterfaceParams.getByName(ifName); + return params != null ? params.index : INVALID_IFINDEX; + } + /** * Create tun interface for a given interface name. */ @@ -135,6 +146,14 @@ public class ClatCoordinator { public int jniOpenRawSocket6(int mark) throws IOException { return openRawSocket6(mark); } + + /** + * Add anycast setsockopt. + */ + public void jniAddAnycastSetsockopt(@NonNull FileDescriptor sock, String v6, int ifindex) + throws IOException { + addAnycastSetsockopt(sock, v6, ifindex); + } } @VisibleForTesting @@ -258,6 +277,18 @@ public class ClatCoordinator { throw new IOException("Open raw socket failed: " + e); } + final int ifaceIndex = mDeps.getInterfaceIndex(iface); + if (ifaceIndex == INVALID_IFINDEX) { + throw new IOException("Fail to get interface index for interface " + iface); + } + + // Start translating packets to the new prefix. + try { + mDeps.jniAddAnycastSetsockopt(writeSock6.getFileDescriptor(), v6, ifaceIndex); + } catch (IOException e) { + throw new IOException("add anycast sockopt failed: " + e); + } + // TODO: start clatd and returns local xlat464 v6 address. return null; } @@ -271,4 +302,6 @@ public class ClatCoordinator { throws IOException; private static native int openPacketSocket() throws IOException; private static native int openRawSocket6(int mark) throws IOException; + private static native void addAnycastSetsockopt(FileDescriptor sock, String v6, int ifindex) + throws IOException; }