Merge "Bypass VPN lockdown for clat initialization"
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
index de0e20a..5cd6e5d 100644
--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
+++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -87,7 +87,8 @@
 
 // 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 @@
     }
 
     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 @@
         {"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 4a125ba..be86612 100644
--- a/service/native/libs/libclat/clatutils.cpp
+++ b/service/native/libs/libclat/clatutils.cpp
@@ -126,10 +126,19 @@
 
 // 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 8cca1f4..abd4e81 100644
--- a/service/native/libs/libclat/clatutils_test.cpp
+++ b/service/native/libs/libclat/clatutils_test.cpp
@@ -202,7 +202,8 @@
     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 812c86e..991b193 100644
--- a/service/native/libs/libclat/include/libclat/clatutils.h
+++ b/service/native/libs/libclat/include/libclat/clatutils.h
@@ -24,7 +24,7 @@
 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 2aa04a4..42b3827 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -183,8 +183,8 @@
          */
         @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 @@
         }
 
         // [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 @@
         }
 
         // Detect ipv4 mtu.
-        final Integer fwmark = getFwmark(netId);
         final int detectedMtu;
         try {
             detectedMtu = mDeps.detectMtu(pfx96Str,
@@ -931,7 +931,7 @@
     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 85bc4a9..49e3514 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 @@
          */
         @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 @@
 
         // 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 @@
         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();
             }
         }