When we get SIGINT or SIGTERM, today chasquid exits with code 1. This
can confuse some of the supervision tools.
In particular, Docker and Kubernetes expect exit 0 upon an intentional
stop.
And systemd, the Restart= semantics make a difference with 0 and non-0,
and exiting with 1 prevents users from making that distinction.
This patch changes the SIGINT/SIGTERM exit code to 0, to make it easier
for users to set up things as desired in those environments.
Thanks to [Guiorgy@github](https://github.com/Guiorgy) for reporting
this problem in https://github.com/albertito/chasquid/pull/70.
Today, the maximum number of items in the queue, as well as how long we
keep attempting to send each item, is hard-coded and not changed by end
users.
While they are totally adequate for chasquid's main use cases, it can
still be useful for some users to change them.
So this patch adds two new configuration options for those settings.
They're marked experimental for now, so we can adjust them if needed
after they get more exposure.
Thanks to Lewis Ross-Jones <lewis_r_j@hotmail.com> for suggesting this
improvement, and help with testing it.
This patch fixes some minor typos in comments and strings found by
codespell.
While at it, also expand some variable names that were not typos, but
caused false positives, and end up being more readable anyway.
This commit updates the uses of math/rand to math/rand/v2, which was
released in Go 1.22 (2024-02).
The new package is generally safer, see https://go.dev/blog/randv2 for
the details.
There are no user-visible changes, it is only adjusting the name of
functions, simplify some code thanks to v2 having a better API, etc.
This patch makes chasquid log how many users, aliases and DKIM keys were
loaded for each domain.
This makes it easier to confirm changes, and troubleshoot problems
related to these per-domain configuration files.
Today, when starting up, if there's an error reading the users or
aliases files, we only log but do not exit. And then those files will
not be attempted to be read on the periodic reload.
We also treat "file does not exist" as an error for users file, but not
aliases file, resulting in inconsistent behaviour between the two.
All of this makes some classes of problems (like permission errors) more
difficult to spot and troubleshoot. For example,
https://github.com/albertito/chasquid/issues/55.
So this patch makes errors reading users/aliases files on startup a
fatal error, and also unifies the "file does not exist" behaviour to
make it not an error in both cases.
Note that the behaviour on the periodic reload is unchanged: treat these
errors as fatal too. This may be changed in future patches.
This prevents chasquid from attempting to look for certs under a
non-directory, e.g. `/etc/chasquid/domains/.gitignore/certs`.
Amended-by: Alberto Bertogli <albertito@blitiri.com.ar>
Adjusted commit message, applied `go fmt`.
Using an empty listening address will result in chasquid listening on a
random port, which is a dangerous misconfiguration.
That is most likely done to prevent it from listening at all.
To prevent this misconfiguration, explicitly reject empty listening
addresses early and with a warning, so there is no ambiguity.
Users can still prevent chasquid from listening by just commenting out
the entry in the config (and not passing any systemd file descriptors).
See https://github.com/albertito/chasquid/issues/45 for more details and
discussion, including alternatives considered.
Thanks to xavierg who reported this via IRC.
This patch moves the top-level certificate loading logic out of main and
into a separate function.
This is only for readability and consistency with how we handle domains
(which have a similar structure already). There are no logic changes.
When starting up, for each domain we parse aliases and users files (if
they exist).
Today we print a line for each, which gets quite verbose and doesn't
offer much useful information.
This patch adjusts that logic so that we only print errors (unless a
file does not exist, which is a normal case).
This also improves the scenario where chasquid does not have permissions
to access the users file: before this patch, that would fail silently,
but with this patch we show the correct error.
While at it, make the "Loading" messages consistent with each other, for
readability.
Currently, if the `certs/` directory has a symlink inside, we skip it.
That is not really intended, it's an unfortunate side-effect of skipping
regular files.
To fix this, this patch adjusts the logic to only ignore regular files
instead. It also adds a message when a directory is skipped, to make it
easier to debug permission issues.
Thanks to @erjoalgo for reporting this in
https://github.com/albertito/chasquid/pull/39, and providing an
alternative patch!
This patch makes chasquid run a localrpc server, exporting two methods:
alias resolve, and domaininfo clear.
They will be used by chasquid-util in later patches.
It is not expected that the user modifies the domaininfo database behind
chasquid's back, and reloading it can be somewhat expensive.
So this patch removes the periodic reload, and instead makes it triggered
by SIGHUP so the user can trigger a reload manually if needed.
Currently, chasquid gets version information from build-time flags that
have to be passed by the user.
This patch extends this logic so, if no flags are given, Go's build
information will be used to construct a synthetic version string.
Go 1.20 finally includes proper support for instrumenting binaries for
coverage. This allows us to drop quite a few hacks and workarounds that
we used for it, and we can now also test exiting cases.
The downside is that coverage tests now require Go 1.20, but it is an
acceptable price to pay for the more accurate results.
Normal integration tests are unchanged.
This patch updates the coverage testing infrastructure to make use of
the new Go 1.20 features.
ioutil package was deprecated in Go 1.16, replace all uses with their
respective replacements.
This patch was generated with a combination of `gofmt -r`, `eg`, and
manually (for `ioutil.ReadDir`).
If the `drop_characters` or `suffix_separators` options are set to "",
currently instead of the empty string, their default value is used instead.
This is a bug, and it also happens on other config options, but because
the others have to be set in order for chasquid to function, it's not a
problem in practice.
Thanks Björn Busse (bbusse@github) for finding and reporting this
problem, on irc and in https://github.com/albertito/chasquid/issues/25.
This patch fixes the problem by marking these fields explicitly
optional, which enables presence testing, as described in the protobuf
documentation:
https://github.com/protocolbuffers/protobuf/blob/master/docs/field_presence.md.
Currently, chasquid attempts to auto-detect dovecot sockets when
starting up (if needed). If autodetection fails, chasquid emits an
error, continues serving, and never tries again.
This can be problematic if chasquid starts up before dovecot, and at the
time the dovecot sockets are not present (e.g. after a reboot). In that
case, chasquid will not use dovecot for authentication even after
dovecot has started.
This patch changes the autodetect logic, by doing autodetection at
startup and on each request, until we find a working pair of sockets.
Once we do, they're used consistently.
That way, if dovecot is not ready when chasquid starts, it's not a
problem and chasquid will start using dovecot once it becomes available.
Thanks to Thor77 (thor77@thor77.org) for reporting and helping
troubleshoot this issue.
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!
Allows terminating chasquid via the network. Useful to trigger a restart
(if there is an init system to relaunch chasquid) and thus reload certificates.
Amended-by: Alberto Bertogli <albertito@blitiri.com.ar>
Added tests, and adjusted shutdown sequence.
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.
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.
This patch improves the organization of the monitoring index page:
- Include the hostname (both OS and configured) for convenience.
- Round the uptime presentation for readability.
- Add a tiny CSS for consistency with the traces.
- Re-arrange the list of links for readability.
This patch adds support for writing maillog to stdout and stderr, which
can be desirable in certain environments.
Thanks to Denys Vitali <denys@denv.it> who sent an alternative patch for
this functionality.
This makes it possible to manage chasquid logs using logrotate.
Amended-by: Alberto Bertogli <albertito@blitiri.com.ar>
Added tests, minor style and comment changes.
In preparation for supporting log rotation, this patch makes the maillog
package to use blitiri.com.ar/go/log instead of its own writer.
Some of the tests are made more strict, to better test the log format.
Amended-by: Alberto Bertogli <albertito@blitiri.com.ar>
Fixed build, extended commit message, adjusted to the log options
API, and added tests.
This patch allows the configuration values to be overridden from the
command-line, with a new -config_overrides flag.
There is a fairly specific use case for this, when editing the
configuration file is not feasible or convenient (e.g. running an
user-supplied configuration in a managed environment).
Currently, the config package logs errors itself, in addition to
returning them.
That is confusing and results in some duplication of logging.
This patch makes config just return errors, and adjusts the callers
to log them properly.
The SMTP courier, which handles outgoing connections, uses the domain of
the envelope's from as the domain in the HELO/EHLO greeting.
This works fine in practice, but ideally the domain used in the greeting
should match the reverse DNS record. This used to be more relevant but
nowadays it is not really enforced; however, it sometimes comes up in
self checks, and might cause some confusion when troubleshooting.
So this patch makes it use the configured hostname instead, which is
under the users' control and more likely to be compliant. It also
simplifies the code.
The documentation of the hostname configuration option is also updated
to mention this behaviour.
Thanks to Jonas Seydel (thor77) for bringing this up.
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.
The daemon attempts to change to the config directory on startup, for
security and convenience.
We currently don't check if this works, which is not a big deal since it
will just fail later on when it can't find the files. However, it makes
things more awkward to debug, so this patch adds an explicit check.
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.
This commit brings back the experimental MTA-STS (Strict Transport
Security) implementation, removed in commit
7f5bedf4aa.
We will continue development in the "sts" branch, subject to rebase,
until it is ready to be integrated into "next" again.
This patch adds dovecot support to the chasquid daemon, using the
internal dovecot library added in previous patches.
Dovecot support is still considered EXPERIMENTAL and may be reverted, or
changed in backwards-incompatible ways.
The patch also adds the corresponding integration test, which brings up
a dovecot server with a custom configuration, and tests chasquid's
authentication against it. If dovecot is not installed, the test is
skipped.
Currently, chasquid exits if any mode (SMTP/submission/submission+tls)
has no addresses to listen on. This means that chasquid must be given
addresses for all three.
While that's generally the expected configuration, there are cases where
users may not want to have all three.
So this patch replaces that fatal error with a warning, and only makes
chasquid exit if there are no addresses to listen on at all.
This commit removes the experimental MTA-STS (Strict Transport Security)
implementation for now, as it's not up to date with the latest draft.
Development will continue on the "sts" branch, but this way it won't
block releases until it is ready.
Commits reverted:
- cb6500b993
- 0eeb964534
- e66288e4b4
- 216cf47ffa
- d66b06de51
- fe00750e39
- 933ab54cd8
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).
This patch extends the SMTP courier to (optionally) do STS policy
checking when delivering mail.
As STS support is currently experimental, we gate this behind a flag and
is disabled by default.
We only care about directories within the certs/, but the code as-is
complains if there are files.
This patch makes the iteration skip non-directories entirely.
Thanks to Martin Ferrari for the bug report!
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.
The default INFO logs are more oriented towards debugging and can be
a bit too verbose when looking for high-level information.
This patch introduces a new "maillog" package, used to log messages of
particular relevance to mail transmission at a higher level.