Proof of concept mechanical port of ircnet/ircd to Rust as part of a bit about C being insecure for network services
4.6 kB
P11 slice 253 — +S service umode + KILL immunity#
Goal#
Add the charybdis +S (UMODE_SERVICE) user mode: a server-set-only umode (a client/oper
MODE +S is silently ignored — set only on an S2S burst) whose holder is immune to an
operator's KILL. The last named charybdis umode candidate in
[[leveva-user-mode-wiring]] (alongside +l locops, which needs a LOCOPS command first).
Charybdis reference (cloned to /tmp/charybdis-ref, verified)#
include/client.h:UMODE_SERVICE 0x0040;IsService(x) = (x)->umodes & UMODE_SERVICE.ircd/s_user.cumode parse switch:case 'S':(with'Z') justbreak;— "can only be set on burst". Confirms server-set-only — exactly how leveva already treats+ZSecure.extensions/no_kill_services.c(thecan_killhook): blocks a KILL only whenMyClient(killer)(the killing oper is local) and the targetIsService; replyERR_ISCHANSERVICE(484)"KILL %s :Cannot kill a network service", setsapproved = 0. An inbound server KILL is NOT blocked (a remote source failsMyClient) — services stay killable by servers (collisions/SQUIT cleanup). So leveva touches onlycommand/kill.rs, NOTs2s/kill.rs.ircd/s_serv.cburst (send_umode(NULL, target_p, 0, ubuf)): iterates the FULLuser_modes[]table — no SEND_UMODES subset — so+Srides the UID introduction.+Sis a global property (a service is a service network-wide), like leveva's+Z/+B/+W.
Divergences (documented)#
- Numeric:
481 ERR_NOPRIVILEGES, not484 ERR_ISCHANSERVICE. leveva's484isErrRestricted(IRCnet meaning); charybdis reassigned484toERR_ISCHANSERVICE. To avoid the collision leveva replies481(its existing KILL/privilege numeric) with the charybdis trailingCannot kill a network service. - Bit
0x20000(next free past+zOperwall0x10000), not charybdis's0x0040(that bit is leveva's native+WWebsocket). leveva bit space diverges from the oracle — standard.
Port checklist#
mode.rs—UserMode::Serviceappended last: enum,ALL(17→18),as_char'S',bit0x20000,flag_name"FLAGS_SERVICE",from_char,from_bit,Display. Predicatepub fn is_service(modes) -> bool.command/mode.rsumode— add'S'to the server-set-only silently-ignored arm ('o' | 'O' | 'r' | 'a' | 'W' | 'Z' | 'S'). NOT in the self-settable group, NOT inumode_diff(server-set-only, like+Z).command/kill.rs— after the victim UID is resolved (before the remote-route and local-eject branches), if the victim is+Sreply481"Cannot kill a network service" and eject/route nothing. Read modes from the registry record OR the net mirror (covers local + remote services).s2s/umode.rsSEND_UMODES— addUserMode::Service(network-visible global property, like+Z/+B). Updatesend_umodes_excludes_*(Service is in the propagates set, not the excludesmatches!) and theSEND_UMODES == 61 | …assertion.- 004 / ISUPPORT — bump
isupport.rs::user_modes_stringassert +registration.rsmyinfo_004assert:oOiwraWBxsgGZDRQz→oOiwraWBxsgGZDRQzS. - snapshots — 5 welcome-burst goldens gain the trailing
Son the 004 line; regenerate. - help — a
+Srow inhelp/USER_MODES.md(no new command → nohelp/<CMD>.md).
Tests (RED first)#
command/kill.rsunits: local+Svictim →481+ not ejected (inverse:-Svictim still ejected); remote+Svictim →481+ not routed; the reply trailing.command/mode.rsunits: a client/operMODE self +Sis silently ignored (no bit, no echo, no501);-Slikewise a no-op.golden_service.rs: boot one server; a client'sMODE +Sis silently ignored (221 shows noS);+Scannot be self-set. (KILL immunity is unit-tested —+Sneeds S2S to set on a real client, untestable in a single-server golden, same constraint as+Z.)service_proptest.rs(FUZZ):is_servicematches& 0x20000over arbitrary words; the bit is independent of neighbours; KILL immunity decided by+Salone; letter/bit uniqueness.
Out of scope (documented follow-ons)#
- WHOIS servicestring (
313"is a Network Service") + channel-list hiding for services (charybdism_whois.c) — a separate display slice. +llocops umode + LOCOPS command — needs a new command first.
Gate#
cargo test -p leveva green; cargo clippy -p leveva --tests clean; cargo build --workspace
0 warnings; the 5 welcome-burst snapshots' only diff is the new S letter.