patchpanel: mark connections with fwmark routing tags
This patch enables per-network tracking of connections using
CONNMARK conntrack for storing the fwmark routing tag associated with
the output interface selected by routing. This is achieved with a mangle
POSTROUTING rule using the CONNMARK target.
A follow-up patch in shill will add the final piece and add ip rules
using these fwmark routing tags to complete the per-network connection
routing and fwmark routing system.
BUG=b:161507671
BUG=b:161508179
TEST=Unit tests. Manual tests: verified with /proc/net/ip_conntrack that
conntrack entries get marked with the fwmark routing tag of the network
through which they are routed.
Change-Id: I9f147179283246c1aafda87ad716e209ce387736
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2377337
Tested-by: Hugo Benichi <hugobenichi@google.com>
Tested-by: Mitu Aktar <mitu64649@gmail.com>
Commit-Queue: Hugo Benichi <hugobenichi@google.com>
Reviewed-by: Taoyu Li <taoyl@chromium.org>
diff --git a/patchpanel/datapath.cc b/patchpanel/datapath.cc
index 73075bd..6155749 100644
--- a/patchpanel/datapath.cc
+++ b/patchpanel/datapath.cc
@@ -571,6 +571,56 @@
process_runner_->ip6("addr", "del", {ipv6_addr, "dev", ifname});
}
+void Datapath::StartConnectionPinning(const std::string& ext_ifname) {
+ if (!ModifyConnmarkSetPostrouting(IpFamily::Dual, "-A", ext_ifname))
+ LOG(ERROR) << "Could not start connection pinning on " << ext_ifname;
+}
+
+void Datapath::StopConnectionPinning(const std::string& ext_ifname) {
+ if (!ModifyConnmarkSetPostrouting(IpFamily::Dual, "-D", ext_ifname))
+ LOG(ERROR) << "Could not stop connection pinning on " << ext_ifname;
+}
+
+bool Datapath::ModifyConnmarkSetPostrouting(IpFamily family,
+ const std::string& op,
+ const std::string& oif) {
+ if (oif.empty()) {
+ LOG(ERROR) << "Cannot change POSTROUTING CONNMARK set-mark with no "
+ "interface specified";
+ return false;
+ }
+
+ if (!IsValidIpFamily(family)) {
+ LOG(ERROR) << "Cannot change POSTROUTING CONNMARK set-mark for " << oif
+ << ": incorrect IP family " << family;
+ return false;
+ }
+
+ int ifindex = FindIfIndex(oif);
+ if (ifindex == 0) {
+ PLOG(ERROR) << "if_nametoindex(" << oif << ") failed";
+ return false;
+ }
+
+ std::vector<std::string> args = {op,
+ "POSTROUTING",
+ "-o",
+ oif,
+ "-j",
+ "CONNMARK",
+ "--set-mark",
+ Fwmark::FromIfIndex(ifindex).ToString() +
+ "/" + kFwmarkRoutingMask.ToString(),
+ "-w"};
+
+ bool success = true;
+ if (family & IPv4)
+ success &= process_runner_->iptables("mangle", args) == 0;
+ if (family & IPv6)
+ success &= process_runner_->ip6tables("mangle", args) == 0;
+ return false;
+}
+
bool Datapath::ModifyConnmarkRestore(IpFamily family,
const std::string& chain,
const std::string& op,