Añadir src/main.rs

This commit is contained in:
nix 2025-06-28 02:32:12 +01:00
parent 72ed05bfa7
commit 5ea643dd9a

147
src/main.rs Normal file
View File

@ -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<Ipv4Addr> {
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<Progress> {
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::<Progress>(&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<String> {
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::<HashSet<String>>(&data) {
return ips;
}
}
}
HashSet::new()
}
async fn save_ips_up_background(ips: Arc<Mutex<HashSet<String>>>) {
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<Semaphore>, ips_up: Arc<Mutex<HashSet<String>>>) {
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::<Ipv4Addr>().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
}