Commit Graph
121 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 28f0786e42 dkim: update crate deps 2023-06-15 11:37:59 -07:00
Wez Furlong ed8ccbc810 dkim: remove slog dependency 2023-06-15 09:27:28 -07:00
Wez Furlong eb44e0780e Use vendored in dkim fork 2023-06-15 09:11:34 -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 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 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 ad70b6ac33 cargo update 2023-06-08 13:29:52 -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 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 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 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 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 927721fc0c Add toml parsing/encoding functions to lua
refs: https://github.com/KumoCorp/kumomta/issues/43
2023-05-09 08:40:37 -07:00
Wez Furlong 992cae1409 Allow loading a key source directly from lua
This makes it easier to compose secret management with a variety
of lua functions without having to build that directly into each
of them.

In particular: one can now use vaults or other secret stores that
we add in the future to manage credentials for HTTP clients.
2023-05-09 08:25:54 -07:00
Wez Furlong 0211b03060 http: add helpers for constructing form data
refs: https://github.com/KumoCorp/kumomta/issues/36
2023-05-08 15:06:09 -07:00
Wez Furlong 713d46e6a8 tests: add end-to-end webhook test
This exercises the log -> webhook delivery path

refs: https://github.com/KumoCorp/kumomta/issues/36
refs: https://github.com/KumoCorp/kumomta/issues/18
2023-05-08 10:14:34 -07:00
Wez Furlong 5dfa6e5865 add http client module
```lua
  local response = kumo.http
    .build_client({})
    :get('https://example.com/')
    :send()
  print(response:status_code(), response:status_reason())
  for k, v in pairs(response:headers()) do
    print("Header", k, v)
  end
  print(response:text())
```
2023-05-05 14:26:09 -07:00
Wez Furlong ac4d645670 Basic plumbing for handling deliveries in lua
```lua
-- Constructs a connection object in lua
kumo.on('make.lua-sender', function(domain, tenant, campaign)
  print 'making lua sender'
  local sender = {}
  function sender:send(message)
    print('Sending a message!', message)

    -- To log a transient failure:
    -- kumo.reject(420, 'boo!')

    -- To log a permanent failure:
    -- kumo.reject(500, "perm fail")

    -- To log success, return a string with additional data
    -- to be logged
    return 'Super!'
  end
  return sender
end)

-- Make everything use the lua "connection":
kumo.on('get_queue_config', function(domain, tenant, campaign)
  return kumo.make_queue_config {
    protocol = {
      custom_lua = {
        constructor = 'make.lua-sender',
      }
    },
  }
end)
```
2023-05-04 13:51:37 -07:00
Wez Furlong 28c3383169 queues: split ready queue in two halves
In preparation for web hook and other protocol delivery,
split the egress path / ready queue stuff into two pieces:

* The ready queue management
* A trait for dispatching ready queues

Implement smtp dispatching in terms of that new trait.

Add a stub trait for performing dispatching via lua; that will
be fleshed out in a follow up commit.

refs: https://github.com/KumoCorp/kumomta/issues/18
refs: https://github.com/KumoCorp/kumomta/issues/31
refs: https://github.com/KumoCorp/kumomta/issues/32
refs: https://github.com/KumoCorp/kumomta/issues/36
2023-05-04 13:51:37 -07:00
Wez Furlong ef2abc7031 allow comments in json parsed by kumo.json_load, kumo.json_parse 2023-04-26 15:08:29 -07:00
Wez Furlong bb64d6d2a8 dns: fix IPv4 and IPv6 literal domain resolving
Bypass the actual DNS resolver when handling literal
domains.
2023-04-21 12:17:09 -07:00
Wez Furlong b8694d00d8 remove problematic time 0.1 dependency 2023-04-18 15:02:59 -07:00
Wez Furlong 07b75dd117 remove oldtime feature from chrono crate
it pulls in an old version of the time crate that flags many
rust projects as being vulnerable to an old CVE.

We still have other references to time that I'll remove in a follow up.
2023-04-18 15:02:59 -07:00
Wez Furlong 2768dd98f7 cargo update 2023-04-13 10:09:31 -07:00
Wez Furlong f4a2d5bb8c cargo update 2023-04-11 17:29:24 -07:00
Wez Furlong 7f0fd509f1 dns: fix ipv6 lookups
A couple of issues in here:

1. a copypasta incident meant that the v6 lookup was really just a v4
   lookup. doh!
2. We would lookup v4 addresses and just be satisfied with those,
   ignoring any v6 addresses

We now run the v4 and v6 lookups concurrently and merge the results
together.

