Commit Graph
303 Commits
Author SHA1 Message Date
Wez Furlong 4cf2e65c94 dkim: add comparitive benchmark against mail-auth
```
signing/sign Simple     time:   [1.2990 ms 1.3002 ms 1.3015 ms]
                        thrpt:  [2.3581 MiB/s 2.3603 MiB/s 2.3626 MiB/s]
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high mild

signing/sign Relaxed    time:   [1.2942 ms 1.2955 ms 1.2968 ms]
                        thrpt:  [2.3665 MiB/s 2.3689 MiB/s 2.3712 MiB/s]
Found 4 outliers among 100 measurements (4.00%)
  1 (1.00%) low mild
  1 (1.00%) high mild
  2 (2.00%) high severe

mail-auth signing/sign Simple
                        time:   [487.97 µs 488.22 µs 488.48 µs]
                        thrpt:  [6.2826 MiB/s 6.2860 MiB/s 6.2892 MiB/s]
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high severe

mail-auth signing/sign Relaxed
                        time:   [494.68 µs 495.68 µs 496.68 µs]
                        thrpt:  [6.1789 MiB/s 6.1913 MiB/s 6.2039 MiB/s]
```
2023-06-15 15:41:18 -07:00
Wez Furlong 30b8522873 dkim: precompile list of headers to sign during signing
We can exploit eg: knowing that the list of headers is a unique
list (no repeated headers) and save some overhead when using the
same signer multiple times.
2023-06-15 15:18:17 -07:00
Wez Furlong 4805f60837 dkim: avoid allocating a vec when signing headers 2023-06-15 14:45:40 -07:00
Wez Furlong 02d1378495 dkim: avoid re-parsing header list during signing 2023-06-15 14:28:11 -07:00
Wez Furlong e5d03052be dkim: tidy up handling of l= body length tag
We should parse at the edge and pass down the parsed number
2023-06-15 13:23:44 -07:00
Wez Furlong cf11540f84 dkim: remove another extraneous allocation, tidy up canon interface 2023-06-15 13:13:28 -07:00
Wez Furlong 28f0786e42 dkim: update crate deps 2023-06-15 11:37:59 -07:00
Wez Furlong 19c9201e44 dkim: remove some redundant clone calls 2023-06-15 11:30:44 -07:00
Wez Furlong 2e40c00121 dkim: introduce ParsedEmail type
This help transitions to a cheaper email parser, that doesn't need to
parse the entire MIME structure

Note that as part of this, I found that several tests were running
against email messages using unix line endings instead of canonical
CRLF.

