@@ -0,0 +1,142 @@
1+import ./make-test-python.nix {
2+ name = "opensmtpd-rspamd";
3+
4+ nodes = {
5+ smtp1 = { pkgs, ... }: {
6+ imports = [ common/user-account.nix ];
7+ networking = {
8+ firewall.allowedTCPPorts = [ 25 143 ];
9+ useDHCP = false;
10+ interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
11+ { address = "192.168.1.1"; prefixLength = 24; }
12+ ];
13+ };
14+ environment.systemPackages = [ pkgs.opensmtpd ];
15+ services.opensmtpd = {
16+ enable = true;
17+ extraServerArgs = [ "-v" ];
18+ serverConfiguration = ''
19+ listen on 0.0.0.0
20+ action dovecot_deliver mda \
21+ "${pkgs.dovecot}/libexec/dovecot/deliver -d %{user.username}"
22+ match from any for local action dovecot_deliver
23+
24+ action do_relay relay
25+ # DO NOT DO THIS IN PRODUCTION!
26+ # Setting up authentication requires a certificate which is painful in
27+ # a test environment, but THIS WOULD BE DANGEROUS OUTSIDE OF A
28+ # WELL-CONTROLLED ENVIRONMENT!
29+ match from any for any action do_relay
30+ '';
31+ };
32+ services.dovecot2 = {
33+ enable = true;
34+ enableImap = true;
35+ mailLocation = "maildir:~/mail";
36+ protocols = [ "imap" ];
37+ };
38+ };
39+
40+ smtp2 = { pkgs, ... }: {
41+ imports = [ common/user-account.nix ];
42+ virtualisation.memorySize = 512;
43+ networking = {
44+ firewall.allowedTCPPorts = [ 25 143 ];
45+ useDHCP = false;
46+ interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
47+ { address = "192.168.1.2"; prefixLength = 24; }
48+ ];
49+ };
50+ environment.systemPackages = [ pkgs.opensmtpd ];
51+ services.rspamd = {
52+ enable = true;
53+ locals."worker-normal.inc".text = ''
54+ bind_socket = "127.0.0.1:11333";
55+ '';
56+ };
57+ services.opensmtpd = {
58+ enable = true;
59+ extraServerArgs = [ "-v" ];
60+ serverConfiguration = ''
61+ filter rspamd proc-exec "${pkgs.opensmtpd-filter-rspamd}/bin/filter-rspamd"
62+ listen on 0.0.0.0 filter rspamd
63+ action dovecot_deliver mda \
64+ "${pkgs.dovecot}/libexec/dovecot/deliver -d %{user.username}"
65+ match from any for local action dovecot_deliver
66+ '';
67+ };
68+ services.dovecot2 = {
69+ enable = true;
70+ enableImap = true;
71+ mailLocation = "maildir:~/mail";
72+ protocols = [ "imap" ];
73+ };
74+ };
75+
76+ client = { pkgs, ... }: {
77+ networking = {
78+ useDHCP = false;
79+ interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
80+ { address = "192.168.1.3"; prefixLength = 24; }
81+ ];
82+ };
83+ environment.systemPackages = let
84+ sendTestMail = pkgs.writeScriptBin "send-a-test-mail" ''
85+ #!${pkgs.python3.interpreter}
86+ import smtplib, sys
87+
88+ with smtplib.SMTP('192.168.1.1') as smtp:
89+ smtp.sendmail('alice@[192.168.1.1]', 'bob@[192.168.1.2]', """
90+ From: alice@smtp1
91+ To: bob@smtp2
92+ Subject: Test
93+
94+ Hello World
95+ Here goes the spam test
96+ XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X
97+ """)
98+ '';
99+
100+ checkMailBounced = pkgs.writeScriptBin "check-mail-bounced" ''
101+ #!${pkgs.python3.interpreter}
102+ import imaplib
103+
104+ with imaplib.IMAP4('192.168.1.1', 143) as imap:
105+ imap.login('alice', 'foobar')
106+ imap.select()
107+ status, refs = imap.search(None, 'ALL')
108+ assert status == 'OK'
109+ assert len(refs) == 1
110+ status, msg = imap.fetch(refs[0], 'BODY[TEXT]')
111+ assert status == 'OK'
112+ content = msg[0][1]
113+ print("===> content:", content)
114+ assert b"An error has occurred while attempting to deliver a message" in content
115+ '';
116+ in [ sendTestMail checkMailBounced ];
117+ };
118+ };
119+
120+ testScript = ''
121+ start_all()
122+
123+ client.wait_for_unit("network-online.target")
124+ smtp1.wait_for_unit("opensmtpd")
125+ smtp2.wait_for_unit("opensmtpd")
126+ smtp2.wait_for_unit("rspamd")
127+ smtp2.wait_for_unit("dovecot2")
128+
129+ # To prevent sporadic failures during daemon startup, make sure
130+ # services are listening on their ports before sending requests
131+ smtp1.wait_for_open_port(25)
132+ smtp2.wait_for_open_port(25)
133+ smtp2.wait_for_open_port(143)
134+ smtp2.wait_for_open_port(11333)
135+
136+ client.succeed("send-a-test-mail")
137+ smtp1.wait_until_fails("smtpctl show queue | egrep .")
138+ client.succeed("check-mail-bounced >&2")
139+ '';
140+
141+ meta.timeout = 1800;
142+}