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-09-p11-slice47-who-whois-whox-parity.md
8.0 kB

P11 slice 47 — WHO / WHOIS / WHOX parity (full)#

Why this slice#

The third parity-matrix slice (user-chosen: "WHO / WHOIS / WHOX", then "Full parity"). Unlike slices 45/46 (which confirmed an already-sound implementation), this slice closes real gaps found while scoping leveva against the oracle (ircd-common s_user.rs m_who/who_one/parse_who_arg/m_whois):

  1. WHOX is entirely missing. The oracle advertises WHOX in 005, parses the WHO second argument for the legacy o opers-only filter and a %fields[,token] selector, and emits 354 RPL_WHOSPCRPL built field-by-field. leveva's who() ignores the second arg completely and isupport::tokens() does not advertise WHOX.

  2. Coupled classic-WHO/WHOIS gaps, now visible because S2S landed after WHO/WHOIS. leveva hardcodes, for every user: server = ctx.name, hopcount = 0, and no * oper flag. With remote users now in the registry (UNICK, slice 31+), a remote user's 352 server/hop and WHOIS 312 server wrongly name leveva itself instead of the user's real server. The Network mirror (ctx.net.server(sid)) already holds the server name + hopcount needed to fix this.

The end state: WHO/WHOIS/WHOX are correct for local and remote users, and WHOX is a real advertised feature.

Oracle reference (the contract to match)#

ircd-common/src/s_user.rs:

  • parse_who_arg (s_user.c:1886): if the arg's first char is o → opers-only. From the first %, each subsequent char sets a field flag; a , begins the token (≤ 3 chars, stored raw). Field letters: t c u i h s n f d l a o S U r (note: lowercase o = op-level field, distinct from the leading o opers-only filter).
  • who_one (s_user.c:1685): status = {G|H} then * if is_an_oper, then @/+. If any field flag beyond opers-only is set → emit 354 with the head :<server> 354 <req> then, in this fixed order, each requested field: t(token|0) c(chan|*) u(user) i(ip) h(host) s(server) n(nick) f(status) d(hop) l(idle; 0 for non-local) a(0) o(n/a) S(sid) U(uid) r( :realname). Else → the classic 352.
  • m_who (s_user.c:1969): parc<2who_find(NULL) + 315 *. parc>2parse_who_arg. Per comma mask: 0→all (chan *), *→all, a channel name → who_channel, an exact client → who_one, else glob who_find; each mask closes with 315 <mask>.
  • m_whois: 312 RPL_WHOISSERVER carries (*user)->server + the server's info string.

leveva mapping & deliberate divergences#

Oracle field leveva source Note
s server name, 312 local: ctx.name; remote: ctx.net.server(sid_of_uid(uid)).name the core remote-field fix
d hop / 352 trailing <hop> local: 0; remote: ctx.net.server(...).hopcount
S SID uid.as_str()[..4] (works for local & remote)
U UID rec.uid
f status `{G H}+*if+o/+O+@/+`
i IP rec.host divergence: leveva has no DNS-resolved host distinct from the peer IP, so %i == %h. Documented.
l idle 0 divergence: leveva has no idle counter (oracle also emits 0 for non-local).
a account 0 matches oracle constant (no SASL).
o op-level n/a matches oracle constant.
312 server info local: ctx.description; remote: ctx.net.server(...). description? RemoteServer has no description field → use a constant "server" placeholder, documented.

Remote-server-info for 312: RemoteServer carries no description, so a remote 312 uses a fixed placeholder string (documented divergence — the oracle has the real burst description, a field leveva never mirrored). The server name (the load-bearing routing identity) is correct.

Design#

