From 155e804779604d38186acecebb72022f9edd6201 Mon Sep 17 00:00:00 2001 From: reverse Date: Wed, 19 Aug 2026 04:45:06 +0000 Subject: [PATCH] =?UTF-8?q?s2s:=20extend=20source=5Fbehind=20to=20FTOPIC/R?= =?UTF-8?q?ENAME/UID/OPERTYPE/REDACT=20=E2=80=94=20the=20guard=20was=20on?= =?UTF-8?q?=20plain=20TOPIC=20but=20not=20its=20S2S=20twin=20FTOPIC=20(a?= =?UTF-8?q?=20peer=20could=20forge=20a=20network-wide=20topic=20overwrite)?= =?UTF-8?q?,=20nor=20channel=20RENAME,=20UID=20(SID=20announce=20unchecked?= =?UTF-8?q?),=20OPERTYPE,=20or=20REDACT;=20all=20now=20validate=20the=20so?= =?UTF-8?q?urce=20lives=20behind=20the=20arriving=20link?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/link.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/link.rs b/src/link.rs index 315487f..774504b 100644 --- a/src/link.rs +++ b/src/link.rs @@ -872,8 +872,11 @@ impl Server { /// `: OPERTYPE :` — a remote user opered up; reflect it on their modes /// so the network's view of who is an operator stays consistent. - fn link_opertype_recv(&mut self, _from: Uid, msg: &Message) { + fn link_opertype_recv(&mut self, via: Uid, msg: &Message) { if let Some(src) = msg.source.as_deref() { + if !self.sourced_via(src, via) { + return; // a peer can't flag a user behind another link as oper + } if let Some(ru) = self.remote_users.get_mut(src) { if !ru.modes.contains('o') { ru.modes.push('o'); @@ -892,6 +895,9 @@ impl Server { let Some(src) = msg.source.clone() else { return; }; + if !self.source_behind(&src, via) { + return; // reject a forged message-deletion from behind another link + } let (target, msgid) = (msg.params[0].clone(), msg.params[1].clone()); if !target.starts_with('#') { return; @@ -1072,6 +1078,11 @@ impl Server { return; } let sid = msg.source.clone().unwrap_or_default(); + // the announcing server must actually sit behind the link this UID arrived on, + // else a peer could introduce phantom users under another server's SID + if !self.source_behind(&sid, via) { + return; + } let uuid = msg.params[0].clone(); // reject a malformed or duplicate UID instead of corrupting the routing // tables: the uuid is 9 chars carrying the announcing server's 3-char SID, @@ -1732,6 +1743,9 @@ impl Server { return; }; let reason = msg.params.get(2).cloned().unwrap_or_default(); + if !self.source_behind(&source, via) { + return; // reject a channel rename forged from behind another link + } let oldkey = old.to_ascii_lowercase(); if !self.channels.contains_key(&oldkey) { return; @@ -2069,6 +2083,9 @@ impl Server { let Some(src) = msg.source.clone() else { return; }; + if !self.source_behind(&src, via) { + return; // a peer can't set a topic sourced from behind another link + } if msg.params.len() < 4 { return; }