Detect /verify/ URLs in NickServ notices and attempt automated
verification via SOCKS proxy (POST with token). If the page requires
a captcha, save creds as pending and log the URL for manual visit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add auth_service config field ("nickserv", "qbot", "none") to support
networks with non-standard auth systems. QuakeNet uses Q bot AUTH
instead of NickServ. Also bumps NickServ timeout from 15s to 30s.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
config: add optional proxy_host/proxy_port to NetworkConfig
router: resolve per-network proxy via _proxy_for() helper
commands: trigger REHASH reconnect on proxy config changes
network: send CERT ADD before CAP END to beat K-line race
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
proxy.py:
- Refactor connection logic into _connect_once() helper
- Fall back to remote DNS via SOCKS5 when local resolution fails
(enables .onion and proxy-only hostnames)
- Skip TLS hostname verification for .onion addresses (Tor routing
provides authentication)
network.py:
- Fall back from SASL EXTERNAL to PLAIN on 904 (same connection)
- Auto-register cert fingerprint with NickServ CERT ADD immediately
after SASL PLAIN success (903) and after RPL_WELCOME (001)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All three registration commands are now explicitly intercepted after
the client has authenticated. NICK gets a notice pointing to the
bouncer command; PASS and USER are silently dropped.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clients sending /nick are intercepted with a NOTICE pointing them
to /msg *bouncer NICK <network> <nick> instead. Prevents unmanaged
nick changes that bypass the bouncer's identity tracking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Users can now inspect bouncer state and manage it from their IRC client
by sending PRIVMSG to *bouncer (or bouncer). Supported commands:
HELP, STATUS, INFO, UPTIME, NETWORKS, CREDS. Responses arrive as
NOTICE messages. All commands are case-insensitive.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reconnect backoff sleeps (up to 300s) were not cancellable, causing
SIGKILL on container stop. Now _schedule_reconnect spawns a tracked
task that stop() cancels, enabling graceful shutdown within the
podman timeout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Filter out messages that are useless to bouncer clients:
- Server notices (prefix without !, NOTICE to */AUTH)
- MOTD numerics (375, 372, 376, 422)
- Welcome/stats numerics (001-005, 042, 250-255, 265-266)
- User mode changes (MODE to non-channel targets)
- CTCP queries and DCC requests (PRIVMSG with \x01, except ACTION)
- CTCP replies in NOTICE
Filter applies to both live dispatch and backlog replay. Purged
existing noise from the backlog database.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
irssi (and other IRC clients) only open a channel window when they see
a JOIN from their own nick. The synthetic JOINs were using the network
nick (e.g. pagumowa) but the client registered as tester -- mismatch.
Three changes:
- Synthetic JOIN prefix is now client_nick!user@bouncer
- 001 welcome uses the client's registered nick
- encode_nick/encode_message accept client_nick param to rewrite own
nicks from any network to the client's nick, so irssi recognizes
all self-actions consistently
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Multiplex all networks onto a single client connection using /network
suffixes on channels and nicks. PASS is now just the password (no
network prefix). Channels appear as #channel/network, foreign nicks as
nick/network, own nicks stay bare.
New namespace.py module with pure encode/decode functions. Router
tracks clients globally (not per-network), namespaces messages before
delivery. Client attaches to all networks on connect, sends synthetic
JOIN/TOPIC/NAMES for every channel across all networks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Send NICK and wait for server confirmation (up to 10s) before
issuing JOIN commands, ensuring channels are joined under the
correct identity.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Nick is now deterministically generated from the exit endpoint
hostname via seeded markov chain. Same exit IP always produces the
same nick. Config nick field is optional fallback only.
Registration uses generic ident (user/ident) and realname
(realname/unknown) instead of random markov words.
Also fixes compose env vars and build target to use podman-compose.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Preserve original server bytes in IRCMessage.raw and forward those
to clients, avoiding parse/format round-trip that altered messages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New docs/DEPLOY.md covering container image, compose config, volume
mounts, host networking, operations, and troubleshooting. Updated
README, INSTALL, CHEATSHEET, and DEBUG to reference it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Containerfile now only installs dependencies; source code and config
are mounted at runtime via compose volumes. Adds k8s-file log driver
and PYTHONUNBUFFERED for reliable container logging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Host network mode for direct access to SOCKS5 proxy on localhost.
Config volume mounted from ./config. Makefile targets: build, up,
down, logs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update README, PROJECT, ROADMAP, TASKS, TODO, USAGE, CHEATSHEET,
INSTALL, and DEBUG to reflect stealth connect, probation window,
markov nick generation, local DNS resolution, and multi-IP failover.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace uniform random chars with English bigram frequency table.
Enforces max 2 consecutive consonants for pronounceability. Nicks,
idents, and realnames now look like plausible human-chosen words.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Register with a fully random nick, user, and realname (no fixed
pattern) to avoid fingerprinting. Enter a 15s probation period
after registration -- if the server k-lines, reconnect with a
fresh identity. Only after surviving probation: switch to the
configured nick and join channels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Many SOCKS5 proxies cannot resolve hostnames reliably. Resolve
locally and iterate through all returned addresses until one
succeeds. Also exclude personal config from git.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Async Python IRC bouncer with SOCKS5 proxy support, multi-network
connections, password auth, and persistent SQLite backlog with replay.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>