use parse_duration;
use rustmap::{probe_host, probe_port, HostStatus, IpAddrRange, PortStatus};
use std::io::{self, Write};
use std::net::SocketAddr;
use std::time::Duration;
use structopt::StructOpt;
#[derive(Debug, StructOpt)]
#[structopt()]
struct Opt {
#[structopt(short, long, require_delimiter = true)]
ports: Option<Vec<u16>>,
#[structopt(short, long, parse(try_from_str = parse_duration::parse), default_value = "1s")]
timeout: Duration,
#[structopt(required = true)]
addr_ranges: Vec<IpAddrRange>,
}
fn main() {
let Opt {
ports,
timeout,
addr_ranges,
} = Opt::from_args();
let show_closed_ports = matches!(ports, Some(ref vec) if !vec.is_empty());
let ports = match ports {
Some(ref vec) if vec.is_empty() => (0..u16::max_value()).collect(),
Some(vec) => vec,
None => Vec::default(),
};
addr_ranges
.iter()
.flatten()
.flat_map(|addr| {
print!("{:<16} ", addr);
io::stdout().flush().expect("flush stdout");
let status = probe_host(&addr, timeout);
match &status {
Ok(status) => println!("{}", status),
Err(error) => println!("{}", error),
}
match status {
Ok(HostStatus::Up) => Some(addr),
_ => None,
}
})
.flat_map(|up_addr| {
ports
.iter()
.map(move |port| SocketAddr::new(up_addr, *port))
})
.for_each(|socket_addr| match probe_port(&socket_addr, timeout) {
Ok(status) => {
if show_closed_ports || status == PortStatus::Open {
println!(" :{:<5} {}", socket_addr.port(), status);
}
}
Err(error) => println!("{}", error),
});
}