about summary refs log tree commit diff
path: root/nixos/modules/services/networking/nftables.nix
diff options
context:
space:
mode:
authorMaciej Krüger <mkg20001@gmail.com>2023-03-27 19:52:19 +0200
committerMaciej Krüger <mkg20001@gmail.com>2023-08-28 00:40:20 +0200
commit55213b54f0ebb96250021a8788e36126174ca8a7 (patch)
treec0399e5605ae6a309c312d050323b1c56c681f30 /nixos/modules/services/networking/nftables.nix
parent5f300ad70cbbb7192f5a86795c37ed99d70ab545 (diff)
downloadnixlib-55213b54f0ebb96250021a8788e36126174ca8a7.tar
nixlib-55213b54f0ebb96250021a8788e36126174ca8a7.tar.gz
nixlib-55213b54f0ebb96250021a8788e36126174ca8a7.tar.bz2
nixlib-55213b54f0ebb96250021a8788e36126174ca8a7.tar.lz
nixlib-55213b54f0ebb96250021a8788e36126174ca8a7.tar.xz
nixlib-55213b54f0ebb96250021a8788e36126174ca8a7.tar.zst
nixlib-55213b54f0ebb96250021a8788e36126174ca8a7.zip
nixos/nftables: save deletions to file and run them afterwards
Co-authored-by: duament
Diffstat (limited to 'nixos/modules/services/networking/nftables.nix')
-rw-r--r--nixos/modules/services/networking/nftables.nix60
1 files changed, 50 insertions, 10 deletions
diff --git a/nixos/modules/services/networking/nftables.nix b/nixos/modules/services/networking/nftables.nix
index b238f09df2f3..2107448131ec 100644
--- a/nixos/modules/services/networking/nftables.nix
+++ b/nixos/modules/services/networking/nftables.nix
@@ -85,6 +85,22 @@ in
 
     networking.nftables.flushRuleset = mkEnableOption (lib.mdDoc "Flush the entire ruleset on each reload.");
 
+    networking.nftables.extraDeletions = mkOption {
+      type = types.lines;
+      default = "";
+      example = ''
+        # this makes deleting a non-existing table a no-op instead of an error
+        table inet some-table;
+
+        delete table inet some-table;
+      '';
+      description =
+        lib.mdDoc ''
+          Extra deletion commands to be run on every firewall start, reload
+          and after stopping the firewall.
+        '';
+    };
+
     networking.nftables.ruleset = mkOption {
       type = types.lines;
       default = "";
@@ -134,6 +150,10 @@ in
         lib.mdDoc ''
           The ruleset to be used with nftables.  Should be in a format that
           can be loaded using "/bin/nft -f".  The ruleset is updated atomically.
+          Note that if the tables should be cleaned first, either:
+          - networking.nftables.flushRuleset = true; needs to be set (flushes all tables)
+          - networking.nftables.extraDeletions needs to be set
+          - or networking.nftables.tables can be used, which will clean up the table automatically
         '';
     };
     networking.nftables.rulesetFile = mkOption {
@@ -218,15 +238,36 @@ in
       reloadIfChanged = true;
       serviceConfig = let
         enabledTables = filterAttrs (_: table: table.enable) cfg.tables;
+        deletionsScript = pkgs.writeScript "nftables-deletions" ''
+          #! ${pkgs.nftables}/bin/nft -f
+          ${if cfg.flushRuleset then "flush ruleset"
+            else concatStringsSep "\n" (mapAttrsToList (_: table: ''
+              table ${table.family} ${table.name}
+              delete table ${table.family} ${table.name}
+            '') enabledTables)}
+          ${cfg.extraDeletions}
+        '';
+        deletionsScriptVar = "/var/lib/nftables/deletions.nft";
+        ensureDeletions = pkgs.writeShellScript "nftables-ensure-deletions" ''
+          touch ${deletionsScriptVar}
+          chmod +x ${deletionsScriptVar}
+        '';
+        saveDeletionsScript = pkgs.writeShellScript "nftables-save-deletions" ''
+          cp ${deletionsScript} ${deletionsScriptVar}
+        '';
+        cleanupDeletionsScript = pkgs.writeShellScript "nftables-cleanup-deletions" ''
+          rm ${deletionsScriptVar}
+        '';
         rulesScript = pkgs.writeTextFile {
           name =  "nftables-rules";
           executable = true;
           text = ''
             #! ${pkgs.nftables}/bin/nft -f
-            ${optionalString cfg.flushRuleset "flush ruleset"}
+            # previous deletions, if any
+            include "${deletionsScriptVar}"
+            # current deletions
+            include "${deletionsScript}"
             ${concatStringsSep "\n" (mapAttrsToList (_: table: ''
-              table ${table.family} ${table.name}
-              delete table ${table.family} ${table.name}
               table ${table.family} ${table.name} {
                 ${table.content}
               }
@@ -237,6 +278,7 @@ in
           '';
           checkPhase = lib.optionalString cfg.checkRuleset ''
             cp $out ruleset.conf
+            sed 's|include "${deletionsScriptVar}"||' -i ruleset.conf
             ${cfg.preCheckRuleset}
             export NIX_REDIRECTS=/etc/protocols=${pkgs.buildPackages.iana-etc}/etc/protocols:/etc/services=${pkgs.buildPackages.iana-etc}/etc/services
             LD_PRELOAD="${pkgs.buildPackages.libredirect}/lib/libredirect.so ${pkgs.buildPackages.lklWithFirewall.lib}/lib/liblkl-hijack.so" \
@@ -246,13 +288,11 @@ in
       in {
         Type = "oneshot";
         RemainAfterExit = true;
-        ExecStart = rulesScript;
-        ExecReload = rulesScript;
-        ExecStop = "${pkgs.nftables}/bin/nft ${
-          if cfg.flushRuleset then "flush ruleset"
-          else escapeShellArg (concatStringsSep "; " (
-            mapAttrsToList (_: table: "delete table ${table.family} ${table.name}") enabledTables
-          ))}";
+        ExecStart = [ ensureDeletions rulesScript ];
+        ExecStartPost = saveDeletionsScript;
+        ExecReload = [ rulesScript saveDeletionsScript ];
+        ExecStop = [ deletionsScriptVar cleanupDeletionsScript ];
+        StateDirectory = "nftables";
       };
     };
   };