285 Commits

Author SHA1 Message Date
Alberto Bertogli
4802e2f3e4 smtpsrv: Check TLS Handshake result
When receiving a message on a TLS socket, we currently don't check the
Handshake result, so connections often fail in a way that is not easy to
troubleshoot.

This patch fixes that by checking the result and emitting a nicer error
message before closing the connection.
2020-04-14 12:01:01 +01:00
Alberto Bertogli
0fd3941cf0 courier: Don't call testing.T.Fatalf from a goroutine
Calling testing.T.Fatalf from a new goroutine is not supported; since
this should be quite exceptional, we just panic instead.
2020-04-14 12:01:01 +01:00
Alberto Bertogli
9fbd1fe786 tlsconst: Update list of ciphers
This patch updates the list of ciphers in tlsconst, using the latest
list from IANA.
2020-04-12 11:25:27 +01:00
Alberto Bertogli
29512f7e4f testlib: Add tests for testlib.WaitFor 2020-03-21 23:56:31 +00:00
Alberto Bertogli
fdae72f275 testlib: Add comments and unexport unnecessary structs
This patch contains some readability improvements to testlib: it
adds/reformats some comments for exported functions for consistency, and
unexports some structs that are not used outside the library.
2020-03-21 23:32:28 +00:00
Alberto Bertogli
44140220b9 test: Improve DATA handling in the smtpsrv fuzzer
The smtpsrv fuzzer doesn't handle DATA commands particularly well:
it will continue to read but will skip lines that have STARTTLS as
content, and only really care for the first line due to a bug.

This patch fixes the handling, and moves the logic to a separate
function for readability.
2020-03-21 23:27:19 +00:00
Alberto Bertogli
c8fbf2ecc9 smtpsrv: Don't consider client EOF an error
When the client closes the connection, which is very common, chasquid
logs it as an error ("exiting with error: EOF").

That can be confusing and mislead users, and also makes a lot of
traces be marked as errored, when nothing wrong occurred.

So this patch changes the log to not treat it as an error.
2020-03-21 16:58:56 +00:00
Alberto Bertogli
8fab350b59 courier: DNS temporary errors should cause temporary delivery failures
In the SMTP courier, when the MX lookup fails with a DNS temporary
error, we should propagate that up and cause delivery to fail with a
temporary error too.

That way the delivery can be attempted later by the queue.

However, the code today doesn't make the distinction and will treat any
temporary DNS error as a permanent delivery failure, which is a bug.

The bug was found by ludusrusso and reported in
https://github.com/albertito/chasquid/issues/4

This patch fixes the bug by propagating the error properly.
2020-03-12 22:07:22 +00:00
Alberto Bertogli
6641d858ad courier: Extend TODO for DNS error handling on Go >= 1.13
In https://github.com/albertito/chasquid/issues/4, ludusrusso comments
that the DNS lookup error handling in the SMTP courier could be improved
by using DNSError.IsNotFound.

That is true, but unfortunately it was only added in Go 1.13, and we are
currently trying to support Go 1.11 since that's what in Debian stable.

So this patch updates the TODO to note this, so that when we can use a
newer Go version, we improve this code.
2020-03-12 22:07:11 +00:00
Alberto Bertogli
4edcd79a25 smtpsrv: Keep reading DATA input even if it's too large
When the DATA input is too large, we should keep on reading through it
until we reach the end marker, otherwise there is a security problem:
the remaining data will be interpreted as SMTP commands, so for example
a forwarded message that is too long might end up executing SMTP
commands under an authenticated user.

This patch implements this behaviour, while being careful not to consume
extra memory to avoid opening up the possibility of a DoS.

Note the equivalent logic for single long lines is already implemented.
2019-12-04 01:46:54 +00:00
Alberto Bertogli
a12875162f smtpsrv: Test too many recipients
This patch adds a test to make sure we don't allow too many recipients.
2019-12-01 19:37:47 +00:00
Alberto Bertogli
99c4ad5ef7 smtpsrv: Disable reloads during tests
Reloading during tests will cause the testing aliases to be removed,
which makes test runs that extend beyond 30s to be flaky.

