From 130e75b0ab7f50257d1c6b5fa1b96894fb916309 Mon Sep 17 00:00:00 2001 From: t-m-w Date: Mon, 24 Oct 2022 02:54:07 +0000 Subject: [PATCH] Bypass VPN lockdown for clat initialization This allows clat to initialize properly when VPNs are configured with "Block connections without VPN", rather than to error out with "no IPv6 addresses were available for clat". This issue primarily affects particular mobile networks configured with NAT64 (without direct IPv4 connectivity). Bug: 255040839 Change-Id: I4a8ee0295e0f5d1e330f7529856347b8bd10360c --- ...om_android_server_connectivity_ClatCoordinator.cpp | 7 ++++--- service/native/libs/libclat/clatutils.cpp | 11 ++++++++++- service/native/libs/libclat/clatutils_test.cpp | 3 ++- .../native/libs/libclat/include/libclat/clatutils.h | 2 +- .../android/server/connectivity/ClatCoordinator.java | 10 +++++----- .../server/connectivity/ClatCoordinatorTest.java | 8 ++++---- 6 files changed, 26 insertions(+), 15 deletions(-) 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 d7c32873e9..fecddd71ad 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(); } }