Commit Graph
106 Commits
Author SHA1 Message Date
Wez Furlong 352ada5042 clippy: address all current clippy issues
Migrate the clippy allowlist from the clunky list in the Makefile
to the workspace config, and ensure that all crates reference it.
2026-08-27 14:38:48 +01:00
Wez Furlong 9efc2a031c allow mocking mta-sts end-to-end, add integration test coverage
This sets up plumbing to allow testing the broken mta-sts aliasing
issue, and enables feeding an optional resolver through the mx lookups
as well.

closes: https://github.com/KumoCorp/kumomta/pull/524
2026-07-27 08:02:37 +01:00
Wez Furlong 41be60dfce Evaluate MTA-STS during MX resolution to fix aliasing issue
refs: https://github.com/KumoCorp/kumomta/issues/484

Briefly, the issue is that if some random domain that shares MX records
with another (eg: someone is using google apps or icloud for their
vanity domain) publishes a broken MTA-STS policy that requires eg:
cloudflare MX hosts then because we roll up by site name, that broken
MTA-STS policy bleeds into all the other domains that share those MX
records.

The resolution is simple, but is technically a breaking change.

Moving the policy resolution to happen during site_name resolution
allows us to resolve both per-domain things at the same and have the
MTA-STS policy amend the effective set of MX hosts.  The output of that
is then used for site_name aggregation/rollup.

The consequence of this is quite nice: an MTA-STS policy that is more
restrictive than the full set of MX hosts now prevents delivering to
any of the excluded hosts, and a totally broken policy that prevents all
of its MX hosts is now completely undeliverable and will produce
transient failures.

The downside is that for users that had previously disabled mta-sts in
their default shaping block, they will need to change a different config
option to continue to prevent MTA-STS from being consulted.  One example
of this that I recall is that one user's network posture prevented
MTA-STS from making HTTPS requests to fetch the policy.  Another user
just wanted to cut out the additional DNS traffic.  Those use cases
require altering the new kumo.dns.set_mta_sts_enabled enabled to false
during `init`.
2026-07-27 08:02:37 +01:00
Wez Furlong 407379dd36 track sched->readyq fan in, clean up some internals
This commit removes the queue_name_for_config_change_purposes_only wart
from inside the readyq machinery.  This field had a bunch of caveats
and could in some cases become stale if the originating scheduled
queue had aged out.

It's been replaced by a HashSet of Weak refs back to the associated
scheduled queues so that it is now possible to walk the reverse of
the fan-in graph when we need to.
2026-06-25 13:41:01 +01:00
Wez Furlong 3174bd5a39 rustfmt again 2026-06-23 11:24:04 +01:00
Wez Furlong 2a657f68fb included scheduled queue config in resolve-egress-path output
and also in resolve-shaping-domain, for consistency.

We can use the message rate from the scheduled queue config to refine
the computed ceilings/constraints too, which is nice.
2026-06-23 10:00:07 +01:00
Wez Furlong 49e1a62733 add resolve-egress-path API endpoint
This is conceptually equivalent to resolve-shaping-domain but operates
on a live instance, rather than loading up the policy offline.
2026-06-23 10:00:05 +01:00
Wez Furlong 61bb95a558 resolve-shaping-domain: expand output
This changes the output to be a bit more human friendly by default
by rendering as toml.

It also includes the rate ceilings added in the prior commit.
2026-06-23 09:59:32 +01:00
Wez Furlong 0a72ce7f02 introduce EgressPathConfigConstraints concept
This can be computed for an EgressPathConfig and is useful to indicate
what the effective ceilings are for this egress path.

We return this from inspect-ready-q
2026-06-23 09:58:38 +01:00
Wez Furlong b9e677dd16 add abort-ready-q-conn and inspect-readyq endpoints/commands
These build on the infrastructure from the prior commit and improve
the observability of the system.

refs: https://github.com/KumoCorp/kumomta/issues/539
2026-06-23 09:58:36 +01:00
Wez Furlong 9987248313 spool: surface and handle rocksdb background errors
We recently investigated an issue where a rocksdb had been damaged by
corrupting/removing SST files (it sounded like this was accidentally
self-inflicted by some backup/orchestration infrastructure) leaving the
system in a silently-broken state: writes just wouldn't make progress
and there were no error messages.

Inspecting the `/var/spool/kumomta/data/LOG` log file (which is a
readable text file) revealed messages like:

```
2026/06/12-14:55:31.884227 2875746 [ERROR] [db/compaction/compaction.cc:262] Unable to load table properties for file 29704 --- IO error: No such file or directory: While open a file for random read: /var/spool/kumomta/data/029704.sst: No such file or directory
2026/06/12-14:55:31.884311 2875746 [ERROR] [db/db_impl/db_impl_compaction_flush.cc:3385] Waiting after background compaction error: IO error: No such file or directory: While open a file for random read: /var/spool/kumomta/data/029704.sst: No such file or directory, Accumulated background error counts: 6363
```

This commit improves the observability in this situation by proactively
checking for error conditions:

1. The store() and remove() operations now use our own polling within
   a deadline loop rather than spawning a blocking task and delegating
   to rocksdb's blocking interface.  This allows us to inspect the
   background error count and be cancellable, safely respecting and
   caller provided smtp max transaction duration.

2. All read and write operations check for IO and Corruption errors
   and immediately latch an error state

3. The metrics monitoring task inspects and track background error
   counts and latch us into an unhealthy state when the background
   error state appears unhealthy and persistent.

4. Additional metrics are exposed to help monitoring and alerting

While adding integration test coverage for this, I found a typo that
meant that spool errors were ignored in the message crate; they got
silently converted to `true` in all cases rather than just mapping
the success case to a `true`.

Integration tests handle the case where an SST file is corrupted
(truncated) during runtime, as well as starting up when an SST file
is missing.   These excercise both the foreground and background
error detection paths.
2026-06-23 09:11:48 +01:00
Wez Furlong 909b1190cd refactor: extract kumo-api-client from kcli
This enables reusing just the http client parts of kcli
in another module in the future.
2026-02-24 12:19:53 +00:00
Wez Furlong 524fdd87af docs: add tags to kcli commands
This helps link together related things in the docs
2026-01-28 12:49:32 +00:00
Wez Furlong 5926112956 acct: add kumo.aaa.configure_acct_log
This function sets up the accounting log which records authentication
and authorization events to a local log file.

Add some test assertions that we're not seeing any failed authn/authz
in a number of integration tests.