This patch fixes the bug by disabling reloads during these tests.
2019-12-01 19:09:58 +00:00
Alberto Bertogli
e8a6bf6188 smtpsrv: Make tests log maillog to stdout 2019-12-01 19:09:57 +00:00
Alberto Bertogli
a6a964ac3e test: Move testing couriers to testlib
The testing couriers are currently only used in the queue tests, but we
also want to use them in smtpsrv tests so we can make them more robusts
by checking the emails got delivered.

This patch moves the testing couriers to testlib, and makes both queue
and smtpsrv use them.
2019-12-01 19:09:12 +00:00
Alberto Bertogli
99df5e7b57 smtpsrv: Limit incoming line length and improve large message handling
Currently, there is no limit to incoming line length, so an evil client
could cause a memory exhaustion DoS by issuing very long lines.

This patch fixes the bug by limiting the size of the lines.

To do that, we replace the textproto.Conn with a pair of buffered reader
and writer, which simplify the code and allow for better and cleaner
control.

Thanks to Max Mazurov (fox.cpp@disroot.org) for finding and reporting
this issue.
2019-12-01 19:07:58 +00:00
Alberto Bertogli
d7006d0e16 smtp: Limit incoming line length
On the smtp client package, there is no limit to the length of the
server's replies, so an evil server could cause a memory exhaustion DoS
by issuing very long lines.

This patch fixes the bug by limiting the total size of received data.
Ideally this would be done per-line instead, but gets much more complex,
so this is a compromise.

The limit chosen is 2 MiB, which should be plenty for any the total size
of server-side replies, considering we only send a single message per
connection anyway.

This is similar to 06d808c (smtpsrv: Limit incoming line length), which
was found and reported by Max Mazurov (fox.cpp@disroot.org).
2019-12-01 17:25:25 +00:00
Alberto Bertogli
34339c4572 smtpsrv: Add fuzz testing
This patch adds a fuzz test for the smtpsrv package.

It brings up a server for test, and then fuzz the data sent over the
network.
2019-11-30 11:38:46 +00:00
Alberto Bertogli
933b979220 smtpsrv: Don't hard-code ports in tests
The smtpsrv tests hard-code ports, but this patch fixes that by making it
use the new testlib.GetFreePort function.
2019-11-30 11:38:46 +00:00
Alberto Bertogli
d0f65881c9 smtpsrv: Allow manual override of submission+TLS port in tests
The smtpsrv server tests allow manual override of testing ports via
flags, but the submission+TLS port was missing (accidental oversight).
2019-11-30 11:38:46 +00:00
Alberto Bertogli
ac2c5ab4db test: Add testlib.GetFreePort function
Some tests require picking ports, and today resort to hard-coding,
which is brittle.

This patch adds a testlib.GetFreePort function to help pick free ports.

It is not totally race-free, but is much better than hard-coding.
2019-11-30 11:38:46 +00:00
Alberto Bertogli
a47faf89a4 smtpsrv: Failures to enqueue are transient, not permanent
If we fail to put the message in the queue (e.g. because we're out of
storage space, or the aliases-resolve hook errored out), it should be
considered a transient failure.

Currently we return a permanent error, which is misleading, as we want
clients to retry in these situations.

So this patch changes the error returned accordingly.
2019-10-24 21:37:09 +01:00
Alberto Bertogli
0718749314 Update auto-generated code
This patch updates the auto-generated code to match the latest tooling
versions.

In particular, the protobufs are regenerated, and the new version no
longer supports unkeyed literals, so some minor changes are needed.

Other than that, the cipher list is extended with the latest ciphers.
2019-10-24 21:37:09 +01:00
Alberto Bertogli
f399fe3e84 aliases: Implement aliases hooks
This patch implements two new hooks: alias-resolve and alias-exists.

They are called during the aliases resolution process, to allow for more
complex integration with other systems, such as storing the aliases in a
database.

See the included documentation for more details.
2019-10-24 21:37:09 +01:00
Alberto Bertogli
dea6f73164 aliases: Treat empty pipe aliases as bad lines and skip them
A pipe alias must have a command, if it doesn't, we should treat the
line as bad and skip it like we do for others.
2019-10-22 22:14:26 +01:00
Alberto Bertogli
5f72f723db smtpsrv: Clean up post-data hook tracing output
This patch does some cleanups on the tracing output for the post-data
hook, to quote the output better and more consistently.
2019-10-22 21:45:54 +01:00
Alberto Bertogli
bb97991a24 docs: Add aliases documentation
The processing of aliases wasn't properly documented in an user-visible
way, so this patch adds a new section for it.
2019-10-19 00:45:18 +01:00
Alberto Bertogli
41d960590d smtpsrv: Use spf.CheckHostWithSender
The spf library has gained support for macros, but to process them
properly, a new function needs to be called with the full sender
address, spf.CheckHostWithSender.

