summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nixos/modules/module-list.nix2
-rw-r--r--nixos/modules/services/monitoring/nagios.nix113
-rw-r--r--nixos/modules/services/networking/shorewall.nix75
-rw-r--r--nixos/modules/services/networking/shorewall6.nix75
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/nagios.nix116
-rw-r--r--pkgs/applications/virtualization/bochs/default.nix4
-rw-r--r--pkgs/development/tools/build-managers/gradle/default.nix4
-rw-r--r--pkgs/servers/monitoring/nagios/default.nix14
-rw-r--r--pkgs/tools/networking/shorewall/default.nix130
-rw-r--r--pkgs/top-level/all-packages.nix2
11 files changed, 481 insertions, 55 deletions
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 914f9a878b0..11bb900f7bb 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -691,6 +691,8 @@
   ./services/networking/skydns.nix
   ./services/networking/shadowsocks.nix
   ./services/networking/shairport-sync.nix
+  ./services/networking/shorewall.nix
+  ./services/networking/shorewall6.nix
   ./services/networking/shout.nix
   ./services/networking/sniproxy.nix
   ./services/networking/smokeping.nix
diff --git a/nixos/modules/services/monitoring/nagios.nix b/nixos/modules/services/monitoring/nagios.nix
index 4128bc12030..94f378bebc3 100644
--- a/nixos/modules/services/monitoring/nagios.nix
+++ b/nixos/modules/services/monitoring/nagios.nix
@@ -17,32 +17,39 @@ let
       preferLocalBuild = true;
     } "mkdir -p $out; ln -s $nagiosObjectDefs $out/";
 
-  nagiosCfgFile = pkgs.writeText "nagios.cfg"
-    ''
-      # Paths for state and logs.
-      log_file=${nagiosLogDir}/current
-      log_archive_path=${nagiosLogDir}/archive
-      status_file=${nagiosState}/status.dat
-      object_cache_file=${nagiosState}/objects.cache
-      temp_file=${nagiosState}/nagios.tmp
-      lock_file=/run/nagios.lock # Not used I think.
-      state_retention_file=${nagiosState}/retention.dat
-      query_socket=${nagiosState}/nagios.qh
-      check_result_path=${nagiosState}
-      command_file=${nagiosState}/nagios.cmd
-
-      # Configuration files.
-      #resource_file=resource.cfg
-      cfg_dir=${nagiosObjectDefsDir}
-
-      # Uid/gid that the daemon runs under.
-      nagios_user=nagios
-      nagios_group=nagios
-
-      # Misc. options.
-      illegal_macro_output_chars=`~$&|'"<>
-      retain_state_information=1
-    ''; # "
+  nagiosCfgFile = let
+    default = {
+      log_file="${nagiosLogDir}/current";
+      log_archive_path="${nagiosLogDir}/archive";
+      status_file="${nagiosState}/status.dat";
+      object_cache_file="${nagiosState}/objects.cache";
+      temp_file="${nagiosState}/nagios.tmp";
+      lock_file="/run/nagios.lock";
+      state_retention_file="${nagiosState}/retention.dat";
+      query_socket="${nagiosState}/nagios.qh";
+      check_result_path="${nagiosState}";
+      command_file="${nagiosState}/nagios.cmd";
+      cfg_dir="${nagiosObjectDefsDir}";
+      nagios_user="nagios";
+      nagios_group="nagios";
+      illegal_macro_output_chars="`~$&|'\"<>";
+      retain_state_information="1";
+    };
+    lines = mapAttrsToList (key: value: "${key}=${value}") (default // cfg.extraConfig);
+    content = concatStringsSep "\n" lines;
+    file = pkgs.writeText "nagios.cfg" content;
+    validated =  pkgs.runCommand "nagios-checked.cfg" {preferLocalBuild=true;} ''
+      cp ${file} nagios.cfg
+      # nagios checks the existence of /var/lib/nagios, but
+      # it does not exists in the build sandbox, so we fake it
+      mkdir lib
+      lib=$(readlink -f lib)
+      sed -i s@=${nagiosState}@=$lib@ nagios.cfg
+      ${pkgs.nagios}/bin/nagios -v nagios.cfg && cp ${file} $out
+    '';
+    defaultCfgFile = if cfg.validateConfig then validated else file;
+  in
+  if cfg.mainConfigFile == null then defaultCfgFile else cfg.mainConfigFile;
 
   # Plain configuration for the Nagios web-interface with no
   # authentication.
@@ -77,16 +84,11 @@ in
     (mkRemovedOptionModule [ "services" "nagios" "urlPath" ] "The urlPath option has been removed as it is hard coded to /nagios in the nagios package.")
   ];
 
