From d7f3e050630ce32a48cbee4bbfad223f3648aa23 Mon Sep 17 00:00:00 2001 From: Daniel Barlow Date: Sun, 16 Jul 2023 16:55:50 +0100 Subject: [PATCH] turn nftables firewall into a service-providing module --- examples/rotuer.nix | 58 ++------------------------- modules/base.nix | 10 ++++- modules/firewall/default.nix | 76 ++++++++++++++++++++++++++++++++++++ modules/firewall/service.nix | 26 ++++++++++++ 4 files changed, 114 insertions(+), 56 deletions(-) create mode 100644 modules/firewall/default.nix create mode 100644 modules/firewall/service.nix diff --git a/examples/rotuer.nix b/examples/rotuer.nix index b9e9e39..8644c2b 100644 --- a/examples/rotuer.nix +++ b/examples/rotuer.nix @@ -35,39 +35,13 @@ in rec { ../modules/standard.nix ../modules/ppp ../modules/dnsmasq + ../modules/firewall ]; rootfsType = "jffs2"; hostname = "rotuer"; kernel = { config = { BRIDGE = "y"; - - NETFILTER_XT_MATCH_CONNTRACK = "y"; - - IP6_NF_IPTABLES= "y"; # do we still need these - IP_NF_IPTABLES= "y"; # if using nftables directly - - IP_NF_NAT = "y"; - IP_NF_TARGET_MASQUERADE = "y"; - NETFILTER = "y"; - NETFILTER_ADVANCED = "y"; - NETFILTER_XTABLES = "y"; - - NFT_COMPAT = "y"; - NFT_CT = "y"; - NFT_LOG = "y"; - NFT_MASQ = "y"; - NFT_NAT = "y"; - NFT_REJECT = "y"; - NFT_REJECT_INET = "y"; - - NF_CONNTRACK = "y"; - NF_NAT = "y"; - NF_NAT_MASQUERADE = "y"; - NF_TABLES= "y"; - NF_TABLES_INET = "y"; - NF_TABLES_IPV4 = "y"; - NF_TABLES_IPV6 = "y"; }; }; @@ -221,33 +195,9 @@ in rec { }; services.firewall = - let - script= pkgs.firewallgen "firewall.nft" (import ./rotuer-firewall.nix); - kmodules = pkgs.kernel-modules.override { - kernelSrc = config.system.outputs.kernel.src; - modulesupport = config.system.outputs.kernel.modulesupport; - kconfig = { - NFT_FIB_IPV4 = "m"; - NFT_FIB_IPV6 = "m"; - NF_TABLES = "m"; - NF_CT_PROTO_DCCP = "y"; - NF_CT_PROTO_SCTP = "y"; - NF_CT_PROTO_UDPLITE = "y"; - # NF_CONNTRACK_FTP = "m"; - NFT_CT = "m"; - }; - targets = [ - "nft_fib_ipv4" - "nft_fib_ipv6" - ]; - }; - in oneshot { - name = "firewall"; - up = '' - sh ${kmodules}/load.sh - ${script}; - ''; - down = "${pkgs.nftables}/bin/nft flush ruleset"; + let ruleset = import ./rotuer-firewall.nix; + in config.system.service.firewall { + inherit ruleset; }; services.packet_forwarding = diff --git a/modules/base.nix b/modules/base.nix index 67eba8a..bd1798d 100644 --- a/modules/base.nix +++ b/modules/base.nix @@ -26,6 +26,11 @@ in { }; kernel = { src = mkOption { type = types.package; } ; + modular = mkOption { + type = types.boolean; + default = true; + description = "support loadable kernel modules"; + }; extraPatchPhase = mkOption { default = "true"; type = types.lines; @@ -67,14 +72,15 @@ in { }; kernel = rec { + modular = true; # disabling this is not yet supported config = { IKCONFIG = "y"; IKCONFIG_PROC = "y"; PROC_FS = "y"; KEXEC = "y"; - MODULES = "y"; - MODULE_SIG = "y"; + MODULES = if modular then "y" else "n"; + MODULE_SIG = if modular then "y" else "n"; DEBUG_FS = "y"; MIPS_BOOTLOADER_CMDLINE_REQUIRE_COOKIE = "y"; diff --git a/modules/firewall/default.nix b/modules/firewall/default.nix new file mode 100644 index 0000000..41b3bdd --- /dev/null +++ b/modules/firewall/default.nix @@ -0,0 +1,76 @@ +{ lib, pkgs, config, ...}: +let + inherit (lib) mkOption types; + inherit (pkgs.liminix.services) oneshot; + + kconf = isModule : + # setting isModule false is utterly untested and mostly + # unimplemented: I say this to preempt any "how on earth is this + # even supposed to work?" questions + let yes = if isModule then "m" else "y"; + in { + NFT_FIB_IPV4 = yes; + NFT_FIB_IPV6 = yes; + NF_TABLES = yes; + NF_CT_PROTO_DCCP = "y"; + NF_CT_PROTO_SCTP = "y"; + NF_CT_PROTO_UDPLITE = "y"; + # NF_CONNTRACK_FTP = yes; + NFT_CT = yes; + }; + kmodules = pkgs.kernel-modules.override { + kernelSrc = config.system.outputs.kernel.src; + modulesupport = config.system.outputs.kernel.modulesupport; + targets = [ + "nft_fib_ipv4" + "nft_fib_ipv6" + ]; + kconfig = kconf true; + }; + loadModules = oneshot { + name = "firewall-modules"; + up = "sh ${kmodules}/load.sh"; + down = "sh ${kmodules}/unload.sh"; + }; +in +{ + options = { + system.service.firewall = mkOption { + type = types.anything; # types.functionTo pkgs.liminix.lib.types.service; + }; + }; + config = { + system.service.firewall = params : + let svc = (pkgs.callPackage ./service.nix {}) params; + in svc // { dependencies = svc.dependencies ++ [loadModules]; }; + + kernel.config = { + NETFILTER_XT_MATCH_CONNTRACK = "y"; + + IP6_NF_IPTABLES= "y"; # do we still need these + IP_NF_IPTABLES= "y"; # if using nftables directly + + IP_NF_NAT = "y"; + IP_NF_TARGET_MASQUERADE = "y"; + NETFILTER = "y"; + NETFILTER_ADVANCED = "y"; + NETFILTER_XTABLES = "y"; + + NFT_COMPAT = "y"; + NFT_CT = "y"; + NFT_LOG = "y"; + NFT_MASQ = "y"; + NFT_NAT = "y"; + NFT_REJECT = "y"; + NFT_REJECT_INET = "y"; + + NF_CONNTRACK = "y"; + NF_NAT = "y"; + NF_NAT_MASQUERADE = "y"; + NF_TABLES= "y"; + NF_TABLES_INET = "y"; + NF_TABLES_IPV4 = "y"; + NF_TABLES_IPV6 = "y"; + }; + }; +} diff --git a/modules/firewall/service.nix b/modules/firewall/service.nix new file mode 100644 index 0000000..9720816 --- /dev/null +++ b/modules/firewall/service.nix @@ -0,0 +1,26 @@ +{ + liminix +, lib +, firewallgen +, nftables +}: +let + inherit (liminix.services) oneshot; + inherit (liminix.lib) typeChecked; + inherit (lib) mkOption types; + t = { + ruleset = mkOption { + type = types.anything; # we could usefully define this more tightly + description = "firewall ruleset"; + }; + }; +in +params: +let + inherit (typeChecked "firewall" t params) ruleset; + script = firewallgen "firewall.nft" ruleset; +in oneshot { + name = "firewall"; + up = script; + down = "${nftables}/bin/nft flush ruleset"; +}