author | Alberto Bertogli
<albertito@blitiri.com.ar> 2016-10-27 00:46:05 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2016-11-03 00:51:59 UTC |
parent | bcea74ca81fbfd1454c6eefc53ccaf41262539e6 |
README.md | +161 | -0 |
docs/flow.md | +48 | -0 |
docs/hooks.md | +45 | -0 |
diff --git a/README.md b/README.md new file mode 100644 index 0000000..869e00d --- /dev/null +++ b/README.md @@ -0,0 +1,161 @@ + +# chasquid + +[chasquid](https://blitiri.com.ar/p/chasquid) is an SMTP (email) server. + +It aims to be easy to configure and maintain for a small mail server, at the +expense of flexibility and functionality. + +It's written in [Go](https://golang.org). + + +## Features + +* Easy to configure, hard to mis-configure in ways that are harmful or + insecure (e.g. no open relay, clear-text authentication, etc.). +* Tracking of per-domain TLS support, prevents connection downgrading. +* SMTP UTF8 (international usernames). +* IDNA (international domain names). +* Hooks for easy integration with greylisting, anti-virus and anti-spam. +* Multiple domains, with per-domain user database and aliases. +* Multiple TLS certificates. +* Suffix dropping (user+something@domain -> user@domain). +* Easy integration with letsencrypt. +* SPF checking. +* Monitoring HTTP server, with exported variables and tracing to help + debugging. + + +The following are intentionally *not* implemented: + +* Custom email routing and transport. +* DKIM/DMARC checking (although the post-data hook can be used for it). +* Different backends for domain and user configuration (Dovecot authentication + may be implemented in the future). + + +## Status + +chasquid is in beta. + +It's functional and has had some production exposure, but some things may +still change in backwards-incompatible way, including the configuration format. +It should be rare and will be avoided if possible. + +You should subscribe to the mailing list to get notifications of such changes. + + +## Contact + +If you have any questions, comments or patches please send them to the mailing +list, chasquid@googlegroups.com. + +To subscribe, send an email to chasquid+subscribe@googlegroups.com. + +You can also browse the +[archives](https://groups.google.com/forum/#!forum/chasquid). + + + +## Installation + +To get the code and build it, you will need a working [Go](http://golang.org) +environment. + +```shell +# Get the code and build the binaries. +go get blitiri.com.ar/go/chasquid +cd "$GOPATH/src/blitiri.com.ar/go/chasquid" +make + +# Install the binaries to /usr/local/bin. +sudo make install-binaries + +# Copy the example configuration to /etc/chasquid and /etc/systemd, and create +# the /var/lib/chasquid directory. +sudo make install-config-skeleton +``` + +## Configuration + +The configuration is in `/etc/chasquid/` by default, and has the following +structure: + +``` +- chasquid.conf Main config file. + +- domains/ Domains' data. + - example.com/ + - users User and password database for the domain. + - aliases Aliases for the domain. + ... + +- certs/ Certificates to use, one dir per pair. + - mx.example.com/ + - fullchain.pem Certificate (full chain). + - privkey.pem Private key. + ... +``` + +Note the certs/ directory matches certbot's structure, so if you use it you +can just symlink to /etc/letsencrypt/live. + +Make sure the user you use to run chasquid under ("mail" in the example +config) can access the certificates and private keys. + + +### Adding users + +You can add users with: + +``` +chasquid-util user-add user@domain +``` + +This will also create the corresponding domain directory if it doesn't exist. + + +### Checking your configuration + +Run `chasquid-util print-config` to parse your configuration and display the +resulting values. + + +### Checking your setup + +Run `smtp-check yourdomain.com`, it will check: + +* MX DNS records. +* SPF DNS records (will just warn if not present). +* TLS certificates. + +It needs to access port 25, which is often blocked by ISPs, so it's likely +that you need to run it from your server. + + +### Greylisting, anti-spam and anti-virus + +chasquid supports running a post-DATA hook, which can be used to perform +greylisting, and run anti-spam and anti-virus filters. + +The hook should be at `/etc/chasquid/hooks/post-data`. + + +The one installed by default is a bash script supporting: + +* greylisting using greylistd. +* anti-spam using spamassassin. +* anti-virus using clamav. + +To use them, they just need to be available in your system. + +For example, in Debian you can run the following to install all three: + + apt install greylistd spamc clamdscan + usermod -a -G greylist mail + + +Note that the default hook may not work in all cases, it is provided as a +practical example but you should adjust it to your particular system if +needed. + diff --git a/docs/flow.md b/docs/flow.md new file mode 100644 index 0000000..f3d2e98 --- /dev/null +++ b/docs/flow.md @@ -0,0 +1,48 @@ + +# Message flows + +This document explains at a high level some parts of chasquid's message +processing, in particular how messages flow through the system. + + +## Message reception + +- Client connects to chasquid on the smtp or submission ports, and issues + HELO/EHLO. +- Client optionally performs STARTTLS. +- Client optionally performs AUTH. + - Check that this is done over TLS. +- Client sends MAIL FROM. + - Check SPF. + - Check connection security level. +- Client sends one or more RCPT TO. + - If the destination is remote, then the user must have authenticated. + - If the destination is local, check that the user exists. +- Client sends DATA. +- Client sends actual data, and ends it with '.' + - Run the post-data hook. If the hook fails, return an error. + - Parse the data contents to perform loop detection. + - Add the required headers (Received, SPF results, post-data hook output). + - Put it in the queue and reply success. + + +## Queue processing + +Before accepting a message: + +- Create a (pseudo) random internal ID for it. +- For each recipient, use the alias database to expand it, add the results to + the list of final recipients (which may not be email). +- Save the resulting envelope (with the final recipients) to disk. + +Queue processing runs asynchronously, there's a goroutine for each message +which does, in a loop: + +- For each recipient which we have not delivered yet: + - Attempt delivery. + - Write to disk the results. +- If there are mails still pending, wait for some time (incrementally). +- When all the recipients have completed delivery, or enough time has passed: + - If all were successful, remove from the queue. + - If some failed, send a delivery status notification back to the sender. + diff --git a/docs/hooks.md b/docs/hooks.md new file mode 100644 index 0000000..d84442b --- /dev/null +++ b/docs/hooks.md @@ -0,0 +1,45 @@ + +# Post-DATA hook + +After completion of DATA, but before accepting the mail for queueing, chasquid +will run the command at `$config_dir/hooks/post-data`. + +The contents of the mail will be written to the command's stdin, and the +environment is detailed below. + +If the exit status is 0, chasquid will move forward processing the command, +and its stdout should contain headers which will be added to contents of +the email (at the top). + +Otherwise, chasquid will respond with an error, and the last line of stdout +will be passed back to the client as the error message. +If the exit status is 20 the error code will be permanent, otherwise it will +be temporary. + + +This hook can be used to block based on contents, for example to check for +spam or virus. See `etc/hooks/post-data` for an example. + + +## Environment + +This hook will run as the chasquid user, so be careful about permissions and +privileges. + +The environment will contain the following variables: + + - USER + - SHELL + - PATH + - PWD + - REMOTE_ADDR + - MAIL_FROM + - RCPT_TO (space separated) + - AUTH_AS (empty if not completed AUTH) + - ON_TLS (0 if not, 1 if yes) + - FROM_LOCAL_DOMAIN (0 if not, 1 if yes) + - SPF_PASS (0 if not, 1 if yes) + +There is a 1 minute timeout for hook execution. +It will be run at the config directory. +