promiscuous: per-interface toggle via netcfg (ip link set promisc)

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.
This commit is contained in:
Red Bear OS
2026-07-08 19:03:53 +03:00
parent c899b42d36
commit 19199096c5
3 changed files with 42 additions and 1 deletions
+11 -1
View File
@@ -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;
}
}
+6
View File
@@ -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
}
+25
View File
@@ -632,6 +632,31 @@ fn mk_root_node(
}
}
|_cur_value| { Ok(()) }
},
"promiscuous" => {
rw [devices] (Option<bool>, 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" => {