2025-04-18 11:00:26 -06:00
|
|
|
use std::cmp::Ordering;
|
2025-04-16 21:46:23 -06:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use std::net::{IpAddr, Ipv4Addr};
|
|
|
|
|
use std::str::FromStr;
|
2025-04-18 11:00:26 -06:00
|
|
|
use std::sync::atomic::AtomicBool;
|
2025-04-16 21:46:23 -06:00
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
|
use std::thread;
|
2025-04-18 11:00:26 -06:00
|
|
|
use std::time::{Duration, Instant};
|
2025-04-16 11:49:51 -06:00
|
|
|
|
2025-04-16 21:46:23 -06:00
|
|
|
use indicatif::ProgressBar;
|
2025-04-17 08:23:43 -06:00
|
|
|
use pnet::datalink::{self};
|
2025-04-16 21:46:23 -06:00
|
|
|
use pnet::packet::ip::IpNextHeaderProtocols;
|
2025-04-17 08:23:43 -06:00
|
|
|
use pnet::packet::tcp::{MutableTcpPacket, TcpFlags, TcpPacket};
|
2025-04-17 23:39:14 -06:00
|
|
|
use pnet::packet::{Packet, tcp};
|
2025-04-17 16:27:45 -06:00
|
|
|
use pnet::transport::{self, TransportChannelType, TransportSender};
|
2025-04-17 08:23:43 -06:00
|
|
|
use rand::random_range;
|
2025-04-16 21:46:23 -06:00
|
|
|
|
2025-04-17 23:39:14 -06:00
|
|
|
use super::port_scan::PortScanResult;
|
2025-04-16 21:46:23 -06:00
|
|
|
|
|
|
|
|
fn std_to_pnet_ipv4(previous: &IpAddr) -> Ipv4Addr {
|
|
|
|
|
Ipv4Addr::from_str(previous.to_string().as_str()).unwrap()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Main scanning function
|
2025-04-17 23:39:14 -06:00
|
|
|
pub fn tcp_scan(targets: Vec<IpAddr>, ports: Vec<i32>, timeout: Duration) -> Vec<PortScanResult> {
|
|
|
|
|
// Search for VPN connection and fall back to regular
|
|
|
|
|
let interface = datalink::interfaces()
|
2025-04-16 21:46:23 -06:00
|
|
|
.into_iter()
|
2025-04-17 16:27:45 -06:00
|
|
|
.find(|iface| {
|
|
|
|
|
iface.is_up()
|
|
|
|
|
&& !iface.is_loopback()
|
|
|
|
|
&& !iface.ips.is_empty()
|
|
|
|
|
&& !iface.is_dormant()
|
|
|
|
|
&& iface.is_running()
|
|
|
|
|
&& iface.is_point_to_point()
|
|
|
|
|
})
|
2025-04-17 23:39:14 -06:00
|
|
|
.or(datalink::interfaces().into_iter().find(|iface| {
|
|
|
|
|
iface.is_up()
|
|
|
|
|
&& !iface.is_loopback()
|
|
|
|
|
&& !iface.ips.is_empty()
|
|
|
|
|
&& !iface.is_dormant()
|
|
|
|
|
&& iface.is_running()
|
|
|
|
|
&& !iface.is_point_to_point()
|
|
|
|
|
}))
|
2025-04-16 21:46:23 -06:00
|
|
|
.expect("No valid network interface found");
|
|
|
|
|
|
|
|
|
|
// Create transport channel for sending and receiving
|
|
|
|
|
let (mut tx, mut rx) = transport::transport_channel(
|
|
|
|
|
65535,
|
|
|
|
|
TransportChannelType::Layer4(pnet::transport::TransportProtocol::Ipv4(
|
|
|
|
|
IpNextHeaderProtocols::Tcp,
|
|
|
|
|
)),
|
|
|
|
|
)
|
|
|
|
|
.expect("Failed to create transport channel");
|
|
|
|
|
|
|
|
|
|
// Shared results
|
|
|
|
|
let results = Arc::new(Mutex::new(HashMap::<IpAddr, Vec<i32>>::new()));
|
|
|
|
|
|
|
|
|
|
// Initialize results map
|
|
|
|
|
{
|
|
|
|
|
let mut results_map = results.lock().unwrap();
|
|
|
|
|
for ip in &targets {
|
|
|
|
|
results_map.insert(*ip, Vec::new());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-18 11:00:26 -06:00
|
|
|
let finished_sending_time = Arc::new(AtomicBool::new(false));
|
|
|
|
|
|
2025-04-16 21:46:23 -06:00
|
|
|
let receiver_results = Arc::clone(&results);
|
2025-04-18 11:00:26 -06:00
|
|
|
let receiver_finished_sending_time = Arc::clone(&finished_sending_time);
|
2025-04-16 21:46:23 -06:00
|
|
|
let receiver_handle = thread::spawn(move || {
|
|
|
|
|
let start_time = std::time::Instant::now();
|
2025-04-18 11:00:26 -06:00
|
|
|
let mut finish_sending_time: Option<Instant> = None;
|
|
|
|
|
|
|
|
|
|
let mut tmp_results: Vec<(TcpPacket<'_>, IpAddr)> = Vec::new();
|
|
|
|
|
|
|
|
|
|
let mut iter = transport::tcp_packet_iter(&mut rx);
|
|
|
|
|
loop {
|
|
|
|
|
// if start_time.elapsed() >= timeout {
|
|
|
|
|
// break;
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
if finish_sending_time.is_some() {
|
|
|
|
|
let delay = finish_sending_time.unwrap().elapsed();
|
|
|
|
|
// pb.as_ref().unwrap().set_position(delay.as_millis() as u64);
|
|
|
|
|
if delay >= timeout {
|
|
|
|
|
// pb.unwrap().finish_and_clear();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else if finish_sending_time.is_none()
|
|
|
|
|
&& receiver_finished_sending_time.load(std::sync::atomic::Ordering::Relaxed)
|
|
|
|
|
{
|
|
|
|
|
finish_sending_time = Some(Instant::now());
|
|
|
|
|
// pb = Some(ProgressBar::new(TIMEOUT.as_millis() as u64));
|
|
|
|
|
println!("Waiting {} seconds for timeout...", timeout.as_secs())
|
|
|
|
|
}
|
2025-04-16 21:46:23 -06:00
|
|
|
|
2025-04-17 16:27:45 -06:00
|
|
|
// println!("loop");
|
2025-04-16 21:46:23 -06:00
|
|
|
|
2025-04-18 11:00:26 -06:00
|
|
|
match iter.next_with_timeout(Duration::from_millis(3)) {
|
2025-04-17 16:27:45 -06:00
|
|
|
Ok(Some((packet, addr))) => {
|
2025-04-16 21:46:23 -06:00
|
|
|
if let Some(tcp) = TcpPacket::new(packet.packet()) {
|
|
|
|
|
// Check for SYN+ACK flags (indicating open port)
|
|
|
|
|
if tcp.get_flags() == TcpFlags::SYN | TcpFlags::ACK {
|
2025-04-17 16:27:45 -06:00
|
|
|
println!(
|
|
|
|
|
"Discovered open port {} on {}",
|
|
|
|
|
tcp.get_source(),
|
|
|
|
|
addr.to_string()
|
|
|
|
|
);
|
2025-04-16 21:46:23 -06:00
|
|
|
let mut results_map = receiver_results.lock().unwrap();
|
|
|
|
|
if let Some(open_ports) = results_map.get_mut(&addr) {
|
|
|
|
|
open_ports.push(tcp.get_source() as i32);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-18 11:00:26 -06:00
|
|
|
Ok(None) => {}
|
2025-04-16 21:46:23 -06:00
|
|
|
Err(_) => {
|
2025-04-18 11:00:26 -06:00
|
|
|
break;
|
2025-04-16 21:46:23 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-18 11:00:26 -06:00
|
|
|
|
|
|
|
|
// for (packet, addr) in tmp_results {}
|
2025-04-16 21:46:23 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let pb = ProgressBar::new((targets.len() * ports.len()) as u64);
|
|
|
|
|
|
2025-04-17 23:39:14 -06:00
|
|
|
// println!("{:?}", interface.ips);
|
2025-04-17 16:27:45 -06:00
|
|
|
|
2025-04-17 23:39:14 -06:00
|
|
|
let source_ip = std_to_pnet_ipv4(
|
|
|
|
|
&interface
|
|
|
|
|
.ips
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|ip| ip.is_ipv4())
|
|
|
|
|
.expect("No IPv4 address found")
|
|
|
|
|
.ip(),
|
|
|
|
|
);
|
2025-04-16 21:46:23 -06:00
|
|
|
|
2025-04-17 16:27:45 -06:00
|
|
|
// let source_ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
|
|
|
|
|
// let source_ip = IpAddr::V4(Ipv4Addr::new(10, 0, 70, 4));
|
|
|
|
|
|
2025-04-17 23:39:14 -06:00
|
|
|
// println!("Using IP: {}", source_ip.to_string());
|
2025-04-17 16:27:45 -06:00
|
|
|
|
2025-04-18 11:00:26 -06:00
|
|
|
let sender_finished_sending_time = Arc::clone(&finished_sending_time);
|
2025-04-16 21:46:23 -06:00
|
|
|
for target in &targets {
|
|
|
|
|
for port in &ports {
|
|
|
|
|
// let source_ip = Ipv4Addr::from_bits(random_range(0..=(0xffffffff)));
|
|
|
|
|
let source_port: u16 = random_range(1..=65535);
|
|
|
|
|
// println!("{}", source_ip.to_string());
|
|
|
|
|
|
|
|
|
|
let mut tcp_buffer = vec![0u8; 20 + 20]; // IP header + TCP header
|
|
|
|
|
let mut tcp_header = MutableTcpPacket::new(&mut tcp_buffer[0..]).unwrap();
|
|
|
|
|
|
|
|
|
|
tcp_header.set_source(source_port);
|
|
|
|
|
tcp_header.set_destination(*port as u16);
|
|
|
|
|
tcp_header.set_sequence(rand::random::<u32>());
|
|
|
|
|
tcp_header.set_acknowledgement(0);
|
|
|
|
|
tcp_header.set_data_offset(5);
|
|
|
|
|
tcp_header.set_reserved(0);
|
|
|
|
|
tcp_header.set_flags(TcpFlags::SYN);
|
|
|
|
|
tcp_header.set_window(64240);
|
|
|
|
|
tcp_header.set_urgent_ptr(0);
|
|
|
|
|
// tcp_header.set_options(&[TcpOption::mss(1460)]);
|
|
|
|
|
|
|
|
|
|
// Calculate checksum
|
|
|
|
|
let checksum = tcp::ipv4_checksum(
|
|
|
|
|
&tcp_header.to_immutable(),
|
2025-04-17 23:39:14 -06:00
|
|
|
if !target.is_loopback() {
|
|
|
|
|
&source_ip
|
|
|
|
|
} else {
|
|
|
|
|
&Ipv4Addr::LOCALHOST
|
|
|
|
|
},
|
2025-04-16 21:46:23 -06:00
|
|
|
&std_to_pnet_ipv4(&target),
|
|
|
|
|
);
|
|
|
|
|
tcp_header.set_checksum(checksum);
|
|
|
|
|
|
2025-04-17 16:27:45 -06:00
|
|
|
send_tcp_packet(&mut tx, tcp_header, target);
|
2025-04-16 21:46:23 -06:00
|
|
|
|
|
|
|
|
pb.inc(1);
|
|
|
|
|
thread::sleep(Duration::from_micros(100));
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-18 11:00:26 -06:00
|
|
|
sender_finished_sending_time.swap(true, std::sync::atomic::Ordering::Relaxed);
|
2025-04-16 21:46:23 -06:00
|
|
|
// Wait for receiver to finish
|
2025-04-17 16:27:45 -06:00
|
|
|
// thread::sleep(timeout);
|
2025-04-16 21:46:23 -06:00
|
|
|
receiver_handle.join().unwrap();
|
|
|
|
|
|
|
|
|
|
// Convert results to the return format
|
|
|
|
|
let results_map = results.lock().unwrap();
|
|
|
|
|
targets
|
|
|
|
|
.iter()
|
2025-04-17 08:23:43 -06:00
|
|
|
.map(|ip| {
|
|
|
|
|
let mut open_ports = results_map.get(ip).cloned().unwrap_or_default();
|
|
|
|
|
open_ports.sort();
|
2025-04-17 16:27:45 -06:00
|
|
|
open_ports.dedup();
|
2025-04-17 23:39:14 -06:00
|
|
|
PortScanResult {
|
2025-04-17 08:23:43 -06:00
|
|
|
ip: *ip,
|
|
|
|
|
open_ports,
|
|
|
|
|
}
|
2025-04-16 21:46:23 -06:00
|
|
|
})
|
|
|
|
|
.collect()
|
|
|
|
|
}
|
2025-04-17 16:27:45 -06:00
|
|
|
|
|
|
|
|
fn send_tcp_packet(tx: &mut TransportSender, tcp_header: MutableTcpPacket<'_>, target: &IpAddr) {
|
|
|
|
|
match tx.send_to(&tcp_header, *target) {
|
|
|
|
|
Ok(_) => {}
|
|
|
|
|
Err(e) => {
|
|
|
|
|
if let Some(code) = e.raw_os_error() {
|
|
|
|
|
if code == 105 {
|
|
|
|
|
thread::sleep(Duration::from_millis(500));
|
|
|
|
|
send_tcp_packet(tx, tcp_header, target);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
eprintln!("Failed to send packet: {}", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|