From 4059698520ae68ee43f9b0fd6ebc7f2bd37978a7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 4 Jul 2024 17:29:39 +0100 Subject: [PATCH 1/3] maintainers: add rvfg and garyguo Co-authored-by: Rvfg --- maintainers/maintainer-list.nix | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index 5d2d0e1c0e9fd..7cda1dbf68063 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -7608,6 +7608,12 @@ githubId = 91987; name = "Jim Garrison"; }; + garyguo = { + email = "gary@garyguo.net"; + github = "nbdd0121"; + githubId = 4065244; + name = "Gary Guo"; + }; gavin = { email = "gavin.rogers@holo.host"; github = "gavinrogers"; @@ -18709,6 +18715,12 @@ githubId = 141248; name = "Ramses"; }; + rvfg = { + email = "i@rvf6.com"; + github = "duament"; + githubId = 30264485; + name = "Rvfg"; + }; rvl = { email = "dev+nix@rodney.id.au"; github = "rvl"; From cabbab19e21814cb41a4d2aff474924e511aaa31 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 4 Jul 2024 17:30:48 +0100 Subject: [PATCH 2/3] nixos-firewall-tool: add nftables support Co-authored-by: Rvfg --- .../manual/release-notes/rl-2411.section.md | 2 + .../services/networking/firewall-iptables.nix | 1 - .../services/networking/firewall-nftables.nix | 9 +++++ .../modules/services/networking/firewall.nix | 5 ++- .../nixos-firewall-tool.sh | 38 +++++++++++++++++-- .../ni/nixos-firewall-tool/package.nix | 8 ++-- 6 files changed, 52 insertions(+), 11 deletions(-) diff --git a/nixos/doc/manual/release-notes/rl-2411.section.md b/nixos/doc/manual/release-notes/rl-2411.section.md index 1b0c29f3809f3..929017a5e5509 100644 --- a/nixos/doc/manual/release-notes/rl-2411.section.md +++ b/nixos/doc/manual/release-notes/rl-2411.section.md @@ -720,6 +720,8 @@ This saves UPS battery and ensures that host(s) get back up again when power comes back, even in the scenario when the UPS would have had enough capacity to keep power on during the whole power outage. If you like the old behaviour of keeping the UPSs on (and emptying the battery) after the host(s) have shut down, and risk not getting a power cycle event to get the host(s) back up, set `power.ups.upsmon.settings.POWERDOWNFLAG = null;`. +- `nixos-firewall-tool` now supports nftables in addition to iptables and is installed by default when NixOS firewall is enabled. + - Support for *runner registration tokens* has been [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) in `gitlab-runner` 15.6 and is expected to be removed in `gitlab-runner` 18.0. Configuration of existing runners should be changed to using *runner authentication tokens* by configuring diff --git a/nixos/modules/services/networking/firewall-iptables.nix b/nixos/modules/services/networking/firewall-iptables.nix index e4fa7676fd077..086106f0d8d2b 100644 --- a/nixos/modules/services/networking/firewall-iptables.nix +++ b/nixos/modules/services/networking/firewall-iptables.nix @@ -297,7 +297,6 @@ in } ]; - environment.systemPackages = [ pkgs.nixos-firewall-tool ]; networking.firewall.checkReversePath = lib.mkIf (!kernelHasRPFilter) (lib.mkDefault false); systemd.services.firewall = { diff --git a/nixos/modules/services/networking/firewall-nftables.nix b/nixos/modules/services/networking/firewall-nftables.nix index f954a52841033..06f070caf25aa 100644 --- a/nixos/modules/services/networking/firewall-nftables.nix +++ b/nixos/modules/services/networking/firewall-nftables.nix @@ -81,6 +81,13 @@ in networking.nftables.tables."nixos-fw".family = "inet"; networking.nftables.tables."nixos-fw".content = '' + set temp-ports { + comment "Temporarily opened ports" + type inet_proto . inet_service + flags interval + auto-merge + } + ${lib.optionalString (cfg.checkReversePath != false) '' chain rpfilter { type filter hook prerouting priority mangle + 10; policy drop; @@ -147,6 +154,8 @@ in '' ) cfg.allInterfaces)} + meta l4proto . th dport @temp-ports accept + ${lib.optionalString cfg.allowPing '' icmp type echo-request ${lib.optionalString (cfg.pingLimit != null) "limit rate ${cfg.pingLimit}"} accept comment "allow ping" ''} diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix index 27e17c464ba9c..ab575b884a71b 100644 --- a/nixos/modules/services/networking/firewall.nix +++ b/nixos/modules/services/networking/firewall.nix @@ -274,7 +274,10 @@ in networking.firewall.trustedInterfaces = [ "lo" ]; - environment.systemPackages = [ cfg.package ] ++ cfg.extraPackages; + environment.systemPackages = [ + cfg.package + pkgs.nixos-firewall-tool + ] ++ cfg.extraPackages; boot.kernelModules = (lib.optional cfg.autoLoadConntrackHelpers "nf_conntrack") ++ map (x: "nf_conntrack_${x}") cfg.connectionTrackingModules; diff --git a/pkgs/by-name/ni/nixos-firewall-tool/nixos-firewall-tool.sh b/pkgs/by-name/ni/nixos-firewall-tool/nixos-firewall-tool.sh index 17e7ce8a724c9..6870277736e7c 100755 --- a/pkgs/by-name/ni/nixos-firewall-tool/nixos-firewall-tool.sh +++ b/pkgs/by-name/ni/nixos-firewall-tool/nixos-firewall-tool.sh @@ -2,10 +2,19 @@ set -euo pipefail +# Detect if iptables or nftables-based firewall is used. +if [[ -e /etc/systemd/system/firewall.service ]]; then + BACKEND=iptables +elif [[ -e /etc/systemd/system/nftables.service ]]; then + BACKEND=nftables +else + echo "nixos-firewall-tool: cannot detect firewall backend" >&2 + exit 1 +fi + ip46tables() { iptables -w "$@" ip6tables -w "$@" - } show_help() { @@ -36,13 +45,34 @@ case $1 in protocol="$2" port="$3" - ip46tables -I nixos-fw -p "$protocol" --dport "$port" -j nixos-fw-accept + case $BACKEND in + iptables) + ip46tables -I nixos-fw -p "$protocol" --dport "$port" -j nixos-fw-accept + ;; + nftables) + nft add element inet nixos-fw "temp-ports" "{ $protocol . $port }" + ;; + esac ;; "show") - ip46tables --numeric --list nixos-fw + case $BACKEND in + iptables) + ip46tables --numeric --list nixos-fw + ;; + nftables) + nft list table inet nixos-fw + ;; + esac ;; "reset") - systemctl restart firewall.service + case $BACKEND in + iptables) + systemctl restart firewall.service + ;; + nftables) + nft flush set inet nixos-fw "temp-ports" + ;; + esac ;; -h|--help|help) show_help diff --git a/pkgs/by-name/ni/nixos-firewall-tool/package.nix b/pkgs/by-name/ni/nixos-firewall-tool/package.nix index 78af5cb8d5715..b5db510822665 100644 --- a/pkgs/by-name/ni/nixos-firewall-tool/package.nix +++ b/pkgs/by-name/ni/nixos-firewall-tool/package.nix @@ -1,15 +1,13 @@ -{ writeShellApplication, iptables, lib }: +{ writeShellApplication, lib }: writeShellApplication { name = "nixos-firewall-tool"; + text = builtins.readFile ./nixos-firewall-tool.sh; - runtimeInputs = [ - iptables - ]; meta = with lib; { description = "Temporarily manipulate the NixOS firewall"; license = licenses.mit; - maintainers = with maintainers; [ clerie ]; + maintainers = with maintainers; [ clerie rvfg garyguo ]; }; } From 9d662d95ee8f1dafe20502e86479e1bc887a46e8 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 4 Jul 2024 17:30:39 +0100 Subject: [PATCH 3/3] nixosTests.firewall: add tests for nixos-firewall-tool Co-authored-by: Rvfg --- nixos/tests/firewall.nix | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/nixos/tests/firewall.nix b/nixos/tests/firewall.nix index 139bc31177402..89f4878fd47f2 100644 --- a/nixos/tests/firewall.nix +++ b/nixos/tests/firewall.nix @@ -3,14 +3,31 @@ import ./make-test-python.nix ( { pkgs, nftables, ... } : { name = "firewall" + pkgs.lib.optionalString nftables "-nftables"; meta = with pkgs.lib.maintainers; { - maintainers = [ ]; + maintainers = [ rvfg garyguo ]; }; nodes = { walled = { ... }: - { networking.firewall.enable = true; - networking.firewall.logRefusedPackets = true; + { networking.firewall = { + enable = true; + logRefusedPackets = true; + # Syntax smoke test, not actually verified otherwise + allowedTCPPorts = [ 25 993 8005 ]; + allowedTCPPortRanges = [ + { from = 980; to = 1000; } + { from = 990; to = 1010; } + { from = 8000; to = 8010; } + ]; + interfaces.eth0 = { + allowedTCPPorts = [ 10003 ]; + allowedTCPPortRanges = [ { from = 10000; to = 10005; } ]; + }; + interfaces.eth3 = { + allowedUDPPorts = [ 10003 ]; + allowedUDPPortRanges = [ { from = 10000; to = 10005; } ]; + }; + }; networking.nftables.enable = nftables; services.httpd.enable = true; services.httpd.adminAddr = "foo@example.org"; @@ -48,6 +65,14 @@ import ./make-test-python.nix ( { pkgs, nftables, ... } : { walled.succeed("curl -v http://attacker/ >&2") walled.succeed("ping -c 1 attacker >&2") + # Open tcp port 80 at runtime + walled.succeed("nixos-firewall-tool open tcp 80") + attacker.succeed("curl -v http://walled/ >&2") + + # Reset the firewall + walled.succeed("nixos-firewall-tool reset") + attacker.fail("curl --fail --connect-timeout 2 http://walled/ >&2") + # If we stop the firewall, then connections should succeed. walled.stop_job("${unit}") attacker.succeed("curl -v http://walled/ >&2")