This was silently being masked and an empty or otherwise incorrect byte
slice was being hashed; I've updated the affected tests and their test
expectations accordingly, as well as made this error bubble up at the
time of parsing the email, rather than silently squashing it in the
depths of the hasher.
2023-06-15 11:27:03 -07:00
Wez Furlong 3af3f52f66 dkim: pick some lint various bits 2023-06-15 10:27:33 -07:00
Wez Furlong 19aca29007 dkim: don't require moving data into verify_signature 2023-06-15 10:07:33 -07:00
Wez Furlong 424192eb5f dkim: tidy up DKIMHeader construction 2023-06-15 10:07:26 -07:00
Wez Furlong aecd187c21 dkim: remove some string copies 2023-06-15 09:53:53 -07:00
Wez Furlong ed8ccbc810 dkim: remove slog dependency 2023-06-15 09:27:28 -07:00
Wez Furlong af3236a72e dkim: remove Cargo.lock 2023-06-15 09:17:43 -07:00
Wez Furlong eb44e0780e Use vendored in dkim fork 2023-06-15 09:11:34 -07:00
Wez Furlong 49c1533435 Merge in my DKIM crate fork 2023-06-15 09:10:39 -07:00
Wez Furlong 907e85053a kumod: improve shutdown diagnostics
Log something every 15 seconds to demonstrate that we didn't get
hung up
2023-06-15 07:47:26 -07:00
Wez Furlong 38ae7cf20e smtp_server: improve debug/trace output
Show the buffer contents as a quoted string rather than an array
of the decimal bytes
2023-06-15 07:32:50 -07:00
Wez Furlong 0c70ab2c52 improve error message when converting lua -> rust types
refs: https://github.com/KumoCorp/kumomta/issues/56
2023-06-14 20:14:14 -07:00
Wez Furlong 8ff2ea950f dkim: update to pick up some perf improvements from my fork 2023-06-14 15:39:24 -07:00
Wez Furlong 2992e42138 add received_from and received_via meta values
We don't set received_via for http because axum/hyper make it a
bit weird to access that information and it will require some
effort to figure out how to get that without breaking the
existing proxy-aware client IP determination.
2023-06-13 15:18:06 -07:00
Wez Furlong 1e3e208405 traffic-gen: fix usage with starttls
We were passing `hostname:port` as the server name used to verify
the certificate name, but it should just be `hostname`.
2023-06-13 10:29:21 -07:00
Wez Furlong 9c0ca973c2 replace ouroborous crate with self_cell
I picked ouroborous originally because the API was a bit nicer than that
in self_cell (we get to pick our own field names with ouroborous, but
don't in self_cell). However, ouroboros is now unmaintained and has a
soundness issue. The recommendation is to migrate, so that's what this
commit is.

refs: https://rustsec.org/advisories/RUSTSEC-2023-0042.html
refs: https://github.com/joshua-maros/ouroboros/issues/88

closes: https://github.com/KumoCorp/kumomta/security/dependabot/8
2023-06-12 14:52:16 -07:00
Wez Furlong b37c75e5e4 integration tests: explain this panic away better
Seemed to be an intermittent burp, but would benefit
from a better explanation anyway.
2023-06-12 14:48:11 -07:00
Wez Furlong 0249bd0d4d kcli: you may now list and cancel admin bounce entries
Entries now have a uuid that identifies them within a given instance
(NOT within a cluster).  The id is returned when the entry is
established:

```console
$ kcli --endpoint http://127.0.0.1:8000 bounce --everything --reason boop
{
  "id": "9a946198-9351-4e0e-b460-fc84e066878a",
  "bounced": {},
  "total_bounced": 0
}
```

You can list entries with their remaining duration:

```console
$ kcli --endpoint http://127.0.0.1:8000 bounce-list
[
  {
    "id": "9a946198-9351-4e0e-b460-fc84e066878a",
    "campaign": null,
    "tenant": null,
    "domain": null,
    "reason": "boop",
    "duration": "4m 57s 313ms 891us 882ns"
  }
]
```

and cancel them:

```console
$ kcli --endpoint http://127.0.0.1:8000 bounce-cancel --id 9a946198-9351-4e0e-b460-fc84e066878a
removed 9a946198-9351-4e0e-b460-fc84e066878a
```

and the error case if you try it again:

```console
$ kcli --endpoint http://127.0.0.1:8000 bounce-cancel --id 9a946198-9351-4e0e-b460-fc84e066878a
Error: bounce entry 9a946198-9351-4e0e-b460-fc84e066878a not found
```
2023-06-12 10:11:53 -07:00
Wez Furlong d6d2064564 admin: bounce: add id field to internals and to response
This doesn't do anything in the current milestone, but I wanted
to get it in there ready for work for the next milestone,
where I plan to make it possible to list and remove/cancel
a bounce, as well as persist them across a restart.
2023-06-12 07:11:43 -07:00
Wez Furlong bcfba07dad dkim: switch to my fork of cfdkim for RSA signatures
That fork removes the lifetime from the Signer type which makes
it easier to cache more efficiently.
2023-06-09 06:46:05 -07:00
Wez Furlong 88fd825be4 dkim: add cfdkim as a runtime alternative RSA signer
The mail-auth crate doesn't support 1024 bit RSA keys, which are
currently the dominant size of key used by senders at scale.

It is not possible to even configure a 2048 bit RSA key in some DNS
providers, which blocks widespread adoption of larger key sizes.

This commit pulls in the cfdkim crate as an alternative implementation.

I'm not happy with this implementation because the API of the crate
defeats some caching optimizations, doesn't support certain signing
attributes that are supported by mail-auth and the generated header isn't
nicely wrapped.

We'll likely "do something" to resolve this in a future commit.

For now, this implementation is enabled by setting `use_cf = true`
in the signing parameters.
2023-06-08 14:29:19 -07:00
Wez Furlong 887bb7e9e4 update rocksdb dep to fix build with gcc 13
refs: https://github.com/facebook/rocksdb/pull/11118
2023-06-08 13:29:53 -07:00
Wez Furlong f11511031a dkim: refine error message
I couldn't find definitive evidence that rsa-1024 has been broken,
but I did find some cases where eg: GPG had a side-channel attack
that could break PGP keys of that size, so it's easy to imagine
that other similar approaches might work for other software.

Regardless, the actual limitation comes from the Rust ring crate:

https://docs.rs/ring/latest/ring/signature/struct.RsaKeyPair.html#method.from_pkcs8

> Only two-prime (not multi-prime) keys are supported. The public modulus
> (n) must be at least 2047 bits. The public modulus must be no larger
> than 4096 bits. It is recommended that the public modulus be exactly
> 2048 or 3072 bits. The public exponent must be at least 65537.

Refine the error message to be more factual.
2023-06-08 10:32:42 -07:00
Wez Furlong ac913fad29 dkim: improve error messaging when loading a key fails 2023-06-08 10:13:58 -07:00
Wez Furlong 22451330f4 CLI: add kcli command for interacting with admin http endpoints
```console
$ kcli --help
KumoMTA CLI.

Full docs available at: <https://docs.kumomta.com>

Usage: kcli --endpoint <ENDPOINT> <COMMAND>

Commands:
  bounce
          Administratively bounce messages in matching queues
  set-log-filter
          Changes the diagnostic log filter
  help
          Print this message or the help of the given subcommand(s)

Options:
      --endpoint <ENDPOINT>
          URL to reach the KumoMTA HTTP API

  -h, --help
          Print help (see a summary with '-h')

  -V, --version
          Print version
```

```console
$ kcli bounce --help
Administratively bounce messages in matching queues.

Each individual message that is bounced will generate a log record capturing the event and then be removed from the spool.

Make sure that you mean it, as there is no going back!

The bounce will be applied immediately to queued messages, and the directive will remain in effect for the duration specified, causing newly received messages or messages that were in a transient state at the time the directive was received, to also be bounced as they are placed back into the matching queue(s).

Usage: kcli --endpoint <ENDPOINT> bounce [OPTIONS] --reason <REASON>

Options:
      --domain <DOMAIN>
          The domain name to match. If omitted, any domains will match!

      --campaign <CAMPAIGN>
          The campaign name to match. If omitted, any campaigns will match!

      --tenant <TENANT>
          The tenant name to match. If omitted, any tenant will match!

      --reason <REASON>
          The reason to log in the delivery logs

      --everything
          Purge all queues

      --duration <DURATION>
          The duration over which matching messages will continue to bounce. The default is '5m'

  -h, --help
          Print help (see a summary with '-h')
```

```console
$ kcli set-log-filter --help
Changes the diagnostic log filter

See <https://docs.kumomta.com/reference/kumo/set_diagnostic_log_filter/> for more information about the log filter syntax.

Usage: kcli --endpoint <ENDPOINT> set-log-filter <FILTER>

Arguments:
  <FILTER>

Options:
  -h, --help  Print help
```

refs: https://github.com/KumoCorp/kumomta/issues/55
2023-06-07 12:09:07 -07:00
Wez Furlong ec85c2da6f gracefully shutdown for SIGHUP, SIGTERM as well as SIGINT
Systemd doesn't terminate processes using SIGINT, so we didn't
get a chance to flush logs or messages to spool.

This should address that.

refs: https://github.com/KumoCorp/kumomta/issues/46
2023-05-31 12:45:36 -07:00
Wez Furlong ce7dece927 move domains out of listener, replace with get_listener_domain event
This commit also includes a policy helper
`policy_extras.listener_domains` to make it convenient to define
listener domains in toml and/or json files.

To facilitate this, the DomainMap rust structure has been exposed
to lua code via the new `kumo.domain_map.new` function.
2023-05-31 12:29:44 -07:00
Wez Furlong b7c557c31a define_egress_(pool|source) -> make_egress_(pool|source)
Switch the configuration plumbing for pools and sources to be pull-based
rather than push based.

In other words, rather than defining them in the `init` event,
you now need to supply them to the new `get_egress_pool` and
`get_egress_source` events.

Data is cached by default for 1 minute. This allows for new sources
to come into being on-demand, and for data to age out and change
over time, without requiring that the server be restarted.

This commit updates the reference section, but there is some content
in the user guide that refers to the old style of configuration that
will need to be updated.

refs: https://github.com/KumoCorp/kumomta/issues/13
2023-05-30 14:08:07 -07:00
Wez Furlong 81a4eba5a2 logging: Explicitly clear and flush the file map before completing
Otherwise we can race on shutdown and the process may exit without
fully flushing the logs!

refs: #46
2023-05-30 11:01:14 -07:00
Wez Furlong 9b1d82275c add spool_message_enumerated event
closes: #42
2023-05-30 10:14:37 -07:00
Wez Furlong ec6a7d83c9 dns: use fully qualified name when resolving A/AAAA records
We were so close, yet so far!

closes: https://github.com/KumoCorp/kumomta/issues/49
2023-05-30 09:57:01 -07:00
Wez Furlong 536827db99 make it an error to redefine an event handler
Produces an error like:

```
; KUMOD_LOG=kumod=info ./target/debug/kumod --policy simple_policy.lua
2023-05-16T18:16:02.112017Z  INFO main kumod::memory: using limits: soft=Some("101.22 GB"), hard=Some("134.96 GB")
Error: callback error
stack traceback:
        [C]: in function 'kumo.on'
        [string "simple_policy.lua"]:232: in main chunk
caused by: smtp_server_auth_plain event already has a handler defined at simple_policy.lua:226
```
2023-05-16 11:16:37 -07:00
Wez Furlong acef2ecab9 Add timeouts to socks server handshake/connection initiation
Let's avoid things hanging forever while setting up a connection.

refs: https://github.com/KumoCorp/kumomta/issues/45
2023-05-15 17:55:28 -07:00
Wez Furlong f21b7c53aa Add socks5 client support
Enable it via:

```lua
kumo.define_egress_source {
  name = "my source",
  socks5_proxy_server = '127.0.0.1:1080',
  socks5_proxy_source_address = '192.168.1.92',
}
```

couple it with:

```console
; RUST_LOG=proxy_server=trace cargo run -p proxy-server -- --listen 127.0.0.1:1080
   Compiling proxy-server v0.1.0 (/home/wez/wez-personal/kumomta/crates/proxy-server)
    Finished dev [unoptimized + debuginfo] target(s) in 1.30s
     Running `target/debug/proxy-server --listen '127.0.0.1:1080'`
[2023-05-11T23:54:56Z INFO  proxy_server] proxy listener on 127.0.0.1:1080
[2023-05-11T23:57:53Z TRACE proxy_server::proxy_handler] peer=127.0.0.1:49824 request: SocksV5Request { command: Bind, host: Ipv4([192, 168, 1, 92]), port: 0 }
[2023-05-11T23:57:53Z TRACE proxy_server::proxy_handler] peer=127.0.0.1:49824: status -> RequestStatus { status: Success, host: Ipv4([0, 0, 0, 0]), port: 0 }
[2023-05-11T23:57:53Z TRACE proxy_server::proxy_handler] peer=127.0.0.1:49824 request: SocksV5Request { command: Connect, host: Ipv4([103, 168, 172, 220]), port: 25 }
[2023-05-11T23:57:53Z TRACE proxy_server::proxy_handler] peer=127.0.0.1:49824: status -> RequestStatus { status: Success, host: Ipv4([192, 168, 1, 92]), port: 54052 }
[2023-05-11T23:57:53Z TRACE proxy_server::proxy_handler] peer=127.0.0.1:49824 -> going to passthru mode
```

refs: https://github.com/KumoCorp/kumomta/issues/45
2023-05-15 17:38:17 -07:00
Wez Furlong beb120fda5 Add a SOCKS5 proxy server implementation
This is a pretty tight, lightweight implementation of SOCKS5
intended to be used to facilitate an MTA asking it to bind and
connect.

It uses the splice(2) syscall to avoid kernel/userspace copies
when passing data through, so it should be quite efficient.

refs: https://github.com/KumoCorp/kumomta/issues/45
2023-05-15 17:38:17 -07:00
Wez Furlong f6ded18a96 add integration tests for smtp auth
refs: https://github.com/KumoCorp/kumomta/issues/10
2023-05-15 17:38:17 -07:00
Wez Furlong 9d3411431f Add outbound SMTP auth support
refs: https://github.com/KumoCorp/kumomta/issues/10
2023-05-15 17:38:17 -07:00
Wez Furlong db0c042cef Add amqp client
refs: https://github.com/KumoCorp/kumomta/issues/31
2023-05-15 17:24:15 -07:00
Wez Furlong 3d6aa1a49d use rustls for reqwest http client
This is a bit of a PITA.

In the docker build we end up with some bad linkage on libssl.so.1.1
on Ubuntu. That is the legacy ssl library, to which we should not
have been able to link, and for which there are no apt installable
sources.

See
<https://askubuntu.com/questions/1465498/update-libssl-so-1-1-for-the-latest-version>

Looking at the deps, the source of this linkage is the new HTTP
client bindings.

This commit dances around this issue by using the rustls implementation
for the client instead.

It's possible that this won't be sufficient, but it at least removes
the openssl linkage issue as a source of headaches for now.
2023-05-15 08:59:49 -07:00
Wez Furlong 75f72aef7d tone down the debug
refs: #19
2023-05-10 09:53:09 -07:00
Wez Furlong 6fdee41600 Add HA Proxy support
I used a config like this for testing:

```
global
    log stdout  format raw  local0  debug

defaults
    timeout connect 10s
    timeout client 30s
    timeout server 30s
    log global

listen outboundsmtp
    log global
    bind 0:2526 accept-proxy
    mode tcp
    use-server v4 if { src 0.0.0.0/0 }
    use-server v6 if { src ::/0 }
    server v4 0.0.0.0 source 0.0.0.0 usesrc clientip
    server v6 ::: source ::: usesrc clientip
```

Launched via:

```console
$ sudo haproxy -f assets/haproxy.conf -V
```

with the source:

```lua
  kumo.define_egress_source {
    name = 'w00t',
    ha_proxy_server = '127.0.0.1:2526',
    ha_proxy_source_address = '192.168.1.92',
  }
```

refs: #19
2023-05-10 09:50:06 -07:00
Wez Furlong de325af0ac surface lua errors raised by get_egress_path_config to diagnostic log
Previously, they would get logged only as a transient failure now
we log to both places.
2023-05-09 10:01:13 -07:00