From 06bcdc177cf4dfe8935a100793d759bab3bc163f Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Mon, 2 Jan 2017 15:09:50 +0100 Subject: [PATCH 1/8] postgrey: extended configuration --- nixos/modules/services/mail/postgrey.nix | 110 +++++++++++++++++++---- 1 file changed, 95 insertions(+), 15 deletions(-) diff --git a/nixos/modules/services/mail/postgrey.nix b/nixos/modules/services/mail/postgrey.nix index 0db631868cc..1c84841f397 100644 --- a/nixos/modules/services/mail/postgrey.nix +++ b/nixos/modules/services/mail/postgrey.nix @@ -4,6 +4,39 @@ with lib; let cfg = config.services.postgrey; + natural = with types; addCheck int (x: x >= 0); + natural' = with types; addCheck int (x: x > 0); + + socket = with types; addCheck (either (submodule unixSocket) (submodule inetSocket)) (x: x ? "path" || x ? "port"); + + inetSocket = with types; { + addr = mkOption { + type = nullOr string; + default = null; + example = "127.0.0.1"; + description = "The address to bind to. Localhost if null"; + }; + port = mkOption { + type = natural'; + default = 10030; + description = "Tcp port to bind to"; + }; + }; + + unixSocket = with types; { + path = mkOption { + type = path; + default = "/var/run/postgrey.sock"; + description = "Path of the unix socket"; + }; + + mode = mkOption { + type = string; + default = "0777"; + description = "Mode of the unix socket"; + }; + }; + in { options = { @@ -13,21 +46,68 @@ in { default = false; description = "Whether to run the Postgrey daemon"; }; - inetAddr = mkOption { - type = nullOr string; - default = null; - example = "127.0.0.1"; - description = "The inet address to bind to. If none given, bind to /var/run/postgrey.sock"; - }; - inetPort = mkOption { - type = int; - default = 10030; - description = "The tcp port to bind to"; + socket = mkOption { + type = socket; + default = { path = "/var/run/postgrey.sock"; }; + example = { + addr = "127.0.0.1"; + port = 10030; + }; + description = "Socket to bind to"; }; greylistText = mkOption { type = string; default = "Greylisted for %%s seconds"; - description = "Response status text for greylisted messages"; + description = "Response status text for greylisted messages; use %%s for seconds left until greylisting is over and %%r for mail domain of recipient"; + }; + greylistAction = mkOption { + type = string; + default = "DEFER_IF_PERMIT"; + description = "Response status for greylisted messages (see access(5))"; + }; + greylistHeader = mkOption { + type = string; + default = "X-Greylist: delayed %%t seconds by postgrey-%%v at %%h; %%d"; + description = "Prepend header to greylisted mails; use %%t for seconds delayed due to greylisting, %%v for the version of postgrey, %%d for the date, and %%h for the host"; + }; + delay = mkOption { + type = natural; + default = 300; + description = "Greylist for N seconds"; + }; + maxAge = mkOption { + type = natural; + default = 35; + description = "Delete entries from whitelist if they haven't been seen for N days"; + }; + retryWindow = mkOption { + type = either string natural; + default = 2; + example = "12h"; + description = "Allow N days for the first retry. Use string with appended 'h' to specify time in hours"; + }; + lookupBySubnet = mkOption { + type = bool; + default = true; + description = "Strip the last N bits from IP addresses, determined by IPv4CIDR and IPv6CIDR"; + }; + IPv4CIDR = mkOption { + type = natural; + default = 24; + }; + IPv6CIDR = mkOption { + type = natural; + default = 64; + }; + privacy = mkOption { + type = bool; + default = true; + description = "Store data using one-way hash functions (SHA1)"; + }; + autoWhitelist = mkOption { + type = nullOr natural'; + default = 5; + description = "Whitelist clients after successful delivery of N messages"; }; }; }; @@ -52,10 +132,10 @@ in { }; systemd.services.postgrey = let - bind-flag = if isNull cfg.inetAddr then - "--unix=/var/run/postgrey.sock" + bind-flag = if cfg.socket ? "path" then + ''--unix=${cfg.socket.path} --socketmode=${cfg.socket.mode}'' else - "--inet=${cfg.inetAddr}:${cfg.inetPort}"; + ''--inet=${optionalString (cfg.socket.addr != null) (cfg.socket.addr + ":")}${cfg.socket.port}''; in { description = "Postfix Greylisting Service"; wantedBy = [ "multi-user.target" ]; @@ -67,7 +147,7 @@ in { ''; serviceConfig = { Type = "simple"; - ExecStart = ''${pkgs.postgrey}/bin/postgrey ${bind-flag} --pidfile=/var/run/postgrey.pid --group=postgrey --user=postgrey --dbdir=/var/postgrey --greylist-text="${cfg.greylistText}"''; + ExecStart = ''${pkgs.postgrey}/bin/postgrey ${bind-flag} --group=postgrey --user=postgrey --dbdir=/var/postgrey --delay=${cfg.delay} --max-age=${cfg.maxAge} --retry-window=${cfg.retryWindow} ${if cfg.lookupBySubnet then "--lookup-by-subnet" else "--lookup-by-host"} --ipv4cidr=${cfg.IPv4CIDR} --ipv6cidr=${cfg.IPv6CIDR} ${optionalString cfg.privacy "--privacy"} --auto-whitelist-clients=${if cfg.autoWhitelist == null then "0" else cfg.autoWhitelist} --greylist-text="${cfg.greylistText}" --x-greylist-header="${cfg.greylistHeader}" --greylist-action=${cfg.greylistAction}''; Restart = "always"; RestartSec = 5; TimeoutSec = 10; From e196ad2c66c13eefa109259e60e91b20b0eb2d55 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Mon, 2 Jan 2017 15:12:39 +0100 Subject: [PATCH 2/8] postgrey: add descriptions to IPv?CIDR --- nixos/modules/services/mail/postgrey.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nixos/modules/services/mail/postgrey.nix b/nixos/modules/services/mail/postgrey.nix index 1c84841f397..c6fec566c0b 100644 --- a/nixos/modules/services/mail/postgrey.nix +++ b/nixos/modules/services/mail/postgrey.nix @@ -94,10 +94,12 @@ in { IPv4CIDR = mkOption { type = natural; default = 24; + description = "Strip N bits from IPv4 addresses if lookupBySubnet is true"; }; IPv6CIDR = mkOption { type = natural; default = 64; + description = "Strip N bits from IPv6 addresses if lookupBySubnet is true"; }; privacy = mkOption { type = bool; From e2dd0799a8cf252d4a8b59006f7b43fa536ee3fb Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Mon, 2 Jan 2017 15:19:00 +0100 Subject: [PATCH 3/8] postgrey: fix submodule syntax --- nixos/modules/services/mail/postgrey.nix | 42 +++++++++++++----------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/nixos/modules/services/mail/postgrey.nix b/nixos/modules/services/mail/postgrey.nix index c6fec566c0b..73f271d2a31 100644 --- a/nixos/modules/services/mail/postgrey.nix +++ b/nixos/modules/services/mail/postgrey.nix @@ -10,30 +10,34 @@ with lib; let socket = with types; addCheck (either (submodule unixSocket) (submodule inetSocket)) (x: x ? "path" || x ? "port"); inetSocket = with types; { - addr = mkOption { - type = nullOr string; - default = null; - example = "127.0.0.1"; - description = "The address to bind to. Localhost if null"; - }; - port = mkOption { - type = natural'; - default = 10030; - description = "Tcp port to bind to"; + options = { + addr = mkOption { + type = nullOr string; + default = null; + example = "127.0.0.1"; + description = "The address to bind to. Localhost if null"; + }; + port = mkOption { + type = natural'; + default = 10030; + description = "Tcp port to bind to"; + }; }; }; unixSocket = with types; { - path = mkOption { - type = path; - default = "/var/run/postgrey.sock"; - description = "Path of the unix socket"; - }; + options = { + path = mkOption { + type = path; + default = "/var/run/postgrey.sock"; + description = "Path of the unix socket"; + }; - mode = mkOption { - type = string; - default = "0777"; - description = "Mode of the unix socket"; + mode = mkOption { + type = string; + default = "0777"; + description = "Mode of the unix socket"; + }; }; }; From 3c0d02c3877bea0d796ff3617a3f4e828295b56d Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Mon, 2 Jan 2017 15:27:00 +0100 Subject: [PATCH 4/8] postgrey: coerce integers --- nixos/modules/services/mail/postgrey.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixos/modules/services/mail/postgrey.nix b/nixos/modules/services/mail/postgrey.nix index 73f271d2a31..ab0ffe7515d 100644 --- a/nixos/modules/services/mail/postgrey.nix +++ b/nixos/modules/services/mail/postgrey.nix @@ -141,7 +141,7 @@ in { bind-flag = if cfg.socket ? "path" then ''--unix=${cfg.socket.path} --socketmode=${cfg.socket.mode}'' else - ''--inet=${optionalString (cfg.socket.addr != null) (cfg.socket.addr + ":")}${cfg.socket.port}''; + ''--inet=${optionalString (cfg.socket.addr != null) (cfg.socket.addr + ":")}${toString cfg.socket.port}''; in { description = "Postfix Greylisting Service"; wantedBy = [ "multi-user.target" ]; @@ -153,7 +153,7 @@ in { ''; serviceConfig = { Type = "simple"; - ExecStart = ''${pkgs.postgrey}/bin/postgrey ${bind-flag} --group=postgrey --user=postgrey --dbdir=/var/postgrey --delay=${cfg.delay} --max-age=${cfg.maxAge} --retry-window=${cfg.retryWindow} ${if cfg.lookupBySubnet then "--lookup-by-subnet" else "--lookup-by-host"} --ipv4cidr=${cfg.IPv4CIDR} --ipv6cidr=${cfg.IPv6CIDR} ${optionalString cfg.privacy "--privacy"} --auto-whitelist-clients=${if cfg.autoWhitelist == null then "0" else cfg.autoWhitelist} --greylist-text="${cfg.greylistText}" --x-greylist-header="${cfg.greylistHeader}" --greylist-action=${cfg.greylistAction}''; + ExecStart = ''${pkgs.postgrey}/bin/postgrey ${bind-flag} --group=postgrey --user=postgrey --dbdir=/var/postgrey --delay=${toString cfg.delay} --max-age=${toString cfg.maxAge} --retry-window=${toString cfg.retryWindow} ${if cfg.lookupBySubnet then "--lookup-by-subnet" else "--lookup-by-host"} --ipv4cidr=${toString cfg.IPv4CIDR} --ipv6cidr=${toString cfg.IPv6CIDR} ${optionalString cfg.privacy "--privacy"} --auto-whitelist-clients=${toString (if cfg.autoWhitelist == null then 0 else cfg.autoWhitelist)} --greylist-text="${cfg.greylistText}" --x-greylist-header="${cfg.greylistHeader}" --greylist-action=${cfg.greylistAction}''; Restart = "always"; RestartSec = 5; TimeoutSec = 10; From 82291bae49fd9e6aa2b899fb5464747a58051822 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Mon, 2 Jan 2017 15:32:50 +0100 Subject: [PATCH 5/8] postgrey: more verbose default socket --- nixos/modules/services/mail/postgrey.nix | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/mail/postgrey.nix b/nixos/modules/services/mail/postgrey.nix index ab0ffe7515d..7bf1c30fc67 100644 --- a/nixos/modules/services/mail/postgrey.nix +++ b/nixos/modules/services/mail/postgrey.nix @@ -52,7 +52,10 @@ in { }; socket = mkOption { type = socket; - default = { path = "/var/run/postgrey.sock"; }; + default = { + path = "/var/run/postgrey.sock"; + mode = "0777"; + }; example = { addr = "127.0.0.1"; port = 10030; From 58fa71b39c9e5d0af7b8329a0c3ebf99f305bc71 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Mon, 2 Jan 2017 15:40:54 +0100 Subject: [PATCH 6/8] postgrey: allow additional whitelists --- nixos/modules/services/mail/postgrey.nix | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/mail/postgrey.nix b/nixos/modules/services/mail/postgrey.nix index 7bf1c30fc67..7db4e4d1c21 100644 --- a/nixos/modules/services/mail/postgrey.nix +++ b/nixos/modules/services/mail/postgrey.nix @@ -118,6 +118,16 @@ in { default = 5; description = "Whitelist clients after successful delivery of N messages"; }; + whitelistClients = mkOption { + type = listOf path; + default = []; + description = "Client address whitelist files (see postgrey(8))"; + }; + whitelistRecipients = mkOption { + type = listOf path; + default = []; + description = "Recipient address whitelist files (see postgrey(8))"; + }; }; }; @@ -156,7 +166,7 @@ in { ''; serviceConfig = { Type = "simple"; - ExecStart = ''${pkgs.postgrey}/bin/postgrey ${bind-flag} --group=postgrey --user=postgrey --dbdir=/var/postgrey --delay=${toString cfg.delay} --max-age=${toString cfg.maxAge} --retry-window=${toString cfg.retryWindow} ${if cfg.lookupBySubnet then "--lookup-by-subnet" else "--lookup-by-host"} --ipv4cidr=${toString cfg.IPv4CIDR} --ipv6cidr=${toString cfg.IPv6CIDR} ${optionalString cfg.privacy "--privacy"} --auto-whitelist-clients=${toString (if cfg.autoWhitelist == null then 0 else cfg.autoWhitelist)} --greylist-text="${cfg.greylistText}" --x-greylist-header="${cfg.greylistHeader}" --greylist-action=${cfg.greylistAction}''; + ExecStart = ''${pkgs.postgrey}/bin/postgrey ${bind-flag} --group=postgrey --user=postgrey --dbdir=/var/postgrey --delay=${toString cfg.delay} --max-age=${toString cfg.maxAge} --retry-window=${toString cfg.retryWindow} ${if cfg.lookupBySubnet then "--lookup-by-subnet" else "--lookup-by-host"} --ipv4cidr=${toString cfg.IPv4CIDR} --ipv6cidr=${toString cfg.IPv6CIDR} ${optionalString cfg.privacy "--privacy"} --auto-whitelist-clients=${toString (if cfg.autoWhitelist == null then 0 else cfg.autoWhitelist)} --greylist-text="${cfg.greylistText}" --x-greylist-header="${cfg.greylistHeader}" --greylist-action=${cfg.greylistAction} ${concatMapStringsSep " " (x: "--whitelist-clients=" + x) cfg.whitelistClients} ${concatMapStringsSep " " (x: "--whitelist-recipients=" + x) cfg.whitelistRecipients}''; Restart = "always"; RestartSec = 5; TimeoutSec = 10; From 65f0ddbd534c1bd74d7fdbd8db3dff0d00a89c5a Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Mon, 2 Jan 2017 15:42:51 +0100 Subject: [PATCH 7/8] postgrey: improve formatting --- nixos/modules/services/mail/postgrey.nix | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/mail/postgrey.nix b/nixos/modules/services/mail/postgrey.nix index 7db4e4d1c21..d4ae25c066a 100644 --- a/nixos/modules/services/mail/postgrey.nix +++ b/nixos/modules/services/mail/postgrey.nix @@ -166,7 +166,23 @@ in { ''; serviceConfig = { Type = "simple"; - ExecStart = ''${pkgs.postgrey}/bin/postgrey ${bind-flag} --group=postgrey --user=postgrey --dbdir=/var/postgrey --delay=${toString cfg.delay} --max-age=${toString cfg.maxAge} --retry-window=${toString cfg.retryWindow} ${if cfg.lookupBySubnet then "--lookup-by-subnet" else "--lookup-by-host"} --ipv4cidr=${toString cfg.IPv4CIDR} --ipv6cidr=${toString cfg.IPv6CIDR} ${optionalString cfg.privacy "--privacy"} --auto-whitelist-clients=${toString (if cfg.autoWhitelist == null then 0 else cfg.autoWhitelist)} --greylist-text="${cfg.greylistText}" --x-greylist-header="${cfg.greylistHeader}" --greylist-action=${cfg.greylistAction} ${concatMapStringsSep " " (x: "--whitelist-clients=" + x) cfg.whitelistClients} ${concatMapStringsSep " " (x: "--whitelist-recipients=" + x) cfg.whitelistRecipients}''; + ExecStart = ''${pkgs.postgrey}/bin/postgrey \ + ${bind-flag} \ + --group=postgrey --user=postgrey \ + --dbdir=/var/postgrey \ + --delay=${toString cfg.delay} \ + --max-age=${toString cfg.maxAge} \ + --retry-window=${toString cfg.retryWindow} \ + ${if cfg.lookupBySubnet then "--lookup-by-subnet" else "--lookup-by-host"} \ + --ipv4cidr=${toString cfg.IPv4CIDR} --ipv6cidr=${toString cfg.IPv6CIDR} \ + ${optionalString cfg.privacy "--privacy"} \ + --auto-whitelist-clients=${toString (if cfg.autoWhitelist == null then 0 else cfg.autoWhitelist)} \ + --greylist-action=${cfg.greylistAction} \ + --greylist-text="${cfg.greylistText}" \ + --x-greylist-header="${cfg.greylistHeader}" \ + ${concatMapStringsSep " " (x: "--whitelist-clients=" + x) cfg.whitelistClients} \ + ${concatMapStringsSep " " (x: "--whitelist-recipients=" + x) cfg.whitelistRecipients} + ''; Restart = "always"; RestartSec = 5; TimeoutSec = 10; From 9383b2cf347c4181bbdd14b5c8bcb929e4cdcb8b Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Mon, 2 Jan 2017 18:01:42 +0100 Subject: [PATCH 8/8] postgrey: backwards compatability --- nixos/modules/rename.nix | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 8102e0e1f64..758f229d59d 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -153,6 +153,17 @@ with lib; # alsa (mkRenamedOptionModule [ "sound" "enableMediaKeys" ] [ "sound" "mediaKeys" "enable" ]) + # postgrey + (mkMergedOptionModule [ [ "services" "postgrey" "inetAddr" ] [ "services" "postgrey" "inetPort" ] ] [ "services" "postgrey" "socket" ] (config: let + value = p: getAttrFromPath p config; + inetAddr = [ "services" "postgrey" "inetAddr" ]; + inetPort = [ "services" "postgrey" "inetPort" ]; + in + if value inetAddr == null + then { path = "/var/run/postgrey.sock"; } + else { addr = value inetAddr; port = value inetPort; } + )) + # Options that are obsolete and have no replacement. (mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ] "") (mkRemovedOptionModule [ "programs" "bash" "enable" ] "")