mirror of
https://blitiri.com.ar/repos/chasquid
synced 2025-12-17 14:37:02 +00:00
test: Unify (most) SMTP client calls
To send mails, today some tests use msmtp and others our internal smtpc.py. This works, but msmtp slows down the tests significantly, and smtpc.py is also not particularly fast, and also has some limitations. This patch introduces a new SMTP client tool written in Go, and makes almost all the tests use it. Some tests still remain on msmtp, mainly for client-check compatibility. It's likely that this will be moved in later patches to a separate special-purpose test. With this patch, integration tests take ~20% less time than before.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -28,6 +28,7 @@ test/util/generate_cert/generate_cert
|
||||
test/util/gocovcat/gocovcat
|
||||
test/util/loadgen/loadgen
|
||||
test/util/minidns/minidns
|
||||
test/util/smtpc/smtpc
|
||||
|
||||
# Test binary, generated during coverage tests.
|
||||
chasquid.test
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
account default
|
||||
|
||||
host srv-chasquid
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file config/certs/srv-chasquid/fullchain.pem
|
||||
|
||||
from user@srv-chasquid
|
||||
|
||||
auth on
|
||||
user user@srv-chasquid
|
||||
password secretpassword
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
# someone@srv-chasquid.
|
||||
#
|
||||
# Test:
|
||||
# msmtp --> chasquid --> exim --> chasquid --> local delivery
|
||||
# smtpc --> chasquid --> exim --> chasquid --> local delivery
|
||||
#
|
||||
# msmtp will auth as user@srv-chasquid to chasquid, and send an email with
|
||||
# smtpc will auth as user@srv-chasquid to chasquid, and send an email with
|
||||
# recipient someone@srv-exim.
|
||||
#
|
||||
# chasquid will deliver the mail to exim.
|
||||
@@ -28,15 +28,15 @@ set -e
|
||||
init
|
||||
check_hostaliases
|
||||
|
||||
if ! .exim4/exim4 --version > /dev/null; then
|
||||
skip "exim4 binary at .exim4/exim4 is not functional"
|
||||
fi
|
||||
|
||||
# Create a temporary directory for exim4 to use, and generate the exim4
|
||||
# config based on the template.
|
||||
mkdir -p .exim4
|
||||
EXIMDIR="$PWD/.exim4" envsubst < config/exim4.in > .exim4/config
|
||||
|
||||
if ! .exim4/exim4 -C "$PWD/.exim4/config" --version > /dev/null; then
|
||||
skip "exim4 binary at .exim4/exim4 is not functional"
|
||||
fi
|
||||
|
||||
# Build with the DNS override, so we can fake DNS records.
|
||||
export GOTAGS="dnsoverride"
|
||||
|
||||
@@ -62,8 +62,8 @@ wait_until_ready 9053
|
||||
.exim4/exim4 -bd -d -C "$PWD/.exim4/config" > .exim4/log 2>&1 &
|
||||
wait_until_ready 2025
|
||||
|
||||
# msmtp will use chasquid to send an email to someone@srv-exim.
|
||||
run_msmtp someone@srv-exim < content
|
||||
# smtpc will use chasquid to send an email to someone@srv-exim.
|
||||
smtpc someone@srv-exim < content
|
||||
|
||||
wait_for_file .mail/someone@srv-chasquid
|
||||
|
||||
|
||||
4
test/t-02-exim/smtpc.conf
Normal file
4
test/t-02-exim/smtpc.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
addr localhost:1465
|
||||
server_cert config/certs/srv-chasquid/fullchain.pem
|
||||
user user@srv-chasquid
|
||||
password secretpassword
|
||||
@@ -1,3 +1,4 @@
|
||||
From: user@testserver
|
||||
Subject: Prueba desde el test
|
||||
|
||||
Crece desde el test el futuro
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
account default
|
||||
|
||||
host testserver
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file config/certs/testserver/fullchain.pem
|
||||
|
||||
from user@testserver
|
||||
|
||||
auth on
|
||||
user user@testserver
|
||||
password secretpassword
|
||||
|
||||
@@ -14,7 +14,7 @@ chasquid -v=2 --logfile=.logs/chasquid.log --config_dir=config &
|
||||
wait_until_ready 1025
|
||||
|
||||
function send_and_check() {
|
||||
run_msmtp "$1@testserver" < content
|
||||
smtpc "$1@testserver" < content
|
||||
shift
|
||||
for i in "$@"; do
|
||||
wait_for_file ".mail/$i@testserver"
|
||||
@@ -42,7 +42,7 @@ send_and_check añil+blah azul índigo
|
||||
|
||||
# Test the pipe alias separately.
|
||||
rm -f .data/pipe_alias_worked
|
||||
run_msmtp tubo@testserver < content
|
||||
smtpc tubo@testserver < content
|
||||
wait_for_file .data/pipe_alias_worked
|
||||
mail_diff content .data/pipe_alias_worked
|
||||
|
||||
@@ -58,17 +58,17 @@ send_and_check vic.uña+abc uña
|
||||
|
||||
# Test the pipe alias separately.
|
||||
rm -f .data/pipe_alias_worked
|
||||
run_msmtp ñandú@testserver < content
|
||||
smtpc ñandú@testserver < content
|
||||
wait_for_file .data/pipe_alias_worked
|
||||
mail_diff content .data/pipe_alias_worked
|
||||
|
||||
# Test when alias-resolve exits with an error
|
||||
if run_msmtp roto@testserver < content 2> .logs/msmtp.out; then
|
||||
if smtpc roto@testserver < content 2> .logs/smtpc.out; then
|
||||
fail "expected delivery to roto@ to fail, but succeeded"
|
||||
fi
|
||||
|
||||
# Test a non-existent alias.
|
||||
if run_msmtp nono@testserver < content 2> .logs/msmtp.out; then
|
||||
if smtpc nono@testserver < content 2> .logs/smtpc.out; then
|
||||
fail "expected delivery to nono@ to fail, but succeeded"
|
||||
fi
|
||||
|
||||
|
||||
4
test/t-04-aliases/smtpc.conf
Normal file
4
test/t-04-aliases/smtpc.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
addr localhost:1465
|
||||
server_cert config/certs/testserver/fullchain.pem
|
||||
user user@testserver
|
||||
password secretpassword
|
||||
@@ -54,7 +54,6 @@ Received: from localhost
|
||||
tls *
|
||||
(over *
|
||||
; *
|
||||
Date: *
|
||||
From: Mailer daemon <somewhere@báratro>
|
||||
Subject: I've come to haunt you
|
||||
Message-Id: <booooo>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
account default
|
||||
|
||||
host testserver
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file config/certs/testserver/fullchain.pem
|
||||
|
||||
from user@testserver
|
||||
|
||||
auth on
|
||||
user user@testserver
|
||||
password secretpassword
|
||||
@@ -22,7 +22,7 @@ rm -f .mail/user@testserver
|
||||
|
||||
|
||||
# Test that we get mail back for a failed delivery
|
||||
run_msmtp fail@testserver < content
|
||||
smtpc fail@testserver < content
|
||||
wait_for_file .mail/user@testserver
|
||||
mail_diff expected_dsr .mail/user@testserver
|
||||
|
||||
|
||||
4
test/t-05-null_address/smtpc.conf
Normal file
4
test/t-05-null_address/smtpc.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
addr localhost:1465
|
||||
server_cert config/certs/testserver/fullchain.pem
|
||||
user user@testserver
|
||||
password secretpassword
|
||||
@@ -1,5 +1,6 @@
|
||||
smtp_address: ":1025"
|
||||
submission_address: ":1587"
|
||||
submission_over_tls_address: ":1465"
|
||||
monitoring_address: ":1099"
|
||||
|
||||
mail_delivery_agent_bin: "test-mda"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
smtp_address: ":2025"
|
||||
submission_address: ":2587"
|
||||
submission_over_tls_address: ":2465"
|
||||
monitoring_address: ":2099"
|
||||
|
||||
mail_delivery_agent_bin: "test-mda"
|
||||
|
||||
@@ -8,8 +8,6 @@ check_hostaliases
|
||||
|
||||
rm -rf .data-A .data-B .mail
|
||||
|
||||
skip_if_python_is_too_old
|
||||
|
||||
# Build with the DNS override, so we can fake DNS records.
|
||||
export GOTAGS="dnsoverride"
|
||||
|
||||
@@ -37,20 +35,22 @@ chasquid -v=2 --logfile=.logs-B/chasquid.log --config_dir=B \
|
||||
--testing__dns_addr=127.0.0.1:9053 \
|
||||
--testing__outgoing_smtp_port=1025 &
|
||||
|
||||
wait_until_ready 1025
|
||||
wait_until_ready 2025
|
||||
wait_until_ready 1465
|
||||
wait_until_ready 2465
|
||||
wait_until_ready 9053
|
||||
|
||||
# Send from A to B.
|
||||
smtpc.py --server=localhost:1025 --user=nadaA@nadaA --password=nadaA \
|
||||
< from_A_to_B
|
||||
smtpc --addr=localhost:1465 --user=nadaA@nadaA --password=nadaA \
|
||||
--server_cert=A/certs/srv-ñ/fullchain.pem \
|
||||
pingüino@srv-ü < from_A_to_B
|
||||
|
||||
wait_for_file .mail/pingüino@srv-ü
|
||||
mail_diff from_A_to_B .mail/pingüino@srv-ü
|
||||
|
||||
# Send from B to A.
|
||||
smtpc.py --server=localhost:2025 --user=nadaB@nadaB --password=nadaB \
|
||||
< from_B_to_A
|
||||
smtpc --addr=localhost:2465 --user=nadaB@nadaB --password=nadaB \
|
||||
--server_cert=B/certs/srv-ü/fullchain.pem \
|
||||
ñangapirí@srv-ñ < from_B_to_A
|
||||
|
||||
wait_for_file .mail/ñangapirí@srv-ñ
|
||||
mail_diff from_B_to_A .mail/ñangapirí@srv-ñ
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
smtp_address: ":1025"
|
||||
submission_address: ":1587"
|
||||
submission_over_tls_address: ":1465"
|
||||
monitoring_address: ":1099"
|
||||
|
||||
mail_delivery_agent_bin: "test-mda"
|
||||
|
||||
@@ -9,25 +9,23 @@ set -e
|
||||
|
||||
init
|
||||
|
||||
skip_if_python_is_too_old
|
||||
|
||||
generate_certs_for ñoños
|
||||
|
||||
# Intentionally have a config directory for upper case; this should be
|
||||
# normalized to lowercase internally (and match the cert accordingly).
|
||||
add_user ñandú@ñoñOS araño
|
||||
add_user ñangapirí@ñoñOS antaño
|
||||
|
||||
# Python doesn't support UTF8 for auth, use an ascii user and domain.
|
||||
add_user nada@nada nada
|
||||
|
||||
mkdir -p .logs
|
||||
chasquid -v=2 --logfile=.logs/chasquid.log --config_dir=config &
|
||||
wait_until_ready 1025
|
||||
wait_until_ready 1465
|
||||
|
||||
# The envelope from and to are taken from the content, and use a mix of upper
|
||||
# and lower case.
|
||||
smtpc.py --server=localhost:1025 --user=nada@nada --password=nada \
|
||||
< content
|
||||
# Use a mix of upper and lower case in the from, to, and username, to check
|
||||
# normalization is well handled end-to-end.
|
||||
smtpc --addr=localhost:1465 \
|
||||
--server_cert=config/certs/ñoños/fullchain.pem \
|
||||
--user=ñanDÚ@ñoños --password=araño \
|
||||
Ñangapirí@Ñoños < content
|
||||
|
||||
# The MDA should see the normalized users and domains, in lower case.
|
||||
wait_for_file .mail/ñangapirí@ñoños
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
account default
|
||||
|
||||
host srv-A
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file A/certs/srv-A/fullchain.pem
|
||||
|
||||
from userA@srv-A
|
||||
|
||||
auth on
|
||||
user userA@srv-A
|
||||
password userA
|
||||
|
||||
@@ -40,7 +40,7 @@ wait_until_ready 1025
|
||||
wait_until_ready 2025
|
||||
wait_until_ready 9053
|
||||
|
||||
run_msmtp aliasB@srv-B < content
|
||||
smtpc aliasB@srv-B < content
|
||||
|
||||
# Get some of the debugging pages, for troubleshooting, and to make sure they
|
||||
# work reasonably well.
|
||||
|
||||
4
test/t-09-loop/smtpc.conf
Normal file
4
test/t-09-loop/smtpc.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
addr localhost:1465
|
||||
server_cert A/certs/srv-A/fullchain.pem
|
||||
user userA@srv-A
|
||||
password userA
|
||||
@@ -1,5 +1,6 @@
|
||||
smtp_address: ":1025"
|
||||
submission_address: ":1587"
|
||||
submission_over_tls_address: ":1465"
|
||||
monitoring_address: ":1099"
|
||||
|
||||
mail_delivery_agent_bin: "test-mda"
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
account default
|
||||
|
||||
host testserver
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file config/certs/testserver/fullchain.pem
|
||||
|
||||
from user@testserver
|
||||
|
||||
auth on
|
||||
user user@testserver
|
||||
password secretpassword
|
||||
|
||||
logfile .logs/msmtp
|
||||
@@ -18,7 +18,7 @@ wait_until_ready 1025
|
||||
|
||||
cp config/hooks/post-data.good config/hooks/post-data
|
||||
|
||||
run_msmtp someone@testserver < content
|
||||
smtpc someone@testserver < content
|
||||
|
||||
wait_for_file .mail/someone@testserver
|
||||
|
||||
@@ -51,20 +51,20 @@ check "SPF_PASS=0"
|
||||
|
||||
# Check that failures in the script result in failing delivery.
|
||||
# Transient failure.
|
||||
if run_msmtp blockme@testserver < content 2>/dev/null; then
|
||||
if smtpc blockme@testserver < content >.logs/smtpc.log 2>&1; then
|
||||
fail "ERROR: hook did not block email as expected"
|
||||
fi
|
||||
if ! tail -n 1 .logs/msmtp | grep -q "smtpstatus=451"; then
|
||||
tail -n 1 .logs/msmtp
|
||||
if ! grep -q "451 ¡No pasarán!" .logs/smtpc.log; then
|
||||
cat .logs/smtpc.log
|
||||
fail "ERROR: transient hook error not returned correctly"
|
||||
fi
|
||||
|
||||
# Permanent failure.
|
||||
if run_msmtp permanent@testserver < content 2>/dev/null; then
|
||||
if smtpc permanent@testserver < content >.logs/smtpc.log 2>&1; then
|
||||
fail "ERROR: hook did not block email as expected"
|
||||
fi
|
||||
if ! tail -n 1 .logs/msmtp | grep -q "smtpstatus=554"; then
|
||||
tail -n 1 .logs/msmtp
|
||||
if ! grep -q "554 Nos hacemos la permanente" .logs/smtpc.log; then
|
||||
cat .logs/smtpc.log
|
||||
fail "ERROR: permanent hook error not returned correctly"
|
||||
fi
|
||||
|
||||
@@ -72,7 +72,7 @@ fi
|
||||
for i in config/hooks/post-data.bad*; do
|
||||
cp "$i" config/hooks/post-data
|
||||
|
||||
run_msmtp someone@testserver < content
|
||||
smtpc someone@testserver < content
|
||||
wait_for_file .mail/someone@testserver
|
||||
mail_diff content .mail/someone@testserver
|
||||
done
|
||||
|
||||
4
test/t-10-hooks/smtpc.conf
Normal file
4
test/t-10-hooks/smtpc.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
addr localhost:1465
|
||||
server_cert config/certs/testserver/fullchain.pem
|
||||
user user@testserver
|
||||
password secretpassword
|
||||
@@ -1,3 +1,4 @@
|
||||
From: user@srv
|
||||
Subject: Prueba desde el test
|
||||
|
||||
Crece desde el test el futuro
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
account default
|
||||
|
||||
host srv
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file config/certs/srv/fullchain.pem
|
||||
|
||||
from user@srv
|
||||
|
||||
auth on
|
||||
user user@srv
|
||||
password password
|
||||
|
||||
account smtpport : default
|
||||
port 1025
|
||||
|
||||
account subm_tls : default
|
||||
port 1465
|
||||
tls_starttls off
|
||||
|
||||
account baduser : default
|
||||
user unknownuser@srv
|
||||
password secretpassword
|
||||
|
||||
account badpasswd : default
|
||||
user user@srv
|
||||
password badsecretpassword
|
||||
|
||||
account naked : default
|
||||
from naked@srv
|
||||
user naked
|
||||
password gun
|
||||
@@ -52,33 +52,33 @@ chasquid -v=2 --logfile=.logs/chasquid.log --config_dir=config &
|
||||
wait_until_ready 1025
|
||||
|
||||
# Send an email as "user@srv" successfully.
|
||||
run_msmtp user@srv < content
|
||||
smtpc user@srv < content
|
||||
wait_for_file .mail/user@srv
|
||||
mail_diff content .mail/user@srv
|
||||
|
||||
# Send an email as "naked" successfully.
|
||||
rm .mail/user@srv
|
||||
run_msmtp -a naked user@srv < content
|
||||
smtpc --user=naked --password=gun --from=naked@srv user@srv < content
|
||||
wait_for_file .mail/user@srv
|
||||
mail_diff content .mail/user@srv
|
||||
|
||||
# Send an email to the "naked" user successfully.
|
||||
run_msmtp naked@srv < content
|
||||
smtpc naked@srv < content
|
||||
wait_for_file .mail/naked@srv
|
||||
mail_diff content .mail/naked@srv
|
||||
|
||||
# Fail to send to nobody@srv (user does not exist).
|
||||
if run_msmtp nobody@srv < content 2> /dev/null; then
|
||||
if smtpc nobody@srv < content 2> /dev/null; then
|
||||
fail "successfully sent an email to a non-existent user"
|
||||
fi
|
||||
|
||||
# Fail to send from baduser@srv (user does not exist).
|
||||
if run_msmtp -a baduser user@srv < content 2> /dev/null; then
|
||||
# Fail to send from unknownuser@srv (user does not exist).
|
||||
if smtpc --user=unknownuser@srv user@srv < content 2> /dev/null; then
|
||||
fail "successfully sent an email with a bad user"
|
||||
fi
|
||||
|
||||
# Fail to send with an incorrect password.
|
||||
if run_msmtp -a badpasswd user@srv < content 2> /dev/null; then
|
||||
if smtpc --password=badpasswd user@srv < content 2> /dev/null; then
|
||||
fail "successfully sent an email with a bad password"
|
||||
fi
|
||||
|
||||
|
||||
4
test/t-11-dovecot/smtpc.conf
Normal file
4
test/t-11-dovecot/smtpc.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
addr localhost:1465
|
||||
server_cert config/certs/srv/fullchain.pem
|
||||
user user@srv
|
||||
password password
|
||||
@@ -1,5 +1,6 @@
|
||||
smtp_address: ":1025"
|
||||
submission_address: ":1587"
|
||||
submission_over_tls_address: ":1465"
|
||||
monitoring_address: ":1099"
|
||||
|
||||
mail_delivery_agent_bin: "test-mda"
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
account default
|
||||
|
||||
host testserver
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file config/certs/testserver/fullchain.pem
|
||||
|
||||
from someone@testserver
|
||||
|
||||
auth on
|
||||
user someone@testserver
|
||||
password password222
|
||||
|
||||
@@ -22,7 +22,7 @@ chasquid -v=2 --logfile=.logs/chasquid.log --config_dir=config \
|
||||
wait_until_ready 1025
|
||||
|
||||
# First, check that delivery fails with the "wrong" password.
|
||||
if run_msmtp someone@testserver < content 2>/dev/null; then
|
||||
if smtpc someone@testserver < content 2>/dev/null; then
|
||||
fail "success using the wrong password"
|
||||
fi
|
||||
|
||||
@@ -32,7 +32,7 @@ chasquid-util-user-add someone@testserver password222
|
||||
echo "analias: someone" > config/domains/testserver/aliases
|
||||
sleep 0.2
|
||||
|
||||
run_msmtp analias@testserver < content
|
||||
smtpc analias@testserver < content
|
||||
wait_for_file .mail/someone@testserver
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ sleep 0.2
|
||||
|
||||
# Send another mail.
|
||||
rm .mail/someone@testserver
|
||||
run_msmtp analias@testserver < content
|
||||
smtpc analias@testserver < content
|
||||
wait_for_file .mail/someone@testserver
|
||||
|
||||
# Check there are new entries.
|
||||
|
||||
4
test/t-13-reload/smtpc.conf
Normal file
4
test/t-13-reload/smtpc.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
addr localhost:1465
|
||||
server_cert config/certs/testserver/fullchain.pem
|
||||
user someone@testserver
|
||||
password password222
|
||||
@@ -1,14 +0,0 @@
|
||||
account default
|
||||
|
||||
host srv-A
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file A/certs/srv-A/fullchain.pem
|
||||
|
||||
from userA@srv-A
|
||||
|
||||
auth on
|
||||
user userA@srv-A
|
||||
password userA
|
||||
|
||||
@@ -45,7 +45,7 @@ wait_until_ready 1025
|
||||
wait_until_ready 2025
|
||||
wait_until_ready 9053
|
||||
|
||||
run_msmtp userB@srv-B < content
|
||||
smtpc userB@srv-B < content
|
||||
|
||||
wait_for_file .mail/userb@srv-b
|
||||
mail_diff content .mail/userb@srv-b
|
||||
|
||||
4
test/t-14-tls_tracking/smtpc.conf
Normal file
4
test/t-14-tls_tracking/smtpc.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
addr localhost:1465
|
||||
server_cert A/certs/srv-A/fullchain.pem
|
||||
user userA@srv-A
|
||||
password userA
|
||||
@@ -1,5 +1,6 @@
|
||||
smtp_address: ":1025"
|
||||
submission_address: ":1587"
|
||||
submission_over_tls_address: ":1465"
|
||||
monitoring_address: ":1099"
|
||||
|
||||
mail_delivery_agent_bin: "test-mda"
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
account default
|
||||
|
||||
host testserver
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file config/certs/testserver/fullchain.pem
|
||||
|
||||
from user@testserver
|
||||
|
||||
auth on
|
||||
user user@testserver
|
||||
password secretpassword
|
||||
|
||||
@@ -23,11 +23,14 @@ add_user someone@testserver secretpassword
|
||||
|
||||
mkdir -p .logs
|
||||
chasquid -v=2 --logfile=.logs/chasquid.log --config_dir=config &
|
||||
wait_until_ready 1025
|
||||
wait_until_ready 1465
|
||||
|
||||
# Authenticated: user@testserver -> someone@testserver
|
||||
# Should be signed.
|
||||
run_msmtp someone@testserver < content
|
||||
smtpc --addr=localhost:1465 \
|
||||
--server_cert=config/certs/testserver/fullchain.pem \
|
||||
--user=user@testserver --password=secretpassword \
|
||||
someone@testserver < content
|
||||
wait_for_file .mail/someone@testserver
|
||||
mail_diff content .mail/someone@testserver
|
||||
grep -q "DKIM-Signature:" .mail/someone@testserver
|
||||
@@ -40,11 +43,14 @@ dkimverify -txt .dkimcerts/dns.txt < .mail/someone@testserver
|
||||
tail -n +2 .mail/someone@testserver > .signed_content
|
||||
|
||||
# Not authenticated: someone@testserver -> someone@testserver
|
||||
smtpc.py --server=localhost:1025 < .signed_content
|
||||
smtpc --addr=localhost:1025 \
|
||||
--from=someone@testserver someone@testserver < .signed_content
|
||||
|
||||
# Check that the signature fails on modified content.
|
||||
echo "Added content, invalid and not signed" >> .signed_content
|
||||
if smtpc.py --server=localhost:1025 < .signed_content 2> /dev/null; then
|
||||
if smtpc --addr=localhost:1025 \
|
||||
--from=someone@testserver someone@testserver < .signed_content \
|
||||
> /dev/null 2>&1 ; then
|
||||
fail "DKIM verification succeeded on modified content"
|
||||
fi
|
||||
|
||||
|
||||
@@ -54,8 +54,6 @@ Received: from localhost
|
||||
tls *
|
||||
(over *
|
||||
; *
|
||||
From: userA@srv-A
|
||||
Date: *
|
||||
Subject: Prueba desde el test
|
||||
|
||||
Crece desde el test el futuro
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
account default
|
||||
|
||||
host srv-A
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file A/certs/srv-A/fullchain.pem
|
||||
|
||||
from userA@srv-A
|
||||
|
||||
auth on
|
||||
user userA@srv-A
|
||||
password userA
|
||||
|
||||
@@ -54,7 +54,7 @@ function launch_minidns() {
|
||||
|
||||
# T0: Successful.
|
||||
launch_minidns zones.t0
|
||||
run_msmtp userB@srv-B < content
|
||||
smtpc userB@srv-B < content
|
||||
wait_for_file .mail/userb@srv-b
|
||||
mail_diff content .mail/userb@srv-b
|
||||
|
||||
@@ -62,7 +62,7 @@ mail_diff content .mail/userb@srv-b
|
||||
# Check that userA got a DSN about it.
|
||||
rm .mail/*
|
||||
launch_minidns zones.t1
|
||||
run_msmtp userB@srv-B < content
|
||||
smtpc userB@srv-B < content
|
||||
wait_for_file .mail/usera@srv-a
|
||||
mail_diff expected_dsn .mail/usera@srv-a
|
||||
|
||||
|
||||
4
test/t-16-spf/smtpc.conf
Normal file
4
test/t-16-spf/smtpc.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
addr localhost:1465
|
||||
server_cert A/certs/srv-A/fullchain.pem
|
||||
user userA@srv-A
|
||||
password userA
|
||||
@@ -1,28 +0,0 @@
|
||||
account default
|
||||
|
||||
host testserver
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file config/certs/testserver/fullchain.pem
|
||||
|
||||
from user@testserver
|
||||
|
||||
auth on
|
||||
user user@testserver
|
||||
password secretpassword
|
||||
|
||||
account smtpport : default
|
||||
port 1025
|
||||
|
||||
account subm_tls : default
|
||||
port 1465
|
||||
tls_starttls off
|
||||
|
||||
account baduser : default
|
||||
user unknownuser@testserver
|
||||
password secretpassword
|
||||
|
||||
account badpasswd : default
|
||||
user user@testserver
|
||||
password badsecretpassword
|
||||
@@ -20,7 +20,7 @@ function send_one() {
|
||||
> .logs/stdout 2> .logs/stderr &
|
||||
wait_until_ready 1025
|
||||
|
||||
run_msmtp someone@testserver < content
|
||||
smtpc someone@testserver < content
|
||||
wait_for_file .mail/someone@testserver
|
||||
mail_diff content .mail/someone@testserver
|
||||
|
||||
|
||||
4
test/t-17-maillog/smtpc.conf
Normal file
4
test/t-17-maillog/smtpc.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
addr localhost:1465
|
||||
server_cert config/certs/testserver/fullchain.pem
|
||||
user user@testserver
|
||||
password secretpassword
|
||||
@@ -1,5 +1,6 @@
|
||||
smtp_address: ":1025"
|
||||
submission_address: ":1587"
|
||||
submission_over_tls_address: ":1465"
|
||||
monitoring_address: ":1099"
|
||||
|
||||
mail_delivery_agent_bin: "test-mda"
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
account default
|
||||
|
||||
host testserver
|
||||
port 1587
|
||||
|
||||
tls on
|
||||
tls_trust_file config/certs/testserver/fullchain.pem
|
||||
|
||||
from user@testserver
|
||||
|
||||
auth on
|
||||
user user@testserver
|
||||
password secretpassword
|
||||
|
||||
@@ -47,7 +47,10 @@ wait_until_ready 1025
|
||||
|
||||
# Authenticated: user@testserver -> someone@testserver
|
||||
# Should be signed.
|
||||
run_msmtp someone@testserver < content
|
||||
smtpc --addr=localhost:1465 \
|
||||
--server_cert=config/certs/testserver/fullchain.pem \
|
||||
--user=user@testserver --password=secretpassword \
|
||||
someone@testserver < content
|
||||
wait_for_file .mail/someone@testserver
|
||||
mail_diff content .mail/someone@testserver
|
||||
if ! grep -q "DKIM-Signature:" .mail/someone@testserver; then
|
||||
@@ -65,11 +68,14 @@ dkimverify -txt .dkimcerts/private.dns < .mail/someone@testserver
|
||||
tail -n +2 .mail/someone@testserver > .signed_content
|
||||
|
||||
# Not authenticated: someone@testserver -> someone@testserver
|
||||
smtpc.py --server=localhost:1025 < .signed_content
|
||||
smtpc --addr=localhost:1025 \
|
||||
--from=someone@testserver someone@testserver < .signed_content
|
||||
|
||||
# Check that the signature fails on modified content.
|
||||
echo "Added content, invalid and not signed" >> .signed_content
|
||||
if smtpc.py --server=localhost:1025 < .signed_content 2> /dev/null; then
|
||||
if smtpc --addr=localhost:1025 \
|
||||
--from=someone@testserver someone@testserver < .signed_content \
|
||||
> /dev/null 2>&1 ; then
|
||||
fail "DKIM verification succeeded on modified content"
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
smtp_address: ":1025"
|
||||
submission_address: ":1587"
|
||||
submission_over_tls_address: ":1465"
|
||||
monitoring_address: ":1099"
|
||||
|
||||
mail_delivery_agent_bin: "test-mda"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
smtp_address: ":2025"
|
||||
submission_address: ":2587"
|
||||
submission_over_tls_address: ":2465"
|
||||
monitoring_address: ":2099"
|
||||
|
||||
mail_delivery_agent_bin: "test-mda"
|
||||
|
||||
@@ -8,8 +8,6 @@ check_hostaliases
|
||||
|
||||
rm -rf .data-A .data-B .mail
|
||||
|
||||
skip_if_python_is_too_old
|
||||
|
||||
# Build with the DNS override, so we can fake DNS records.
|
||||
export GOTAGS="dnsoverride"
|
||||
|
||||
@@ -45,20 +43,24 @@ chasquid -v=2 --logfile=.logs-B/chasquid.log --config_dir=B \
|
||||
--testing__dns_addr=127.0.0.1:9053 \
|
||||
--testing__outgoing_smtp_port=1025 &
|
||||
|
||||
wait_until_ready 1025
|
||||
wait_until_ready 2025
|
||||
wait_until_ready 1465
|
||||
wait_until_ready 2465
|
||||
wait_until_ready 9053
|
||||
|
||||
# Send from A to B.
|
||||
smtpc.py --server=localhost:1025 --user=user-a@srv-a --password=nadaA \
|
||||
< from_A_to_B
|
||||
smtpc --addr=localhost:1465 \
|
||||
--server_cert=A/certs/srv-A/fullchain.pem \
|
||||
--user=user-a@srv-a --password=nadaA \
|
||||
user-b@srv-b < from_A_to_B
|
||||
|
||||
wait_for_file .mail/user-b@srv-b
|
||||
mail_diff from_A_to_B.expected .mail/user-b@srv-b
|
||||
|
||||
# Send from B to A.
|
||||
smtpc.py --server=localhost:2025 --user=user-b@srv-b --password=nadaB \
|
||||
< from_B_to_A
|
||||
smtpc --addr=localhost:2465 \
|
||||
--server_cert=B/certs/srv-B/fullchain.pem \
|
||||
--user=user-b@srv-b --password=nadaB \
|
||||
user-a@srv-a < from_B_to_A
|
||||
|
||||
wait_for_file .mail/user-a@srv-a
|
||||
mail_diff from_B_to_A.expected .mail/user-a@srv-a
|
||||
|
||||
@@ -120,10 +120,6 @@ function run_msmtp() {
|
||||
"${UTILDIR}/.msmtp-bin" -C msmtprc "$@"
|
||||
}
|
||||
|
||||
function smtpc.py() {
|
||||
"${UTILDIR}/smtpc.py" "$@"
|
||||
}
|
||||
|
||||
function mail_diff() {
|
||||
"${UTILDIR}/mail_diff" "$@"
|
||||
}
|
||||
@@ -158,6 +154,11 @@ function fexp() {
|
||||
"${UTILDIR}/fexp/fexp" "$@"
|
||||
}
|
||||
|
||||
function smtpc() {
|
||||
go-build-cached "${UTILDIR}/smtpc/"
|
||||
"${UTILDIR}/smtpc/smtpc" "$@"
|
||||
}
|
||||
|
||||
function timeout() {
|
||||
MYPID=$$
|
||||
(
|
||||
@@ -232,16 +233,6 @@ function generate_certs_for() {
|
||||
cp -p "${CACHEDIR}/$1"/* "${CONFDIR}/certs/$1/"
|
||||
}
|
||||
|
||||
# Check the Python version, and skip if it's too old.
|
||||
# This will check against the version required for smtpc.py.
|
||||
function skip_if_python_is_too_old() {
|
||||
# We need Python >= 3.5 to be able to use SMTPUTF8.
|
||||
check='import sys; sys.exit(0 if sys.version_info >= (3, 5) else 1)'
|
||||
if ! python3 -c "${check}" > /dev/null 2>&1; then
|
||||
skip "python3 >= 3.5 not available"
|
||||
fi
|
||||
}
|
||||
|
||||
function chasquid_ram_peak() {
|
||||
# Find the pid of the daemon, which we expect is running on the
|
||||
# background somewhere within our current session.
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Simple SMTP client for testing purposes.
|
||||
|
||||
import argparse
|
||||
import email.parser
|
||||
import email.policy
|
||||
import re
|
||||
import smtplib
|
||||
import sys
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--server", help="SMTP server to connect to")
|
||||
ap.add_argument("--user", help="Username to use in SMTP AUTH")
|
||||
ap.add_argument("--password", help="Password to use in SMTP AUTH")
|
||||
args = ap.parse_args()
|
||||
|
||||
# Parse the email using the "default" policy, which is not really the default.
|
||||
# If unspecified, compat32 is used, which does not support UTF8.
|
||||
rawmsg = sys.stdin.buffer.read()
|
||||
msg = email.parser.Parser(policy=email.policy.default).parsestr(
|
||||
rawmsg.decode('utf8'))
|
||||
|
||||
s = smtplib.SMTP(args.server)
|
||||
s.starttls()
|
||||
if args.user:
|
||||
s.login(args.user, args.password)
|
||||
|
||||
# Send the raw message, not parsed, because the parser does not handle some
|
||||
# corner cases that well (for example, DKIM-Signature headers get mime-encoded
|
||||
# incorrectly).
|
||||
# Replace \n with \r\n, which is normally done by the library, but will not do
|
||||
# it in this case because we are giving it bytes and not a string (which we
|
||||
# cannot do because it tries to incorrectly escape the headers).
|
||||
crlfmsg = re.sub(br'(?:\r\n|\n|\r(?!\n))', b"\r\n", rawmsg)
|
||||
|
||||
s.sendmail(
|
||||
from_addr=msg['from'], to_addrs=msg.get_all('to'),
|
||||
msg=crlfmsg,
|
||||
mail_options=['SMTPUTF8'])
|
||||
s.quit()
|
||||
|
||||
|
||||
142
test/util/smtpc/smtpc.go
Normal file
142
test/util/smtpc/smtpc.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"flag"
|
||||
"io"
|
||||
"net"
|
||||
"net/smtp"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
addr = flag.String("addr", "", "Address of the SMTP server")
|
||||
|
||||
user = flag.String("user", "", "Username to use in SMTP AUTH")
|
||||
password = flag.String("password", "", "Password to use in SMTP AUTH")
|
||||
|
||||
from = flag.String("from", "", "From address to use in the message")
|
||||
|
||||
serverCert = flag.String("server_cert", "",
|
||||
"Path to the server certificate to expect")
|
||||
|
||||
confPath = flag.String("c", "smtpc.conf",
|
||||
"Path to the configuration file")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
loadConfig()
|
||||
|
||||
// Read message from stdin.
|
||||
rawMsg, err := io.ReadAll(os.Stdin)
|
||||
notnil(err)
|
||||
|
||||
// RCPT TO from the command line.
|
||||
tos := make([]string, len(flag.Args()))
|
||||
for i, to := range flag.Args() {
|
||||
tos[i] = to
|
||||
}
|
||||
|
||||
// Connect to the server.
|
||||
var conn net.Conn
|
||||
if *serverCert != "" {
|
||||
cert := loadCert(*serverCert)
|
||||
rootCAs := x509.NewCertPool()
|
||||
|
||||
rootCAs.AddCert(cert)
|
||||
tlsConfig := &tls.Config{
|
||||
ServerName: cert.DNSNames[0],
|
||||
RootCAs: rootCAs,
|
||||
}
|
||||
|
||||
conn, err = tls.Dial("tcp", *addr, tlsConfig)
|
||||
defer conn.Close()
|
||||
} else {
|
||||
conn, err = net.Dial("tcp", *addr)
|
||||
}
|
||||
notnil(err)
|
||||
|
||||
// Send the message.
|
||||
client, err := smtp.NewClient(conn, *addr)
|
||||
notnil(err)
|
||||
|
||||
if *user != "" {
|
||||
auth := smtp.PlainAuth("", *user, *password, *addr)
|
||||
err = client.Auth(auth)
|
||||
notnil(err)
|
||||
}
|
||||
|
||||
if *from == "" {
|
||||
*from = *user
|
||||
}
|
||||
err = client.Mail(*from)
|
||||
notnil(err)
|
||||
|
||||
for _, to := range tos {
|
||||
err = client.Rcpt(to)
|
||||
notnil(err)
|
||||
}
|
||||
|
||||
w, err := client.Data()
|
||||
notnil(err)
|
||||
_, err = io.Copy(w, bytes.NewReader(rawMsg))
|
||||
notnil(err)
|
||||
err = w.Close()
|
||||
notnil(err)
|
||||
|
||||
err = client.Quit()
|
||||
notnil(err)
|
||||
}
|
||||
|
||||
func loadConfig() {
|
||||
data, err := os.ReadFile(*confPath)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return
|
||||
}
|
||||
notnil(err)
|
||||
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
k, v, ok := strings.Cut(line, " ")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
k = strings.TrimSpace(k)
|
||||
|
||||
// Set the flag but only if it wasn't already set.
|
||||
// Command-line flags take precedence.
|
||||
isSet := false
|
||||
flag.Visit(func(f *flag.Flag) {
|
||||
if f.Name == k {
|
||||
isSet = true
|
||||
}
|
||||
})
|
||||
if !isSet {
|
||||
flag.Lookup(k).Value.Set(strings.TrimSpace(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func loadCert(path string) *x509.Certificate {
|
||||
data, err := os.ReadFile(path)
|
||||
notnil(err)
|
||||
|
||||
block, _ := pem.Decode(data)
|
||||
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
notnil(err)
|
||||
|
||||
return cert
|
||||
}
|
||||
|
||||
func notnil(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user