Add explicit check for failed a request to kcli's streaming metrics
parser, which previously would ignore the request status.
2025-12-18 08:22:31 +00:00
Wez Furlong 2d557f68bf kcli: expose smtp_server_rejections counter 2025-11-20 15:39:36 +00:00
Wez Furlong 32763a98b8 kcli provider-summary: dedup domains in domains list 2025-10-10 18:45:51 +01:00
Wez Furlong 8fc11713d8 deps: update axum and utoipa ecosystem crates
A "casualty" of this is that the client-ip crate, which we were using
for its InsecureClientIp type for informational purposes, has retired
the InsecureClientIp type because it wasn't trustworthy overall
(https://github.com/imbolc/axum-client-ip/issues/32).

What we do for the time being is configure that crate to use the direct
peer IP.  There isn't a way to automagically select the "best"
information available without building in some kind of middleware, and
we probably should make that configurable in order to be fully
trustworthy.

So for now, we're punting on that until someone shows up with some
requirements and sponsorship and we'll make it happen then.
2025-10-08 10:24:57 +01:00
Wez Furlong 7f4a929ca2 message transfer (xfer) support
This commit implements a kumomta-specific message transfer
protocol that is intended to be used to migrate messages
from one kumomta node to another.

The transfer is carried out using an HTTP POST request
to the destination node's http listener.

The request includes the full message metadata and body,
in a compressed form.

An xfer request can be made via `kcli xfer` (and thus also via an HTTP API
endpoint).  It works similarly to a rebind operation; you specify the
criteria to be used to match scheduled queues, along with the target
node for the xfer, and kumomta will find matching queues, drain out the
messages, make an adjustment to the metadata to capture current
scheduling information, and then place the messages into an xfer queue.

The xfer queue has hard-coded scheduling queue configuration of its own,
with the base retry interval set to 10 seconds, which should be suitably
aggressive for the intended use case.

You may apply shaping to affect the number of concurrent requests in a
similar way to how TSA shaping is configured.

On the receiving side, the incoming xfer sanity check to prohibit
trying to xfer to itself.

The spool id of the Message is not suitable to be reused verbatim on
another node (spool ids include the local mac address and creation
timestamp information, as well as a random component), so the receiving
side will derive an id that should be suitable for use on that node.
The originating node id and spool id will be preserved in metadata to
aid in tracing.

It is possible for an xfer request to target an existing xfer queue, so
that you can correct/update the target in various circumstances. In that
situation the messages will be "simply" moved from the source queue to
the destination queue.

It is possible to cancel an xfer request via `kcli xfer-cancel` (and
thus also via an HTTP API endpoint).  You specify the target queue,
which must be an xfer queue, and it will have its messages drained and
the metadata changes that were applied when the xfer was initiated will
be reversed, allowing the messages to then be reinserted into their
originating queue.

refs: https://github.com/KumoCorp/kumomta/issues/311
2025-10-07 10:58:07 +01:00
Wez Furlong de6e3bd0de allow admin bounce and suspend to specify exact queue name 2025-10-07 08:43:16 +01:00
Wez Furlong 4255e02ffa WIP: smtp_server: scaffolding to support for batching by domain
This adds a `batch_handling` parameter that optionally allows splitting
up a recipient batch based on the destination domain.

The system does not yet have any support for correctly delivering such a
batch.
2025-10-07 07:52:57 +01:00
Wez Furlong 13a3debd6c rustfmt 2025-05-16 15:11:50 -07:00
Wez Furlong 42bf5c5e61 docs: adjust reference to improve search terms
We've been hoping that mkdocs-material will ship the much anticipated
search enhancements for some time, but it's time to recognize that
we need to do something to improve the search results with how
things work right now.

This is a big commit that changes the titles of the various pages
from the code-annotated synopsis to just the name of the function.

This makes it much easier now to match things like `kumo.reject`
directly, but `reject` remains awkward to find.

I think this is the best that we can do at this time.

A few functions have been annotated with the `status: deprecated` to
show as deprecated in the toc/nav (shows with a little trash can next
to the name).
2025-05-16 14:02:19 -07:00
Wez Furlong fedd2959b6 enhance log_arf, log_oob to support LogThenDrop
It is common to want to express that incoming reports should
be logged, but not relayed.

This commit facilitates that by expanding `log_arf` and `log_oob`
to allow more than just a simple boolean value.

We now support both LogThenRelay and LogThenDrop as dispositions
for an incoming report, as well as Ignore to not care about the
report content.

For the LogThenDrop case we'll log only the incoming OOB or Feedback
record to the logs and then discard the incoming message.

For LogThenRelay we'll log the incoming OOB/Feedback report as well
as enqueue the message and log a Reception and, subsequently, records
for its delivery attempts.

The previously supported boolean values are mapped to `Ignore` (false)
and `LogThenRelay` (true), respectively: their behavior is the same as
in prior releases.

The integration test and smtp server tracing infra has been enhanced a
bit to support extracting these new disposition states from the tracer
during the integration test.
2025-05-05 08:25:40 -07:00
Wez Furlong e3fdcaa628 cargo clippy --fix 2025-04-09 10:26:07 -07:00
Wez Furlong 129dbac461 kcli/top: support fuzzy matching series and heatmap names
Press f to edit the filter, watch it fuzzy match as you type.
2025-04-04 13:49:44 -07:00
Wez Furlong a9a096e76b kcli/top: refactor keyboard input
Move processing into state; this will aid in a future commit.
2025-04-04 10:32:07 -07:00
Wez Furlong bb9d786c86 kcli/top: scroll to tab when switching tabs 2025-04-04 08:14:04 -07:00
Wez Furlong f3a84fd40f kci/top: shift most heatmap math to accumulator stage
No need to rebuild/recompute the full data on each render
2025-04-04 08:11:12 -07:00
Wez Furlong 319b83bf8f kcli top: improve avg/freq labels
Some of the series ended up with bland labels like "lua" with
no context.  Let's include the overall metric name for those.

The consequence of this is that the labels column gets wider,
but I think that now that we have scrolling, we can adjust
that presentation in a follow up commit.
2025-04-04 07:59:46 -07:00
Wez Furlong 04ea7e5804 kcli top: auto add all histograms 2025-04-04 07:49:50 -07:00
Wez Furlong cb1c87ab15 kcli top: initial support for showing heatmaps 2025-04-04 07:17:05 -07:00
Wez Furlong ad7e98e7c5 kcli top: add basic help tab 2025-04-03 14:57:51 -07:00
Wez Furlong 4f8aadb05a kcli top: +/- increase/decrease the "zoom" of each row 2025-04-03 14:19:29 -07:00
Wez Furlong 0fc21cbbc6 kcli top: add vertical scrollbar
There are a lot of metrics these days, we need to scroll through them!
Use the arrow keys, page up/down and home/end for this purpose.

closes: https://github.com/KumoCorp/kumomta/issues/372
2025-04-03 14:00:59 -07:00
Wez Furlong 5e6e2c9497 kcli: update ratatui dep 2025-04-03 14:00:59 -07:00
Wez Furlong 3d0d0ebce1 kcli: refactor: split into more modules
no functional change
2025-04-03 12:48:57 -07:00
Wez Furlong 3af505f450 kcli: tracer: allow unbounded buffering of trace data
It's more acceptable for the client to go nuts with its own memory usage
than it is for the server side to waste memory on trace data, so let's
allow it to buffer indefinitely while it is busy formatting the output.
2025-01-28 11:07:59 -07:00
Wez Furlong dc1541c030 kcli: tracer: remove redundant bytes read|written output
When we output just a single line of data, there is no need
to also emit another line with its length. This was a side effect
of adding terse mode to the client side.

Now that we're doing the terse processing server side, the
non-Abbreviated cases are never actually terse-processing eligible
on the client (assuming that the client and server version match),
so having the byte length summary presented there is especially
noticeable.

We can simply elide it by trimming off trailing whitespace.
2025-01-28 10:59:09 -07:00
Wez Furlong 5f76d85d23 kcli: switch tracers to async websocket client
This should make things play a little more nicely in the client,
but it's not a significant difference in throughput or performance.
2025-01-28 10:49:23 -07:00
Wez Furlong d224feb62f tracing: enable server-side processing of terse flag
Cutting down on the data being transmitted can reduce the number
of lag events.

Increase the channel buffer size as well while we're in here.
2025-01-28 10:35:19 -07:00
Wez Furlong e3c3f5fbe0 tracing: emit diagnostic if the tracer has lagged
Previously we'd simply drop the connection. With this behavior we now
emit an error to the journal (once per tracer session) and emit a
diagnost to the client (each time) whenever some number of events
were dropped by the internal broadcast channel.
2025-01-28 10:35:19 -07:00
Wez Furlong 6841841283 first run at an inspect-sched-q command
This can return a sample (or all) of the messages as well as
some additional queue metadata for a named scheduled queue.

refs: #231
2025-01-23 17:10:41 -07:00
Wez Furlong ff8c0ccff2 Expose ready queue states via api, and in kcli queue-summary
This adds connection limit/throttle states to the readyq rows
in `kcli queue-summary`, alongside where we would show the
suspension state.

This makes it easier to understand when a given egress path
might be hitting connection limits.
2024-12-21 07:44:29 -07:00
Wez Furlong 6da455d42b kumod: process TSA Bounce rules and apply as bounces
Accepts scheduled queue bounce events from the event subscription,
and translates them into local admin bounce records.

refs: https://github.com/KumoCorp/kumomta/issues/272
2024-12-09 07:15:45 -07:00
Dirkjan Ochtman 16c73dfff8 Drop direct tungstenite dependency in favor of tokio-tungstenite 2024-11-13 13:50:27 -07:00
Wez Furlong a510e0d90c fix kcli double counting the ready queue size 2024-11-07 16:29:11 -07:00
Wez Furlong 12b3ae51ac fix TSA SuspendTenant rules always set duration to 5 minutes 2024-09-18 09:37:31 -07:00
Wez Furlong bb3a84fff5 provider-summary: make order of C/Q consistent with queue-summary 2024-09-16 18:24:31 -07:00
Wez Furlong a0d9fd7164 kcli: make bounce-list easier to read by default
Sites with lots of tenants and campaigns would produce an overwhelming
amount of output with the default json output mode.

Let's make json opt-in and default to a human readable output
mode that is more concise.

```console
$ kcli bounce-list
ID                                   REASON REMAIN                   BOUNCED CRITERIA
0d2402cc-2dce-44c8-85f6-a4c056300f55 boingo 4m 31s 150ms 560us 575ns  10,990 domain=hotmail.com
```
2024-09-13 08:52:54 -07:00
Wez Furlong be2eeda1f5 the bounce API endpoint is now always asynchronous
In systems with very large numbers of queues, it will take an
effectively unbounded amount of time to produce the initial
summary of results if we were to wait for the bounce to be
applied to every queue.

Let's adjust the output of the kcli to indicate that it is async,
and update the docs which already suggested that the numbers would
be partial to indicate that you can only really consume the id
from the response.
2024-09-13 08:52:54 -07:00