From 19199096c5ce8901df3c3ec196536b2d7acad815 Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Wed, 8 Jul 2026 19:03:53 +0300 Subject: [PATCH] promiscuous: per-interface toggle via netcfg (ip link set promisc) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LinkDevice trait gains is_promiscuous() and set_promiscuous(). EthernetLink stores promiscuous flag (default: false). Receive path bypasses MAC check when promiscuous enabled — captures all frames regardless of destination MAC. netcfg/ifaces/eth0/promiscuous rw: cat /scheme/netcfg/ifaces/eth0/promiscuous → 'off' or 'on' echo on > .../promiscuous → enable promiscuous mode echo off > .../promiscuous → disable Accepts: on/off/1/0/yes/no/true/false. Mirrors Linux 'ip link set dev promisc on/off'. Required for packet capture tools that need to see all traffic. --- netstack/src/link/ethernet.rs | 12 +++++++++++- netstack/src/link/mod.rs | 6 ++++++ netstack/src/scheme/netcfg/mod.rs | 25 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/netstack/src/link/ethernet.rs b/netstack/src/link/ethernet.rs index 3ea92ed955..21a90be99b 100644 --- a/netstack/src/link/ethernet.rs +++ b/netstack/src/link/ethernet.rs @@ -88,6 +88,7 @@ pub struct EthernetLink { qdisc_config: QdiscConfig, mtu: usize, enabled: bool, + promiscuous: bool, stats: Stats, arp_requests: u64, arp_replies: u64, @@ -125,6 +126,7 @@ impl EthernetLink { qdisc_config: QdiscConfig::default(), mtu: Self::MTU, enabled: true, + promiscuous: false, stats: Stats::default(), neighbor_cache: Default::default(), arp_requests: 0, @@ -799,7 +801,7 @@ impl LinkDevice for EthernetLink { (is_for_us, repr.ethertype) }; - if !is_for_us { + if !is_for_us && !self.promiscuous { continue; } @@ -970,5 +972,13 @@ impl LinkDevice for EthernetLink { fn remove_neighbor(&mut self, ip: IpAddress) -> bool { self.neighbor_cache.remove(&ip).is_some() } + + fn is_promiscuous(&self) -> bool { + self.promiscuous + } + + fn set_promiscuous(&mut self, enabled: bool) { + self.promiscuous = enabled; + } } diff --git a/netstack/src/link/mod.rs b/netstack/src/link/mod.rs index ebaf368843..23dda10e96 100644 --- a/netstack/src/link/mod.rs +++ b/netstack/src/link/mod.rs @@ -65,6 +65,12 @@ pub trait LinkDevice { false } + fn is_promiscuous(&self) -> bool { + false + } + + fn set_promiscuous(&mut self, _enabled: bool) {} + fn mtu(&self) -> usize { 1500 } diff --git a/netstack/src/scheme/netcfg/mod.rs b/netstack/src/scheme/netcfg/mod.rs index 50b56017ee..deb626b9d9 100644 --- a/netstack/src/scheme/netcfg/mod.rs +++ b/netstack/src/scheme/netcfg/mod.rs @@ -632,6 +632,31 @@ fn mk_root_node( } } |_cur_value| { Ok(()) } + }, + "promiscuous" => { + rw [devices] (Option, None) + || { + match devices.borrow().get("eth0") { + Some(dev) => if dev.is_promiscuous() { "on\n".to_string() } else { "off\n".to_string() }, + None => "Device not found\n".into(), + } + } + |cur_value, line| { + let s = line.trim(); + let enabled = match s { + "on" | "1" | "true" | "yes" => true, + "off" | "0" | "false" | "no" => false, + _ => return Err(SyscallError::new(syscall::EINVAL)), + }; + if let Some(dev) = devices.borrow_mut().get_mut("eth0") { + dev.set_promiscuous(enabled); + *cur_value = Some(enabled); + Ok(()) + } else { + Err(SyscallError::new(syscall::ENODEV)) + } + } + |_cur_value| { Ok(()) } } }, "lo" => {