diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index dce6e878540d5..c28f186025f71 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -829,6 +829,7 @@ ./services/networking/firewall.nix ./services/networking/firewall-iptables.nix ./services/networking/firewall-nftables.nix + ./services/networking/firewalld.nix ./services/networking/flannel.nix ./services/networking/freenet.nix ./services/networking/freeradius.nix diff --git a/nixos/modules/services/networking/firewalld.nix b/nixos/modules/services/networking/firewalld.nix new file mode 100644 index 0000000000000..994d665e826c8 --- /dev/null +++ b/nixos/modules/services/networking/firewalld.nix @@ -0,0 +1,59 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.services.firewalld; +in +{ + options.services.firewalld = { + enable = lib.mkEnableOption (lib.mdDoc '' + Whether to enable DBus-enabled firewall daemon. + + ::: {.warning} + Enabling this service WILL disable the existing NixOS + firewall! Default firewall rules provided by packages are not + considered at the moment. + ::: + ''); + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.firewalld; + defaultText = lib.literalExpression "pkgs.firewalld"; + description = lib.mdDoc "The firewalld package to use."; + }; + + config = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = {}; + example = { + DefaultZone = "drop"; + }; + description = lib.mdDoc '' + Each attribute in this set specifies an option in firewalld.conf. + + If set to non-empty, the permanent configuration will be immutable and + cannot be modified via firewalld. The runtime configuration remains mutable. + + Refer to [`firewalld.conf(5)`](https://firewalld.org/documentation/man-pages/firewalld.conf.html) + for available configuration options. + ''; + }; + }; + + config = lib.mkIf (cfg.enable) { + networking.firewall.enable = false; + security.polkit.enable = lib.mkDefault true; + + environment.systemPackages = [ cfg.package ]; + systemd.packages = [ cfg.package ]; + services.dbus.packages = [ cfg.package ]; + + environment.etc."firewalld/firewalld.conf" = lib.mkIf (cfg.config != {}) { + text = lib.generators.toKeyValue {} cfg.config; + }; + + systemd.services.firewalld = { + aliases = [ "dbus-org.fedoraproject.FirewallD1.service" ]; + wantedBy = [ "multi-user.target" ]; + }; + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 8227f606d1692..07aba894ebba9 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -218,6 +218,7 @@ in { firejail = handleTest ./firejail.nix {}; firewall = handleTest ./firewall.nix { nftables = false; }; firewall-nftables = handleTest ./firewall.nix { nftables = true; }; + firewalld = handleTest ./firewalld.nix {}; fish = handleTest ./fish.nix {}; flannel = handleTestOn ["x86_64-linux"] ./flannel.nix {}; fluentd = handleTest ./fluentd.nix {}; diff --git a/nixos/tests/firewalld.nix b/nixos/tests/firewalld.nix new file mode 100644 index 0000000000000..847c4108866d3 --- /dev/null +++ b/nixos/tests/firewalld.nix @@ -0,0 +1,55 @@ +import ./make-test-python.nix { + name = "firewalld"; + + nodes = { + walled = { + services.firewalld.enable = true; + services.httpd.enable = true; + services.httpd.adminAddr = "foo@example.org"; + }; + + open = { + services.firewalld = { + enable = true; + config.DefaultZone = "trusted"; + }; + services.httpd.enable = true; + services.httpd.adminAddr = "foo@example.org"; + }; + }; + + testScript = '' + start_all() + + walled.wait_for_unit("firewalld"); + walled.wait_for_unit("httpd") + + open.wait_for_unit("network.target") + + with subtest("enable denial logging"): + walled.succeed("firewall-cmd --set-log-denied=all") + walled.succeed("firewall-cmd --runtime-to-permanent") + + with subtest("walled local httpd works"): + walled.succeed("curl -v http://localhost/ >&2") + + with subtest("incoming connections are blocked"): + open.fail("curl --fail --connect-timeout 2 http://walled/ >&2") + + with subtest("outgoing connections are allowed"): + walled.succeed("curl -v http://open/ >&2") + + with subtest("runtime configuration can be changed"): + walled.succeed("firewall-cmd --add-service=http") + open.succeed("curl -v http://walled/ >&2") + + with subtest("runtime configuration are not permanent"): + walled.succeed("firewall-cmd --complete-reload") + open.fail("curl --fail --connect-timeout 2 http://walled/ >&2") + + with subtest("permanent configuration are permanent"): + walled.succeed("firewall-cmd --add-service=http --permanent") + walled.succeed("firewall-cmd --complete-reload") + open.succeed("curl -v http://walled/ >&2") + ''; +} diff --git a/pkgs/applications/networking/firewalld/default.nix b/pkgs/applications/networking/firewalld/default.nix index b11c3d60c9087..3b2de825710ce 100644 --- a/pkgs/applications/networking/firewalld/default.nix +++ b/pkgs/applications/networking/firewalld/default.nix @@ -1,6 +1,7 @@ { lib , stdenv , fetchFromGitHub +, nixosTests , autoreconfHook , bash , docbook_xml_dtd_42 @@ -12,9 +13,11 @@ , libnotify , libxml2 , libxslt +, networkmanager , networkmanagerapplet , pkg-config , python3 +, wrapQtAppsHook , wrapGAppsNoGuiHook , withGui ? false }: @@ -46,7 +49,8 @@ stdenv.mkDerivation rec { postPatch = '' substituteInPlace src/firewall/config/__init__.py.in \ - --replace "/usr/share" "$out/share" + --replace "/usr/share" "$out/share" \ + --replace "/usr/lib/" "$out/lib/" for file in config/firewall-{applet,config}.desktop.in; do substituteInPlace $file \ @@ -54,13 +58,14 @@ stdenv.mkDerivation rec { done '' + lib.optionalString withGui '' substituteInPlace src/firewall-applet.in \ - --replace "/usr/bin/nm-connection-editor" "${networkmanagerapplet}/bin/nm-conenction-editor" + --replace "/usr/bin/nm-connection-editor" "${networkmanagerapplet}/bin/nm-connection-editor" ''; nativeBuildInputs = [ autoreconfHook docbook_xml_dtd_42 docbook-xsl-nons + gobject-introspection glib intltool libxml2 @@ -68,14 +73,15 @@ stdenv.mkDerivation rec { pkg-config python3 python3.pkgs.wrapPython - ] ++ lib.optionals withGui [ - gobject-introspection wrapGAppsNoGuiHook + ] ++ lib.optionals withGui [ + wrapQtAppsHook ]; buildInputs = [ bash glib + networkmanager ] ++ lib.optionals withGui [ gtk3 libnotify @@ -83,9 +89,12 @@ stdenv.mkDerivation rec { ]; dontWrapGApps = true; + dontWrapQtApps = true; - preFixup = lib.optionalString withGui '' + preFixup = '' makeWrapperArgs+=("''${gappsWrapperArgs[@]}") + '' + lib.optionalString withGui '' + makeWrapperArgs+=("''${qtWrapperArgs[@]}") ''; postFixup = '' @@ -95,9 +104,12 @@ stdenv.mkDerivation rec { wrapPythonProgramsIn "$out/share/firewalld/testsuite/python" "$out ${pythonPath}" ''; + passthru.tests = nixosTests.firewalld; + meta = with lib; { description = "Firewall daemon with D-Bus interface"; homepage = "https://github.com/firewalld/firewalld"; + platforms = platforms.linux; license = licenses.gpl2Plus; maintainers = with maintainers; [ SuperSandro2000 ]; }; diff --git a/pkgs/os-specific/linux/nftables/default.nix b/pkgs/os-specific/linux/nftables/default.nix index 340ad619ecb6c..d0f4c4fb2debc 100644 --- a/pkgs/os-specific/linux/nftables/default.nix +++ b/pkgs/os-specific/linux/nftables/default.nix @@ -29,6 +29,13 @@ stdenv.mkDerivation rec { ] ++ lib.optional withXtables iptables ++ lib.optional withPython python3; + patches = [ ./fix-py-libnftables.patch ]; + + postPatch = '' + substituteInPlace "py/nftables.py" \ + --subst-var-by "out" "$out" + ''; + configureFlags = [ "--with-json" "--with-cli=editline" diff --git a/pkgs/os-specific/linux/nftables/fix-py-libnftables.patch b/pkgs/os-specific/linux/nftables/fix-py-libnftables.patch new file mode 100644 index 0000000000000..f03a1856760b1 --- /dev/null +++ b/pkgs/os-specific/linux/nftables/fix-py-libnftables.patch @@ -0,0 +1,13 @@ +diff --git a/py/nftables.py b/py/nftables.py +index 6daeafc2..07e2c048 100644 +--- a/py/nftables.py ++++ b/py/nftables.py +@@ -64,7 +64,7 @@ class Nftables: + + validator = None + +- def __init__(self, sofile="libnftables.so.1"): ++ def __init__(self, sofile="@out@/lib/libnftables.so.1"): + """Instantiate a new Nftables class object. + + Accepts a shared object file to open, by default standard search path diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index e38850a768acd..644dde2ded7d5 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -28893,7 +28893,7 @@ with pkgs; inherit (darwin.apple_sdk.frameworks) Security; }; - firewalld = callPackage ../applications/networking/firewalld { }; + firewalld = libsForQt5.callPackage ../applications/networking/firewalld { }; firewalld-gui = firewalld.override { withGui = true; };