diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index f706b63b5e3e..d0a4f0b7db12 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1162,6 +1162,7 @@ ./services/networking/ferm.nix ./services/networking/firefox-syncserver.nix ./services/networking/fireqos.nix + ./services/networking/firewall-firewalld.nix ./services/networking/firewall-iptables.nix ./services/networking/firewall-nftables.nix ./services/networking/firewall.nix diff --git a/nixos/modules/services/networking/firewall-firewalld.nix b/nixos/modules/services/networking/firewall-firewalld.nix new file mode 100644 index 000000000000..2db34eb1cad1 --- /dev/null +++ b/nixos/modules/services/networking/firewall-firewalld.nix @@ -0,0 +1,61 @@ +{ config, lib, ... }: + +let + cfg = config.networking.firewall; +in +{ + config = lib.mkIf (cfg.enable && cfg.backend == "firewalld") { + assertions = [ + { + assertion = cfg.interfaces == { }; + message = '' + Per interface configurations is not supported with the firewalld based firewall. + Create zones with `services.firewalld.zones` instead. + ''; + } + ]; + + boot.kernel.sysctl."net.ipv4.conf.all.rp_filter" = + if cfg.checkReversePath == false then + 0 + else if cfg.checkReversePath == "loose" then + 1 + else + 2; + + services.firewalld = { + settings = { + DefaultZone = lib.mkDefault "nixos-fw-default"; + LogDenied = + if cfg.logRefusedConnections then + (if cfg.logRefusedUnicastsOnly then "unicast" else "all") + else + "off"; + IPv6_rpfilter = + if cfg.checkReversePath == false then + "no" + else + let + mode = if cfg.checkReversePath == true then "strict" else cfg.checkReversePath; + suffix = if cfg.filterForward then "" else "-forward"; + in + "${mode}${suffix}"; + }; + zones = { + nixos-fw-default = { + target = if cfg.rejectPackets then "%%REJECT%%" else "DROP"; + icmpBlockInversion = true; + icmpBlocks = lib.mkIf cfg.allowPing [ "echo-request" ]; + ports = + let + f = protocol: port: { inherit protocol port; }; + tcpPorts = map (f "tcp") (cfg.allowedTCPPorts ++ cfg.allowedTCPPortRanges); + udpPorts = map (f "udp") (cfg.allowedUDPPorts ++ cfg.allowedUDPPortRanges); + in + tcpPorts ++ udpPorts; + }; + trusted.interfaces = cfg.trustedInterfaces; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/firewall-iptables.nix b/nixos/modules/services/networking/firewall-iptables.nix index 53d7d3434dae..36b4cfc6f9b7 100644 --- a/nixos/modules/services/networking/firewall-iptables.nix +++ b/nixos/modules/services/networking/firewall-iptables.nix @@ -285,9 +285,7 @@ let in { - options = { - networking.firewall = { extraCommands = lib.mkOption { type = lib.types.lines; @@ -317,13 +315,11 @@ in ''; }; }; - }; # FIXME: Maybe if `enable' is false, the firewall should still be # built but not started by default? - config = lib.mkIf (cfg.enable && config.networking.nftables.enable == false) { - + config = lib.mkIf (cfg.enable && cfg.backend == "iptables") { assertions = [ # This is approximately "checkReversePath -> kernelHasRPFilter", # but the checkReversePath option can include non-boolean @@ -336,6 +332,8 @@ in networking.firewall.checkReversePath = lib.mkIf (!kernelHasRPFilter) (lib.mkDefault false); + environment.systemPackages = [ pkgs.nixos-firewall-tool ]; + systemd.services.firewall = { description = "Firewall"; wantedBy = [ "sysinit.target" ]; @@ -365,7 +363,5 @@ in ExecStop = "@${stopScript} firewall-stop"; }; }; - }; - } diff --git a/nixos/modules/services/networking/firewall-nftables.nix b/nixos/modules/services/networking/firewall-nftables.nix index d9695c0e4d27..a22fc29d35ff 100644 --- a/nixos/modules/services/networking/firewall-nftables.nix +++ b/nixos/modules/services/networking/firewall-nftables.nix @@ -19,9 +19,7 @@ let in { - options = { - networking.firewall = { extraInputRules = lib.mkOption { type = lib.types.lines; @@ -59,11 +57,9 @@ in ''; }; }; - }; - config = lib.mkIf (cfg.enable && config.networking.nftables.enable) { - + config = lib.mkIf (cfg.enable && cfg.backend == "nftables") { assertions = [ { assertion = cfg.extraCommands == ""; @@ -83,6 +79,8 @@ in } ]; + environment.systemPackages = [ pkgs.nixos-firewall-tool ]; + networking.nftables.tables."nixos-fw".family = "inet"; networking.nftables.tables."nixos-fw".content = '' set temp-ports { @@ -203,7 +201,5 @@ in } ''} ''; - }; - } diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix index e733e9e6b87b..95308c2a9cfc 100644 --- a/nixos/modules/services/networking/firewall.nix +++ b/nixos/modules/services/networking/firewall.nix @@ -68,9 +68,7 @@ let in { - options = { - networking.firewall = { enable = lib.mkOption { type = lib.types.bool; @@ -82,6 +80,32 @@ in ''; }; + backend = lib.mkOption { + type = lib.types.enum [ + "iptables" + "nftables" + "firewalld" + ]; + default = + if config.services.firewalld.enable then + "firewalld" + else if config.networking.nftables.enable then + "nftables" + else + "iptables"; + defaultText = lib.literalExpression '' + if config.services.firewalld.enable then + "firewalld" + else if config.networking.nftables.enable then + "nftables" + else + "iptables" + ''; + description = '' + Underlying implementation for the firewall service. + ''; + }; + package = lib.mkOption { type = lib.types.package; default = if config.networking.nftables.enable then pkgs.nftables else pkgs.iptables; @@ -292,11 +316,9 @@ in }; } // commonOptions; - }; config = lib.mkIf cfg.enable { - assertions = [ { assertion = cfg.filterForward -> config.networking.nftables.enable; @@ -311,11 +333,7 @@ in networking.firewall.trustedInterfaces = [ "lo" ]; - environment.systemPackages = [ - cfg.package - pkgs.nixos-firewall-tool - ] - ++ cfg.extraPackages; + environment.systemPackages = [ cfg.package ] ++ cfg.extraPackages; boot.kernelModules = (lib.optional cfg.autoLoadConntrackHelpers "nf_conntrack") @@ -323,7 +341,5 @@ in boot.extraModprobeConfig = lib.optionalString cfg.autoLoadConntrackHelpers '' options nf_conntrack nf_conntrack_helper=1 ''; - }; - } diff --git a/nixos/tests/firewall.nix b/nixos/tests/firewall.nix index 019508adb0b2..2adf54f007ad 100644 --- a/nixos/tests/firewall.nix +++ b/nixos/tests/firewall.nix @@ -12,10 +12,11 @@ nodes = { walled = - { ... }: + { lib, ... }: { networking.firewall = { enable = true; + inherit backend; logRefusedPackets = true; # Syntax smoke test, not actually verified otherwise allowedTCPPorts = [ @@ -37,23 +38,25 @@ to = 8010; } ]; - interfaces.eth0 = { - allowedTCPPorts = [ 10003 ]; - allowedTCPPortRanges = [ - { - from = 10000; - to = 10005; - } - ]; - }; - interfaces.eth3 = { - allowedUDPPorts = [ 10003 ]; - allowedUDPPortRanges = [ - { - from = 10000; - to = 10005; - } - ]; + interfaces = lib.mkIf (backend != "firewalld") { + eth0 = { + allowedTCPPorts = [ 10003 ]; + allowedTCPPortRanges = [ + { + from = 10000; + to = 10005; + } + ]; + }; + eth3 = { + allowedUDPPorts = [ 10003 ]; + allowedUDPPortRanges = [ + { + from = 10000; + to = 10005; + } + ]; + }; }; }; networking.nftables.enable = nftables;