[ipsec-qtaguid] Reserve mark, add ipsec bw exemptions

This change reserves a mark denoting that a packet has already been
accounted for, along with adding rules in BandwidthController to support
IPSec packets being billed correctly.

Bug: 62994731
Test: BandwidthControllerTest updated, passing. CTS tests also modified
and passing

Change-Id: I8b42975d1502a0d3b9e533bddc0892cfe1556bed
diff --git a/server/BandwidthController.cpp b/server/BandwidthController.cpp
index 04e5d75..4a5fad8 100644
--- a/server/BandwidthController.cpp
+++ b/server/BandwidthController.cpp
@@ -53,6 +53,7 @@
 #include <netdutils/Syscalls.h>
 #include "BandwidthController.h"
 #include "FirewallController.h" /* For makeCriticalCommands */
+#include "Fwmark.h"
 #include "NetdConstants.h"
 
 /* Alphabetical */
@@ -168,10 +169,53 @@
     COMMIT_AND_CLOSE
 };
 
+static const uint32_t uidBillingMask = Fwmark::getUidBillingMask();
+
+/**
+ * Basic commands for creation of hooks into data accounting and data boxes.
+ *
+ * Included in these commands are rules to prevent the double-counting of IPsec
+ * packets. The general overview is as follows:
+ * > All interface counters (counted in PREROUTING, POSTROUTING) must be
+ *     completely accurate, and count only the outer packet. As such, the inner
+ *     packet must be ignored, which is done through the use of two rules: use
+ *     of the policy module (for tunnel mode), and VTI interface checks (for
+ *     tunnel or transport-in-tunnel mode). The VTI interfaces should be named
+ *     ipsec*
+ * > Outbound UID billing can always be done with the outer packets, due to the
+ *     ability to always find the correct UID (based on the skb->sk). As such,
+ *     the inner packets should be ignored based on the policy module, or the
+ *     output interface if a VTI (ipsec+)
+ * > Inbound UDP-encap-ESP packets can be correctly mapped to the UID that
+ *     opened the encap socket, and as such, should be billed as early as
+ *     possible (for transport mode; tunnel mode usage should be billed to
+ *     sending/receiving application). Due to the inner packet being
+ *     indistinguishable from the inner packet of ESP, a uidBillingDone mark
+ *     has to be applied to prevent counting a second time.
+ * > Inbound ESP has no socket, and as such must be accounted later. ESP
+ *     protocol packets are skipped via a blanket rule.
+ * > Note that this solution is asymmetrical. Adding the VTI or policy matcher
+ *     ignore rule in the input chain would actually break the INPUT chain;
+ *     Those rules are designed to ignore inner packets, and in the tunnel
+ *     mode UDP, or any ESP case, we would not have billed the outer packet.
+ *
+ * See go/ipsec-data-accounting for more information.
+ */
 static const std::vector<std::string> IPT_BASIC_ACCOUNTING_COMMANDS = {
     "*filter",
+    // Prevents IPSec double counting (ESP and UDP-encap-ESP respectively)
+    "-A bw_INPUT -p esp -j RETURN",
+    StringPrintf("-A bw_INPUT -m mark --mark 0x%x/0x%x -j RETURN",
+                 uidBillingMask, uidBillingMask),
     "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
+    StringPrintf("-A bw_INPUT -j MARK --or-mark 0x%x", uidBillingMask),
+
+    // Prevents IPSec double counting (Tunnel mode and Transport mode,
+    // respectively)
+    "-A bw_OUTPUT -o " IPSEC_IFACE_PREFIX "+ -j RETURN",
+    "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN",
     "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
+
     "-A bw_costly_shared --jump bw_penalty_box",
     "-A bw_penalty_box --jump bw_happy_box",
     "-A bw_happy_box --jump bw_data_saver",
@@ -180,11 +224,21 @@
     "COMMIT",
 
     "*raw",
+    // Prevents IPSec double counting (Tunnel mode and Transport mode,
+    // respectively)
+    "-A bw_raw_PREROUTING -i " IPSEC_IFACE_PREFIX "+ -j RETURN",
+    "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN",
     "-A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
     "COMMIT",
 
     "*mangle",
+    // Prevents IPSec double counting (Tunnel mode and Transport mode,
+    // respectively)
+    "-A bw_mangle_POSTROUTING -o " IPSEC_IFACE_PREFIX "+ -j RETURN",
+    "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN",
     "-A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
+    StringPrintf("-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x%x",
+                 uidBillingMask), // Clear the mark before sending this packet
     COMMIT_AND_CLOSE
 };