We do still list the v4 addresses first in the list of addresses.
We don't try to be smart about using the "right" addresses when
work through the list; we try them all until one works out.

Correctly guessing at which one will work means replicating logic
in the kernel, and would potentially be screwed up when we add in
HAProxy support later.
2023-04-04 13:04:16 -07:00
Wez Furlong 95a3c37104 tailer: implement checkpointing
It doesn't do much more than act as a glorified persistent
cursor at the moment, but the plumbing will enable calling
out to eg: lua or an arbitrary subprocess to process batches
in the future.
2023-04-04 12:36:43 -07:00
Wez Furlong d3a5626180 Add log tailer utility
This commit adjusts the logger:

* When a log segment is finised, the `w` permission bits are removed.
  This is used to signal to the tailer that there will be no additional
  data written to that file.

* On startup, kumod will remove the `w` bits from all files in the
  configured log directories so that any that were left on by a prior
  incarnation will be considered closed when the new generation is
  started up.

* Add a `tailer` utility that will essentially `cat` all of the log
  files in a given directory in the appropriate order, then go into
  log tailing mode, where it will wait for new data to show up.

* When reading data, if it hits EOF, the tailer will wait around until
  more data shows up, or until the `w` bit is removed from the file
  that it is reading.

The idea is that, in a later commit, the tailer will be able to persist
a checkpoint file to record where it got to, and be able to dispatch
chunks of data to eg: a webhook push utility, advancing the checkpoint
only when the utility indicates success.

For now, running `cargo run -p tailer -- --tail /var/tmp/kumo-logs` is
a convenient way to tail the logs as they are written.
2023-03-30 14:01:46 -07:00
Wez Furlong e87a5b18bb Improve performance of finding CRLF.CRLF for large messages by 20x
Using a better tuned algorithm for finding a substring match removes
a CPU bottleneck and improves message throughput by 20x at 100Kb
message sizes.
2023-03-27 09:39:51 -07:00
Wez Furlong 0167041ed0 add kumo.memoize as a way to add caching to any lua function 2023-03-22 17:01:07 -07:00
Wez Furlong b43e88985c add kumo.dns.lookup_mx
This function returns MX information, including the computed site_name.
Update the queue example to show how to use it to populate the SITE_OF
map used in that example.

This commit switches to using the `Name` type under the covers to ensure
that we use canonical names for our cache keys.
2023-03-15 09:34:23 -07:00
Wez Furlong b3f3f877df add functions for working with address headers 2023-03-14 18:53:47 -07:00
Wez Furlong 7c6547d0e4 commit cargo.lock after sqlite-src change 2023-03-14 15:59:43 -07:00
Wez Furlong b287db1944 ensure that we statically link sqlite
This avoids picking up a dynamic dep on libsqlite3.so
when we build the docker image.
2023-03-13 19:41:33 -07:00
Wez Furlong ec920535e3 refactor: move arf and bounce report parsing to kumo-log-types
This reduces transitive deps for other crates that want ostensibly just
the type definitions.
2023-03-12 20:16:05 -07:00
Wez Furlong 31f072978d refactor: move mx resolver into separate crate 2023-03-12 15:00:02 -07:00
Wez Furlong 98091b688d cidr-map: add CidrMap type
Unfortunately, the upstream bitstring-trees crate didn't expose
a way to query the tree (only iterate it), so I pulled in a copy
of the implementation and adjusted it for that purpose, removing
some unsafe code that replaced values during insertion (for performance)
with a simpler implementation that clones values instead.

With the map implementation in the crate, I adjusted the set
implementation to be a `CidrMap<()>` and dropped the bitstring-trees
dependency.
2023-03-12 10:59:57 -07:00
Wez Furlong 6304ee18c3 improve cidrset data structure
Improve the big-O cost of finding an entry by storing
the ranges in a compressed radix tree under the covers.

Make it a bit easier to work with the type in code while
we're in here.

"any" is now a possible value for cidrsets, representing
any value.
2023-03-12 09:21:56 -07:00
Wez Furlong 6477fc8a25 refactor: move CidrSet to its own crate 2023-03-12 06:46:54 -07:00
Wez Furlong 8989586c9b refactor: move version info to its own crate
Several crates depend on the config crate, which means that
several things needed to be rebuilt after committing/amending/syncing.

Separating it out reduces that impact.
2023-03-11 06:27:31 -07:00
Wez Furlong d86b8df202 spool: expose a number of rocksdb tuning options
There are loads more; I got bored adding them for now,
and more can be added later.
2023-03-10 07:29:36 -07:00