This patch updates chasquid's calls to the new API.
2019-10-14 19:37:14 +01:00
Alberto Bertogli
3584441549 test: Use testlib.RemoveIfOk where appropriate
Some tests did not make use of testlib.RemoveIfOk, which resulted in
some duplication; this patch fixes that.

While at it, userdb tests have its own simpler variant, so add some
safety checks to it.
2019-09-10 01:09:44 +01:00
Alberto Bertogli
f63e5bf0b2 sts: Reject policies with max_age > 1y, as per RFC
The MTA-STS standard explicitly says the maximum max_age is 1 year.

This patch adds a check to the STS library to enforce this. Policies
with max_age > 1y will be treated as invalid.

See this email thread for some discussion on the topic:
https://mailarchive.ietf.org/arch/msg/uta/bnUjy9jxM_Va-lDXVtbB32zIkYI
2019-08-31 01:14:56 +01:00
Alberto Bertogli
25624b406d docs: Document submission_over_tls_address option
The submission_over_tls_address configuration option has existed for a
long time, but was not properly documented.

This patch adds it to the manpage, as well as printing it in the
configuration output on startup.
2019-07-15 01:58:55 +01:00
Alberto Bertogli
d6bbea391f maillog: Test that we log to the system logger on write errors
The maillog package will write to the system logger if it can't write to
the mail log. It does this only once to avoid spamming the system logger
on misconfigurations.

This patch adds a test for this condition.
2019-07-13 14:45:59 +01:00
Alberto Bertogli
d53d97aba0 dovecot: Test autodetection works with closed sockets
We want to test that autodetection works with closed sockets, as we
explicitly support that scenario: chasquid might be up before dovecot
is, and we still want the detection to work.

The code is written that way, but we had no tests for it until now,
because we were blocked on the unix listeners supporting
SetUnlinkOnClose, which appeared in Go 1.8.

Now that the minimum Go version has been raised past that, we can
implement the test.
2019-07-13 14:06:13 +01:00
Alberto Bertogli
9821a17d6c sts: Use expvar.Int.Value in tests
Now that we raised the minimum Go version to 1.9, we can make use of
expvar's .Value methods to simplify some of the STS tests.

This patch makes those simplifications, which do not change the logic of
the tests themselves.
2019-07-13 13:52:28 +01:00
Alberto Bertogli
2943f994e7 Use context.WithTimeout instead of context.WithDeadline
There are a few context.WithDeadline calls that can be simplified by
using context.WithTimeout.

At the time they were added, WithTimeout was too new so we didn't want
to depend on it. But now that the minimum Go version has been raised to
1.9, we can simplify the calls.

This patch does that simplification, which is purely mechanical, and
does not change the logic itself.
2019-07-13 13:44:25 +01:00
Alberto Bertogli
a5edd9053f queue: Make DSN tidier, especially in handling multi-line errors
This patch contains some changes to generate tidier DSNs, which should
make them slightly more readable.

In particular, it also makes it able to handle multi-line errors much
better than before.
2019-05-04 21:28:07 +01:00
Alberto Bertogli
cac1e161ac smtpsrv: Set connection deadline before the initial greeting
When handling a connection, today we only set a deadline after each
command received.

However, this does not cover our initial greeting, or the initial TLS
handshake (if the socket is TLS), so a connection can hang
indefininitely at that stage.

This patch fixes that by setting a deadline earlier, before we send or
receive anythong on the connection.
2019-03-31 12:13:09 +01:00
Alberto Bertogli
ec95131bb4 Miscellaneous style fixes
This patch has some miscellaneous style fixes to issues found by the
staticcheck tool.

There are no functional changes.
2019-02-10 12:46:15 +00:00
Alberto Bertogli
1ecc957aba queue: Internationalized Delivery Status Notifications (DSN)
Our non-delivery status notifications are quite simple today, but that
makes it much more difficult to support internationalization and
cross-language reporting.

There is a standard for internationalized DSNs, RFC 6533 (which builds
on top of the structured DSNs from RFC 3464).

