nixos/firewall: add firewalld backend

This commit is contained in:
Sizhe Zhao 2025-04-15 13:35:57 +08:00
commit 87882c1e3e
No known key found for this signature in database
GPG key ID: ED1807251A7DA08F
6 changed files with 116 additions and 43 deletions

View file

@ -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

View file

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

View file

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

View file

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

View file

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

View file

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