+  meta.maintainers = with lib.maintainers; [ symphorien ];
+
   options = {
     services.nagios = {
-      enable = mkOption {
-        default = false;
-        description = "
-          Whether to use <link
-          xlink:href='http://www.nagios.org/'>Nagios</link> to monitor
-          your system or network.
-        ";
-      };
+      enable = mkEnableOption "<link xlink:href='http://www.nagios.org/'>Nagios</link> to monitor your system or network.";
 
       objectDefs = mkOption {
         description = "
@@ -94,12 +96,14 @@ in
           the hosts, host groups, services and contacts for the
           network that you want Nagios to monitor.
         ";
+        type = types.listOf types.path;
+        example = literalExample "[ ./objects.cfg ]";
       };
 
       plugins = mkOption {
         type = types.listOf types.package;
-        default = [pkgs.nagiosPluginsOfficial pkgs.ssmtp];
-        defaultText = "[pkgs.nagiosPluginsOfficial pkgs.ssmtp]";
+        default = with pkgs; [ nagiosPluginsOfficial ssmtp mailutils ];
+        defaultText = "[pkgs.nagiosPluginsOfficial pkgs.ssmtp pkgs.mailutils]";
         description = "
           Packages to be added to the Nagios <envar>PATH</envar>.
           Typically used to add plugins, but can be anything.
@@ -107,14 +111,29 @@ in
       };
 
       mainConfigFile = mkOption {
-        type = types.package;
-        default = nagiosCfgFile;
-        defaultText = "nagiosCfgFile";
+        type = types.nullOr types.package;
+        default = null;
         description = "
-          Derivation for the main configuration file of Nagios.
+          If non-null, overrides the main configuration file of Nagios.
         ";
       };
 
+      extraConfig = mkOption {
+        type = types.attrsOf types.str;
+        example = {
+          debug_level = "-1";
+          debug_file = "/var/log/nagios/debug.log";
+        };
+        default = {};
+        description = "Configuration to add to /etc/nagios.cfg";
+      };
+
+      validateConfig = mkOption {
+        type = types.bool;
+        default = pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform;
+        description = "if true, the syntax of the nagios configuration file is checked at build time";
+      };
+
       cgiConfigFile = mkOption {
         type = types.package;
         default = nagiosCGICfgFile;
@@ -126,6 +145,7 @@ in
       };
 
       enableWebInterface = mkOption {
+        type = types.bool;
         default = false;
         description = "
           Whether to enable the Nagios web interface.  You should also
@@ -165,7 +185,7 @@ in
     # This isn't needed, it's just so that the user can type "nagiostats
     # -c /etc/nagios.cfg".
     environment.etc = [
-      { source = cfg.mainConfigFile;
+      { source = nagiosCfgFile;
         target = "nagios.cfg";
       }
     ];
@@ -173,7 +193,7 @@ in
     environment.systemPackages = [ pkgs.nagios ];
     systemd.services.nagios = {
       description = "Nagios monitoring daemon";
-      path     = [ pkgs.nagios ];
+      path     = [ pkgs.nagios ] ++ cfg.plugins;
       wantedBy = [ "multi-user.target" ];
       after    = [ "network.target" ];
 
@@ -184,14 +204,9 @@ in
         RestartSec = 2;
         LogsDirectory = "nagios";
         StateDirectory = "nagios";
+        ExecStart = "${pkgs.nagios}/bin/nagios /etc/nagios.cfg";
+        X-ReloadIfChanged = nagiosCfgFile;
       };
-
-      script = ''
-        for i in ${toString cfg.plugins}; do
-          export PATH=$i/bin:$i/sbin:$i/libexec:$PATH
-        done
-        exec ${pkgs.nagios}/bin/nagios ${cfg.mainConfigFile}
-      '';
     };
 
     services.httpd.virtualHosts = optionalAttrs cfg.enableWebInterface {
diff --git a/nixos/modules/services/networking/shorewall.nix b/nixos/modules/services/networking/shorewall.nix
new file mode 100644
index 00000000000..0f94d414fcf
--- /dev/null
+++ b/nixos/modules/services/networking/shorewall.nix
@@ -0,0 +1,75 @@
+{ config, lib, pkgs, ... }:
+let
+  types = lib.types;
+  cfg = config.services.shorewall;
+in {
+  options = {
+    services.shorewall = {
+      enable = lib.mkOption {
+        type        = types.bool;
+        default     = false;
+        description = ''
+          Whether to enable Shorewall IPv4 Firewall.
+          <warning>
+            <para>
+            Enabling this service WILL disable the existing NixOS
+            firewall! Default firewall rules provided by packages are not
+            considered at the moment.
+            </para>
+          </warning>
+        '';
+      };
+      package = lib.mkOption {
+        type        = types.package;
+        default     = pkgs.shorewall;
+        defaultText = "pkgs.shorewall";
+        description = "The shorewall package to use.";
+      };
+      configs = lib.mkOption {
+        type        = types.attrsOf types.str;
+        default     = {};
+        description = ''
+          This option defines the Shorewall configs.
+          The attribute name defines the name of the config,
+          and the attribute value defines the content of the config.
+        '';
+        apply = lib.mapAttrs (name: text: pkgs.writeText "${name}" text);
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    systemd.services.firewall.enable = false;
+    systemd.services.shorewall = {
+      description     = "Shorewall IPv4 Firewall";
+      after           = [ "ipset.target" ];
+      before          = [ "network-pre.target" ];
+      wants           = [ "network-pre.target" ];
+      wantedBy        = [ "multi-user.target" ];
+      reloadIfChanged = true;
+      restartTriggers = lib.attrValues cfg.configs;
+      serviceConfig = {
+        Type            = "oneshot";
+        RemainAfterExit = "yes";
+        ExecStart       = "${cfg.package}/bin/shorewall start";
+        ExecReload      = "${cfg.package}/bin/shorewall reload";
+        ExecStop        = "${cfg.package}/bin/shorewall stop";
+      };
+      preStart = ''
+        install -D -d -m 750 /var/lib/shorewall
+        install -D -d -m 755 /var/lock/subsys
+        touch                /var/log/shorewall.log
+        chown 750            /var/log/shorewall.log
+      '';
+    };
+    environment = {
+      etc = lib.mapAttrsToList
+              (name: file:
+                { source = file;
+                  target = "shorewall/${name}";
+                })
+              cfg.configs;
+      systemPackages = [ cfg.package ];
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/shorewall6.nix b/nixos/modules/services/networking/shorewall6.nix
new file mode 100644
index 00000000000..9c22a037c0b
--- /dev/null
+++ b/nixos/modules/services/networking/shorewall6.nix
@@ -0,0 +1,75 @@
+{ config, lib, pkgs, ... }:
+let
+  types = lib.types;
+  cfg = config.services.shorewall6;
+in {
+  options = {
+    services.shorewall6 = {
+      enable = lib.mkOption {
+        type        = types.bool;
+        default     = false;
+        description = ''
+          Whether to enable Shorewall IPv6 Firewall.
+          <warning>
+            <para>
+            Enabling this service WILL disable the existing NixOS
+            firewall! Default firewall rules provided by packages are not
+            considered at the moment.
+            </para>
+          </warning>
+        '';
+      };
+      package = lib.mkOption {
+        type        = types.package;
+        default     = pkgs.shorewall;
+        defaultText = "pkgs.shorewall";
+        description = "The shorewall package to use.";
+      };
+      configs = lib.mkOption {
+        type        = types.attrsOf types.str;
+        default     = {};
+        description = ''
+          This option defines the Shorewall configs.
+          The attribute name defines the name of the config,
+          and the attribute value defines the content of the config.
+        '';
+        apply = lib.mapAttrs (name: text: pkgs.writeText "${name}" text);
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    systemd.services.firewall.enable = false;
+    systemd.services.shorewall6 = {
+      description     = "Shorewall IPv6 Firewall";
+      after           = [ "ipset.target" ];
+      before          = [ "network-pre.target" ];
+      wants           = [ "network-pre.target" ];
+      wantedBy        = [ "multi-user.target" ];
+      reloadIfChanged = true;
+      restartTriggers = lib.attrValues cfg.configs;
+      serviceConfig = {
+        Type            = "oneshot";
+        RemainAfterExit = "yes";
+        ExecStart       = "${cfg.package}/bin/shorewall6 start";
+        ExecReload      = "${cfg.package}/bin/shorewall6 reload";
+        ExecStop        = "${cfg.package}/bin/shorewall6 stop";
+      };
+      preStart = ''
+        install -D -d -m 750 /var/lib/shorewall6
+        install -D -d -m 755 /var/lock/subsys
+        touch                /var/log/shorewall6.log
+        chown 750            /var/log/shorewall6.log
+      '';
+    };
+    environment = {
+      etc = lib.mapAttrsToList
+              (name: file:
+                { source = file;
+                  target = "shorewall6/${name}";
+                })
+              cfg.configs;
+      systemPackages = [ cfg.package ];
+    };
+  };
+}
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 111643ad69c..0bbf0d9ab41 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -179,6 +179,7 @@ in
   mysql = handleTest ./mysql.nix {};
   mysqlBackup = handleTest ./mysql-backup.nix {};
   mysqlReplication = handleTest ./mysql-replication.nix {};
+  nagios = handleTest ./nagios.nix {};
   nat.firewall = handleTest ./nat.nix { withFirewall = true; };
   nat.firewall-conntrack = handleTest ./nat.nix { withFirewall = true; withConntrackHelpers = true; };
   nat.standalone = handleTest ./nat.nix { withFirewall = false; };
diff --git a/nixos/tests/nagios.nix b/nixos/tests/nagios.nix
new file mode 100644
index 00000000000..6f5d4447287
--- /dev/null
+++ b/nixos/tests/nagios.nix
@@ -0,0 +1,116 @@
+import ./make-test-python.nix (
+  { pkgs, ... }: {
+    name = "nagios";
+    meta = with pkgs.stdenv.lib.maintainers; {
+      maintainers = [ symphorien ];
+    };
+
+    machine = { lib, ... }: let
+      writer = pkgs.writeShellScript "write" ''
+        set -x
+        echo "$@"  >> /tmp/notifications
+      '';
+    in
+      {
+        # tested service
+        services.sshd.enable = true;
+        # nagios
+        services.nagios = {
+          enable = true;
+          # make state transitions faster
+          extraConfig.interval_length = "5";
+          objectDefs =
+            (map (x: "${pkgs.nagios}/etc/objects/${x}.cfg") [ "templates" "timeperiods" "commands" ]) ++ [
+              (
+                pkgs.writeText "objects.cfg" ''
+                  # notifications are written to /tmp/notifications
+                  define command {
+                  command_name notify-host-by-file
+                  command_line ${writer} "$HOSTNAME is $HOSTSTATE$"
+                  }
+                  define command {
+                  command_name notify-service-by-file
+                  command_line ${writer} "$SERVICEDESC$ is $SERVICESTATE$"
+                  }
+
+                  # nagios boilerplate
+                  define contact {
+                  contact_name                    alice
+                  alias                           alice
+                  host_notifications_enabled      1
+                  service_notifications_enabled   1
+                  service_notification_period     24x7
+                  host_notification_period        24x7
+                  service_notification_options    w,u,c,r,f,s
+                  host_notification_options       d,u,r,f,s
+                  service_notification_commands   notify-service-by-file
+                  host_notification_commands      notify-host-by-file
+                  email                           foo@example.com
+                  }
+                  define contactgroup {
+                  contactgroup_name   admins
+                  alias               Admins
+                  members alice
+                  }
+                  define hostgroup{
+                  hostgroup_name  allhosts
+                  alias  All hosts
+                  }
+
+                  # monitored objects
+                  define host {
+                  use         generic-host
+                  host_name   localhost
+                  alias       localhost
+                  address     localhost
+                  hostgroups  allhosts
+                  contact_groups admins
+                  # make state transitions faster.
+                  max_check_attempts 2
+                  check_interval 1
+                  retry_interval 1
+                  }
+                  define service {
+                  use                 generic-service
+                  host_name           localhost
+                  service_description ssh
+                  check_command       check_ssh
+                  # make state transitions faster.
+                  max_check_attempts 2
+                  check_interval 1
+                  retry_interval 1
+                  }
+                ''
+              )
+            ];
+        };
+      };
+
+    testScript = { ... }: ''
+      with subtest("ensure sshd starts"):
+          machine.wait_for_unit("sshd.service")
+
+
+      with subtest("ensure nagios starts"):
+          machine.wait_for_file("/var/log/nagios/current")
+
+
+      def assert_notify(text):
+          machine.wait_for_file("/tmp/notifications")
+          real = machine.succeed("cat /tmp/notifications").strip()
+          print(f"got {real!r}, expected {text!r}")
+          assert text == real
+
+
+      with subtest("ensure we get a notification when sshd is down"):
+          machine.succeed("systemctl stop sshd")
+          assert_notify("ssh is CRITICAL")
+
+
+      with subtest("ensure tests can succeed"):
+          machine.succeed("systemctl start sshd")
+          machine.succeed("rm /tmp/notifications")
+          assert_notify("ssh is OK")
+    '';
+  }
+)
diff --git a/pkgs/applications/virtualization/bochs/default.nix b/pkgs/applications/virtualization/bochs/default.nix
index 48ff2d3cf49..f6e202ac499 100644
--- a/pkgs/applications/virtualization/bochs/default.nix
+++ b/pkgs/applications/virtualization/bochs/default.nix
@@ -28,7 +28,7 @@ stdenv.mkDerivation rec {
 
   patches = [ ./bochs-2.6.10-glibc-2.26.patch ];
 
-  buildInputs = with stdenv.lib;
+  buildInputs =
   [ pkgconfig libtool gtk2 libGLU libGL readline libX11 libXpm docbook_xml_dtd_45 docbook_xsl ]
   ++ optionals termSupport [ ncurses ]
   ++ optionals sdlSupport [ SDL2 ]
@@ -118,7 +118,7 @@ stdenv.mkDerivation rec {
       in C++, that runs on most popular platforms. It includes emulation of the
       Intel x86 CPU, common I/O devices, and a custom BIOS.
     '';
-    homepage = http://bochs.sourceforge.net/;
+    homepage = "http://bochs.sourceforge.net/";
     license = licenses.lgpl2Plus;
     maintainers = with maintainers; [ AndersonTorres ];
     platforms = platforms.unix;
diff --git a/pkgs/development/tools/build-managers/gradle/default.nix b/pkgs/development/tools/build-managers/gradle/default.nix
index 5e01438844c..a15eb275231 100644
--- a/pkgs/development/tools/build-managers/gradle/default.nix
+++ b/pkgs/development/tools/build-managers/gradle/default.nix
@@ -54,12 +54,12 @@ rec {
   gradle_latest = gradle_5_6;
 
   gradle_5_6 = gradleGen rec {
-    name = "gradle-5.6.1";
+    name = "gradle-5.6.4";
     nativeVersion = "0.18";
 
     src = fetchurl {
       url = "http://services.gradle.org/distributions/${name}-bin.zip";
-      sha256 = "04pccfcry5c59xwm6rr4r3baanwbfr5yrwhxv4r5v8z4414291h9";
+      sha256 = "1f3067073041bc44554d0efe5d402a33bc3d3c93cc39ab684f308586d732a80d";
     };
   };
 
diff --git a/pkgs/servers/monitoring/nagios/default.nix b/pkgs/servers/monitoring/nagios/default.nix
index 8df30645725..006d91ef74e 100644
--- a/pkgs/servers/monitoring/nagios/default.nix
+++ b/pkgs/servers/monitoring/nagios/default.nix
@@ -1,4 +1,4 @@
-{ stdenv, fetchurl, perl, php, gd, libpng, zlib, unzip }:
+{ stdenv, fetchurl, perl, php, gd, libpng, zlib, unzip, nixosTests }:
 
 stdenv.mkDerivation rec {
   pname = "nagios";
@@ -19,7 +19,17 @@ stdenv.mkDerivation rec {
   preInstall = ''
     substituteInPlace Makefile --replace '$(MAKE) install-basic' ""
   '';
-  installTargets = [ "install" "install-config" ];
+  installTargets = "install install-config";
+  postInstall = ''
+    # don't make default files use hardcoded paths to commands
+    sed -i 's@command_line *[^ ]*/\([^/]*\) @command_line \1 @'  $out/etc/objects/commands.cfg
+    sed -i 's@/usr/bin/@@g' $out/etc/objects/commands.cfg
+    sed -i 's@/bin/@@g' $out/etc/objects/commands.cfg
+  '';
+
+  passthru.tests = {
+    inherit (nixosTests) nagios;
+  };
 
   meta = {
     description = "A host, service and network monitoring program";
diff --git a/pkgs/tools/networking/shorewall/default.nix b/pkgs/tools/networking/shorewall/default.nix
new file mode 100644
index 00000000000..8e62aa735a4
--- /dev/null
+++ b/pkgs/tools/networking/shorewall/default.nix
@@ -0,0 +1,130 @@
+{ coreutils
+, ebtables
+, fetchurl
+, gnugrep
+, gnused
+, iproute
+, ipset
+, iptables
+, perl
+, perlPackages
+, stdenv
+, tree
+, utillinux
+}:
+let
+  PATH = stdenv.lib.concatStringsSep ":"
+           [ "${coreutils}/bin"
+             "${iproute}/bin"
+             "${iptables}/bin"
+             "${ipset}/bin"
+             "${ebtables}/bin"
+             "${utillinux}/bin"
+             "${gnugrep}/bin"
+             "${gnused}/bin"
+           ];
+in
+stdenv.mkDerivation rec {
+  pname = "shorewall";
+  version = "5.2.3.3";
+
+  srcs = [
+    (fetchurl {
+      url = "http://www.shorewall.net/pub/shorewall/5.2/shorewall-5.2.3/shorewall-core-${version}.tar.bz2";
+      sha256 = "1gg2yfxzm3y9qqjrrg5nq2ggi1c6yfxx0s7fvwjw70b185mwa5p5";
+    })
+    (fetchurl {
+      url = "http://www.shorewall.net/pub/shorewall/5.2/shorewall-5.2.3/shorewall-${version}.tar.bz2";
+      sha256 = "1ka70pa3s0cnvc83rlm57r05cdv9idnxnq0vmxi6nr7razak5f3b";
+    })
+    (fetchurl {
+      url = "http://www.shorewall.net/pub/shorewall/5.2/shorewall-5.2.3/shorewall6-${version}.tar.bz2";
+      sha256 = "0mhs4m6agwk082h1n69gnyfsjpycdd8215r4r9rzb3czs5xi087n";
+    })
+  ];
+  sourceRoot = ".";
+
+  buildInputs = [
+    coreutils
+    iproute
+    ipset
+    iptables
+    ebtables
+    utillinux
+    gnugrep
+    gnused
+    perl
+  ] ++ (with perlPackages; [
+    DigestSHA1
+  ]);
+  prePatch = ''
+    # Patch configure and install.sh files
+    patchShebangs .
+
+    # Remove hardcoded PATH
+    sed -i shorewall-core-${version}/lib.cli \
+        -e '/^ *PATH=.*/d'
+  '';
+  configurePhase = ''
+    shorewall-core-${version}/configure \
+      HOST=linux \
+      PREFIX=$out \
+      CONFDIR=\$PREFIX/etc-example \
+      SBINDIR=\$PREFIX/sbin \
+      SYSCONFDIR= \
+      SHAREDIR=\$PREFIX/share \
+      LIBEXECDIR=\$SHAREDIR \
+      PERLLIBDIR=\$SHAREDIR/shorewall \
+      MANDIR=$out/man \
+      VARLIB=/var/lib \
+      INITSOURCE= \
+      INITDIR= \
+      INITFILE= \
+      DEFAULT_PAGER=
+  '';
+  installPhase = ''
+    export DESTDIR=/
+    shorewall-core-${version}/install.sh
+
+    ln -s ../shorewall-core-${version}/shorewallrc shorewall-${version}/
+    shorewall-${version}/install.sh
+
+    ln -s ../shorewall-core-${version}/shorewallrc shorewall6-${version}/
+    shorewall6-${version}/install.sh
+
+    # Patch the example shorewall{,6}.conf in case it is included
+    # in services.shorewall{,6}.configs
+    sed -i $out/etc-example/shorewall/shorewall.conf \
+           $out/etc-example/shorewall6/shorewall6.conf \
+        -e 's|^LOGFILE=.*|LOGFILE=/var/log/shorewall.log|' \
+        -e 's|^PATH=.*|PATH=${PATH}|' \
+        -e 's|^PERL=.*|PERL=${perl}/bin/perl|' \
+        -e 's|^SHOREWALL_SHELL=.*|SHOREWALL_SHELL=${stdenv.shell}|'
+    sed -i $out/etc-example/shorewall6/shorewall6.conf \
+        -e 's|^CONFIG_PATH=.*|CONFIG_PATH=:''${CONFDIR}/shorewall6:''${SHAREDIR}/shorewall6:''${SHAREDIR}/shorewall|'
+    # FIXME: the default GEOIPDIR=/usr/share/xt_geoip/LE may require attention.
+
+    # Redirect CONFDIR to /etc where services.shorewall{,6}.configs
+    # will generate the config files.
+    sed -i $out/share/shorewall/shorewallrc \
+        -e 's~^CONFDIR=.*~CONFDIR=/etc~'
+  '';
+
+  meta = {
+    homepage = http://www.shorewall.net/;
+    description = "An IP gateway/firewall configuration tool for GNU/Linux";
+    longDescription = ''
+      Shorewall is a high-level tool for configuring Netfilter. You describe your
+      firewall/gateway requirements using entries in a set of configuration
+      files. Shorewall reads those configuration files and with the help of the
+      iptables, iptables-restore, ip and tc utilities, Shorewall configures
+      Netfilter and the Linux networking subsystem to match your requirements.
+      Shorewall can be used on a dedicated firewall system, a multi-function
+      gateway/router/server or on a standalone GNU/Linux system. Shorewall does
+      not use Netfilter's ipchains compatibility mode and can thus take
+      advantage of Netfilter's connection state tracking capabilities.
+    '';
+    license = stdenv.lib.licenses.gpl2Plus;
+    platforms = stdenv.lib.platforms.linux;
+  };
+}
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 2194fcbc56c..8c19ab0e8d0 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -6285,6 +6285,8 @@ in
 
   shocco = callPackage ../tools/text/shocco { };
 
+  shorewall = callPackage ../tools/networking/shorewall { };
+
   shotwell = callPackage ../applications/graphics/shotwell { };
 
   shout = nodePackages.shout;