Merge 91bd9db65b819e58dbf14eef67b8729b419ebc8d on remote branch

Change-Id: I5206f3fceb5227127c8af87a765f5e2becd4fdd1
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
index 102ecd9..e758692 100644
--- a/bpf_progs/clatd.c
+++ b/bpf_progs/clatd.c
@@ -26,6 +26,10 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+// bionic kernel uapi linux/udp.h header is munged...
+#define __kernel_udphdr udphdr
+#include <linux/udp.h>
+
 #include "bpf_helpers.h"
 #include "bpf_net_helpers.h"
 #include "netdbpf/bpf_shared.h"
@@ -226,9 +230,18 @@
 
     switch (ip4->protocol) {
         case IPPROTO_TCP:  // For TCP & UDP the checksum neutrality of the chosen IPv6
-        case IPPROTO_UDP:  // address means there is no need to update their checksums.
-        case IPPROTO_GRE:  // We do not need to bother looking at GRE/ESP headers,
-        case IPPROTO_ESP:  // since there is never a checksum to update.
+        case IPPROTO_GRE:  // address means there is no need to update their checksums.
+        case IPPROTO_ESP:  // We do not need to bother looking at GRE/ESP headers,
+            break;         // since there is never a checksum to update.
+
+        case IPPROTO_UDP:  // See above comment, but must also have UDP header...
+            if (data + sizeof(*ip4) + sizeof(struct udphdr) > data_end) return TC_ACT_OK;
+            const struct udphdr* uh = (const struct udphdr*)(ip4 + 1);
+            // If IPv4/UDP checksum is 0 then fallback to clatd so it can calculate the
+            // checksum.  Otherwise the network or more likely the NAT64 gateway might
+            // drop the packet because in most cases IPv6/UDP packets with a zero checksum
+            // are invalid. See RFC 6935.  TODO: calculate checksum via bpf_csum_diff()
+            if (!uh->check) return TC_ACT_OK;
             break;
 
         default:  // do not know how to handle anything else
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index 70e0ae7..f347028 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -30,6 +30,7 @@
 #include "netdbpf/bpf_shared.h"
 
 // This is defined for cgroup bpf filter only.
+#define BPF_DROP_UNLESS_DNS 2
 #define BPF_PASS 1
 #define BPF_DROP 0
 
@@ -206,7 +207,7 @@
     if (direction == BPF_INGRESS && (uidRules & IIF_MATCH)) {
         // Drops packets not coming from lo nor the whitelisted interface
         if (allowed_iif && skb->ifindex != 1 && skb->ifindex != allowed_iif) {
-            return BPF_DROP;
+            return BPF_DROP_UNLESS_DNS;
         }
     }
     return BPF_PASS;
@@ -247,6 +248,17 @@
         tag = 0;
     }
 
+// Workaround for secureVPN with VpnIsolation enabled, refer to b/159994981 for details.
+// Keep TAG_SYSTEM_DNS in sync with DnsResolver/include/netd_resolv/resolv.h
+// and TrafficStatsConstants.java
+#define TAG_SYSTEM_DNS 0xFFFFFF82
+    if (tag == TAG_SYSTEM_DNS && uid == AID_DNS) {
+        uid = sock_uid;
+        if (match == BPF_DROP_UNLESS_DNS) match = BPF_PASS;
+    } else {
+        if (match == BPF_DROP_UNLESS_DNS) match = BPF_DROP;
+    }
+
     StatsKey key = {.uid = uid, .tag = tag, .counterSet = 0, .ifaceIndex = skb->ifindex};
 
     uint8_t* counterSet = bpf_uid_counterset_map_lookup_elem(&uid);
diff --git a/server/main.cpp b/server/main.cpp
index 0a86b0a..4949ff6 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -83,6 +83,8 @@
 }
 
 int tagSocketCallback(int sockFd, uint32_t tag, uid_t uid, pid_t) {
+    // Workaround for secureVPN with VpnIsolation enabled, refer to b/159994981 for details.
+    if (tag == TAG_SYSTEM_DNS) uid = AID_DNS;
     return gCtls->trafficCtrl.tagSocket(sockFd, tag, uid, geteuid());
 }