This patch changes our DSN messages to be based on those standards, so
it is easier for MUAs to display reports according to the users'
languages preferences.

Note we still use message/rfc822 + 8bit to transmit the message, instead
of message/global, for compatibility reasons. This seems to be more
universally compatible, but the decision might be revisited in the
future. See RFC 5335 (section 4.6 in particular).
2019-01-18 23:27:10 +00:00
Alberto Bertogli
e7309a2c7b smtpsrv: Send enhanced status codes
SMTP supports enhanced status codes, which help with
internationalization and accessibility in cases where protocol errors
make their way to the users.

This patch makes chasquid include these extended status codes in the
corresponding replies, as well as advertising support in the EHLO reply.

Main references:
- RFC 3463 (https://tools.ietf.org/html/rfc3463)
- RFC 2034 (https://tools.ietf.org/html/rfc2034)
- SMTP Enhanced Status Codes Registry
  (https://www.iana.org/assignments/smtp-enhanced-status-codes/smtp-enhanced-status-codes.xhtml)
2019-01-10 15:44:25 +00:00
Alberto Bertogli
4db9ffec09 Code style improvements
This patch contains some minor code style improvements, to leave the
linter happier and generally follow best practices in some areas where
things snuck through.
2018-12-01 11:58:50 +00:00
Alberto Bertogli
4296e28074 test: Fix flaky courier test
In the upcoming Go release, logging from a finished testing.T triggers a
panic.  In the courier tests, this is possible because we don't wait for
completion of fakeServer before ending the test.

This patch makes the tests wait for fakeServer to finish before exiting,
removing the race.
2018-11-30 10:03:48 +00:00
Alberto Bertogli
29709a0d58 smtpsrv: Improve "Received" header standard compliance
Despite its loose appearance, the "Received" header has a reasonably
standarized format.

We were not following the standard format as closely as we should; this
rarely causes problems in this particular case, but there's no need to
deviate from it.

This patch changes the Received header generation as follows:

 - The "from" section now uses the remote address as canonical (for
   non-authenticated users) which provides more valuable information
   than the user-supplied EHLO address (which is also included).
 - The remote authenticated user is now hidden, for additional privacy.
 - Use the "with" optional clause.
 - Use the standard way of printing TLS cipher suite.
 - Use the standard way of printing address literals.
2018-11-30 10:03:48 +00:00
Alberto Bertogli
328008061d tlsconst: Update TLS cipher suites, and include TLS 1.3
This patch updates the list of known TLS cipher suites, and adds TLS 1.3
to the list of known versions (it will be included in Go 1.12).
2018-11-30 10:03:48 +00:00
Alberto Bertogli
2dfed059e4 MTA-STS is now RFC 8461
MTA-STS has been published as RFC 8461, with no major changes since the
last draft we updated (-18).

This patch updates the documentation accordingly (no code changes).
2018-09-26 21:42:50 +01:00
Alberto Bertogli
644cd63eff sts: Use keyed fields in io.LimitedReader literal
Flagged by go vet:
internal/sts/sts.go:256: io.LimitedReader composite literal uses unkeyed fields
2018-07-14 10:23:36 +01:00
Alberto Bertogli
ccb9ba47d2 smtp: Remove --experimental__enable_sts flag
This patch removes the --experimental__enable_sts flag, making STS
checking the default.
2018-07-14 10:08:27 +01:00
Alberto Bertogli
0ee7cb4cce sts: Add documentation and fix minor style issues
This patch adds some missing function documentation entries, and fixes
minor style issues caught by the linter.

No functional changes.
2018-07-14 10:08:27 +01:00
Alberto Bertogli
46bce576e8 sts: Add miscellaneous tests
This patch adds a few miscellaneous tests to the sts package, covering
various previously-untested code paths.
2018-07-14 10:08:09 +01:00
Alberto Bertogli
79a8cfc21c sts: DNS TXT record support
This patch adds support for checking the MTA-STS TXT record before
fetching the policy via https.

The content of the record is unused.
2018-07-01 12:19:02 +01:00
Alberto Bertogli
8bf584bd86 sts: Don't pre-filter MX list, but skip them if needed
Instead of pre-filtering the MX list based on STS policy, just check
if it's allowed before each attempt, and skip it if not.

This simplifies the code.
2018-07-01 12:19:02 +01:00