Exponential backoff up to 300s made no sense with rotating Tor exits where each reconnect gets a fresh IP. Single 1s delay is sufficient. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
711 lines
21 KiB
Markdown
711 lines
21 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 probation
|
|
window (default 45s, configurable via `probation_seconds`). 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
|
|
(configurable via `backoff_steps`):
|
|
|
|
Reconnection delay is **1 second** (flat, no escalation). Each attempt gets a
|
|
fresh random identity and potentially a different exit IP.
|
|
|
|
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.
|
|
|
|
## Client TLS
|
|
|
|
The bouncer can accept TLS-encrypted connections from IRC clients. This
|
|
encrypts the password and all traffic between your client and the bouncer.
|
|
|
|
### Setup
|
|
|
|
```toml
|
|
[bouncer]
|
|
client_tls = true
|
|
```
|
|
|
|
On first start with `client_tls = true`, the bouncer auto-generates a
|
|
self-signed EC P-256 certificate at `{data_dir}/bouncer.pem` (10-year validity).
|
|
The certificate fingerprint is logged at startup.
|
|
|
|
### Custom Certificate
|
|
|
|
To use your own certificate (e.g. from Let's Encrypt):
|
|
|
|
```toml
|
|
[bouncer]
|
|
client_tls = true
|
|
client_tls_cert = "/path/to/fullchain.pem"
|
|
client_tls_key = "/path/to/privkey.pem"
|
|
```
|
|
|
|
If the cert and key are in the same PEM file, set only `client_tls_cert`.
|
|
|
|
### Client Examples
|
|
|
|
**irssi:**
|
|
```
|
|
/connect -tls -tls_verify no -password mypassword 127.0.0.1 6667
|
|
```
|
|
|
|
**weechat:**
|
|
```
|
|
/server add bouncer 127.0.0.1/6667 -password=mypassword -ssl -ssl_verify=0
|
|
/connect bouncer
|
|
```
|
|
|
|
**hexchat:**
|
|
|
|
Enable "Use SSL for all the servers on this network" and accept the
|
|
self-signed certificate.
|
|
|
|
### Verify with openssl
|
|
|
|
```bash
|
|
openssl s_client -connect 127.0.0.1:6667
|
|
```
|
|
|
|
## 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`.
|
|
|
|
## PING Watchdog
|
|
|
|
The bouncer sends periodic PING messages to detect stale server connections
|
|
(socket open but no data flowing). If no data is received within the configured
|
|
interval, a PING is sent. If the server doesn't respond within the timeout,
|
|
the connection is dropped and a reconnect is scheduled.
|
|
|
|
```toml
|
|
[bouncer]
|
|
ping_interval = 120 # seconds of silence before sending PING
|
|
ping_timeout = 30 # seconds to wait for PONG after PING
|
|
```
|
|
|
|
The watchdog starts automatically when a network enters the READY state.
|
|
Any received data (not just PONG) resets the timer.
|
|
|
|
## IRCv3 server-time
|
|
|
|
The bouncer requests the `server-time` IRCv3 capability on every connection.
|
|
When enabled by the server, timestamps on incoming messages are preserved and
|
|
forwarded to clients. When the server does not provide a timestamp, the bouncer
|
|
injects one using the current UTC time.
|
|
|
|
Backlog replay also includes timestamps from when messages were originally
|
|
stored, so clients that support `server-time` see accurate times on replayed
|
|
messages.
|
|
|
|
No client configuration is needed -- timestamps appear automatically if the
|
|
client supports IRCv3 message tags.
|
|
|
|
## Push Notifications
|
|
|
|
When no IRC clients are connected to the bouncer, highlights and private
|
|
messages can trigger push notifications via [ntfy](https://ntfy.sh) or a
|
|
generic webhook.
|
|
|
|
### Setup
|
|
|
|
```toml
|
|
[bouncer]
|
|
notify_url = "https://ntfy.sh/my-bouncer-topic"
|
|
notify_on_highlight = true # mentions of your nick in channels
|
|
notify_on_privmsg = true # private messages
|
|
notify_cooldown = 60 # min seconds between notifications
|
|
notify_proxy = false # route notifications through SOCKS5
|
|
```
|
|
|
|
### ntfy Example
|
|
|
|
```toml
|
|
notify_url = "https://ntfy.sh/my-secret-topic"
|
|
```
|
|
|
|
Install the ntfy app on your phone and subscribe to the topic. Notifications
|
|
include the sender, target, and message text.
|
|
|
|
### Generic Webhook
|
|
|
|
Any URL that does not contain `ntfy` in the hostname is treated as a generic
|
|
webhook. The bouncer POSTs JSON:
|
|
|
|
```json
|
|
{
|
|
"network": "libera",
|
|
"sender": "user",
|
|
"target": "#channel",
|
|
"text": "hey mynick, check this out"
|
|
}
|
|
```
|
|
|
|
### Behavior
|
|
|
|
- Notifications only fire when **no clients** are attached
|
|
- The cooldown prevents notification floods (one per `notify_cooldown` seconds)
|
|
- When `notify_proxy = true`, notification requests are routed through the
|
|
configured SOCKS5 proxy
|
|
|
|
## Configuration Reference
|
|
|
|
```toml
|
|
[bouncer]
|
|
bind = "127.0.0.1" # listen address
|
|
port = 6667 # listen port
|
|
password = "changeme" # client authentication password
|
|
|
|
# Client TLS
|
|
client_tls = false # enable TLS for client listener
|
|
client_tls_cert = "" # path to PEM cert (auto-generated if empty)
|
|
client_tls_key = "" # path to PEM key (or same file as cert)
|
|
|
|
# Captcha solving (NoCaptchaAI)
|
|
captcha_api_key = "" # API key (optional, for auto-verification)
|
|
captcha_poll_interval = 3 # seconds between solve polls
|
|
captcha_poll_timeout = 120 # max seconds to wait for solve
|
|
|
|
# Connection tuning
|
|
probation_seconds = 45 # post-connect watch period for k-lines
|
|
backoff_steps = [1] # reconnect delay (seconds)
|
|
nick_timeout = 10 # seconds to wait for nick change
|
|
rejoin_delay = 3 # seconds before rejoin after kick
|
|
http_timeout = 15 # per-request HTTP timeout
|
|
|
|
# Email verification
|
|
email_poll_interval = 15 # seconds between inbox checks
|
|
email_max_polls = 30 # max inbox checks (~7.5 min)
|
|
email_request_timeout = 20 # per-request timeout for email APIs
|
|
|
|
# Certificate generation
|
|
cert_validity_days = 3650 # client cert validity (~10 years)
|
|
|
|
# PING watchdog
|
|
ping_interval = 120 # seconds of silence before sending PING
|
|
ping_timeout = 30 # seconds to wait for PONG after PING
|
|
|
|
# Push notifications
|
|
notify_url = "" # ntfy or webhook URL (empty = disabled)
|
|
notify_on_highlight = true # notify on nick mentions
|
|
notify_on_privmsg = true # notify on private messages
|
|
notify_cooldown = 60 # min seconds between notifications
|
|
notify_proxy = false # route notifications through SOCKS5
|
|
|
|
# Background account farming
|
|
farm_enabled = false # enable background registration
|
|
farm_interval = 3600 # seconds between attempts per network
|
|
farm_max_accounts = 10 # max verified accounts per network
|
|
|
|
[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)
|
|
channel_keys = { "#secret" = "hunter2" } # keys for +k channels (optional)
|
|
autojoin = true # auto-join channels on ready (default: true)
|
|
password = "" # IRC server password (optional, for PASS command)
|
|
```
|
|
|
|
## Automatic Captcha Solving
|
|
|
|
Some IRC networks (e.g. OFTC) require visiting a URL with hCaptcha to verify
|
|
nick registration. The bouncer can solve these automatically using NoCaptchaAI.
|
|
|
|
### Setup
|
|
|
|
1. Sign up at [dash.nocaptchaai.com](https://dash.nocaptchaai.com) (free tier: 6000 solves/month)
|
|
2. Copy your API key from the dashboard
|
|
3. Add to config:
|
|
```toml
|
|
[bouncer]
|
|
captcha_api_key = "your-api-key-here"
|
|
```
|
|
4. Reload config:
|
|
```
|
|
/msg *bouncer REHASH
|
|
```
|
|
|
|
### How It Works
|
|
|
|
When NickServ sends a verification URL containing `/verify/`:
|
|
|
|
1. The bouncer fetches the page via the SOCKS proxy
|
|
2. If hCaptcha is detected and an API key is configured, it submits the
|
|
challenge to NoCaptchaAI for solving (all traffic routed through the proxy)
|
|
3. The solved token is submitted with the verification form
|
|
4. On success, the nick is promoted from `pending` to `verified` status
|
|
|
|
If no API key is set, or solving fails, the URL is stored as `pending` and
|
|
shown via the `CREDS` command for manual verification.
|
|
|
|
## 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 [key]` | Add channel (with optional key for +k channels) |
|
|
| `AUTOJOIN <network> -#channel` | Remove channel from autojoin list |
|
|
|
|
**ADDNETWORK keys:** `host` (required), `port`, `tls` (yes/no), `nick`,
|
|
`channels` (comma-separated), `channel_keys` (`#chan=key,...`), `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 |
|
|
|
|
### Account Farming
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `FARM` | Global farming status (enabled/disabled, per-network stats) |
|
|
| `FARM <network>` | Network stats + trigger an immediate registration attempt |
|
|
| `ACCOUNTS [network]` | List all stored accounts with verified/pending counts |
|
|
|
|
### 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 +#secret hunter2
|
|
/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
|
|
/msg *bouncer FARM
|
|
/msg *bouncer FARM libera
|
|
/msg *bouncer ACCOUNTS
|
|
/msg *bouncer ACCOUNTS libera
|
|
```
|
|
|
|
### 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
|
|
```
|
|
|
|
## Background Account Farming
|
|
|
|
The bouncer can automatically grow a pool of verified NickServ accounts across
|
|
all configured networks. Primary connections stay active with SASL-authenticated
|
|
identities while ephemeral connections register new nicks in the background.
|
|
|
|
### Setup
|
|
|
|
```toml
|
|
[bouncer]
|
|
farm_enabled = true
|
|
farm_interval = 3600 # seconds between attempts per network
|
|
farm_max_accounts = 10 # max verified accounts per network
|
|
```
|
|
|
|
### How It Works
|
|
|
|
1. A sweep loop runs every 60 seconds (after an initial 60s stabilization delay)
|
|
2. For each NickServ-enabled network, it checks:
|
|
- Is there already an active farming attempt? (skip)
|
|
- Has the cooldown (`farm_interval`) elapsed since the last attempt? (skip)
|
|
- Are there already `farm_max_accounts` verified accounts? (skip)
|
|
3. If eligible, an ephemeral connection is spawned with a random nick
|
|
4. The ephemeral goes through the full registration lifecycle: REGISTER, email
|
|
verification (or captcha), and credential storage
|
|
5. Credentials are saved under the real network name, not the ephemeral's
|
|
internal `_farm_` prefix
|
|
6. Each ephemeral has a 15-minute deadline before being terminated
|
|
7. Ephemeral connections are invisible to IRC clients (no status broadcasts,
|
|
no channel joins)
|
|
|
|
### Commands
|
|
|
|
| Command | What it does |
|
|
|---------|-------------|
|
|
| `FARM` | Global overview: enabled/disabled, interval, per-network stats |
|
|
| `FARM <network>` | Network stats + triggers an immediate registration attempt |
|
|
| `ACCOUNTS` | List all stored accounts with verified/pending counts |
|
|
| `ACCOUNTS <network>` | Accounts for a specific network |
|
|
|
|
### Configuration Reference
|
|
|
|
```toml
|
|
[bouncer]
|
|
farm_enabled = false # enable background registration (default: off)
|
|
farm_interval = 3600 # seconds between attempts per network
|
|
farm_max_accounts = 10 # stop farming when this many verified accounts exist
|
|
```
|
|
|
|
## Channel Keys
|
|
|
|
Channels with mode `+k` require a key to join. Configure keys in TOML:
|
|
|
|
```toml
|
|
[networks.libera]
|
|
channels = ["#secret", "#public"]
|
|
channel_keys = { "#secret" = "hunter2" }
|
|
```
|
|
|
|
Keys are used automatically during autojoin and KICK rejoin. To add a keyed
|
|
channel at runtime:
|
|
|
|
```
|
|
/msg *bouncer AUTOJOIN libera +#secret hunter2
|
|
```
|
|
|
|
Removing a channel also clears its key:
|
|
|
|
```
|
|
/msg *bouncer AUTOJOIN libera -#secret
|
|
```
|
|
|
|
## DCC Stripping
|
|
|
|
DCC requests (`DCC SEND`, `DCC CHAT`) embed the sender's real IP address in the
|
|
protocol payload. The bouncer strips all DCC and non-ACTION CTCP messages in
|
|
both directions:
|
|
|
|
- **Inbound** (server to client): silently dropped, logged as warning
|
|
- **Outbound** (client to server): blocked before reaching the network
|
|
|
|
ACTION (`/me`) is preserved. This is a hard security boundary -- there is no
|
|
config toggle to disable it.
|
|
|
|
## Hot Reload
|
|
|
|
The bouncer reloads its config file on `SIGHUP` or via the `REHASH` command.
|
|
Both use the same logic: re-read TOML, diff networks (add/remove/reconnect),
|
|
and update mutable fields (channels, channel_keys, nick, password).
|
|
|
|
### SIGHUP
|
|
|
|
```bash
|
|
kill -HUP $(pidof bouncer)
|
|
```
|
|
|
|
Results are logged (no client connection needed). Useful for headless
|
|
operation (systemd, containers).
|
|
|
|
### REHASH command
|
|
|
|
```
|
|
/msg *bouncer REHASH
|
|
```
|
|
|
|
Results are sent back as NOTICE messages.
|
|
|
|
### What changes on reload
|
|
|
|
| Field | Effect |
|
|
|-------|--------|
|
|
| Network host/port/tls/proxy | Network reconnected |
|
|
| channels, channel_keys, nick, password | Updated in-place |
|
|
| notify_url, notify_cooldown, etc. | Notifier recreated |
|
|
| farm_enabled, farm_interval, etc. | Farm started/stopped |
|
|
| bind, port, password, client_tls | Warning logged (restart required) |
|
|
|
|
## Systemd
|
|
|
|
The bouncer ships with a systemd user service file. See [INSTALL.md](INSTALL.md)
|
|
for setup. Key operations:
|
|
|
|
```bash
|
|
systemctl --user start bouncer # start
|
|
systemctl --user stop bouncer # stop
|
|
systemctl --user reload bouncer # hot reload (SIGHUP)
|
|
journalctl --user -u bouncer -f # follow logs
|
|
```
|
|
|
|
The service restarts automatically on failure (`RestartSec=10`).
|
|
|
|
## Stopping
|
|
|
|
Press `Ctrl+C` or send `SIGTERM`. The bouncer shuts down gracefully, closing
|
|
all network connections and the backlog database.
|