Files
bouncer/docs/USAGE.md
user 2f40f5e508 feat: add CertFP authentication with SASL EXTERNAL
Per-network, per-nick client certificates (EC P-256, self-signed,
10-year validity) stored as combined PEM files. Authentication
cascade: SASL EXTERNAL > SASL PLAIN > NickServ IDENTIFY.

New commands: GENCERT, CERTFP, DELCERT. GENCERT auto-registers
the fingerprint with NickServ CERT ADD when the network is connected.

Includes email verification module for NickServ registration and
expanded NickServ interaction (IDENTIFY, REGISTER, VERIFY).
2026-02-21 01:15:25 +01:00

367 lines
10 KiB
Markdown

# Usage
## Starting the Bouncer
```bash
bouncer -c config/bouncer.toml -v
```
| Flag | Description |
|------|-------------|
| `-c, --config PATH` | Config file (default: `config/bouncer.toml`) |
| `-v, --verbose` | Debug logging |
| `--version` | Show version |
## Connection Lifecycle
The bouncer goes through several states when connecting to an IRC server:
```
DISCONNECTED -> CONNECTING -> REGISTERING -> PROBATION -> READY
| | |
`--------------+--------------'
(failure = reconnect)
```
### 1. Stealth Registration
On connect, the bouncer registers with a **random identity**:
- **Nick**: pronounceable markov-generated word (e.g., `heliagu`, `crewo`, `midon`)
- **User/Ident**: random pronounceable word
- **Realname**: random capitalized word
No fixed prefix or pattern -- each attempt looks like a different person.
### 2. Probation (15 seconds)
After registration succeeds (001 RPL_WELCOME), the bouncer enters a 15-second
probation window. During this time it watches for:
- `ERROR` messages (K-line, ban)
- Server closing the connection
If the connection drops during probation, the bouncer reconnects with a fresh
random identity and tries again.
### 3. Ready
Once probation passes without incident:
1. Bouncer switches to your configured nick (`NICK mynick`)
2. Joins configured channels (if `autojoin = true`)
3. Begins relaying messages to/from connected clients
### 4. Reconnection
On any disconnection, the bouncer reconnects with exponential backoff:
| Attempt | Delay |
|---------|-------|
| 1 | 5s |
| 2 | 10s |
| 3 | 30s |
| 4 | 60s |
| 5 | 120s |
| 6+ | 300s |
Each reconnection uses a fresh random identity.
## DNS Resolution
Hostnames are resolved locally before being passed to the SOCKS5 proxy. If a
hostname resolves to multiple IPs, the bouncer tries each one until a connection
succeeds. This handles proxies that don't support remote DNS and avoids IPs
that are unreachable through the proxy.
## Connecting with an IRC Client
Configure your IRC client to connect to the bouncer:
| Setting | Value |
|---------|-------|
| Server | `127.0.0.1` |
| Port | `6667` (or as configured) |
| Password | `yourpassword` |
### Password Format
```
PASS <password>
```
The password is the `bouncer.password` value from config. A single connection
automatically attaches to **all** configured networks.
### Client Examples
**irssi:**
```
/connect -password mypassword 127.0.0.1 6667
```
**weechat:**
```
/server add bouncer 127.0.0.1/6667 -password=mypassword
/connect bouncer
```
**hexchat:**
Set server password to `mypassword` in the network settings.
## Multi-Network Namespacing
All configured networks are multiplexed onto a single client connection. Channels
and nicks carry a `/network` suffix so you can tell which network they belong to:
```
Client sees: Server wire:
#libera/libera <-> #libera (on libera network)
#debian/oftc <-> #debian (on oftc network)
user123/libera <-> user123 (on libera network)
```
### Rules
- **Channels**: `#channel/network` in client, `#channel` on wire
- **Foreign nicks**: `nick/network` in client, `nick` on wire
- **Own nicks**: shown without suffix (prevents client confusion)
- **Sending messages**: include the `/network` suffix in the target
```
/msg #libera/libera hello -> sends "hello" to #libera on libera network
/join #test/oftc -> joins #test on oftc network
/msg user123/libera hi -> private message to user123 on libera
```
### Comma-Separated JOIN/PART
Targets can span networks:
```
/join #a/libera,#b/oftc -> joins #a on libera AND #b on oftc
```
Multiple clients can attach simultaneously. All receive the same namespaced
messages in real time.
## What Clients Receive on Connect
When a client authenticates:
1. **Backlog replay** -- missed messages (namespaced) from all networks
2. **Synthetic welcome** -- 001-004 numeric replies listing all networks
3. **Channel state** -- synthetic JOIN, TOPIC, and NAMES for every joined
channel across all networks (all namespaced with `/network` suffix)
## Backlog
Messages are stored in `bouncer.db` (SQLite) next to the config file. When
you reconnect, missed messages are automatically replayed.
Configure in `bouncer.toml`:
```toml
[bouncer.backlog]
max_messages = 10000 # per network, 0 = unlimited
replay_on_connect = true # set false to disable replay
```
Stored commands: `PRIVMSG`, `NOTICE`, `TOPIC`, `KICK`, `MODE`.
## Configuration Reference
```toml
[bouncer]
bind = "127.0.0.1" # listen address
port = 6667 # listen port
password = "changeme" # client authentication password
[bouncer.backlog]
max_messages = 10000 # per network, 0 = unlimited
replay_on_connect = true # replay missed messages on client connect
[proxy]
host = "127.0.0.1" # SOCKS5 proxy address
port = 1080 # SOCKS5 proxy port
[networks.libera]
host = "irc.libera.chat" # IRC server hostname
port = 6697 # server port (default: 6697 if tls, 6667 otherwise)
tls = true # use TLS for server connection
nick = "mynick" # desired IRC nick (set after probation)
channels = ["#test"] # channels to join (after probation)
autojoin = true # auto-join channels on ready (default: true)
password = "" # IRC server password (optional, for PASS command)
```
## CertFP Authentication
The bouncer supports client certificate fingerprint (CertFP) authentication
via SASL EXTERNAL. Each certificate is unique per (network, nick) pair and
stored as a combined PEM file at `{data_dir}/certs/{network}/{nick}.pem`.
### Authentication Cascade
When connecting, the bouncer selects the strongest available method:
| Priority | Method | Condition |
|----------|--------|-----------|
| 1 | SASL EXTERNAL | Stored creds + cert file exists |
| 2 | SASL PLAIN | Stored creds, no cert |
| 3 | NickServ IDENTIFY | Fallback after SASL failure |
### Setup
1. Generate a certificate:
```
/msg *bouncer GENCERT libera
```
This creates an EC P-256 self-signed cert (10-year validity) and
auto-sends `NickServ CERT ADD <fingerprint>` if the network is connected.
2. Reconnect to use CertFP:
```
/msg *bouncer RECONNECT libera
```
The bouncer will now present the client certificate during TLS and
authenticate via SASL EXTERNAL.
3. Verify the fingerprint is registered:
```
/msg *bouncer CERTFP libera
```
### Certificate Storage
Certificates are stored alongside the config file:
```
{data_dir}/certs/
libera/
fabesune.pem # cert + private key (chmod 600)
oftc/
mynick.pem
```
## Bouncer Commands
Send a PRIVMSG to `*bouncer` (or `bouncer`) from your IRC client to inspect
and control the bouncer. All commands are case-insensitive.
Responses arrive as NOTICE messages from `*bouncer`.
### Inspection
| Command | Description |
|---------|-------------|
| `HELP` | List available commands |
| `STATUS` | Overview: state, nick, host per network |
| `INFO <network>` | Detailed info for one network (state, server, channels, creds) |
| `UPTIME` | Bouncer uptime since process start |
| `NETWORKS` | List all configured networks with state |
| `CREDS [network]` | NickServ credential status (all or per-network) |
| `CHANNELS [network]` | List joined channels with topics (all or per-network) |
| `CLIENTS` | List connected bouncer clients |
| `BACKLOG [network]` | Message counts per network and database size |
| `VERSION` | Bouncer and Python version |
### Network Control
| Command | Description |
|---------|-------------|
| `CONNECT <network>` | Start a disconnected network |
| `DISCONNECT <network>` | Stop a network |
| `RECONNECT <network>` | Stop and restart with a fresh identity |
| `NICK <network> <nick>` | Change nick on a network |
| `RAW <network> <command>` | Send a raw IRC command to a network |
### Config Management
| Command | Description |
|---------|-------------|
| `REHASH` | Reload config file, add/remove/reconnect networks |
| `ADDNETWORK <name> key=val ...` | Create a network at runtime |
| `DELNETWORK <name>` | Stop and remove a network |
| `AUTOJOIN <network> +/-#channel` | Add or remove channel from autojoin list |
**ADDNETWORK keys:** `host` (required), `port`, `tls` (yes/no), `nick`,
`channels` (comma-separated), `password`.
### NickServ
| Command | Description |
|---------|-------------|
| `IDENTIFY <network>` | Force NickServ IDENTIFY with stored credentials |
| `REGISTER <network>` | Trigger NickServ registration attempt |
| `DROPCREDS <network> [nick]` | Delete stored NickServ credentials |
### CertFP
| Command | Description |
|---------|-------------|
| `GENCERT <network> [nick]` | Generate client cert, auto-register with NickServ |
| `CERTFP [network]` | Show certificate fingerprints (all or per-network) |
| `DELCERT <network> [nick]` | Delete a client certificate |
### Examples
```
/msg *bouncer HELP
/msg *bouncer STATUS
/msg *bouncer INFO libera
/msg *bouncer CHANNELS
/msg *bouncer CLIENTS
/msg *bouncer BACKLOG
/msg *bouncer VERSION
/msg *bouncer CONNECT libera
/msg *bouncer DISCONNECT libera
/msg *bouncer RECONNECT libera
/msg *bouncer NICK libera newnick
/msg *bouncer RAW libera WHOIS someuser
/msg *bouncer REHASH
/msg *bouncer ADDNETWORK oftc host=irc.oftc.net port=6697 tls=yes channels=#test
/msg *bouncer DELNETWORK oftc
/msg *bouncer AUTOJOIN libera +#newchannel
/msg *bouncer AUTOJOIN libera -#oldchannel
/msg *bouncer IDENTIFY libera
/msg *bouncer REGISTER libera
/msg *bouncer DROPCREDS libera
/msg *bouncer DROPCREDS libera oldnick
/msg *bouncer GENCERT libera
/msg *bouncer GENCERT libera fabesune
/msg *bouncer CERTFP
/msg *bouncer CERTFP libera
/msg *bouncer DELCERT libera
/msg *bouncer DELCERT libera fabesune
```
### Example Output
```
[STATUS]
libera ready fabesune user/fabesune
oftc ready ceraty cloaked.user
hackint connecting (attempt 3)
quakenet ready spetyo --
[CHANNELS]
libera #test Welcome to the test channel
libera #dev
oftc #debian Debian support
[CLIENTS]
myuser 127.0.0.1:54321 connected 2h 15m 3s
[BACKLOG]
libera 1,500 messages
oftc 842 messages
DB size: 2.1 MB
```
## Stopping
Press `Ctrl+C` or send `SIGTERM`. The bouncer shuts down gracefully, closing
all network connections and the backlog database.