use clap::Parser;
use crate::output::OutputFormat;
#[derive(Parser, Debug)]
#[command(
author,
version,
about = "A fast and efficient network scanner written in Rust",
long_about = r#"
A powerful network scanner that allows you to scan for available hosts and ports.
Examples:
# Scan a range of ports
asphyxia ps -t example.com -r 80 443
# Scan specific ports
asphyxia ps -t example.com -s 22,80,443,8080
# Scan a subnet (IPv4 or IPv6)
asphyxia as -s 192.168.1.0/24
asphyxia as -s 2001:db8::/120
# Scan a specific IP address (IPv4 or IPv6)
asphyxia as -t 192.168.1.1
asphyxia as -t 2001:db8::1
# Scan a range of IP addresses
asphyxia as -r 192.168.1.1 192.168.1.20
# Use a custom connection timeout (milliseconds)
asphyxia ps -t example.com -s 22,80,443 --timeout 500
# Raise concurrency to speed up a large subnet scan
asphyxia as -s 10.0.0.0/22 --concurrency 512
# Emit machine-readable output for a pipeline (text | json | jsonl)
asphyxia ps -t example.com -s 22,80,443 -o jsonl
asphyxia as -s 10.0.0.0/24 -o json
Required arguments:
For port scanning (ps):
-t, --host <HOST> Target host to scan (e.g., example.com)
-r, --range <START> <END> Scan a range of ports (e.g., 80 443)
-s, --specific <PORTS> Scan specific ports (comma-separated, e.g., 22,80,443)
--timeout <MS> Connection timeout in milliseconds (default: 2000)
For address scanning (as):
-s, --subnet <SUBNET> Scan a subnet (e.g., 192.168.1.0/24 or 2001:db8::/120)
-t, --target <IP> Scan a specific IP address (IPv4 or IPv6)
-r, --range <START> <END> Scan a range of IP addresses
--timeout <MS> Connection timeout in milliseconds (default: 2000)
"#
)]
pub enum Args {
#[command(name = "ps", about = "Start port scanning")]
PortScan {
#[arg(short = 't', long)]
host: String,
#[arg(short = 'r', long, num_args = 2, group = "ports")]
range: Option<Vec<u16>>,
#[arg(short = 's', long, group = "ports")]
specific: Option<String>,
#[arg(long, value_name = "MS", default_value_t = 2000)]
timeout: u64,
#[arg(short = 'c', long, value_name = "N", default_value_t = 256)]
concurrency: usize,
#[arg(short = 'o', long, value_enum, default_value_t = OutputFormat::Text)]
output: OutputFormat,
},
#[command(name = "as", about = "Start address scanning")]
AddressScan {
#[arg(short = 's', long, group = "scan_type")]
subnet: Option<String>,
#[arg(short = 't', long, group = "scan_type")]
target: Option<String>,
#[arg(short = 'r', long, num_args = 2, group = "scan_type")]
range: Option<Vec<String>>,
#[arg(long, value_name = "MS", default_value_t = 2000)]
timeout: u64,
#[arg(short = 'c', long, value_name = "N", default_value_t = 256)]
concurrency: usize,
#[arg(short = 'o', long, value_enum, default_value_t = OutputFormat::Text)]
output: OutputFormat,
},
}
impl Args {
pub fn concurrency(&self) -> usize {
match self {
Args::PortScan { concurrency, .. } | Args::AddressScan { concurrency, .. } => {
*concurrency
}
}
}
pub fn output_format(&self) -> OutputFormat {
match self {
Args::PortScan { output, .. } | Args::AddressScan { output, .. } => *output,
}
}
}