turn nftables firewall into a service-providing module

This commit is contained in:
Daniel Barlow 2023-07-16 16:55:50 +01:00
parent 73e5916cc5
commit d7f3e05063
4 changed files with 114 additions and 56 deletions

View file

@ -35,39 +35,13 @@ in rec {
../modules/standard.nix ../modules/standard.nix
../modules/ppp ../modules/ppp
../modules/dnsmasq ../modules/dnsmasq
../modules/firewall
]; ];
rootfsType = "jffs2"; rootfsType = "jffs2";
hostname = "rotuer"; hostname = "rotuer";
kernel = { kernel = {
config = { config = {
BRIDGE = "y"; 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 = services.firewall =
let let ruleset = import ./rotuer-firewall.nix;
script= pkgs.firewallgen "firewall.nft" (import ./rotuer-firewall.nix); in config.system.service.firewall {
kmodules = pkgs.kernel-modules.override { inherit ruleset;
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";
}; };
services.packet_forwarding = services.packet_forwarding =

View file

@ -26,6 +26,11 @@ in {
}; };
kernel = { kernel = {
src = mkOption { type = types.package; } ; src = mkOption { type = types.package; } ;
modular = mkOption {
type = types.boolean;
default = true;
description = "support loadable kernel modules";
};
extraPatchPhase = mkOption { extraPatchPhase = mkOption {
default = "true"; default = "true";
type = types.lines; type = types.lines;
@ -67,14 +72,15 @@ in {
}; };
kernel = rec { kernel = rec {
modular = true; # disabling this is not yet supported
config = { config = {
IKCONFIG = "y"; IKCONFIG = "y";
IKCONFIG_PROC = "y"; IKCONFIG_PROC = "y";
PROC_FS = "y"; PROC_FS = "y";
KEXEC = "y"; KEXEC = "y";
MODULES = "y"; MODULES = if modular then "y" else "n";
MODULE_SIG = "y"; MODULE_SIG = if modular then "y" else "n";
DEBUG_FS = "y"; DEBUG_FS = "y";
MIPS_BOOTLOADER_CMDLINE_REQUIRE_COOKIE = "y"; MIPS_BOOTLOADER_CMDLINE_REQUIRE_COOKIE = "y";

View file

@ -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";
};
};
}

View file

@ -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";
}