firewall: use watch-outputs to track changes in zone->interface map

includes a horrible hack to work around (claimed (by me)) deficiencies
in the nftables parser
This commit is contained in:
Daniel Barlow
2025-02-28 00:43:20 +00:00
parent 929226ed9e
commit 6649ebeccd
7 changed files with 108 additions and 48 deletions

View File

@@ -5,6 +5,9 @@
nftables,
writeFennel,
anoia,
svc,
lua,
output-template,
lualinux,
linotify,
}:
@@ -18,14 +21,18 @@ let
inherit (lib.attrsets) mapAttrs' nameValuePair mapAttrsToList;
inherit (lib.strings) concatStringsSep;
inherit (lib.lists) flatten;
inherit (builtins) concatLists attrValues;
inherit (liminix) outputRef;
mkSet =
family: name:
nameValuePair "${name}-set-${family}" {
kind = "set";
inherit name family;
type = "ifname";
elements = map (s: "{{ output(${builtins.toJSON s}, \"ifname\", \"\") }}") zones.${name};
};
sets = (mapAttrs' (n: _: mkSet "ip" n) zones) // (mapAttrs' (n: _: mkSet "ip6" n) zones);
sets = (mapAttrs' (n: _: mkSet "ip" n) zones) //
(mapAttrs' (n: _: mkSet "ip6" n) zones);
allRules = lib.recursiveUpdate extraRules (lib.recursiveUpdate (builtins.trace sets sets) rules);
script = firewallgen "firewall1.nft" allRules;
ifwatch = writeFennel "ifwatch" {
@@ -37,13 +44,26 @@ let
mainFunction = "run";
} ./ifwatch.fnl;
watchArg = z: intfs: map (i: "${z}:${i}/.outputs") intfs;
in
longrun {
name = "firewall";
run = ''
${script}
PATH=${nftables}/bin:$PATH
${ifwatch} ${concatStringsSep " " (flatten (mapAttrsToList watchArg zones))}
'';
finish = "${nftables}/bin/nft flush ruleset";
service = longrun {
inherit name;
run = ''
mkdir -p /run/${name}; in_outputs ${name}
# exec > /dev/console 2>&1
echo RESTARTING FIREWALL >/dev/console
PATH=${nftables}/bin:${lua}/bin:$PATH
${output-template}/bin/output-template '{{' '}}' < ${script} | lua -e 'for x in io.lines() do if not string.match(x, "elements = {%s+}") then print(x) end; end' > /run/${name}/fw.nft
# cat /run/${name}/fw.nft > /dev/console
nft -f /run/${name}/fw.nft
while sleep 86400 ; do : ; done
'';
finish = "${nftables}/bin/nft flush ruleset";
};
in
svc.secrets.subscriber.build {
watch =
concatLists
(mapAttrsToList (_zone : services : map (s: outputRef s "ifname") services) zones);
inherit service;
}

View File

@@ -13,12 +13,11 @@
}:
let
inherit (liminix.services) oneshot longrun;
inherit (builtins) length head toString;
inherit (lib) unique optional optionals;
inherit (builtins) map length head toString;
inherit (lib) unique optional optionals concatStringsSep;
inherit (service) name;
watched-services = unique (map (f: f "service") watch);
paths = unique (map (f: f "path") watch);
restart-flag =
{
@@ -35,17 +34,11 @@ let
}
.${action};
watched-service =
if length watched-services == 0 then
null
else if length watched-services == 1 then
head watched-services
else
throw "cannot subscribe to more than one source service for secrets";
watcher =
let
name' = "restart-${name}";
refs = concatStringsSep " "
(map (s: "${s "service"}:${s "path"}") watch);
in
longrun {
name = name';
@@ -55,16 +48,16 @@ let
if test -e $dir/notification-fd; then flag="-U"; else flag="-u"; fi
${s6}/bin/s6-svwait $flag /run/service/${name} || exit
PATH=${s6-rc}/bin:${s6}/bin:$PATH
${watch-outputs}/bin/watch-outputs ${restart-flag} ${name} ${watched-service.name} ${lib.concatStringsSep " " paths}
${watch-outputs}/bin/watch-outputs ${restart-flag} ${name} ${refs}
'';
};
in
service.overrideAttrs (o: {
buildInputs = (lim.orEmpty o.buildInputs) ++ optional (watched-service != null) watcher;
buildInputs = (lim.orEmpty o.buildInputs) ++ optional (watch != []) watcher;
dependencies =
(lim.orEmpty o.dependencies)
++ optionals (watched-service != null) [
watcher
watched-service
];
# ++ optionals
# (watch != [])
# ([ watcher ] ++ watched-services);
;
})