Proof of concept mechanical port of ircnet/ircd to Rust as part of a bit about C being insecure for network services
3.7 kB
77 lines
1# leveva — an idiomatic-Rust IRC daemon
2
3NOTE: by reading this README or any of the code, you hereby and irrevocably
4agree to leave the IRCNet team alone with regards to this repo. This experiment
5was done without their knowledge, consultation, or any belief on my part that
6this will be anything but an experiment to see what is possible with tools
7that exist today.
8
9This repo started as a *mechanical* C→Rust port of
10[ircnet/ircd](https://github.com/ircnet/ircd) 2.11 — a faithful, byte-for-byte
11translation kept honest against the original C as a differential oracle. That
12port did its job and is **gone**. What remains is what it was scaffolding for:
13**leveva**, a from-scratch, idiomatic-Rust IRC daemon that grew to feature parity
14against the mechanical port and then replaced it.
15
16So this is a finished [strangler fig](https://martinfowler.com/bliki/StranglerFigApplication.html):
17the C tree was strangled by a faithful Rust port, the faithful port was strangled
18by leveva, and now only leveva is left standing.
19
20## What leveva is
21
22A single-binary IRCnet-style daemon written in idiomatic async Rust:
23
24- **tokio** runtime, one task per connection — no `select()`/`poll()` loop, no
25 global buffers, no `unsafe` FFI seam.
26- **rustls** TLS (via `ring`, no system OpenSSL) with hot certificate reload.
27- **KDL** config (typed, validated) instead of the C daemon's pipe-delimited
28 single-letter lines.
29- Typed identifier strings (`Nick`/`ChanName`/`Uid`/`Sid`/…) that reject illegal
30 input at construction, and casemapping-aware string types.
31- The full IRCnet client surface (registration, channels + channel/user modes,
32 WHO/WHOIS/WHOX, OPER/STATS, …), the UID-based S2S link/burst/netsplit protocol
33 (UNICK/NJOIN/SAVE/EOB), and a growing IRCv3 track (CAP, message-tags + delivery
34 plane, away/account/invite/echo/server-time, MONITOR, chghost/setname,
35 multi-prefix, standard-replies, WebSocket transport, …).
36- In-process authentication (`leveva-iauth`: ident/dnsbl/socks/webproxy), running
37 as an `.await` in the per-connection task rather than a separate iauth process.
38
39The behavioral guarantees are carried by leveva's own self-contained test suite —
40boot-golden snapshots plus property-based (`proptest`) fuzzing for essentially
41every command.
42
43## Workspace layout
44
45| Crate | What it is |
46| -------------- | ----------------------------------------------------------------- |
47| `leveva` | the daemon (library + the `leveva` binary) |
48| `leveva-iauth` | in-process async authentication modules |
49
50## Build and run
51
52```sh
53cargo build --release -p leveva --bin leveva
54./target/release/leveva --config path/to/ircd.kdl
55```
56
57Useful flags: `--check` (validate the config and exit), `--motd <file>`,
58`--log-level <level|RUST_LOG-filter>`. Example configs live in
59[`leveva/examples/`](./leveva/examples/) (`simple.kdl` is a good starting point).
60
61Container images build with [buildx bake](./docker-bake.hcl):
62
63```sh
64docker buildx bake leveva
65```
66
67## History and how it was built
68
69leveva was built with Claude Code and the
70[superpowers](https://github.com/obra/superpowers) plugin, one differentially
71verified slice at a time. The full migration story — the mechanical port, the
724-layer test harness, the phase-by-phase plan, and the pivot to leveva — lives in
73[PLAN.md](./PLAN.md), with per-phase progress logs under
74[`docs/progress-log/`](./docs/progress-log/) and the generated specs/plans under
75[`docs/superpowers/`](./docs/superpowers/). The deleted mechanical port, the C
76source tree, and the differential oracles all remain recoverable from git
77history.