2018-05-13 02:40:58 +02:00
# nixos-mailserver: a simple mail server
# Copyright (C) 2016-2018 Robin Raymond
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
2020-04-11 15:38:52 +02:00
{ pkgs ? import <nixpkgs> { } }:
import ( pkgs . path + " / n i x o s / t e s t s / m a k e - t e s t . n i x " ) {
2018-05-13 02:40:58 +02:00
nodes = {
server = { config , pkgs , lib , . . . }:
let
2019-12-14 19:04:20 +01:00
clamav-db-files = pkgs . stdenv . mkDerivation rec {
name = " c l a m a v - d b - f i l e s " ;
src = lib . cleanSource ./clamav ;
dontUnpack = true ;
installPhase = ''
mkdir $ out
cp - R $ src /* . c v d $ o u t /
'' ;
} ;
2018-05-13 02:40:58 +02:00
in
{
imports = [
../default.nix
2019-06-30 10:43:29 +02:00
./lib/config.nix
2018-05-13 02:40:58 +02:00
] ;
virtualisation . memorySize = 1500 ;
services . rsyslogd = {
enable = true ;
defaultConfig = ''
* . * /dev/console
'' ;
} ;
services . clamav . updater . enable = lib . mkForce false ;
systemd . services . old-clam = {
before = [ " c l a m a v - d a e m o n . s e r v i c e " ] ;
requiredBy = [ " c l a m a v - d a e m o n . s e r v i c e " ] ;
description = " C l a m A V v i r u s d a t a b a s e " ;
preStart = ''
mkdir - m 0755 - p /var/lib/clamav
chown clamav:clamav /var/lib/clamav
'' ;
script = ''
2019-12-14 19:04:20 +01:00
cp $ { clamav-db-files } /main.cvd /var/lib/clamav /
cp $ { clamav-db-files } /daily.cvd /var/lib/clamav /
cp $ { clamav-db-files } /bytecode.cvd /var/lib/clamav /
2018-05-13 02:40:58 +02:00
chown clamav:clamav /var/lib/clamav /*
'' ;
serviceConfig = {
Type = " o n e s h o t " ;
PrivateTmp = " y e s " ;
PrivateDevices = " y e s " ;
} ;
} ;
mailserver = {
enable = true ;
debug = true ;
fqdn = " m a i l . e x a m p l e . c o m " ;
domains = [ " e x a m p l e . c o m " " e x a m p l e 2 . c o m " ] ;
virusScanning = true ;
loginAccounts = {
" u s e r 1 @ e x a m p l e . c o m " = {
hashedPassword = " $ 6 $ / z 4 n 8 A Q l 6 K $ k i O k B T W l Z f B d 7 P v F 5 G s J 8 P m P g d Z s F G N 1 j P G Z u f x x r 6 0 P o R 0 o U s r v z m 2 o Q i f l y z 5 i r 9 f F J . d / z K m / N g L X N U s N X / " ;
aliases = [ " p o s t m a s t e r @ e x a m p l e . c o m " ] ;
catchAll = [ " e x a m p l e . c o m " ] ;
} ;
" u s e r @ e x a m p l e 2 . c o m " = {
hashedPassword = " $ 6 $ u 6 1 J r A t u I 0 a $ n G E E f T P 5 . e e f x o S c U G V G / T l 0 a l q l a 2 a G a x 4 o T d 8 5 v 3 j 3 x S m h v / 0 2 g N f S e m v / a a M i n l v 9 j / Z A B o s V K B r R v N 5 Q v 0 " ;
} ;
} ;
enableImap = true ;
} ;
environment . etc = {
" r o o t / e i c a r . c o m . t x t " . text = " X 5 O ! P % @ A P [ 4 \P Z X 5 4 ( P ^ ) 7 C C ) 7 } $ E I C A R - S T A N D A R D - A N T I V I R U S - T E S T - F I L E ! $ H + H * " ;
} ;
} ;
client = { nodes , config , pkgs , . . . }: let
serverIP = nodes . server . config . networking . primaryIPAddress ;
clientIP = nodes . client . config . networking . primaryIPAddress ;
grep-ip = pkgs . writeScriptBin " g r e p - i p " ''
#!${pkgs.stdenv.shell}
echo grep ' $ { clientIP } ' " $ @ " > & 2
exec grep ' $ { clientIP } ' " $ @ "
'' ;
in {
2019-06-30 10:43:29 +02:00
imports = [
./lib/config.nix
] ;
2018-05-13 02:40:58 +02:00
environment . systemPackages = with pkgs ; [
fetchmail msmtp procmail findutils grep-ip
] ;
environment . etc = {
" r o o t / . f e t c h m a i l r c " = {
text = ''
poll $ { serverIP } with proto IMAP
user ' user1 @ example . com' there with password ' user1' is ' root' here
mda procmail
'' ;
mode = " 0 7 0 0 " ;
} ;
" r o o t / . p r o c m a i l r c " = {
text = " D E F A U L T = $ H O M E / m a i l " ;
} ;
" r o o t / . m s m t p r c " = {
text = ''
2019-07-06 11:31:24 +02:00
defaults
tls on
tls_certcheck off
account user2
2018-05-13 02:40:58 +02:00
host $ { serverIP }
port 587
from user @ example2 . com
2019-07-06 11:31:24 +02:00
auth on
2018-05-13 02:40:58 +02:00
user user @ example2 . com
password user2
'' ;
} ;
" r o o t / v i r u s - e m a i l " . text = ''
From : User2 < user @ example2 . com >
Content-Type : multipart/mixed ;
boundary = " A p p l e - M a i l = _ 2 6 8 9 C 6 3 E - F D 1 8 - 4 E 4 D - 8 8 2 2 - 5 4 7 9 7 B D A 9 6 0 7 "
Mime-Version : 1 .0 ( Mac OS X Mail 11 .3 \ ( 3445 .6 .18 \ ) )
Subject : Testy McTest
Message-Id : < 9 4 5 5 0 DD9-1FF1-4ED1-9F09-8812FF2E59AA @ example . com >
Date : Sat , 12 M ay 2018 14 : 15 : 44 + 0200
To : User1 < user1 @ example . com >
X-Mailer : Apple Mail ( 2 .3445 .6 .18 )
- - Apple-Mail = _2689C63E-FD18-4E4D-8822-54797BDA9607
Content-Transfer-Encoding : 7 bit
Content-Type : text/plain ;
charset = us-ascii
Hello
I have attached a dangerous virus .
Mfg .
User2
- - Apple-Mail = _2689C63E-FD18-4E4D-8822-54797BDA9607
Content-Disposition : attachment ;
filename = eicar . com . txt
Content-Type : text/plain ;
x-unix-mode = 0644 ;
name = " e i c a r . c o m . t x t "
Content-Transfer-Encoding : 7 bit
X5O ! P % @ AP [ 4 \ PZX54 ( P ^ ) 7 CC ) 7 } $ EICAR-STANDARD-ANTIVIRUS-TEST-FILE ! $ H + H *
- - Apple-Mail = _2689C63E-FD18-4E4D-8822-54797BDA9607--
'' ;
2019-07-06 11:31:24 +02:00
" r o o t / s a f e - e m a i l " . text = ''
2018-05-13 02:40:58 +02:00
From : User < user @ example2 . com >
To : User1 < user1 @ example . com >
Cc :
Bcc :
Subject : This is a test Email from user @ example2 . com to user1
Reply-To :
Hello User1 ,
how are you doing today ?
XOXO User1
'' ;
} ;
} ;
} ;
2019-07-06 11:31:24 +02:00
testScript = { nodes , . . . }:
2018-05-13 02:40:58 +02:00
''
startAll ;
$ server- > waitForUnit ( " m u l t i - u s e r . t a r g e t " ) ;
$ client- > waitForUnit ( " m u l t i - u s e r . t a r g e t " ) ;
2019-07-06 11:31:24 +02:00
# TODO put this blocking into the systemd units? I am not sure if rspamd already waits for the clamd socket.
$ server- > waitUntilSucceeds ( " t i m e o u t 1 ${ nodes . server . pkgs . netcat } / b i n / n c - U / r u n / r s p a m d / r s p a m d - m i l t e r . s o c k < / d e v / n u l l ; [ \$ ? - e q 1 2 4 ] " ) ;
$ server- > waitUntilSucceeds ( " t i m e o u t 1 ${ nodes . server . pkgs . netcat } / b i n / n c - U / r u n / c l a m a v / c l a m d . c t l < / d e v / n u l l ; [ \$ ? - e q 1 2 4 ] " ) ;
2018-05-13 02:40:58 +02:00
$ client- > execute ( " c p - p / e t c / r o o t / . * ~ / " ) ;
$ client- > succeed ( " m k d i r - p ~ / m a i l " ) ;
$ client- > succeed ( " l s - l a ~ / > & 2 " ) ;
$ client- > succeed ( " c a t ~ / . f e t c h m a i l r c > & 2 " ) ;
$ client- > succeed ( " c a t ~ / . p r o c m a i l r c > & 2 " ) ;
$ client- > succeed ( " c a t ~ / . m s m t p r c > & 2 " ) ;
# fetchmail returns EXIT_CODE 1 when no new mail
2020-04-11 21:49:15 +02:00
$ client- > succeed ( " f e t c h m a i l - - n o s s l c e r t c k - v | | [ \$ ? - e q 1 ] > & 2 " ) ;
2018-05-13 02:40:58 +02:00
# Verify that mail can be sent and received before testing virus scanner
$ client- > execute ( " r m ~ / m a i l / * " ) ;
2019-07-06 11:31:24 +02:00
$ client- > succeed ( " m s m t p - a u s e r 2 u s e r 1 \@ e x a m p l e . c o m < / e t c / r o o t / s a f e - e m a i l > & 2 " ) ;
2018-05-13 02:40:58 +02:00
# give the mail server some time to process the mail
$ server- > waitUntilFails ( ' [ " $ ( p o s t q u e u e - p ) " != " M a i l q u e u e i s e m p t y " ] ' ) ;
$ client- > execute ( " r m ~ / m a i l / * " ) ;
# fetchmail returns EXIT_CODE 0 when it retrieves mail
2020-04-11 21:49:15 +02:00
$ client- > succeed ( " f e t c h m a i l - - n o s s l c e r t c k - v > & 2 " ) ;
2018-05-13 02:40:58 +02:00
$ client- > execute ( " r m ~ / m a i l / * " ) ;
subtest " v i r u s s c a n f i l e " , sub {
2019-07-06 11:31:24 +02:00
$ server- > succeed ( " c l a m d s c a n \$ ( r e a d l i n k - f / e t c / r o o t / e i c a r . c o m . t x t ) | g r e p \" T x t \\ . M a l w a r e \\ . A g e n t - 1 7 8 7 5 9 7 F O U N D \" > & 2 " ) ;
2018-05-13 02:40:58 +02:00
} ;
2019-07-06 11:31:24 +02:00
subtest " v i r u s s c a n e m a i l " , sub {
$ client- > succeed ( " m s m t p - a u s e r 2 u s e r 1 \@ e x a m p l e . c o m < / e t c / r o o t / v i r u s - e m a i l 2 > & 1 | g r e p \" s e r v e r m e s s a g e : 5 5 4 5 \\ . 7 \\ . 1 c l a m a v : v i r u s f o u n d : . * \\ ( E i c a r \\ | E I C A R \\ ) \" > & 2 " ) ; # for some reason this ID is nondetermistic...
2018-05-13 02:40:58 +02:00
# give the mail server some time to process the mail
$ server- > waitUntilFails ( ' [ " $ ( p o s t q u e u e - p ) " != " M a i l q u e u e i s e m p t y " ] ' ) ;
} ;
subtest " n o w a r n i n g s o r e r r o r s " , sub {
$ server- > fail ( " j o u r n a l c t l - u p o s t f i x | g r e p - i e r r o r > & 2 " ) ;
$ server- > fail ( " j o u r n a l c t l - u p o s t f i x | g r e p - i w a r n i n g > & 2 " ) ;
$ server- > fail ( " j o u r n a l c t l - u d o v e c o t 2 | g r e p - i e r r o r > & 2 " ) ;
$ server- > fail ( " j o u r n a l c t l - u d o v e c o t 2 | g r e p - i w a r n i n g > & 2 " ) ;
} ;
'' ;
}