New leveva/src/command/who_opts.rs (or inline in who.rs): a WhoOpts struct (opers_only: bool, fields: WhoFields bitset-or-bools, token: Option<String>) + a pure parse_who_arg(arg: &str) -> WhoOpts matching the oracle letter-for-letter. Pure → unit- and proptest-friendly, and the natural differential candidate (but the oracle parse_who_arg is unsafe extern "C" over raw *mut c_char + a who_opts C struct — not a clean pure entry, so no leveva-integration differential, as with every recent leveva-native slice; pinned by unit + proptest + golden).

A server_view(ctx, uid) -> (server_name: String, hopcount: u16, sid: String) helper resolves local-vs-remote once, used by both 352/354 (WHO) and 312 (WHOIS).

who_reply gains the * oper flag + remote server/hop. A new whox_reply builds 354 field-by-field in the oracle order. who() calls parse_who_arg on params()[1], applies the opers-only filter in every sweep (channel, all-users, exact, glob), and dispatches to whox_reply when fields is non-empty else who_reply.

isupport::tokens() gains "WHOX".

TDD checklist (RED → GREEN per step, one commit each)#

Tests first, always paired with inverses.

  1. parse_who_arg unit tests (in who.rs): o sets opers-only; %cn sets chan+nick only; %tcuihsnfdlaorSU,123 sets all + token 123; o%cn legacy combo; token > 3 chars ignored; % with junk letters ignored; empty/no-% → no fields. Inverse: a field not named is unset.
  2. 354 field-by-field unit tests: each field renders in the right slot; WHO #c %cn, %tcuhsnfdlaorSU full line; token present vs absent (0); channel * for a user sweep.
  3. classic 352 parity unit tests: an oper shows * in f (H*, H*@); inverse — deopering clears *. The o filter drops non-opers from a channel/all sweep; inverse — without o they reappear.
  4. remote-user unit tests (new testutil claim_remote helper: a 0XYZ… UID + a RemoteServer{0XYZ, peer.test, hop 2} in ctx.net): WHO %s/352 server = peer.test, %d/trailing hop = 2, %S = 0XYZ; WHOIS 312 server = peer.test. Inverse: a local user still shows ctx.name/0/our sid.
  5. WHOIS 312 remote unit test (covered by 4) + ensure local WHOIS unchanged.
  6. isupport test: tokens() includes WHOX.
  7. Boot golden golden_whox.rs (NEW): a real client WHO #chan %tcuhnfr,42 → snapshot the 354 lines + 315; plus a classic WHO #chan still works; plus an oper * flag line.
  8. Boot golden golden_s2s_who.rs (NEW — the REQUIRED S2S test per the cluster skill): on the s2s.kdl fixture, NJOIN/UNICK a remote user into a shared channel; a local client WHO #hub shows the remote user's 352 with server = the peer's name and hop ≥ 1 (not leveva); WHOIS <remote>312 names the peer; WHO #hub %s354 server field = peer. Inverse: after the peer drops (slice 46 teardown), WHO/WHOIS no longer list it.
  9. proptest whox_proptest.rs (NEW): random %-field subsets + token → the rendered 354 has exactly the requested fields in the canonical order and is well-formed CRLF; a second prop feeds arbitrary bytes after WHO #x for panic-freedom. (Extend the existing who_proptest model only if cheap; otherwise a focused field-order model.)

Verification gate#

cargo build --workspace 0 warnings; cargo clippy -p leveva --tests clean; new + existing who/whois goldens & proptests green (golden_who/_whois/_whox/_s2s_who, who_proptest/whois_proptest/whox_proptest); sibling S2S goldens still green. Update PLAN.md P11 row + append to PLAN-P11-progress.md (n/a — P11 uses the progress log) and docs/progress-log/p11.md; update the leveva-next-step-s2s-completeness memory.

Classification / S2S#

WHO and WHOIS are handler clusters that format remote-user fields (server/hop/SID) → an L2-S2S test is REQUIRED (step 8), not deferred. No oracle differential (the oracle entry points are unsafe/global-buffer); parity pinned by unit + proptest + boot-golden + S2S-golden.