1
0
mirror of https://blitiri.com.ar/repos/chasquid synced 2025-12-17 14:37:02 +00:00
Commit Graph

58 Commits

Author SHA1 Message Date
Alberto Bertogli
8c8e64dc29 smtpsrv: Reject HTTP commands
To help with defense-in-depth on cross-protocol attacks (e.g.
https://alpaca-attack.com/), this patch makes chasquid reject HTTP
commands.
2021-06-11 10:35:51 +01:00
Alberto Bertogli
85305f4bd9 smtpsrv: Close the connection after 3 errors (lowering from 10)
Today, we close the connection after 10 errors. While this is fine for
normal use, it is unnecessarily large.

Lowering it to 3 helps with defense-in-depth for cross-protocol attacks
(e.g. https://alpaca-attack.com/), while still being large enough for
useful troubleshooting and normal operation.

As part of this change, we also remove the AUTH-specific failures limit,
because they're covered by the connection limit.
2021-06-11 10:34:20 +01:00
Alberto Bertogli
44eb0b903a smtpsrv: Quote unknown commands for debugging
When we receive unknown commands, we use the first 6 bytes for
troubleshooting (e.g. put them in traces and exported metrics).

While this is safe, since the different places know how to quote them
properly, it makes things more difficult to analyse, since it's not
uncommon to see be binary blobs.

This patch makes us use the ascii-quoted version instead, to make things
easier to analyze.
2021-06-11 10:34:20 +01:00
Alberto Bertogli
d3396ace0b smtpsrv: Return a temporary error when we fail to check if a user exists
When we fail to check if a user exists, we currently return a permanent
error, which can be misleading and also make things more difficult to
troubleshoot.

This patch makes chasquid return a temporary error in that case.

Thanks to Thor77 (thor77@thor77.org) for suggesting this change.
2021-05-30 00:39:24 +01:00
Alberto Bertogli
e79586a014 Implement HAProxy protocol support
This patch implements support for incoming connections wrapped in the
HAProxy protocol v1.

This is useful when running chasquid behind a HAProxy server, as it
needs the original source IP to perform SPF checks.

This patch is a reimplementation of one originally provided by Denys
Vitali in pull request #15, except the logic for the protocol handling
is moved to a new package, and the smtpsrv.Conn handling of the source
IP is simplified.

It is marked as experimental for now, since we want to give it a bit
more exposure just in case the option/api needs adjustment.

Thanks a lot to Denys Vitali (@denysvitali in github) for sending the
original patch for this, and helping test it!
2020-11-13 20:49:42 +00:00
Alberto Bertogli
025cb2d96a courier: Rename Procmail to MDA
This patch renames courier.Procmail to courier.MDA, to make it more
obvious that the functionality is not tied to that particular MDA.

It's just for readability, there are no functional changes.
2020-09-17 02:47:42 +01:00
Alberto Bertogli
1cc7b9a864 smtpsrv: Pass EHLO/HELO domain to the post-data hook
Some utilities might want to access the EHLO/HELO domain in the
post-data hook (for example, to do additional SPF validations).

This patch implements that support, including sanitizing the EHLO domain
on the environment variable to reduce the risk of problems.
2020-09-17 01:29:49 +01:00
Alberto Bertogli
5bebb00af9 smtpsrv: Rename internal variable ehloAddress -> ehloDomain
The EHLO parameter is generally referred to as "domain", even though it
can take either a domain or an address.

For clarity, rename the variable and comments to match.

This is stylistic only, there are no functional changes.
2020-09-17 01:29:49 +01:00
Alberto Bertogli
7fe42a368a monitoring: Add OpenMetrics exporter
This patch makes chasquid's monitoring server expose an OpenMetrics
metrics endpoint.

It adds a new package "expvarom" which implements an HTTP handler that
exports expvar variables in the OpenMetrics text format.

Then, the handler is registered by the monitoring server at /metrics
(where most things expect it to be).

The existing exported variables are also extended with descriptions,
which is optional, but improves the readability of the metrics.
2020-08-21 12:07:33 +01:00
Alberto Bertogli
d83c1dc591 smtpsrv: Fix error code on transient authentication issues
When we can't authenticate due to a transient issue, for example if we
rely on Dovecot and it is not responding, we should use a differentiated
error code to avoid confusing users.

However, today we return the same error code as when the user enters the
wrong password, which could confuse users as their MUA might think their
credentials are no longer valid.

This patch fixes the issue by returning a differentiated error code in
that case, as per RFC 4954.

Thanks to Max Mazurov (fox.cpp@disroot.org) for reporting this problem.
2020-05-23 01:05:12 +01:00
Alberto Bertogli
7fa564f822 smtpsrv: Add comment on BuildNameToCertificate being deprecated
tls.Config.BuildNameToCertificate was deprecated in Go 1.14, and is no
longer necessary.

However, we support down to 1.11, so we will keep it for now.

This patch adds a TODO to remove it in the future once the minimum
supported version is 1.14; and adjust the CI linter accordingly.
2020-05-13 23:42:37 +01:00
Alberto Bertogli
7b0703eaa0 queue: Check that we can create the queue directory
When creating a new Queue instance, we os.MkdirAll the queue directory.

Currently we don't check if it fails, which will cause us to find out
about problems when the queue is first used, where it is more annoying
to troubleshoot.

This patch adjusts the code so that we check and propagate the error.
That way, problems with the queue directory will be more evident and
easier to handle.
2020-04-14 12:01:01 +01:00
Alberto Bertogli
25ebc4f2e2 Avoid unnecessary calls to fmt.Sprintf
The linter caught some unnecessary calls to fmt.Sprintf. This patch
removes them.

There are no functional changes.
2020-04-14 12:01:01 +01:00
Alberto Bertogli
d6b512166b Make it explicit when we are intentionally not checking errors
The linter complains that we're not checking for errors, but on some
cases it's on code paths were it is reasonable to do so (e.g. we're
closing the connection and it's a best-effort write).

This patch adjusts the code to make those cases explicit.
2020-04-14 12:01:01 +01:00
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
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
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
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
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
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
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
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
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
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
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
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
a177fec7c3 domaininfo: Reload periodically
This patch makes chasquid reload domaininfo periodically, so it notices
any external changes made to it.

It is in line with what we do for aliases and authentication already,
and makes it possible for external removals an additions to the
domaininfo database to be picked up without a restart.
2018-05-20 13:18:17 +01:00
Alberto Bertogli
f3b01cb493 docs: Add missing docstrings, adjust wording to match standard style
This patch adds a missing docstrings for exported identifiers, and
adjust some of the existing ones to match the standard style.

In some cases, the identifiers were un-exported after noticing they had
no external users.

Besides improving documentation, it also reduces the linter noise
significantly.
2018-03-04 16:00:06 +00:00
Alberto Bertogli
751fbd4b55 test: Integration test for reload
This patch implements an integration test for reloading; in particular
it exercises reloading aliases and user databases.
2018-03-02 19:37:37 +00:00
Alberto Bertogli
d4992ef8c5 auth: Implement an Authenticator type
This patch implements an Authenticator type, which connections use to
do authentication and user existence checks.

It simplifies the abstractions (the server doesn't need to know about
userdb, or keep track of domain-userdb maps), and lays the foundation
for other types of authentication backends which will come in later
patches.
2018-02-10 22:24:39 +00:00
Alberto Bertogli
033a5d657b Use the external log, spf and systemd packages
The log, spf and systemd packages have been externalized; use them
instead of the internal version to avoid having two versions of the same
thing.
2017-09-17 22:17:14 +01:00
Alberto Bertogli
72477c0cfd smtpsrv: Get TLS information for direct connections
For direct TLS connections, such as submission-over-TLS, we currently
don't get the TLS information so it appears in the headers as "plain
text", which is misleading.

This patch fixes the problem by getting the connection information
early. Note it explicitly triggers the handshake, which would otherwise
happen transparently on the first read/write, so we can use the hostname
(if any) in our hello message.
2017-09-10 11:20:57 +01:00
Alberto Bertogli
9864f40f3b test: Tidy up creation and removal of test directories
We have many places in our tests where we create temporary directories,
which we later remove (most of the time). We have at least 3 helpers to
do this, and various places where it's done ad-hoc (and the cleanup is
not always present).

To try to reduce the clutter, and make the tests more uniform and
readable, this patch introduces two helpers in a new "testutil" package:
one for creating and one for removing temporary directories.

These new functions are safer, better tested, and make the tests more
consistent.  All the tests are updated to use them.
2017-07-14 02:02:43 +01:00
Alberto Bertogli
213bc63a95 Support submission (directly) over TLS (submissions/smtps/port 465)
This patch adds support for TLS-wrapped submission connections.

Instead of clients establishing a connection over plain text and then
using STARTTLS to switch over a TLS connection, this new mode allows the
clients to connect directly over TLS, like it's done in HTTPS.

This is not an official standard yet, but it's reasonably common in
practice, and provides some advantages over the traditional submission
port.

The default port is 465, commonly used for this; chasquid defaults to
systemd file descriptor passing as for the other protocols (for now).
2017-04-10 19:59:04 +01:00
Alberto Bertogli
75cc038e68 smtpsrv: Fail to listen if there are no certificates configured
The server is written assuming there's at least one valid SSL/TLS
certificate. For example, it unconditionally advertises STARTTLS, and
only supports AUTH over TLS.

This patch makes the server fail to listen if there are no certificates
configured, so the users don't accidentally run an unsupported
configuration.
2016-11-24 10:09:11 +00:00
Alberto Bertogli
de09923933 smtpsrv: Disable SPF lookups in tests
When testing, we don't want the server to do SPF lookups, as those cause
real DNS queries which can be problematic and add a dependency on the
environment.

This patch adds an internal boolean to disable the SPF lookups, which is
only set from the tests.
2016-11-22 22:05:07 +00:00
Alberto Bertogli
f7cdbae8e3 Fix minor typos and formatting directives
This small patch fixes a typo in a comment, and a missing formatting
directive; both were caught by static analysis tools (misspell and go
vet).
2016-11-20 18:32:26 +00:00
Alberto Bertogli
fea808f8e3 queue: Get the DSN domain from the message
Picking the domain used in the DSN message "From" header is more
complicated than it needs to be, causing confusing code paths and having
different uses for the hostname, which should be purely aesthetic.

This patch makes the queue pick the DSN "From" domain from the message
itself, by looking for a local domain in either the sender or the
original recipients. We should find at least one, otherwise it'd be
relaying.

This allows the code to be simplified, and we can narrow the scope of
the hostname option even further.
2016-11-03 00:51:59 +00:00
Alberto Bertogli
54cce0c2bf test: Reduce the loop detection threshold from 50 down to 5
The loop test can be quite slow, specially on computers without
cryptography-friendly instructions.

This patch introduces a new flag for testing, so that we can bring the
threshold down to 5. The test is just as useful but now runs in a few
seconds, as opposed to a few minutes.
2016-11-01 23:56:04 +00:00
Alberto Bertogli
60a7932bd3 log: Replace glog with a new logging module
glog works fine and has great features, but it does not play along well
with systemd or standard log rotators (as it does the rotation itself).

So this patch replaces glog with a new logging module "log", which by
default logs to stderr, in a systemd-friendly manner.

Logging to files or syslog is still supported.
2016-11-01 23:56:04 +00:00
Alberto Bertogli
6640c09b9e smtpsrv: Always pass the environment variables to the hook
This patch makes the hooks always have a complete set of environment
varuables, set to 0/1 or whatever is appropriate, to make it easier to
write the checks for them.
2016-10-22 18:55:09 +01:00