[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
};