From 21f2cc6dad805a583ec64d53d342edd938847fcb Mon Sep 17 00:00:00 2001
From: Daniel Barlow <dan@telent.net>
Date: Thu, 6 Feb 2025 11:57:06 +0000
Subject: [PATCH] WIP add zones to firewall module

- zones are an attrset of name -> [interface-service]

- the firewall will create empty "ifname" sets for each zone name
 in each address family (ip, ip6)

- then watch the interface services, and add the "ifname" outputs
to the corresponding sets when they appear

This commit only adds the empty sets
---
 examples/rotuer.nix                |  4 ++++
 modules/firewall/default-rules.nix |  9 ---------
 modules/firewall/default.nix       | 10 ++++++++++
 modules/firewall/service.nix       | 28 ++++++++++++++++++++++------
 modules/profiles/gateway.nix       |  4 ++++
 5 files changed, 40 insertions(+), 15 deletions(-)

diff --git a/examples/rotuer.nix b/examples/rotuer.nix
index 1d2a726..78251e2 100644
--- a/examples/rotuer.nix
+++ b/examples/rotuer.nix
@@ -69,6 +69,10 @@ in rec {
     firewall = {
       enable = true;
       rules = secrets.firewallRules;
+      zones = {
+        lan = [ config.services.int ];
+        wan = [ config.services.wan  ] ;
+      };
     };
     wireless.networks = {
       # EDIT: if you have more or fewer wireless radios, here is where
diff --git a/modules/firewall/default-rules.nix b/modules/firewall/default-rules.nix
index e8ee4d0..e821d70 100644
--- a/modules/firewall/default-rules.nix
+++ b/modules/firewall/default-rules.nix
@@ -248,13 +248,4 @@ in {
     ];
   };
 
-  lan-set-ip = ifname-set "ip" "lan" [ "int" ];
-  wan-set-ip = ifname-set "ip" "wan" [ "ppp0" ];
-  dmz-set-ip = ifname-set "ip" "dmz" [ ];
-  guest-set-ip = ifname-set "ip" "guest" [ ];
-
-  lan-set-ip6 = ifname-set "ip6" "lan" [ "int" ];
-  wan-set-ip6 = ifname-set "ip6" "wan" [ "ppp0" ];
-  dmz-set-ip6 = ifname-set "ip6" "dmz" [ ];
-  guest-set-ip6 = ifname-set "ip6" "guest" [ ];
 }
diff --git a/modules/firewall/default.nix b/modules/firewall/default.nix
index 539eba5..03ff1d9 100644
--- a/modules/firewall/default.nix
+++ b/modules/firewall/default.nix
@@ -60,6 +60,16 @@ in
               description = "firewall ruleset";
               default = {};
             };
+            zones = mkOption {
+              type = types.attrsOf (types.listOf  liminix.lib.types.service);
+              default = {};
+              example = lib.literalExpression ''
+                {
+                  lan = with config.hardware.networkInterfaces; [ int ];
+                  wan = [ config.services.ppp0 ];
+                }
+              '';
+            };
             rules = mkOption {
               type = types.attrsOf types.attrs;   # we could usefully tighten this a bit :-)
               default = import ./default-rules.nix;
diff --git a/modules/firewall/service.nix b/modules/firewall/service.nix
index 9bb022f..ca8431e 100644
--- a/modules/firewall/service.nix
+++ b/modules/firewall/service.nix
@@ -4,12 +4,28 @@
 , firewallgen
 , nftables
 }:
-{ rules, extraRules }:
+{ rules, extraRules, zones }:
 let
-  inherit (liminix.services) oneshot;
-  script = firewallgen "firewall.nft" (lib.recursiveUpdate rules extraRules);
-in oneshot {
+  inherit (liminix.services) longrun ; # oneshot;
+  inherit (lib.attrsets) mapAttrs' nameValuePair;
+  mkSet = family : name :
+    nameValuePair
+      "${name}-set-${family}"
+      {
+        kind = "set";
+        inherit name family;
+        type = "ifname";
+      };
+  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;
+
+in longrun {
   name = "firewall";
-  up = script;
-  down = "${nftables}/bin/nft flush ruleset";
+  run = ''
+    ${script}
+    while : ; do sleep 86400 ; done
+  '';
+  finish = "${nftables}/bin/nft flush ruleset";
 }
diff --git a/modules/profiles/gateway.nix b/modules/profiles/gateway.nix
index ef6eca6..1e0ae48 100644
--- a/modules/profiles/gateway.nix
+++ b/modules/profiles/gateway.nix
@@ -48,6 +48,9 @@ in {
     firewall = {
       enable = mkEnableOption "firewall";
       rules = mkOption { type = types.attrsOf types.attrs; };
+      zones = mkOption {
+        type = types.attrsOf (types.listOf  liminix.lib.types.service);
+      };
     };
 
     wan = {
@@ -143,6 +146,7 @@ in {
     services.firewall = mkIf cfg.firewall.enable
       (svc.firewall.build {
         extraRules = cfg.firewall.rules;
+        inherit (cfg.firewall) zones;
       });
 
     services.resolvconf = oneshot rec {