use std::time::Duration;
pub fn is_monitor_mode(iface: &str) -> bool {
let output = std::process::Command::new("iw")
.args(["dev", iface, "info"])
.output();
match output {
Ok(o) => {
let s = String::from_utf8_lossy(&o.stdout);
s.contains("type monitor")
}
Err(_) => false,
}
}
pub fn get_iface_type(iface: &str) -> String {
let output = std::process::Command::new("iw")
.args(["dev", iface, "info"])
.output();
match output {
Ok(o) => {
let s = String::from_utf8_lossy(&o.stdout);
for line in s.lines() {
let trimmed = line.trim();
if trimmed.starts_with("type ") {
return trimmed.strip_prefix("type ").unwrap_or("unknown").to_string();
}
}
"unknown".to_string()
}
Err(_) => "error".to_string(),
}
}
pub fn is_root() -> bool {
unsafe { libc::geteuid() == 0 }
}
fn kill_interfering_processes() {
let _ = std::process::Command::new("airmon-ng")
.args(["check", "kill"])
.output();
for proc in &["wpa_supplicant", "NetworkManager", "dhclient"] {
let _ = std::process::Command::new("pkill")
.args(["-f", proc])
.output();
}
std::thread::sleep(Duration::from_millis(500));
}
pub fn enable_monitor_mode(iface: &str) -> Result<String, String> {
if is_monitor_mode(iface) {
return Ok(iface.to_string());
}
eprintln!("[*] Killing interfering processes...");
kill_interfering_processes();
eprintln!("[*] Setting {} down...", iface);
let down = std::process::Command::new("ip")
.args(["link", "set", iface, "down"])
.output()
.map_err(|e| format!("Failed to run ip: {}", e))?;
if !down.status.success() {
return Err(format!(
"Failed to bring {} down: {}",
iface,
String::from_utf8_lossy(&down.stderr)
));
}
eprintln!("[*] Setting monitor mode via iw...");
let monitor = std::process::Command::new("iw")
.args(["dev", iface, "set", "type", "monitor"])
.output()
.map_err(|e| format!("Failed to run iw: {}", e))?;
if monitor.status.success() {
eprintln!("[*] Bringing {} up...", iface);
let up = std::process::Command::new("ip")
.args(["link", "set", iface, "up"])
.output()
.map_err(|e| format!("Failed to run ip: {}", e))?;
if !up.status.success() {
return Err(format!(
"Failed to bring {} up: {}",
iface,
String::from_utf8_lossy(&up.stderr)
));
}
std::thread::sleep(Duration::from_millis(500));
if is_monitor_mode(iface) {
return Ok(iface.to_string());
}
}
eprintln!("[*] iw method failed, trying airmon-ng...");
let _ = std::process::Command::new("ip")
.args(["link", "set", iface, "up"])
.output();
let airmon = std::process::Command::new("airmon-ng")
.args(["start", iface])
.output();
match airmon {
Ok(o) if o.status.success() => {
let s = String::from_utf8_lossy(&o.stdout);
let mon_name = format!("{}mon", iface);
if is_monitor_mode(&mon_name) {
return Ok(mon_name);
}
if is_monitor_mode(iface) {
return Ok(iface.to_string());
}
for line in s.lines() {
if line.contains("monitor mode") || line.contains("enabled") {
if let Some(start) = line.find('(') {
if let Some(end) = line.find(')') {
let candidate = &line[start + 1..end];
if candidate.contains("mon") && is_monitor_mode(candidate) {
return Ok(candidate.to_string());
}
}
}
}
}
Err("airmon-ng ran but monitor mode not confirmed".to_string())
}
_ => Err(format!(
"Could not enable monitor mode on {}. Check that your adapter supports monitor mode.",
iface
)),
}
}
pub fn disable_monitor_mode(iface: &str) {
let _ = std::process::Command::new("ip")
.args(["link", "set", iface, "down"])
.output();
let _ = std::process::Command::new("iw")
.args(["dev", iface, "set", "type", "managed"])
.output();
let _ = std::process::Command::new("ip")
.args(["link", "set", iface, "up"])
.output();
let _ = std::process::Command::new("systemctl")
.args(["start", "NetworkManager"])
.output();
}