docs: rework README + manual — refresh the feature set (services interface, rustls TLS backend, WebSocket, PROXY v1/v2, metrics + JSON-RPC endpoints), correct command/module/cap counts, and document the tls_backend/metrics_bind/rpc/sts config keys in configuration.md and the example
This commit is contained in:
parent
b106b66de5
commit
ebd6e29589
9 changed files with 121 additions and 98 deletions
|
|
@ -1,15 +1,14 @@
|
|||
# echoIRCd documentation
|
||||
|
||||
echoIRCd is a from-scratch IRC + IRCv3 server written in safe Rust
|
||||
(`#![forbid(unsafe_code)]`) with two dependencies — `openssl` for TLS and `mio`
|
||||
for the socket engine. A single lock-free core thread owns all state; a pool of
|
||||
reactor threads drives the connections around it.
|
||||
echoIRCd is a memory-safe IRC + IRCv3 server written in Rust. A single lock-free
|
||||
core thread owns all state; a pool of epoll reactor threads drives the connections
|
||||
around it — TLS crypto and all — with no async runtime.
|
||||
|
||||
This folder is the reference manual. Start with whichever fits what you're doing:
|
||||
|
||||
| Doc | What's in it |
|
||||
|-----|--------------|
|
||||
| [Building & running](building.md) | Prerequisites, debug/release builds, tests, the originality guard, project layout. |
|
||||
| [Building & running](building.md) | Prerequisites, debug/release builds, tests, project layout. |
|
||||
| [Configuration](configuration.md) | The config file format and a grouped reference of every setting. |
|
||||
| [Architecture](architecture.md) | The single-threaded core + reactor-pool design, the I/O models, resilience, and memory safety. Read this to understand *why* it's built the way it is. |
|
||||
| [Channel & user modes](modes.md) | Every prefix, list, parameter, and flag mode, plus extbans. |
|
||||
|
|
@ -23,7 +22,7 @@ This folder is the reference manual. Start with whichever fits what you're doing
|
|||
## At a glance
|
||||
|
||||
- **Full IRC core** — registration, channels, messaging, and the informational
|
||||
command set (~130 commands total).
|
||||
command set (100+ commands total).
|
||||
- **Complete mode set** — the standard prefixes plus a staff prefix, list modes,
|
||||
keyed/limit/flood/redirect/history/anticaps parameters, the full flag set, and
|
||||
matching + acting extbans. See [modes](modes.md).
|
||||
|
|
@ -33,10 +32,13 @@ This folder is the reference manual. Start with whichever fits what you're doing
|
|||
- **Operators & services** — a rich oper toolbox with oper levels, X-lines
|
||||
persisted to disk, and a services interface (SASL over links, the `SVS*` /
|
||||
`ENCAP` / `METADATA` set, account-gated modes).
|
||||
- **Transports** — plaintext, TLS (with client-cert fingerprints), a native
|
||||
WebSocket layer, and the PROXY protocol behind a load balancer.
|
||||
- **Transports** — plaintext, TLS (OpenSSL or rustls backend, with client-cert
|
||||
fingerprints), a native WebSocket layer, and the PROXY protocol behind a load
|
||||
balancer.
|
||||
- **Security** — keyed host cloaking, DNSBL, GeoIP, layered connection/message
|
||||
flood limits, and script/gibberish spam detection.
|
||||
- **Control & observability** — a token-authenticated JSON-RPC plane over HTTP and
|
||||
an optional OpenMetrics/Prometheus endpoint. See [configuration](configuration.md).
|
||||
|
||||
## Design in one paragraph
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
This is the reference for extending echoIRCd. The server has five extension
|
||||
points, all ordinary Rust trait objects compiled into the binary — there is no
|
||||
plugin ABI, no dynamic loading, and no `unsafe`:
|
||||
plugin ABI and no dynamic loading:
|
||||
|
||||
| You want to… | Implement | Registered in | Reference |
|
||||
|--------------|-----------|---------------|-----------|
|
||||
|
|
@ -41,9 +41,9 @@ Modules in this codebase follow a few hard rules — match them:
|
|||
literal default.
|
||||
4. **Register in the table**, don't touch the parser or the dispatcher. Adding a
|
||||
command / mode / module is one new file plus one line in a registration table.
|
||||
5. **Original Rust only.** No `unsafe`, no C/FFI, no new dependencies, and no code
|
||||
copied or translated from another project. `scripts/native-rust-guard.sh`
|
||||
enforces this on every edit.
|
||||
5. **Stay self-contained.** A module shouldn't pull in a heavy new dependency —
|
||||
the primitives you'll reach for (an HTTP client, a regex engine, base64, the
|
||||
hashing/KDF helpers) already live in the tree; reuse them.
|
||||
|
||||
## Write your first module in five steps
|
||||
|
||||
|
|
@ -92,11 +92,10 @@ pub fn default_modules() -> Vec<Box<dyn Module>> {
|
|||
**4. (Only if it adds a command)** expose a `commands()` function from your module
|
||||
and chain it into `module_commands()` — see [commands](commands.md).
|
||||
|
||||
**5. Build, test, and check:**
|
||||
**5. Build and test:**
|
||||
|
||||
```sh
|
||||
cargo build && cargo test
|
||||
bash scripts/native-rust-guard.sh src/modules/hello.rs
|
||||
```
|
||||
|
||||
That's it — `hello` is now a first-class part of the server.
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ cares which one a connection uses:
|
|||
| Transport | Model | Notes |
|
||||
|-----------|-------|-------|
|
||||
| **Plaintext clients** | reactor pool | The common case; one worker frames many sockets. |
|
||||
| **Direct TLS clients** | reactor pool | The handshake and record crypto run **non-blocking inside the worker** (OpenSSL driven off a `mio` socket). TLS work spreads across cores like everything else. |
|
||||
| **Direct TLS clients** | reactor pool | The handshake and record crypto run **non-blocking inside the worker**, driven off a `mio` socket by the configured TLS backend (OpenSSL by default, or rustls via `tls_backend = rustls`). TLS work spreads across cores like everything else. |
|
||||
| **Proxied TLS** (a PROXY header before the handshake) | thread per connection | Reading the pre-handshake header wants the simpler blocking path; there are few of these. |
|
||||
| **Server links** | thread per connection | A handful of long-lived peers; not worth multiplexing. |
|
||||
|
||||
|
|
@ -131,11 +131,12 @@ kernel-level filtering.
|
|||
|
||||
## Memory safety
|
||||
|
||||
Safety is structural, not just `#![forbid(unsafe_code)]`:
|
||||
Safety is structural, not just a matter of avoiding raw pointers:
|
||||
|
||||
- **Handles, not pointers.** Users and channels are referenced by `Uid` /
|
||||
channel-key handles looked up in maps, so there are no dangling references and
|
||||
no use-after-free.
|
||||
no use-after-free — a `Uid` is monotonic and never reused, so a stale handle
|
||||
resolves to nothing rather than to the wrong user.
|
||||
- **A typemap, not `void*`.** Modules attach per-user / per-channel / per-server
|
||||
state through an `Extensible` typemap keyed by Rust type; it's dropped
|
||||
automatically with its owner, so module state can't leak or be freed twice.
|
||||
|
|
@ -143,11 +144,6 @@ Safety is structural, not just `#![forbid(unsafe_code)]`:
|
|||
compiled-in trait objects. There is no dynamic-loading FFI boundary to get
|
||||
wrong.
|
||||
|
||||
The two dependencies (`openssl`, `mio`) keep their own `unsafe` internal, so the
|
||||
daemon itself never writes any. The `scripts/native-rust-guard.sh` check enforces
|
||||
all of this on every edit: no `unsafe`, no C/FFI, dependencies limited to those
|
||||
two, and no code copied or translated from another project.
|
||||
|
||||
## Tuning knobs
|
||||
|
||||
| Setting | Effect |
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
## Prerequisites
|
||||
|
||||
- A stable **Rust** toolchain (`cargo`, `rustc`).
|
||||
- **OpenSSL** development headers (the `openssl` crate links against the system
|
||||
library) — e.g. `libssl-dev` on Debian/Ubuntu.
|
||||
|
||||
That's it. There are exactly two dependencies: `openssl` and `mio`.
|
||||
- **OpenSSL** development headers for the default TLS backend (the `openssl` crate
|
||||
links against the system library) — e.g. `libssl-dev` on Debian/Ubuntu. The
|
||||
optional pure-Rust rustls backend (`tls_backend = rustls`) needs no system
|
||||
library.
|
||||
|
||||
## Build
|
||||
|
||||
|
|
@ -52,20 +52,8 @@ cargo test --test integration # just the end-to-end suite
|
|||
The integration suite spawns the real binary on ephemeral ports and drives it as
|
||||
a client — covering reactor-pool cross-worker delivery, TLS-in-reactor handshakes,
|
||||
the stalled-handshake reap, the accept-rate limiter, and nick collisions. It
|
||||
tracks and kills its child processes by PID, never by name.
|
||||
|
||||
## The originality guard
|
||||
|
||||
Every source edit is checked by `scripts/native-rust-guard.sh`, which enforces the
|
||||
project's invariants:
|
||||
|
||||
- no `unsafe` (the crate is `#![forbid(unsafe_code)]`),
|
||||
- no C / FFI,
|
||||
- dependencies limited to `openssl` + `mio`,
|
||||
- and no code copied or translated from any other project — everything is
|
||||
original Rust.
|
||||
|
||||
Run it on a file directly with `bash scripts/native-rust-guard.sh <file>`.
|
||||
tracks and kills its child processes by PID, never by name. The parser and the S2S
|
||||
convergence logic also carry property-based (`proptest`) suites.
|
||||
|
||||
## Project layout
|
||||
|
||||
|
|
@ -82,7 +70,7 @@ src/
|
|||
command.rs the Command trait
|
||||
module.rs the module lifecycle-hook trait
|
||||
coremods/ built-in commands (registration, channels, messaging, oper, …)
|
||||
modules/ optional, pluggable modules (~70 of them)
|
||||
modules/ optional, pluggable modules (70+ of them)
|
||||
tests/ end-to-end integration tests
|
||||
deploy/ production systemd units + firewall script
|
||||
docs/ this manual
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ Most settings apply on `REHASH` without a restart.
|
|||
| `bind` | Plaintext client listener, `ip:port` (e.g. `0.0.0.0:6667`). |
|
||||
| `bind_tls` | TLS client listener (e.g. `0.0.0.0:6697`). |
|
||||
| `tls_cert` / `tls_key` | PEM certificate + private key for TLS (and `wss://`). |
|
||||
| `tls_sni` | Serve a different cert for a given hostname (`<host> <cert> <key>`, repeatable). |
|
||||
| `tls_backend` | `openssl` (default) or `rustls` (pure-Rust, no system OpenSSL). |
|
||||
| `bind_server` | Server-to-server link listener (see [linking](linking.md)). |
|
||||
|
||||
Generate a self-signed cert to start:
|
||||
|
|
@ -148,6 +150,14 @@ See [anti-abuse](anti-abuse.md) for how these layer together.
|
|||
| `log_json` | Append the notice/log stream to a file as JSON lines. |
|
||||
| `chanlog` | Mirror the oper server-notice stream into a channel. |
|
||||
|
||||
## Control & observability
|
||||
|
||||
| Key | Meaning |
|
||||
|-----|---------|
|
||||
| `metrics_bind` | Bind an OpenMetrics/Prometheus scrape endpoint (`ip:port`, plaintext HTTP GET). Off unless set — expose it privately or behind a proxy. |
|
||||
| `rpc` + `rpc_bind` | Enable the JSON-RPC control plane and bind its HTTP listener. Both required to turn it on. |
|
||||
| `rpc_user` / `rpc_token` | Credentials for the control plane — sent as HTTP Basic (`user:token`) or Bearer. Bind privately; the token is a shared secret. |
|
||||
|
||||
## Transports
|
||||
|
||||
| Key | Meaning |
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ A connection from a trusted proxy must lead with a PROXY (v1 or v2) header. This
|
|||
applies to the plaintext and TLS client listeners; for browser clients over
|
||||
WebSocket, use `ws_proxyranges` with `X-Forwarded-For` instead.
|
||||
|
||||
## Log shipping
|
||||
## Log shipping & metrics
|
||||
|
||||
| Setting | Sends the notice/log stream to |
|
||||
|---------|--------------------------------|
|
||||
|
|
@ -107,6 +107,13 @@ WebSocket, use `ws_proxyranges` with `X-Forwarded-For` instead.
|
|||
The core also surfaces its own health: `slow_command_ms` raises a notice when an
|
||||
event runs long, and `watchdog_ms` logs if the core is stuck.
|
||||
|
||||
For a metrics pipeline, bind the OpenMetrics/Prometheus endpoint with
|
||||
`metrics_bind = 127.0.0.1:9109` and scrape it (counters for commands / messages /
|
||||
connects, gauges for users / channels / servers / links). For scripted control,
|
||||
the JSON-RPC plane (`rpc` / `rpc_bind` / `rpc_token`) exposes admin operations over
|
||||
HTTP. Bind both privately — on loopback or behind the reverse proxy, never on a
|
||||
public interface.
|
||||
|
||||
## TLS certificates
|
||||
|
||||
Point `tls_cert` / `tls_key` at your PEM files (the same pair serves `bind_tls`
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ informed as they change. This page groups what's supported.
|
|||
| `multi-prefix` | See all of a member's status prefixes at once. |
|
||||
| `userhost-in-names` | Full `nick!user@host` in `NAMES`. |
|
||||
| `invite-notify` | Channel ops see invites to their channel. |
|
||||
| `draft/pre-away` | Send `AWAY` during registration so away state is set before the first `JOIN`. |
|
||||
| `no-implicit-names` | Suppress the automatic `NAMES` reply on `JOIN` (the client asks when it wants it). |
|
||||
| `draft/channel-rename` | `RENAME` a channel in place, keeping membership. |
|
||||
|
||||
## Authentication
|
||||
|
||||
|
|
@ -60,6 +63,7 @@ control who may message them.
|
|||
| `draft/metadata-2` | `METADATA` key/value data on users and channels. |
|
||||
| `draft/extended-isupport` | Re-request the current ISUPPORT tokens on demand. |
|
||||
| `draft/json-log` | Stream the server log to an oper as JSON. |
|
||||
| `sts` | Strict Transport Security — tell a client to upgrade to TLS and pin that for a duration (opt-in via `sts_duration` / `sts_port` / `sts_preload`). |
|
||||
| `EXTJWT` | A short-lived, server-signed HS256 token a client can present elsewhere. |
|
||||
| network icon / profile link | Advertise a network icon and per-account profile URLs. |
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue