mirror of
https://github.com/Astatin3/rust-scan-mc.git
synced 2026-06-09 00:18:02 -06:00
Add scan after search functionality
This commit is contained in:
+8
-4
@@ -109,6 +109,10 @@ impl DatabaseResult {
|
|||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sameas(&self, other: &DatabaseResult) -> bool {
|
||||||
|
return self.port == other.port && self.ip == other.ip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn join_nums(nums: &Vec<i32>, sep: &str) -> String {
|
pub fn join_nums(nums: &Vec<i32>, sep: &str) -> String {
|
||||||
@@ -238,7 +242,7 @@ impl ResultDatabase {
|
|||||||
|
|
||||||
pub fn add_data_row(
|
pub fn add_data_row(
|
||||||
&self,
|
&self,
|
||||||
results: Vec<DatabaseResult>,
|
results: &Vec<DatabaseResult>,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut string_rows = Vec::with_capacity(results.len()); // Pre-allocate capacity
|
let mut string_rows = Vec::with_capacity(results.len()); // Pre-allocate capacity
|
||||||
|
|
||||||
@@ -251,7 +255,7 @@ impl ResultDatabase {
|
|||||||
|
|
||||||
pub fn save_rows(
|
pub fn save_rows(
|
||||||
&self,
|
&self,
|
||||||
string_rows: Vec<DatabaseResult>,
|
string_rows: Vec<&DatabaseResult>,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let db = Arc::new(DB::open_cf(&self.options, &self.path, &self.columns)?);
|
let db = Arc::new(DB::open_cf(&self.options, &self.path, &self.columns)?);
|
||||||
|
|
||||||
@@ -273,7 +277,7 @@ impl ResultDatabase {
|
|||||||
let length = string_rows.len();
|
let length = string_rows.len();
|
||||||
|
|
||||||
// Split the rows into chunks for parallel processing
|
// Split the rows into chunks for parallel processing
|
||||||
let chunks: Vec<Vec<DatabaseResult>> = string_rows
|
let chunks: Vec<Vec<&DatabaseResult>> = string_rows
|
||||||
.chunks(BATCH_SIZE)
|
.chunks(BATCH_SIZE)
|
||||||
.map(|chunk| chunk.to_vec())
|
.map(|chunk| chunk.to_vec())
|
||||||
.collect();
|
.collect();
|
||||||
@@ -290,7 +294,7 @@ impl ResultDatabase {
|
|||||||
|
|
||||||
for row in chunk {
|
for row in chunk {
|
||||||
let key = row.get_addr();
|
let key = row.get_addr();
|
||||||
println!("{}", key);
|
// println!("{}", key);
|
||||||
let key = key.as_bytes();
|
let key = key.as_bytes();
|
||||||
|
|
||||||
batch.put_cf(cf_addr, key, key);
|
batch.put_cf(cf_addr, key, key);
|
||||||
|
|||||||
+83
-17
@@ -16,7 +16,7 @@ use rand::{
|
|||||||
seq::{IteratorRandom, SliceRandom},
|
seq::{IteratorRandom, SliceRandom},
|
||||||
};
|
};
|
||||||
use untitled::{
|
use untitled::{
|
||||||
database::ResultDatabase,
|
database::{DatabaseResult, ResultDatabase},
|
||||||
online_scan,
|
online_scan,
|
||||||
parse_ip_range::{self, extract_ipv4_from_file, generate_random_ipv4_addresses},
|
parse_ip_range::{self, extract_ipv4_from_file, generate_random_ipv4_addresses},
|
||||||
port_scan::tcp_scan,
|
port_scan::tcp_scan,
|
||||||
@@ -76,7 +76,26 @@ enum Commands {
|
|||||||
query: Vec<String>,
|
query: Vec<String>,
|
||||||
/// Select N random results
|
/// Select N random results
|
||||||
#[arg(short, long, default_value_t = 0)]
|
#[arg(short, long, default_value_t = 0)]
|
||||||
random: usize,
|
num: usize,
|
||||||
|
|
||||||
|
/// Scan results again before printing
|
||||||
|
#[arg(short, long, default_value_t = false)]
|
||||||
|
rescan: bool,
|
||||||
|
/// (For Rescan only) Size of block of IPs to scan
|
||||||
|
#[arg(short, long, default_value_t = 4096)]
|
||||||
|
batch_size: usize,
|
||||||
|
/// (For Rescan only) The top N most common ports to scan
|
||||||
|
#[arg(short, long, default_value_t = 150)]
|
||||||
|
n_ports: usize,
|
||||||
|
/// (For Rescan only) Timeout for requests
|
||||||
|
#[arg(short, long, default_value_t = 3000)]
|
||||||
|
timeout_ms: u64,
|
||||||
|
/// (For Rescan only) Delay between icmp echo requests
|
||||||
|
#[arg(short, long, default_value_t = 80)]
|
||||||
|
ping_delay_micros: u64,
|
||||||
|
/// (For Rescan only) Delay between tcp syn packets
|
||||||
|
#[arg(short, long, default_value_t = 100)]
|
||||||
|
syn_tcp_delay_micros: u64,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,30 +338,74 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Commands::Search { query, random } => {
|
Commands::Search {
|
||||||
|
query,
|
||||||
|
num,
|
||||||
|
rescan,
|
||||||
|
|
||||||
|
batch_size,
|
||||||
|
n_ports,
|
||||||
|
timeout_ms,
|
||||||
|
ping_delay_micros,
|
||||||
|
syn_tcp_delay_micros,
|
||||||
|
} => {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
if let Ok(query) = query::search(query) {
|
if let Ok(query) = query::search(query) {
|
||||||
let results = database.search(query);
|
let results = database.search(query);
|
||||||
if let Ok(results) = results {
|
if let Ok(results) = results {
|
||||||
let total_len = results.len();
|
let total_len = results.len();
|
||||||
if random != 0 {
|
|
||||||
let local_len = min(random, total_len);
|
let results = if num != 0 {
|
||||||
let results = results.iter().choose_multiple(&mut rng(), local_len);
|
results
|
||||||
|
.into_iter()
|
||||||
|
.choose_multiple(&mut rng(), min(num, total_len))
|
||||||
|
} else {
|
||||||
|
results
|
||||||
|
};
|
||||||
|
|
||||||
|
let results = if rescan {
|
||||||
|
let scan_results = scan(
|
||||||
|
batch_size,
|
||||||
|
&database,
|
||||||
|
results
|
||||||
|
.iter()
|
||||||
|
.map(|r| IpAddr::from_str(&r.ip).unwrap())
|
||||||
|
.collect::<Vec<IpAddr>>(),
|
||||||
|
ports::PORTS[0..n_ports].to_vec(),
|
||||||
|
Duration::from_millis(timeout_ms),
|
||||||
|
Duration::from_micros(ping_delay_micros),
|
||||||
|
Duration::from_micros(syn_tcp_delay_micros),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Filter out only ips and ports which are the same
|
||||||
|
scan_results
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|curresult| {
|
||||||
|
for prevresult in &results {
|
||||||
|
if prevresult.sameas(&curresult) {
|
||||||
|
return Some(curresult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect::<Vec<DatabaseResult>>()
|
||||||
|
} else {
|
||||||
|
results
|
||||||
|
};
|
||||||
|
|
||||||
|
let len = results.len();
|
||||||
|
|
||||||
for result in results {
|
for result in results {
|
||||||
println!("{}", result.to_string());
|
println!("{}", result.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"{} results in {}ms, selected {}",
|
"{} results in {}ms, selected {}",
|
||||||
total_len,
|
total_len,
|
||||||
start.elapsed().as_millis(),
|
start.elapsed().as_millis(),
|
||||||
local_len
|
len
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
for result in results {
|
|
||||||
println!("{}", result.to_string());
|
|
||||||
}
|
|
||||||
println!("{} results in {}ms", total_len, start.elapsed().as_millis());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -359,12 +422,13 @@ fn scan(
|
|||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
ping_delay: Duration,
|
ping_delay: Duration,
|
||||||
tcp_delay: Duration,
|
tcp_delay: Duration,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<Vec<DatabaseResult>, Box<dyn std::error::Error>> {
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let mut server_count = 0;
|
let mut server_count = 0;
|
||||||
|
|
||||||
let chunks = hosts.chunks(batch_size);
|
let chunks = hosts.chunks(batch_size);
|
||||||
let num_chunks = chunks.len();
|
let num_chunks = chunks.len();
|
||||||
|
let mut results: Vec<DatabaseResult> = Vec::new();
|
||||||
for (i, hosts) in chunks.enumerate() {
|
for (i, hosts) in chunks.enumerate() {
|
||||||
let hosts = hosts.to_vec();
|
let hosts = hosts.to_vec();
|
||||||
let length = hosts.len();
|
let length = hosts.len();
|
||||||
@@ -383,10 +447,12 @@ fn scan(
|
|||||||
let tcp_results = tcp_scan::tcp_scan(up_hosts, &ports, timeout, tcp_delay);
|
let tcp_results = tcp_scan::tcp_scan(up_hosts, &ports, timeout, tcp_delay);
|
||||||
println!("Finished port scan");
|
println!("Finished port scan");
|
||||||
|
|
||||||
let service_results = scan_services(tcp_results, min(50, up_len), timeout);
|
let mut service_results = scan_services(tcp_results, min(50, up_len), timeout);
|
||||||
println!("Finished service scan");
|
println!("Finished service scan");
|
||||||
server_count += service_results.len();
|
server_count += service_results.len();
|
||||||
let _ = database.add_data_row(service_results);
|
let _ = database.add_data_row(&service_results)?;
|
||||||
|
|
||||||
|
results.append(&mut service_results);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Total Servers: {}", server_count);
|
println!("Total Servers: {}", server_count);
|
||||||
@@ -394,5 +460,5 @@ fn scan(
|
|||||||
println!("Total Elapsed: {} min", elapsed);
|
println!("Total Elapsed: {} min", elapsed);
|
||||||
println!("Rate: {} servers/min", (server_count as f32 / elapsed));
|
println!("Rate: {} servers/min", (server_count as f32 / elapsed));
|
||||||
|
|
||||||
Ok(())
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-10
@@ -65,12 +65,22 @@ pub fn tcp_scan(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pb = Arc::new(
|
||||||
|
ProgressBar::new((targets.len() * ports.len()) as u64).with_style(
|
||||||
|
ProgressStyle::with_template(
|
||||||
|
"[{msg}] {wide_bar:.cyan/blue} {pos}/{len} ({eta_precise})",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
let finished_sending_time = Arc::new(AtomicBool::new(false));
|
let finished_sending_time = Arc::new(AtomicBool::new(false));
|
||||||
let port_count = Arc::new(AtomicU32::new(0));
|
let port_count = Arc::new(AtomicU32::new(0));
|
||||||
|
|
||||||
let receiver_results = Arc::clone(&results);
|
let receiver_results = Arc::clone(&results);
|
||||||
let receiver_finished_sending_time = Arc::clone(&finished_sending_time);
|
let receiver_finished_sending_time = Arc::clone(&finished_sending_time);
|
||||||
let receiver_port_count = Arc::clone(&port_count);
|
let receiver_port_count = Arc::clone(&port_count);
|
||||||
|
let reciever_pb = Arc::clone(&pb);
|
||||||
let receiver_handle = thread::spawn(move || {
|
let receiver_handle = thread::spawn(move || {
|
||||||
let mut finish_sending_time: Option<Instant> = None;
|
let mut finish_sending_time: Option<Instant> = None;
|
||||||
|
|
||||||
@@ -93,8 +103,11 @@ pub fn tcp_scan(
|
|||||||
&& receiver_finished_sending_time.load(std::sync::atomic::Ordering::Relaxed)
|
&& receiver_finished_sending_time.load(std::sync::atomic::Ordering::Relaxed)
|
||||||
{
|
{
|
||||||
finish_sending_time = Some(Instant::now());
|
finish_sending_time = Some(Instant::now());
|
||||||
// pb = Some(ProgressBar::new(TIMEOUT.as_millis() as u64));
|
|
||||||
println!("Waiting {} seconds for timeout...", timeout.as_secs_f32())
|
reciever_pb.set_message(format!(
|
||||||
|
"Waiting {} seconds for timeout...",
|
||||||
|
timeout.as_secs_f32()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// println!("loop");
|
// println!("loop");
|
||||||
@@ -127,11 +140,6 @@ pub fn tcp_scan(
|
|||||||
// for (packet, addr) in tmp_results {}
|
// for (packet, addr) in tmp_results {}
|
||||||
});
|
});
|
||||||
|
|
||||||
let pb = ProgressBar::new((targets.len() * ports.len()) as u64).with_style(
|
|
||||||
ProgressStyle::with_template("[{msg}] {wide_bar:.cyan/blue} {pos}/{len} ({eta_precise})")
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// println!("{:?}", interface.ips);
|
// println!("{:?}", interface.ips);
|
||||||
|
|
||||||
let source_ip = std_to_pnet_ipv4(
|
let source_ip = std_to_pnet_ipv4(
|
||||||
@@ -194,7 +202,6 @@ pub fn tcp_scan(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pb.finish_with_message("Finished!");
|
|
||||||
sender_finished_sending_time.swap(true, std::sync::atomic::Ordering::Relaxed);
|
sender_finished_sending_time.swap(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
// Wait for receiver to finish
|
// Wait for receiver to finish
|
||||||
// thread::sleep(timeout);
|
// thread::sleep(timeout);
|
||||||
@@ -202,18 +209,24 @@ pub fn tcp_scan(
|
|||||||
|
|
||||||
// Convert results to the return format
|
// Convert results to the return format
|
||||||
let results_map = results.lock().unwrap();
|
let results_map = results.lock().unwrap();
|
||||||
targets
|
let mut total_ips = 0;
|
||||||
|
let result = targets
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ip| {
|
.map(|ip| {
|
||||||
let mut open_ports = results_map.get(ip).cloned().unwrap_or_default();
|
let mut open_ports = results_map.get(ip).cloned().unwrap_or_default();
|
||||||
open_ports.sort();
|
open_ports.sort();
|
||||||
open_ports.dedup();
|
open_ports.dedup();
|
||||||
|
total_ips += open_ports.len();
|
||||||
PortScanResult {
|
PortScanResult {
|
||||||
ip: *ip,
|
ip: *ip,
|
||||||
open_ports,
|
open_ports,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect();
|
||||||
|
|
||||||
|
pb.finish_with_message(format!("Finished! {:?} ports", total_ips));
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_tcp_packet(tx: &mut TransportSender, tcp_header: MutableTcpPacket<'_>, target: &IpAddr) {
|
fn send_tcp_packet(tx: &mut TransportSender, tcp_header: MutableTcpPacket<'_>, target: &IpAddr) {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ pub fn scan_services(
|
|||||||
|
|
||||||
// Create a thread for each chunk of IPs
|
// Create a thread for each chunk of IPs
|
||||||
// let chunks = split_ips_into_chunks(port_scan_results, num_threads);
|
// let chunks = split_ips_into_chunks(port_scan_results, num_threads);
|
||||||
for i in 0..=min(num_threads, host_port_count) {
|
for _ in 0..=min(num_threads, host_port_count) {
|
||||||
// println!("Thread {},{}", i, chunk.len());
|
// println!("Thread {},{}", i, chunk.len());
|
||||||
// let chunk_hosts = chunk.clone();
|
// let chunk_hosts = chunk.clone();
|
||||||
let thread_hosts = Arc::clone(&host_port);
|
let thread_hosts = Arc::clone(&host_port);
|
||||||
@@ -134,7 +134,8 @@ pub fn scan_services(
|
|||||||
|
|
||||||
if let Some(result) = result {
|
if let Some(result) = result {
|
||||||
let mut results_guard = thread_results.lock().unwrap();
|
let mut results_guard = thread_results.lock().unwrap();
|
||||||
println!("{}, {}", i, result.to_string());
|
thread_pb.set_message(format!("{} Found", results_guard.len()));
|
||||||
|
// println!("{}, {}", i, result.to_string());
|
||||||
results_guard.push(result);
|
results_guard.push(result);
|
||||||
std::mem::drop(results_guard);
|
std::mem::drop(results_guard);
|
||||||
}
|
}
|
||||||
@@ -155,12 +156,15 @@ pub fn scan_services(
|
|||||||
handle.join().unwrap();
|
handle.join().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pb.clone().finish_with_message("Finished!");
|
let results = Arc::try_unwrap(results)
|
||||||
|
|
||||||
Arc::try_unwrap(results)
|
|
||||||
.expect("Arc still has multiple owners")
|
.expect("Arc still has multiple owners")
|
||||||
.into_inner()
|
.into_inner()
|
||||||
.expect("Mutex poisoned")
|
.expect("Mutex poisoned");
|
||||||
|
|
||||||
|
pb.clone()
|
||||||
|
.finish_with_message(format!("Finished! {} Found", results.len()));
|
||||||
|
|
||||||
|
results
|
||||||
// .into_iter()
|
// .into_iter()
|
||||||
// .map(|a| {
|
// .map(|a| {
|
||||||
// println!("{:?}", a);
|
// println!("{:?}", a);
|
||||||
|
|||||||
+1389543
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user