From 5ea643dd9a4cb5bf184ec0d7c2f7e0b83fe9ccac Mon Sep 17 00:00:00 2001 From: nix Date: Sat, 28 Jun 2025 02:32:12 +0100 Subject: [PATCH] =?UTF-8?q?A=C3=B1adir=20src/main.rs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.rs | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 src/main.rs diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..8eb4f40 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,147 @@ +use clap::Parser; +use reqwest::Client; +use serde::{Deserialize, Serialize}; +use std::{collections::HashSet, net::Ipv4Addr, path::Path, sync::Arc}; +use tokio::{fs, sync::{Semaphore, Mutex}}; + +const MAX_CONCURRENT_SCANS: usize = 500; +const PROGRESS_FILE: &str = "progress.json"; +const IPS_UP_FILE: &str = "ips_up.json"; + +#[derive(Parser, Debug)] +#[command(author, version, about = "Async IP Scanner", long_about = None)] +struct Args { + /// IP to start scanning from + #[arg(short, long, default_value = "0.0.0.0")] + start: String, +} + +#[derive(Serialize, Deserialize)] +struct Progress { + current_ip: String, +} + +fn increment_ip(ip: Ipv4Addr) -> Option { + let mut octets = ip.octets(); + for i in (0..4).rev() { + if octets[i] < 255 { + octets[i] += 1; + return Some(Ipv4Addr::from(octets)); + } else { + octets[i] = 0; + } + } + None +} + +async fn load_progress() -> Option { + if Path::new(PROGRESS_FILE).exists() { + if let Ok(data) = fs::read_to_string(PROGRESS_FILE).await { + if let Ok(progress) = serde_json::from_str::(&data) { + return Some(progress); + } + } + } + None +} + +async fn save_progress_background(ip: Ipv4Addr) { + tokio::spawn(async move { + let progress = Progress { + current_ip: ip.to_string(), + }; + if let Ok(data) = serde_json::to_string(&progress) { + let _ = fs::write(PROGRESS_FILE, data).await; + } + }); +} + +async fn load_ips_up() -> HashSet { + if Path::new(IPS_UP_FILE).exists() { + if let Ok(data) = fs::read_to_string(IPS_UP_FILE).await { + if let Ok(ips) = serde_json::from_str::>(&data) { + return ips; + } + } + } + HashSet::new() +} + +async fn save_ips_up_background(ips: Arc>>) { + let ips_clone = ips.clone(); + tokio::spawn(async move { + let lock = ips_clone.lock().await; + if let Ok(data) = serde_json::to_string(&*lock) { + let _ = fs::write(IPS_UP_FILE, data).await; + } + }); +} + +async fn scan_ip(ip: String, client: Client, sem: Arc, ips_up: Arc>>) { + let _permit = sem.acquire().await.unwrap(); + let url = format!("http://{}", ip); + match client.get(&url).send().await { + Ok(response) if response.status().is_success() => { + println!("{} is UP", ip); + let mut lock = ips_up.lock().await; + lock.insert(ip); + } + Ok(response) => { + println!("{} is DOWN (status {})", ip, response.status()); + } + Err(err) => { + println!("{} is DOWN (error: {})", ip, err); + } + } +} + +#[tokio::main] +async fn main() { + let args = Args::parse(); + + let starting_ip = args.start.parse::().unwrap_or(Ipv4Addr::new(0, 0, 0, 0)); + let saved_progress = load_progress().await; + let mut current_ip = saved_progress + .map(|p| p.current_ip.parse().unwrap_or(starting_ip)) + .unwrap_or(starting_ip); + + let ips_up = Arc::new(Mutex::new(load_ips_up().await)); + let client = Client::builder() + .timeout(std::time::Duration::from_secs(2)) + .build() + .unwrap(); + let sem = Arc::new(Semaphore::new(MAX_CONCURRENT_SCANS)); + let end_ip = Ipv4Addr::new(255, 255, 255, 255); + + while current_ip <= end_ip { + let mut handles = vec![]; + let mut ip_batch = vec![]; + + for _ in 0..MAX_CONCURRENT_SCANS { + ip_batch.push(current_ip); + if let Some(next_ip) = increment_ip(current_ip) { + current_ip = next_ip; + } else { + break; + } + } + + for ip in &ip_batch { + let ip_str = ip.to_string(); + let client_clone = client.clone(); + let sem_clone = sem.clone(); + let ips_clone = ips_up.clone(); + + handles.push(tokio::spawn(scan_ip(ip_str, client_clone, sem_clone, ips_clone))); + } + + for h in handles { + let _ = h.await; + } + + save_progress_background(current_ip).await; + save_ips_up_background(ips_up.clone()).await; + } + + println!("Finished scanning."); // lol, lmao even +}