fuego 0.1.1

port scanner api for pelican
Documentation
use crate::records::{BannerHostRecord, BannerScanRecord, DropBox, ScanRecord};
use crate::serializer::deserialize_dropbox;
use crate::tcp_worker::{Grabber, Scnr};
use dns_lookup::lookup_host;
use std::error::Error;
use std::net::{AddrParseError, IpAddr};
use std::str::FromStr;
use tokio::fs::File;
use tokio::io::AsyncReadExt;

pub struct RadioFlyer {}

impl RadioFlyer {
    /**
    Props:

    addr: host

    msg: message to send

    port_to: port sending it to

    This is to write strings via tcp to different ports.
    */
    pub async fn string_drop(
        addr: &str,
        msg: &str,
        port: u16,
    ) -> Result<BannerHostRecord, Box<dyn Error>> {
        let host = host_check(addr).await.expect("bad host");
        match Grabber::string_grab(host, port, msg, 80).await {
            Ok(banner) => {
                let host = host.to_string();
                let banner_record: BannerHostRecord = BannerHostRecord { host, port, banner };
                Ok(banner_record)
            }
            Err(error) => Err(error),
        }
    }
    /**
    Props:

    addr: host

    port_to: port sending it to

    This attempts to grab a banner, this creates a TCP stream.
     */
    pub async fn get_banner(addr: &str, port: u16) -> Result<BannerHostRecord, Box<dyn Error>> {
        let host = host_check(addr).await?;
        let banner = Grabber::banner_grab(host, port, 80).await?;
        let host = host.to_string();
        let banner_record: BannerHostRecord = BannerHostRecord { host, port, banner };
        Ok(banner_record)
    }

    /**
    Props:

    addr: host

    ports: ports being checked

    This does a basic connect scan.
     */
    pub async fn scan_drop(
        addr: &str,
        ports: Vec<u16>,
        timeout: u64,
    ) -> Result<ScanRecord, Box<dyn Error>> {
        let host = host_check(addr).await?;
        let open_ports = Scnr::scan(host, ports, timeout).await?;
        let host = host.to_string();
        let record = ScanRecord { host, open_ports };

        Ok(record)
    }

    /**
    Props:

    addr: host

    ports: ports being checked

    This does a basic connect scan. This doesn't have a timeout.
    Use with fewer ports, otherwise every bad connect times out long.
     */
    pub async fn scan_drops(
        addrs: Vec<&str>,
        ports: Vec<u16>,
        timeout: u64,
    ) -> Result<Vec<ScanRecord>, Box<dyn Error>> {
        let mut records: Vec<ScanRecord> = vec![];

        for addr in addrs {
            let host = host_check(addr).await?;
            let open_ports = Scnr::scan(host, ports.clone(), timeout).await?;
            let host = host.to_string();
            let record = ScanRecord { host, open_ports };
            records.push(record);
        }

        Ok(records)
    }

    /**
    Props:

    addr: host

    ports: ports to check

    timeout: time willing to wait

    This banner grabs all open ports.
     */
    pub async fn banner_drop(
        addr: &str,
        ports: Vec<u16>,
        timeout: u64,
    ) -> Result<BannerScanRecord, Box<dyn Error>> {
        let host = host_check(addr).await?;
        let banners = Scnr::banner_scan(host, ports, timeout).await?;
        let host = host.to_string();
        let record = BannerScanRecord { host, banners };

        Ok(record)
    }

    /**
    Props:

    addr: host

    ports: ports to check

    timeout: time willing to wait

    This banner grabs all open ports from a vector of addresses.
     */
    pub async fn banner_drops(
        addrs: Vec<&str>,
        ports: Vec<u16>,
        timeout: u64,
    ) -> Result<Vec<BannerScanRecord>, Box<dyn Error>> {
        let mut records: Vec<BannerScanRecord> = vec![];

        for addr in addrs {
            let host = host_check(addr).await?;
            let banners = Scnr::banner_scan(host, ports.clone(), timeout).await?;
            let host = host.to_string();
            let record = BannerScanRecord { host, banners };
            records.push(record);
        }

        Ok(records)
    }
    /**
    Props:

    addr: host

    This just looks up hosts.
     */
    pub async fn host_drop(addr: &str) -> Result<Vec<String>, Box<dyn Error>> {
        let ip_vecs: Vec<IpAddr> = lookup_host(addr).unwrap();
        let mut return_array: Vec<String> = vec![];

        for ip in ip_vecs {
            return_array.push(ip.to_string())
        }

        Ok(return_array)
    }
}

pub struct CommonCarrier {}

impl CommonCarrier {
    /**
    Props:

    file_name &str : the file linking to the JSON file of
    hosts to scan
     */
    pub async fn from_file(file_name: &str) -> Result<Vec<ScanRecord>, Box<dyn Error>> {
        let mut file = File::open(file_name).await?;
        let mut data = String::new();

        file.read_to_string(&mut data).await?;
        let records = CommonCarrier::from_string(&data).await?;

        Ok(records)
    }
    /**
    Props:

    db_string &str : the file linking to the JSON file of
    hosts to scan
     */
    pub async fn from_string(db_string: &str) -> Result<Vec<ScanRecord>, Box<dyn Error>> {
        let dropbox: DropBox = deserialize_dropbox(db_string).await?;
        let mut return_vector: Vec<ScanRecord> = vec![];
        for mut address in dropbox.addresses {
            for i in 0..dropbox.global_ports.len() {
                address.ports.push(dropbox.global_ports[i]);
            }

            address.ports.dedup();

            match RadioFlyer::scan_drop(&address.host, address.ports, 60).await {
                Ok(record) => return_vector.push(record),
                Err(_) => continue,
            }
        }
        Ok(return_vector)
    }
}

/*

PRIVATES

 */

/**
Props

addr: unsanitized address
 */
async fn host_check(addr: &str) -> std::result::Result<IpAddr, AddrParseError> {
    match IpAddr::from_str(addr) {
        Err(_) => {
            let ip_vecs: Vec<IpAddr> = lookup_host(addr).unwrap();

            IpAddr::from_str(&ip_vecs[0].to_string())
        }

        Ok(IpAddr::V4(..)) => IpAddr::from_str(addr),
        Ok(IpAddr::V6(..)) => IpAddr::from_str(addr),
    }
}