Proof of concept mechanical port of ircnet/ircd to Rust as part of a bit about C being insecure for network services
0

Configure Feed

Select the types of activity you want to include in your feed.

ircd.rs / docs / superpowers / plans / 2026-06-15-p11-slice182-sanick-s2s.md
4.7 kB

P11 slice 182 — SANICK S2S propagation#

Problem#

SANICK <nick> <newnick> (slice 151/152, the SA* oper-override family) is local-target only: a remote/mirrored target gets a server NOTICE and nothing happens. The handler doc cites "the KILL-local scope" as the rationale — but slice 179 (KILL S2S propagation) closed exactly that gap, so the rationale is now stale. This slice is the natural continuation of the active S2S notify-propagation arc (177 METADATA, 178 WALLOPS, 179 KILL, 180 metrics): make an oper's forced rename of a remote user take effect network-wide.

Scope is SANICK only. SAJOIN/SAPART cross-link forcing (forced membership) is a separate mechanism (NJOIN/PART propagation from the home server) and is the named follow-on.

Design — route to the home server, reuse the local rename machinery#

Extension verbs must ride ENCAP (the slice-126 lesson: a bare unknown verb SQUITs a stricter peer). Server-authoritative, so server-prefixed like SU/METADATA:

:<our-sid> ENCAP * SANICK <target-uid> <newnick>

Broadcast to every peer (ENCAP *, apply-where-relevant). Only the target's home server acts: its apply_encap_sanick runs the same three calls the local sanick() success path runs — try_renamecommand::nick::apply_local_nick_changeforce_nick_uid. Because apply_local_nick_change already relays :<oldmask> NICK <new> to all peers + co-members + files WHOWAS + fires MONITOR, the actual rename then propagates network-wide as an ordinary NICK change (every other server updates its mirror from that, not from the ENCAP). On a transit / the oper's own server the inbound apply is a no-op (uid not local); the caller onward-relays the ENCAP verbatim split-horizon so it reaches the home server across hops.

This keeps SANICK transparent (slice-152 principle): network-wide it is indistinguishable from the user renaming itself.

Changes#

  1. leveva/src/s2s/sanick.rs (new):
    • pub fn propagate(ctx, uid, new) — broadcast :<sid> ENCAP * SANICK <uid> <new> to peers (ctx.peers.broadcast(None, …)); no-op when there are no peers. The fuzz seam (outbound).
    • pub(crate) fn apply_encap_sanick(_link, msg, ctx) — parse <uid> (params[2]) + <newnick> (params[3] or trailing); only if is_local_uid validate the nick, capture the record, try_rename (InUse → silent no-op, collision race), apply_local_nick_change, force_nick_uid. Non-local / unknown / malformed → no-op.
  2. leveva/src/s2s/forward.rs — add Some("SANICK") => super::sanick::apply_encap_sanick(...).
  3. leveva/src/s2s/mod.rsmod sanick;.
  4. leveva/src/command/sanick.rs — the remote branch (!is_local_uid): replace the NOTICE with a network-wide collision pre-check (uid_of(new) held by a different uid → 433 to the oper, immediate feedback) then s2s::sanick::propagate(ctx, &uid, &new); return no numeric on success (like KILL). The format 432 / 461 / 401 checks stay ahead of the locality branch.

Tests (TDD — RED first; inverse invariants + fuzz)#

s2s/sanick.rs:

  • home server (local uid): renames registry + force-nicks session (ForceNick) + co-member sees client-form :<oldmask> NICK <new> + WHOWAS filed.
  • inverse: non-local (mirrored) uid → no-op, mirror nick unchanged (waits for the NICK relay).
  • unknown uid → no-op; malformed newnick → no-op.
  • collision inverse: local uid, new held by another local user → no-op, both nicks survive.
  • propagate broadcasts the exact ENCAP * SANICK line to a linked peer; no-peers → no-op.
  • proptest (fuzz): arbitrary valid uid/nick — apply_encap_sanick never panics, and a propagate → apply_encap_sanick round-trip on the home server leaves the target holding new (when free), else unchanged.

command/sanick.rs:

  • remote target → broadcasts ENCAP * SANICK <uid> <newnick> to the peer mailbox, no NOTICE, no numeric to the oper.
  • remote target whose newnick is taken network-wide → 433 to the oper, nothing broadcast.
  • the existing local tests stay green (the local success path is untouched).

Gate#

cargo test -p leveva green (incl. new units + proptest); cargo clippy -p leveva --tests clean; cargo build -p leveva 0 warnings. No boot-golden (forced rename is a mailbox/peer effect the units assert; the resulting NICK line is characterized by existing nick goldens).

Follow-on#

SAJOIN/SAPART S2S propagation — route ENCAP * SAJOIN/SAPART to the home server, which runs its existing local force_join/force_part (whose JOIN/NJOIN/PART S2S relay then propagates).