diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp index de0e20a252..5cd6e5ddf0 100644 --- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp +++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp @@ -87,7 +87,8 @@ jstring com_android_server_connectivity_ClatCoordinator_selectIpv4Address(JNIEnv // Picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix. jstring com_android_server_connectivity_ClatCoordinator_generateIpv6Address( - JNIEnv* env, jobject clazz, jstring ifaceStr, jstring v4Str, jstring prefix64Str) { + JNIEnv* env, jobject clazz, jstring ifaceStr, jstring v4Str, jstring prefix64Str, + jint mark) { ScopedUtfChars iface(env, ifaceStr); ScopedUtfChars addr4(env, v4Str); ScopedUtfChars prefix64(env, prefix64Str); @@ -111,7 +112,7 @@ jstring com_android_server_connectivity_ClatCoordinator_generateIpv6Address( } in6_addr v6; - if (net::clat::generateIpv6Address(iface.c_str(), v4, nat64Prefix, &v6)) { + if (net::clat::generateIpv6Address(iface.c_str(), v4, nat64Prefix, &v6, mark)) { jniThrowExceptionFmt(env, "java/io/IOException", "Unable to find global source address on %s for %s", iface.c_str(), prefix64.c_str()); @@ -447,7 +448,7 @@ static const JNINativeMethod gMethods[] = { {"native_selectIpv4Address", "(Ljava/lang/String;I)Ljava/lang/String;", (void*)com_android_server_connectivity_ClatCoordinator_selectIpv4Address}, {"native_generateIpv6Address", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;", (void*)com_android_server_connectivity_ClatCoordinator_generateIpv6Address}, {"native_createTunInterface", "(Ljava/lang/String;)I", (void*)com_android_server_connectivity_ClatCoordinator_createTunInterface}, diff --git a/service/native/libs/libclat/clatutils.cpp b/service/native/libs/libclat/clatutils.cpp index 4a125ba9ff..be866120e6 100644 --- a/service/native/libs/libclat/clatutils.cpp +++ b/service/native/libs/libclat/clatutils.cpp @@ -126,10 +126,19 @@ void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Pr // Picks a random interface ID that is checksum neutral with the IPv4 address and the NAT64 prefix. int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix, - in6_addr* v6) { + in6_addr* v6, uint32_t mark) { int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (s == -1) return -errno; + // Socket's mark affects routing decisions (network selection) + // An fwmark is necessary for clat to bypass the VPN during initialization. + if ((mark != MARK_UNSET) && setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark))) { + int ret = errno; + ALOGE("setsockopt(SOL_SOCKET, SO_MARK) failed: %s", strerror(errno)); + close(s); + return -ret; + } + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, iface, strlen(iface) + 1) == -1) { close(s); return -errno; diff --git a/service/native/libs/libclat/clatutils_test.cpp b/service/native/libs/libclat/clatutils_test.cpp index 8cca1f44bf..abd4e81f8f 100644 --- a/service/native/libs/libclat/clatutils_test.cpp +++ b/service/native/libs/libclat/clatutils_test.cpp @@ -202,7 +202,8 @@ TEST_F(ClatUtils, GenerateIpv6AddressFailWithUlaSocketAddress) { in6_addr v6; EXPECT_EQ(1, inet_pton(AF_INET6, "::", &v6)); // initialize as zero - EXPECT_EQ(-ENETUNREACH, generateIpv6Address(tun.name().c_str(), v4, nat64Prefix, &v6)); + // 0u is MARK_UNSET + EXPECT_EQ(-ENETUNREACH, generateIpv6Address(tun.name().c_str(), v4, nat64Prefix, &v6, 0u)); EXPECT_TRUE(IN6_IS_ADDR_ULA(&v6)); tun.destroy(); diff --git a/service/native/libs/libclat/include/libclat/clatutils.h b/service/native/libs/libclat/include/libclat/clatutils.h index 812c86eb21..991b1938cc 100644 --- a/service/native/libs/libclat/include/libclat/clatutils.h +++ b/service/native/libs/libclat/include/libclat/clatutils.h @@ -24,7 +24,7 @@ bool isIpv4AddressFree(in_addr_t addr); in_addr_t selectIpv4Address(const in_addr ip, int16_t prefixlen); void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix); int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix, - in6_addr* v6); + in6_addr* v6, uint32_t mark); int detect_mtu(const struct in6_addr* plat_subnet, uint32_t plat_suffix, uint32_t mark); int configure_packet_socket(int sock, in6_addr* addr, int ifindex); diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java index 2aa04a4894..42b382777b 100644 --- a/service/src/com/android/server/connectivity/ClatCoordinator.java +++ b/service/src/com/android/server/connectivity/ClatCoordinator.java @@ -183,8 +183,8 @@ public class ClatCoordinator { */ @NonNull public String generateIpv6Address(@NonNull String iface, @NonNull String v4, - @NonNull String prefix64) throws IOException { - return native_generateIpv6Address(iface, v4, prefix64); + @NonNull String prefix64, int mark) throws IOException { + return native_generateIpv6Address(iface, v4, prefix64, mark); } /** @@ -629,10 +629,11 @@ public class ClatCoordinator { } // [2] Generate a checksum-neutral IID. + final Integer fwmark = getFwmark(netId); final String pfx96Str = nat64Prefix.getAddress().getHostAddress(); final String v6Str; try { - v6Str = mDeps.generateIpv6Address(iface, v4Str, pfx96Str); + v6Str = mDeps.generateIpv6Address(iface, v4Str, pfx96Str, fwmark); } catch (IOException e) { throw new IOException("no IPv6 addresses were available for clat: " + e); } @@ -676,7 +677,6 @@ public class ClatCoordinator { } // Detect ipv4 mtu. - final Integer fwmark = getFwmark(netId); final int detectedMtu; try { detectedMtu = mDeps.detectMtu(pfx96Str, @@ -931,7 +931,7 @@ public class ClatCoordinator { private static native String native_selectIpv4Address(String v4addr, int prefixlen) throws IOException; private static native String native_generateIpv6Address(String iface, String v4, - String prefix64) throws IOException; + String prefix64, int mark) throws IOException; private static native int native_createTunInterface(String tuniface) throws IOException; private static native int native_detectMtu(String platSubnet, int platSuffix, int mark) throws IOException; diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java index 85bc4a905b..49e3514536 100644 --- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java +++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java @@ -220,12 +220,12 @@ public class ClatCoordinatorTest { */ @Override public String generateIpv6Address(@NonNull String iface, @NonNull String v4, - @NonNull String prefix64) throws IOException { + @NonNull String prefix64, int mark) throws IOException { if (BASE_IFACE.equals(iface) && XLAT_LOCAL_IPV4ADDR_STRING.equals(v4) && NAT64_PREFIX_STRING.equals(prefix64)) { return XLAT_LOCAL_IPV6ADDR_STRING; } - fail("unsupported args: " + iface + ", " + v4 + ", " + prefix64); + fail("unsupported args: " + iface + ", " + v4 + ", " + prefix64 + ", " + mark); return null; } @@ -417,7 +417,7 @@ public class ClatCoordinatorTest { // Generate a checksum-neutral IID. inOrder.verify(mDeps).generateIpv6Address(eq(BASE_IFACE), - eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(NAT64_PREFIX_STRING)); + eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(NAT64_PREFIX_STRING), eq(MARK)); // Open, configure and bring up the tun interface. inOrder.verify(mDeps).createTunInterface(eq(STACKED_IFACE)); @@ -617,7 +617,7 @@ public class ClatCoordinatorTest { class FailureDependencies extends TestDependencies { @Override public String generateIpv6Address(@NonNull String iface, @NonNull String v4, - @NonNull String prefix64) throws IOException { + @NonNull String prefix64, int mark) throws IOException { throw new IOException(); } }