use crate::records::BannerRecord;
use std::error::Error;
use std::io::{ErrorKind, Read, Write};
use std::net::{IpAddr, SocketAddr, TcpStream};
use std::time::Duration;
pub struct Scnr {}
impl Scnr {
pub async fn scan(
address: IpAddr,
ports: Vec<u16>,
timeout: u64,
) -> Result<Vec<u16>, Box<dyn Error>> {
let mut open_port_vector: Vec<u16> = vec![];
let timeout = Duration::from_millis(timeout);
for port in ports {
let socket_address: SocketAddr = SocketAddr::new(address, port);
if (try_connect(socket_address, timeout).await).is_ok() {
open_port_vector.push(port)
}
}
Ok(open_port_vector)
}
pub async fn banner_scan(
address: IpAddr,
ports: Vec<u16>,
timeout: u64,
) -> Result<Vec<BannerRecord>, Box<dyn Error>> {
let mut banner_vector: Vec<BannerRecord> = vec![];
let duration = Duration::from_millis(timeout);
for port in ports {
let socket_address: SocketAddr = SocketAddr::new(address, port);
if let Ok(stream) = try_connect(socket_address, duration).await {
match Grabber::stream_grab(stream, 150).await {
Ok(banner) => {
let banner = if banner.is_empty() {
"nil".to_string()
} else {
parse_banner(&banner)
};
banner_vector.push(BannerRecord { port, banner });
}
Err(_) => {
banner_vector.push(BannerRecord {
port,
banner: "nil".to_string(),
});
}
}
}
}
Ok(banner_vector)
}
}
pub struct Grabber {}
impl Grabber {
pub async fn string_grab(
address: IpAddr,
port: u16,
msg: &str,
timeout: u64,
) -> Result<String, Box<dyn Error>> {
let socket_address: SocketAddr = SocketAddr::new(address, port);
let timeout = Duration::from_millis(timeout);
let rw_duration = Duration::from_millis(1000);
let mut response_shell = String::new();
let req_bytes = msg.as_bytes();
let mut stream = match try_connect(socket_address, timeout).await {
Ok(stream) => stream,
Err(err) => return Err(Box::from(err.to_string())),
};
stream.set_read_timeout(Option::from(rw_duration))?;
stream.set_write_timeout(Option::from(rw_duration))?;
stream.write_all(req_bytes).expect("could not write bytes");
stream
.read_to_string(&mut response_shell)
.expect("could not read string");
Ok(parse_banner(&response_shell))
}
pub async fn banner_grab(
address: IpAddr,
port: u16,
timeout: u64,
) -> Result<String, Box<dyn Error>> {
let server_socket: SocketAddr = SocketAddr::new(address, port);
let duration = Duration::from_millis(timeout);
let rw_duration = Duration::from_millis(1000);
let mut banner = String::new();
let mut stream =
TcpStream::connect_timeout(&server_socket, duration).expect("could not connect");
stream.set_read_timeout(Option::from(rw_duration))?;
stream.set_write_timeout(Option::from(rw_duration))?;
let result = stream.read_to_string(&mut banner);
if result.is_ok() && !banner.is_empty() {
return Ok(banner);
}
let error = result.err().unwrap();
if error.kind() != ErrorKind::WouldBlock {
return Err(error.into());
}
if banner.is_empty() {
stream.write_all("GET / HTTP/1.1\n\n".as_ref())?;
stream.read_to_string(&mut banner)?;
}
Ok(parse_banner(&banner))
}
pub async fn stream_grab(
mut stream: TcpStream,
timeout: u64,
) -> Result<String, Box<dyn Error>> {
let rw_duration = Duration::from_millis(timeout);
let mut banner = String::new();
stream.set_read_timeout(Option::from(rw_duration))?;
stream.set_write_timeout(Option::from(rw_duration))?;
let result = stream.read_to_string(&mut banner);
if result.is_ok() && !banner.is_empty() {
return Ok(banner);
}
let error = result.err().unwrap();
if error.kind() != ErrorKind::WouldBlock {
return Err(error.into());
}
if banner.is_empty() {
stream.write_all("HEAD / HTTP/1.1\n\n".as_ref())?;
stream.read_to_string(&mut banner)?;
}
Ok(banner)
}
}
fn parse_banner(banner: &str) -> String {
let b_vec = Vec::from_iter(banner.split(' '));
String::from(b_vec[0])
}
async fn try_connect(
socketaddr: SocketAddr,
timeout: Duration,
) -> Result<TcpStream, std::io::Error> {
match TcpStream::connect_timeout(&socketaddr, timeout) {
Ok(stream) => Ok(stream),
Err(err) => Err(err),
}
}