Watch
0
0
Fork
You've already forked hyperhive
0

egress: forward = reject for intercepted agents, direct_mac exempt in log mode too

This commit is contained in:
atlas 2026-11-13 12:22:36 +01:00
commit dad15ca855

View file

@ -72,17 +72,17 @@ let
# The two settings of `egress.forward` the ordinary host (`log`) does not
# render, for ../host-modules/hive-egress.nix: `accept` leaves the table
# without a forward chain, `drop` is refused by an assertion. The `accept`
# host also sets `egress.antiSpoof = "log"`, the one setting the ordinary
# host (`drop`) does not render.
# without a forward chain, `reject` renders the chain that refuses. The
# `accept` host also sets `egress.antiSpoof = "log"`, the one setting the
# ordinary host (`drop`) does not render.
egressForwardAccept = hive {
network.enable = true;
network.egress.forward = "accept";
network.egress.antiSpoof = "log";
};
egressForwardDrop = hive {
egressForwardReject = hive {
network.enable = true;
network.egress.forward = "drop";
network.egress.forward = "reject";
};
# Every hive defaults the agents' queue address to the queue's name, so the
@ -1561,6 +1561,13 @@ let
&& lib.hasInfix ''iifname "hive-br0" oifname != "hive-br0" ct state new update @log_v6 { ip6 saddr limit rate'' chain
&& lib.hasInfix ''log prefix "hive-egress-would-drop "'' chain
&& lib.hasInfix ''iifname "hive-br0" oifname "wg-hive" accept'' chain
# The mesh comes first, then the exempt MACs (service containers and
# unrestricted agents), then the counter and the logging: a flow of an
# exempt MAC is neither counted nor logged.
&& lib.hasInfix ''iifname "hive-br0" oifname != "hive-br0" ether saddr @direct_mac accept'' chain
&& idx ''oifname "wg-hive" accept'' < idx "ether saddr @direct_mac accept"
&& idx "ether saddr @direct_mac accept" < idx "counter"
&& idx "counter" < idx "update @log_v4"
# The per-source rules accept after logging, and the unmetered rule
# comes after both: a flow gets one line, and one the per-source rules
# cannot log still gets the unmetered one.
@ -1672,22 +1679,48 @@ let
&& !(lib.any (a: !a.assertion) egressForwardAccept.assertions);
}
{
# `drop` is refused by an assertion that names the option and says it is
# not available; `bare` and the `accept` host, which set `log` and
# `accept`, are the controls that the lookup finds nothing for them.
name = "egress.forward drop is refused as not available yet";
# `reject` logs and refuses in one rule, as a TCP rule (reset) and a
# non-TCP rule (ICMP admin-prohibited) for each of the four log/verdict
# positions, after the mesh and the exempt MACs. The ruleset is read as
# text. The `accept` count (the mesh and the exempt MACs only) and the
# `bare` host, whose chain has no refusal, are the controls that the
# lookups find what is there.
name = "egress.forward reject refuses the bridge's forwarded flows after the mesh and the exempt MACs";
ok =
let
refused =
m:
lib.any (
a:
!a.assertion
&& lib.hasInfix "services.hyperhive.network.egress.forward" a.message
&& lib.hasInfix "not available yet" a.message
) m.assertions;
text = lib.head (
lib.splitString "table bridge hive_egress {" egressForwardReject.services.hyperhive.network.egress.ruleset
);
chain = lib.last (lib.splitString "chain forward" text);
rules = lib.filter (l: l != "" && l != "}") (map lib.trim (lib.splitString "\n" chain));
idx = pat: lib.lists.findFirstIndex (lib.hasInfix pat) 1000 rules;
tcp = lib.filter (lib.hasInfix " meta l4proto tcp ") rules;
other = lib.filter (lib.hasInfix " meta l4proto != tcp") rules;
logged = lib.filter (lib.hasInfix "log prefix") rules;
bareText = bare.services.hyperhive.network.egress.ruleset;
in
refused egressForwardDrop && !(refused bare) && !(refused egressForwardAccept);
!(lib.any (a: !a.assertion) egressForwardReject.assertions)
&& lib.hasInfix "type filter hook forward priority filter - 10; policy accept;" chain
&& lib.hasInfix "chain input" text
&& idx ''oifname "wg-hive" accept'' < idx "ether saddr @direct_mac accept"
&& idx "ether saddr @direct_mac accept" < idx "counter"
&& idx "counter" < idx "reject"
&& lib.length (lib.filter (lib.hasSuffix " accept") rules) == 2
&& lib.length tcp == 4
&& lib.length other == 4
&& lib.all (lib.hasSuffix " reject with tcp reset") tcp
&& lib.all (lib.hasSuffix " reject with icmpx type admin-prohibited") other
&& lib.length logged == 6
&& lib.all (l: lib.hasInfix ''log prefix "hive-egress-reject'' l) logged
&& !(lib.hasInfix "hive-egress-would-drop" chain)
&& lib.all (
l: lib.hasInfix "update @log_" l || lib.hasInfix "limit rate 5/second burst 50 packets" l
) logged
&&
lib.last rules
== ''iifname "hive-br0" oifname != "hive-br0" meta l4proto != tcp reject with icmpx type admin-prohibited''
&& !(lib.hasInfix "reject with" bareText)
&& lib.hasInfix "would-drop" bareText;
}
{
# The redirect of the agents' web traffic: IPv4 TCP 80 and 443 from the
@ -1715,6 +1748,10 @@ let
lib.hasInfix "type nat hook prerouting priority dstnat; policy accept;" chain
&& lib.hasInfix "set direct_mac { type ether_addr; }" inet
&& idx "ether saddr @direct_mac return" < idx "tcp dport 80"
# The same MACs are exempt in the forward chain, which follows the
# redirect chain in the table.
&& lib.hasInfix ''oifname != "hive-br0" ether saddr @direct_mac accept'' inet
&& !(lib.hasInfix "ether saddr @direct_mac accept" without)
&& idx "fib daddr type local return" < idx "tcp dport 80"
&& idx ''fib daddr oifname { "hive-br0", "wg-hive" } return'' < idx "tcp dport 80"
&& lib.length redirects == 2