lol

nixos/clamsmtp: init

authored by

Léo Gaspard and committed by
Joachim Fasting
cb506e6e e016a68b

+180
+1
nixos/modules/module-list.nix
··· 260 260 ./services/logging/rsyslogd.nix 261 261 ./services/logging/syslog-ng.nix 262 262 ./services/logging/syslogd.nix 263 + ./services/mail/clamsmtp.nix 263 264 ./services/mail/dkimproxy-out.nix 264 265 ./services/mail/dovecot.nix 265 266 ./services/mail/dspam.nix
+179
nixos/modules/services/mail/clamsmtp.nix
··· 1 + { config, lib, pkgs, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.services.clamsmtp; 6 + clamdSocket = "/run/clamav/clamd.ctl"; # See services/security/clamav.nix 7 + in 8 + { 9 + ##### interface 10 + options = { 11 + services.clamsmtp = { 12 + enable = mkOption { 13 + type = types.bool; 14 + default = false; 15 + description = "Whether to enable clamsmtp."; 16 + }; 17 + 18 + instances = mkOption { 19 + description = "Instances of clamsmtp to run."; 20 + type = types.listOf (types.submodule { options = { 21 + action = mkOption { 22 + type = types.enum [ "bounce" "drop" "pass" ]; 23 + default = "drop"; 24 + description = 25 + '' 26 + Action to take when a virus is detected. 27 + 28 + Note that viruses often spoof sender addresses, so bouncing is 29 + in most cases not a good idea. 30 + ''; 31 + }; 32 + 33 + header = mkOption { 34 + type = types.str; 35 + default = ""; 36 + example = "X-Virus-Scanned: ClamAV using ClamSMTP"; 37 + description = 38 + '' 39 + A header to add to scanned messages. See clamsmtpd.conf(5) for 40 + more details. Empty means no header. 41 + ''; 42 + }; 43 + 44 + keepAlives = mkOption { 45 + type = types.int; 46 + default = 0; 47 + description = 48 + '' 49 + Number of seconds to wait between each NOOP sent to the sending 50 + server. 0 to disable. 51 + 52 + This is meant for slow servers where the sending MTA times out 53 + waiting for clamd to scan the file. 54 + ''; 55 + }; 56 + 57 + listen = mkOption { 58 + type = types.str; 59 + example = "127.0.0.1:10025"; 60 + description = 61 + '' 62 + Address to wait for incoming SMTP connections on. See 63 + clamsmtpd.conf(5) for more details. 64 + ''; 65 + }; 66 + 67 + quarantine = mkOption { 68 + type = types.bool; 69 + default = false; 70 + description = 71 + '' 72 + Whether to quarantine files that contain viruses by leaving them 73 + in the temporary directory. 74 + ''; 75 + }; 76 + 77 + maxConnections = mkOption { 78 + type = types.int; 79 + default = 64; 80 + description = "Maximum number of connections to accept at once."; 81 + }; 82 + 83 + outAddress = mkOption { 84 + type = types.str; 85 + description = 86 + '' 87 + Address of the SMTP server to send email to once it has been 88 + scanned. 89 + ''; 90 + }; 91 + 92 + tempDirectory = mkOption { 93 + type = types.str; 94 + default = "/tmp"; 95 + description = 96 + '' 97 + Temporary directory that needs to be accessible to both clamd 98 + and clamsmtpd. 99 + ''; 100 + }; 101 + 102 + timeout = mkOption { 103 + type = types.int; 104 + default = 180; 105 + description = "Time-out for network connections."; 106 + }; 107 + 108 + transparentProxy = mkOption { 109 + type = types.bool; 110 + default = false; 111 + description = "Enable clamsmtp's transparent proxy support."; 112 + }; 113 + 114 + virusAction = mkOption { 115 + type = with types; nullOr path; 116 + default = null; 117 + description = 118 + '' 119 + Command to run when a virus is found. Please see VIRUS ACTION in 120 + clamsmtpd(8) for a discussion of this option and its safe use. 121 + ''; 122 + }; 123 + 124 + xClient = mkOption { 125 + type = types.bool; 126 + default = false; 127 + description = 128 + '' 129 + Send the XCLIENT command to the receiving server, for forwarding 130 + client addresses and connection information if the receiving 131 + server supports this feature. 132 + ''; 133 + }; 134 + };}); 135 + }; 136 + }; 137 + }; 138 + 139 + ##### implementation 140 + config = let 141 + configfile = conf: pkgs.writeText "clamsmtpd.conf" 142 + '' 143 + Action: ${conf.action} 144 + ClamAddress: ${clamdSocket} 145 + Header: ${conf.header} 146 + KeepAlives: ${toString conf.keepAlives} 147 + Listen: ${conf.listen} 148 + Quarantine: ${if conf.quarantine then "on" else "off"} 149 + MaxConnections: ${toString conf.maxConnections} 150 + OutAddress: ${conf.outAddress} 151 + TempDirectory: ${conf.tempDirectory} 152 + TimeOut: ${toString conf.timeout} 153 + TransparentProxy: ${if conf.transparentProxy then "on" else "off"} 154 + User: clamav 155 + ${optionalString (conf.virusAction != null) "VirusAction: ${conf.virusAction}"} 156 + XClient: ${if conf.xClient then "on" else "off"} 157 + ''; 158 + in 159 + mkIf cfg.enable { 160 + assertions = [ 161 + { assertion = config.services.clamav.daemon.enable; 162 + message = "clamsmtp requires clamav to be enabled"; 163 + } 164 + ]; 165 + 166 + systemd.services = listToAttrs (imap1 (i: conf: 167 + nameValuePair "clamsmtp-${toString i}" { 168 + description = "ClamSMTP instance ${toString i}"; 169 + wantedBy = [ "multi-user.target" ]; 170 + script = "exec ${pkgs.clamsmtp}/bin/clamsmtpd -f ${configfile conf}"; 171 + after = [ "clamav-daemon.service" ]; 172 + requires = [ "clamav-daemon.service" ]; 173 + serviceConfig.Type = "forking"; 174 + serviceConfig.PrivateTmp = "yes"; 175 + unitConfig.JoinsNamespaceOf = "clamav-daemon.service"; 176 + } 177 + ) cfg.instances); 178 + }; 179 + }