Add: description in help message

This commit is contained in:
DaZuo0122
2026-01-17 19:49:53 +08:00
parent 7f6ee839b2
commit f349d4b4fa
3 changed files with 183 additions and 148 deletions

View File

@@ -73,41 +73,8 @@ wtfn calc overlap 10.0.0.0/24 10.0.1.0/24
wtfn calc summarize 10.0.0.0/24 10.0.1.0/24 wtfn calc summarize 10.0.0.0/24 10.0.1.0/24
``` ```
## Supported flags ## Command reference
Global flags: See `docs/COMMANDS.md` for the full list of commands and flags (with descriptions).
- `--json` / `--pretty`
- `--no-color` / `--quiet`
- `-v` / `-vv` / `--verbose`
- `--log-level <error|warn|info|debug|trace>`
- `--log-format <text|json>`
- `--log-file <path>`
- `NETTOOL_LOG_FILTER` or `RUST_LOG` can override log filters (ex: `maxminddb::decoder=debug`)
Command flags (implemented):
- `sys ip`: `--all`, `--iface <name>`
- `sys route`: `--ipv4`, `--ipv6`, `--to <ip>`
- `ports listen`: `--tcp`, `--udp`, `--port <n>`
- `neigh list`: `--ipv4`, `--ipv6`, `--iface <name>`
- `ports conns`: `--top <n>`, `--by-process`
- `cert baseline`: `<path>`
- `cert diff`: `<path>`
- `probe ping`: `--count <n>`, `--timeout-ms <n>`, `--interval-ms <n>`, `--no-geoip`
- `probe tcping`: `--count <n>`, `--timeout-ms <n>`, `--socks5 <url>`, `--prefer-ipv4`, `--no-geoip`
- `probe trace`: `--max-hops <n>`, `--per-hop <n>`, `--timeout-ms <n>`, `--udp`, `--port <n>`, `--rdns`, `--no-geoip`
- `dns query`: `--server <ip[:port]>`, `--transport <udp|tcp|dot|doh>`, `--tls-name <name>`, `--socks5 <url>`, `--prefer-ipv4`, `--timeout-ms <n>`
- `dns detect`: `--servers <csv>`, `--transport <udp|tcp|dot|doh>`, `--tls-name <name>`, `--socks5 <url>`, `--prefer-ipv4`, `--repeat <n>`, `--timeout-ms <n>`
- `dns watch`: `--duration <Ns|Nms>`, `--iface <name>`, `--filter <pattern>`
- `dns leak status`: `--profile <full-tunnel|proxy-stub|split>`, `--policy <path>`
- `dns leak watch`: `--duration <Ns|Nms>`, `--iface <name>`, `--profile <full-tunnel|proxy-stub|split>`, `--policy <path>`, `--privacy <full|redacted|minimal>`, `--out <path>`, `--summary-only`
- `dns leak watch`: `--iface-diag` (prints capture-capable interfaces)
- `dns leak report`: `<path>`, `--privacy <full|redacted|minimal>`
- `http head|get`: `--timeout-ms <n>`, `--follow-redirects <n>`, `--show-headers`, `--show-body`, `--max-body-bytes <n>`, `--http1-only`, `--http2-only`, `--http3` (feature `http3`), `--http3-only` (feature `http3`), `--geoip`, `--socks5 <url>`
- `tls handshake|cert|verify|alpn`: `--sni <name>`, `--alpn <csv>`, `--timeout-ms <n>`, `--insecure`, `--socks5 <url>`, `--prefer-ipv4`, `--show-extensions`, `--ocsp`
- `discover mdns`: `--duration <Ns|Nms>`, `--service <type>`
- `discover ssdp`: `--duration <Ns|Nms>`
- `discover llmnr`: `--duration <Ns|Nms>`, `--name <host>`
- `discover nbns`: `--duration <Ns|Nms>`
- `diag`: `--out <path>`, `--bundle <path>`, `--dns-detect <domain>`, `--dns-timeout-ms <n>`, `--dns-repeat <n>`
## GeoIP data files ## GeoIP data files
GeoLite2 mmdb files should live in `data/`. GeoLite2 mmdb files should live in `data/`.

View File

@@ -16,21 +16,21 @@ use wtfnet_platform::{Platform, PlatformError};
arg_required_else_help = true arg_required_else_help = true
)] )]
struct Cli { struct Cli {
#[arg(long)] #[arg(long, help = "Emit JSON output")]
json: bool, json: bool,
#[arg(long)] #[arg(long, help = "Pretty-print JSON output")]
pretty: bool, pretty: bool,
#[arg(long)] #[arg(long, help = "Disable ANSI colors")]
no_color: bool, no_color: bool,
#[arg(long)] #[arg(long, help = "Reduce stdout output")]
quiet: bool, quiet: bool,
#[arg(short = 'v', long = "verbose", action = clap::ArgAction::Count)] #[arg(short = 'v', long = "verbose", action = clap::ArgAction::Count, help = "Increase log verbosity (-v, -vv)")]
verbose: u8, verbose: u8,
#[arg(long)] #[arg(long, help = "Set log level (error|warn|info|debug|trace)")]
log_level: Option<String>, log_level: Option<String>,
#[arg(long)] #[arg(long, help = "Set log format (text|json)")]
log_format: Option<String>, log_format: Option<String>,
#[arg(long)] #[arg(long, help = "Write logs to a file")]
log_file: Option<PathBuf>, log_file: Option<PathBuf>,
#[command(subcommand)] #[command(subcommand)]
command: Commands, command: Commands,
@@ -38,98 +38,130 @@ struct Cli {
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum Commands { enum Commands {
/// System snapshot: interfaces, IPs, routes, DNS
Sys { Sys {
#[command(subcommand)] #[command(subcommand)]
command: SysCommand, command: SysCommand,
}, },
/// Ports and socket ownership
Ports { Ports {
#[command(subcommand)] #[command(subcommand)]
command: PortsCommand, command: PortsCommand,
}, },
/// Neighbor table (ARP/NDP)
Neigh { Neigh {
#[command(subcommand)] #[command(subcommand)]
command: NeighCommand, command: NeighCommand,
}, },
/// Certificate roots and baselines
Cert { Cert {
#[command(subcommand)] #[command(subcommand)]
command: CertCommand, command: CertCommand,
}, },
/// GeoIP lookup helpers
Geoip { Geoip {
#[command(subcommand)] #[command(subcommand)]
command: GeoIpCommand, command: GeoIpCommand,
}, },
/// Probing tools (ping/tcping/trace)
Probe { Probe {
#[command(subcommand)] #[command(subcommand)]
command: ProbeCommand, command: ProbeCommand,
}, },
/// DNS query, detect, watch, and leak detection
Dns { Dns {
#[command(subcommand)] #[command(subcommand)]
command: DnsCommand, command: DnsCommand,
}, },
/// Subnet calculator
Calc { Calc {
#[command(subcommand)] #[command(subcommand)]
command: CalcCommand, command: CalcCommand,
}, },
/// HTTP head/get diagnostics
Http { Http {
#[command(subcommand)] #[command(subcommand)]
command: HttpCommand, command: HttpCommand,
}, },
/// TLS handshake and certificate analysis
Tls { Tls {
#[command(subcommand)] #[command(subcommand)]
command: TlsCommand, command: TlsCommand,
}, },
/// Local network discovery (mDNS/SSDP/LLMNR/NBNS)
Discover { Discover {
#[command(subcommand)] #[command(subcommand)]
command: DiscoverCommand, command: DiscoverCommand,
}, },
/// Bundle a diagnostic report
Diag(DiagArgs), Diag(DiagArgs),
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum SysCommand { enum SysCommand {
/// List network interfaces
Ifaces, Ifaces,
/// Show IP addresses
Ip(SysIpArgs), Ip(SysIpArgs),
/// Show route table
Route(SysRouteArgs), Route(SysRouteArgs),
/// Show DNS configuration
Dns, Dns,
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum PortsCommand { enum PortsCommand {
/// List listening sockets
Listen(PortsListenArgs), Listen(PortsListenArgs),
/// Find socket owners for a port
Who(PortsWhoArgs), Who(PortsWhoArgs),
/// List active TCP connections
Conns(PortsConnsArgs), Conns(PortsConnsArgs),
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum NeighCommand { enum NeighCommand {
/// List ARP/NDP neighbors
List(NeighListArgs), List(NeighListArgs),
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum CertCommand { enum CertCommand {
/// List trusted root certificates
Roots, Roots,
/// Write a baseline file of trusted roots
Baseline(CertBaselineArgs), Baseline(CertBaselineArgs),
/// Diff trusted roots against a baseline
Diff(CertDiffArgs), Diff(CertDiffArgs),
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum GeoIpCommand { enum GeoIpCommand {
/// Lookup GeoIP for an IP address
Lookup(GeoIpLookupArgs), Lookup(GeoIpLookupArgs),
/// Show GeoIP database status
Status, Status,
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum ProbeCommand { enum ProbeCommand {
/// ICMP ping
Ping(ProbePingArgs), Ping(ProbePingArgs),
/// TCP ping (connect timing)
Tcping(ProbeTcpingArgs), Tcping(ProbeTcpingArgs),
/// Traceroute
Trace(ProbeTraceArgs), Trace(ProbeTraceArgs),
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum DnsCommand { enum DnsCommand {
/// DNS query
Query(DnsQueryArgs), Query(DnsQueryArgs),
/// DNS poisoning detection (active)
Detect(DnsDetectArgs), Detect(DnsDetectArgs),
/// DNS passive watch (pcap)
Watch(DnsWatchArgs), Watch(DnsWatchArgs),
/// DNS leak detection
Leak { Leak {
#[command(subcommand)] #[command(subcommand)]
command: DnsLeakCommand, command: DnsLeakCommand,
@@ -138,345 +170,381 @@ enum DnsCommand {
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum DnsLeakCommand { enum DnsLeakCommand {
/// Show current policy and interface snapshot
Status(DnsLeakStatusArgs), Status(DnsLeakStatusArgs),
/// Passive leak detection watch
Watch(DnsLeakWatchArgs), Watch(DnsLeakWatchArgs),
/// Summarize a saved leak report
Report(DnsLeakReportArgs), Report(DnsLeakReportArgs),
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum CalcCommand { enum CalcCommand {
/// Subnet info
Subnet(CalcSubnetArgs), Subnet(CalcSubnetArgs),
/// Check CIDR containment
Contains(CalcContainsArgs), Contains(CalcContainsArgs),
/// Check CIDR overlap
Overlap(CalcOverlapArgs), Overlap(CalcOverlapArgs),
/// Summarize CIDRs
Summarize(CalcSummarizeArgs), Summarize(CalcSummarizeArgs),
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum HttpCommand { enum HttpCommand {
/// HTTP HEAD request
Head(HttpRequestArgs), Head(HttpRequestArgs),
/// HTTP GET request
Get(HttpRequestArgs), Get(HttpRequestArgs),
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum TlsCommand { enum TlsCommand {
/// TLS handshake summary
Handshake(TlsArgs), Handshake(TlsArgs),
/// TLS certificate details
Cert(TlsArgs), Cert(TlsArgs),
/// TLS verification
Verify(TlsArgs), Verify(TlsArgs),
/// TLS ALPN negotiation
Alpn(TlsArgs), Alpn(TlsArgs),
} }
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum DiscoverCommand { enum DiscoverCommand {
/// mDNS discovery
Mdns(DiscoverMdnsArgs), Mdns(DiscoverMdnsArgs),
/// SSDP discovery
Ssdp(DiscoverSsdpArgs), Ssdp(DiscoverSsdpArgs),
/// LLMNR discovery
Llmnr(DiscoverLlmnrArgs), Llmnr(DiscoverLlmnrArgs),
/// NBNS discovery
Nbns(DiscoverNbnsArgs), Nbns(DiscoverNbnsArgs),
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct SysIpArgs { struct SysIpArgs {
#[arg(long)] #[arg(long, help = "Show all addresses (including link-local)")]
all: bool, all: bool,
#[arg(long)] #[arg(long, help = "Filter by interface name")]
iface: Option<String>, iface: Option<String>,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct SysRouteArgs { struct SysRouteArgs {
#[arg(long)] #[arg(long, help = "Show IPv4 routes")]
ipv4: bool, ipv4: bool,
#[arg(long)] #[arg(long, help = "Show IPv6 routes")]
ipv6: bool, ipv6: bool,
#[arg(long)] #[arg(long, help = "Filter routes by destination")]
to: Option<String>, to: Option<String>,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct PortsListenArgs { struct PortsListenArgs {
#[arg(long)] #[arg(long, help = "Show TCP listeners")]
tcp: bool, tcp: bool,
#[arg(long)] #[arg(long, help = "Show UDP listeners")]
udp: bool, udp: bool,
#[arg(long)] #[arg(long, help = "Filter by port")]
port: Option<u16>, port: Option<u16>,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct PortsWhoArgs { struct PortsWhoArgs {
#[arg(help = "Target port number")]
target: String, target: String,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct PortsConnsArgs { struct PortsConnsArgs {
#[arg(long)] #[arg(long, help = "Show top N remote endpoints")]
top: Option<usize>, top: Option<usize>,
#[arg(long)] #[arg(long, help = "Group by process")]
by_process: bool, by_process: bool,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct NeighListArgs { struct NeighListArgs {
#[arg(long)] #[arg(long, help = "Show IPv4 neighbors")]
ipv4: bool, ipv4: bool,
#[arg(long)] #[arg(long, help = "Show IPv6 neighbors")]
ipv6: bool, ipv6: bool,
#[arg(long)] #[arg(long, help = "Filter by interface name")]
iface: Option<String>, iface: Option<String>,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct GeoIpLookupArgs { struct GeoIpLookupArgs {
#[arg(help = "Target IP address")]
target: String, target: String,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct CertBaselineArgs { struct CertBaselineArgs {
#[arg(help = "Path to write baseline JSON")]
path: PathBuf, path: PathBuf,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct CertDiffArgs { struct CertDiffArgs {
#[arg(help = "Path to baseline JSON")]
path: PathBuf, path: PathBuf,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct ProbePingArgs { struct ProbePingArgs {
#[arg(help = "Target hostname or IP")]
target: String, target: String,
#[arg(long, default_value_t = 4)] #[arg(long, default_value_t = 4, help = "Ping count")]
count: u32, count: u32,
#[arg(long, default_value_t = 800)] #[arg(long, default_value_t = 800, help = "Timeout per ping (ms)")]
timeout_ms: u64, timeout_ms: u64,
#[arg(long, default_value_t = 200)] #[arg(long, default_value_t = 200, help = "Interval between pings (ms)")]
interval_ms: u64, interval_ms: u64,
#[arg(long)] #[arg(long, help = "Disable GeoIP enrichment")]
no_geoip: bool, no_geoip: bool,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct ProbeTcpingArgs { struct ProbeTcpingArgs {
#[arg(help = "Target host:port")]
target: String, target: String,
#[arg(long, default_value_t = 4)] #[arg(long, default_value_t = 4, help = "Ping count")]
count: u32, count: u32,
#[arg(long, default_value_t = 800)] #[arg(long, default_value_t = 800, help = "Timeout per connect (ms)")]
timeout_ms: u64, timeout_ms: u64,
#[arg(long)] #[arg(long, help = "SOCKS5 proxy URL")]
socks5: Option<String>, socks5: Option<String>,
#[arg(long)] #[arg(long, help = "Prefer IPv4 resolution")]
prefer_ipv4: bool, prefer_ipv4: bool,
#[arg(long)] #[arg(long, help = "Disable GeoIP enrichment")]
no_geoip: bool, no_geoip: bool,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct ProbeTraceArgs { struct ProbeTraceArgs {
#[arg(help = "Target host:port")]
target: String, target: String,
#[arg(long, default_value_t = 30)] #[arg(long, default_value_t = 30, help = "Maximum hops")]
max_hops: u8, max_hops: u8,
#[arg(long, default_value_t = 3)] #[arg(long, default_value_t = 3, help = "Probes per hop")]
per_hop: u32, per_hop: u32,
#[arg(long, default_value_t = 800)] #[arg(long, default_value_t = 800, help = "Timeout per hop (ms)")]
timeout_ms: u64, timeout_ms: u64,
#[arg(long)] #[arg(long, help = "Use UDP traceroute")]
udp: bool, udp: bool,
#[arg(long, default_value_t = 33434)] #[arg(long, default_value_t = 33434, help = "Destination port for UDP/TCP trace")]
port: u16, port: u16,
#[arg(long)] #[arg(long, help = "Reverse DNS lookup per hop")]
rdns: bool, rdns: bool,
#[arg(long)] #[arg(long, help = "Disable GeoIP enrichment")]
no_geoip: bool, no_geoip: bool,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct DnsQueryArgs { struct DnsQueryArgs {
#[arg(help = "Domain name to query")]
domain: String, domain: String,
#[arg(help = "Record type (A, AAAA, MX, TXT, ...)")]
record_type: String, record_type: String,
#[arg(long)] #[arg(long, help = "DNS server IP[:port]")]
server: Option<String>, server: Option<String>,
#[arg(long, default_value = "udp")] #[arg(long, default_value = "udp", help = "Transport (udp|tcp|dot|doh)")]
transport: String, transport: String,
#[arg(long)] #[arg(long, help = "TLS server name for DoT/DoH")]
tls_name: Option<String>, tls_name: Option<String>,
#[arg(long)] #[arg(long, help = "SOCKS5 proxy URL")]
socks5: Option<String>, socks5: Option<String>,
#[arg(long)] #[arg(long, help = "Prefer IPv4 resolution")]
prefer_ipv4: bool, prefer_ipv4: bool,
#[arg(long, default_value_t = 2000)] #[arg(long, default_value_t = 2000, help = "Timeout (ms)")]
timeout_ms: u64, timeout_ms: u64,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct DnsDetectArgs { struct DnsDetectArgs {
#[arg(help = "Domain name to test")]
domain: String, domain: String,
#[arg(long)] #[arg(long, help = "Comma-separated DNS servers")]
servers: Option<String>, servers: Option<String>,
#[arg(long, default_value = "udp")] #[arg(long, default_value = "udp", help = "Transport (udp|tcp|dot|doh)")]
transport: String, transport: String,
#[arg(long)] #[arg(long, help = "TLS server name for DoT/DoH")]
tls_name: Option<String>, tls_name: Option<String>,
#[arg(long)] #[arg(long, help = "SOCKS5 proxy URL")]
socks5: Option<String>, socks5: Option<String>,
#[arg(long)] #[arg(long, help = "Prefer IPv4 resolution")]
prefer_ipv4: bool, prefer_ipv4: bool,
#[arg(long, default_value_t = 3)] #[arg(long, default_value_t = 3, help = "Repeat count per server")]
repeat: u32, repeat: u32,
#[arg(long, default_value_t = 2000)] #[arg(long, default_value_t = 2000, help = "Timeout (ms)")]
timeout_ms: u64, timeout_ms: u64,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct DnsWatchArgs { struct DnsWatchArgs {
#[arg(long, default_value = "30s")] #[arg(long, default_value = "30s", help = "Capture duration")]
duration: String, duration: String,
#[arg(long)] #[arg(long, help = "Capture interface name")]
iface: Option<String>, iface: Option<String>,
#[arg(long)] #[arg(long, help = "Filter by domain substring")]
filter: Option<String>, filter: Option<String>,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct DnsLeakStatusArgs { struct DnsLeakStatusArgs {
#[arg(long)] #[arg(long, help = "Policy profile (full-tunnel|proxy-stub|split)")]
profile: Option<String>, profile: Option<String>,
#[arg(long)] #[arg(long, help = "Path to policy JSON")]
policy: Option<PathBuf>, policy: Option<PathBuf>,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct DnsLeakWatchArgs { struct DnsLeakWatchArgs {
#[arg(long, default_value = "10s")] #[arg(long, default_value = "10s", help = "Capture duration")]
duration: String, duration: String,
#[arg(long)] #[arg(long, help = "Capture interface name")]
iface: Option<String>, iface: Option<String>,
#[arg(long)] #[arg(long, help = "Policy profile (full-tunnel|proxy-stub|split)")]
profile: Option<String>, profile: Option<String>,
#[arg(long)] #[arg(long, help = "Path to policy JSON")]
policy: Option<PathBuf>, policy: Option<PathBuf>,
#[arg(long, default_value = "redacted")] #[arg(long, default_value = "redacted", help = "Privacy mode (full|redacted|minimal)")]
privacy: String, privacy: String,
#[arg(long)] #[arg(long, help = "Write JSON report to file")]
out: Option<PathBuf>, out: Option<PathBuf>,
#[arg(long)] #[arg(long, help = "Only print summary (no events)")]
summary_only: bool, summary_only: bool,
#[arg(long)] #[arg(long, help = "List capture-capable interfaces and exit")]
iface_diag: bool, iface_diag: bool,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct DnsLeakReportArgs { struct DnsLeakReportArgs {
#[arg(help = "Path to leak report JSON")]
path: PathBuf, path: PathBuf,
#[arg(long, default_value = "redacted")] #[arg(long, default_value = "redacted", help = "Privacy mode (full|redacted|minimal)")]
privacy: String, privacy: String,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct CalcSubnetArgs { struct CalcSubnetArgs {
#[arg(help = "CIDR or IP + mask")]
input: Vec<String>, input: Vec<String>,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct CalcContainsArgs { struct CalcContainsArgs {
#[arg(help = "CIDR A")]
a: String, a: String,
#[arg(help = "CIDR B")]
b: String, b: String,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct CalcOverlapArgs { struct CalcOverlapArgs {
#[arg(help = "CIDR A")]
a: String, a: String,
#[arg(help = "CIDR B")]
b: String, b: String,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct CalcSummarizeArgs { struct CalcSummarizeArgs {
#[arg(help = "CIDR list to summarize")]
cidrs: Vec<String>, cidrs: Vec<String>,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct HttpRequestArgs { struct HttpRequestArgs {
#[arg(help = "Target URL")]
url: String, url: String,
#[arg(long, default_value_t = 3000)] #[arg(long, default_value_t = 3000, help = "Request timeout (ms)")]
timeout_ms: u64, timeout_ms: u64,
#[arg(long)] #[arg(long, help = "Follow redirects (limit)")]
follow_redirects: Option<u32>, follow_redirects: Option<u32>,
#[arg(long)] #[arg(long, help = "Include response headers")]
show_headers: bool, show_headers: bool,
#[arg(long)] #[arg(long, help = "Include response body")]
show_body: bool, show_body: bool,
#[arg(long, default_value_t = 8192)] #[arg(long, default_value_t = 8192, help = "Max body bytes")]
max_body_bytes: usize, max_body_bytes: usize,
#[arg(long)] #[arg(long, help = "Force HTTP/1.1 only")]
http1_only: bool, http1_only: bool,
#[arg(long)] #[arg(long, help = "Force HTTP/2 prior knowledge")]
http2_only: bool, http2_only: bool,
#[arg(long)] #[arg(long, help = "Enable HTTP/3 (feature gated)")]
http3: bool, http3: bool,
#[arg(long)] #[arg(long, help = "Require HTTP/3 (feature gated)")]
http3_only: bool, http3_only: bool,
#[arg(long)] #[arg(long, help = "Enable GeoIP enrichment")]
geoip: bool, geoip: bool,
#[arg(long)] #[arg(long, help = "SOCKS5 proxy URL")]
socks5: Option<String>, socks5: Option<String>,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct TlsArgs { struct TlsArgs {
#[arg(help = "Target host:port")]
target: String, target: String,
#[arg(long)] #[arg(long, help = "Override SNI")]
sni: Option<String>, sni: Option<String>,
#[arg(long)] #[arg(long, help = "ALPN protocols (comma-separated)")]
alpn: Option<String>, alpn: Option<String>,
#[arg(long, default_value_t = 3000)] #[arg(long, default_value_t = 3000, help = "Timeout (ms)")]
timeout_ms: u64, timeout_ms: u64,
#[arg(long)] #[arg(long, help = "Skip TLS verification")]
insecure: bool, insecure: bool,
#[arg(long)] #[arg(long, help = "SOCKS5 proxy URL")]
socks5: Option<String>, socks5: Option<String>,
#[arg(long)] #[arg(long, help = "Prefer IPv4 resolution")]
prefer_ipv4: bool, prefer_ipv4: bool,
#[arg(long)] #[arg(long, help = "Show X.509 extensions")]
show_extensions: bool, show_extensions: bool,
#[arg(long)] #[arg(long, help = "Show OCSP stapling if available")]
ocsp: bool, ocsp: bool,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct DiscoverMdnsArgs { struct DiscoverMdnsArgs {
#[arg(long, default_value = "3s")] #[arg(long, default_value = "3s", help = "Capture duration")]
duration: String, duration: String,
#[arg(long)] #[arg(long, help = "Service type filter")]
service: Option<String>, service: Option<String>,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct DiscoverSsdpArgs { struct DiscoverSsdpArgs {
#[arg(long, default_value = "3s")] #[arg(long, default_value = "3s", help = "Capture duration")]
duration: String, duration: String,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct DiscoverLlmnrArgs { struct DiscoverLlmnrArgs {
#[arg(long, default_value = "3s")] #[arg(long, default_value = "3s", help = "Capture duration")]
duration: String, duration: String,
#[arg(long)] #[arg(long, help = "Query name (default: wpad)")]
name: Option<String>, name: Option<String>,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct DiscoverNbnsArgs { struct DiscoverNbnsArgs {
#[arg(long, default_value = "3s")] #[arg(long, default_value = "3s", help = "Capture duration")]
duration: String, duration: String,
} }
#[derive(Parser, Debug, Clone)] #[derive(Parser, Debug, Clone)]
struct DiagArgs { struct DiagArgs {
#[arg(long)] #[arg(long, help = "Write JSON report to file")]
out: Option<PathBuf>, out: Option<PathBuf>,
#[arg(long)] #[arg(long, help = "Write zip bundle to file")]
bundle: Option<PathBuf>, bundle: Option<PathBuf>,
#[arg(long)] #[arg(long, help = "Run DNS detect on domain")]
dns_detect: Option<String>, dns_detect: Option<String>,
#[arg(long, default_value_t = 2000)] #[arg(long, default_value_t = 2000, help = "DNS detect timeout (ms)")]
dns_timeout_ms: u64, dns_timeout_ms: u64,
#[arg(long, default_value_t = 3)] #[arg(long, default_value_t = 3, help = "DNS detect repeat count")]
dns_repeat: u32, dns_repeat: u32,
} }

View File

@@ -3,36 +3,36 @@
This document lists CLI commands and supported flags. Output defaults to text; use `--json` for structured output. This document lists CLI commands and supported flags. Output defaults to text; use `--json` for structured output.
## Global flags ## Global flags
- `--json` / `--pretty` - `--json` / `--pretty`: emit JSON output (pretty-print if requested)
- `--no-color` / `--quiet` - `--no-color` / `--quiet`: disable ANSI colors / reduce stdout output
- `-v` / `-vv` / `--verbose` - `-v` / `-vv` / `--verbose`: increase log verbosity
- `--log-level <error|warn|info|debug|trace>` - `--log-level <error|warn|info|debug|trace>`: set log level
- `--log-format <text|json>` - `--log-format <text|json>`: set log format
- `--log-file <path>` - `--log-file <path>`: write logs to file
- `NETTOOL_LOG_FILTER` or `RUST_LOG` can override log filters (ex: `maxminddb::decoder=debug`) - `NETTOOL_LOG_FILTER` or `RUST_LOG` can override log filters (ex: `maxminddb::decoder=debug`)
## sys ## sys
- `sys ifaces` - `sys ifaces`: list network interfaces
- `sys ip` flags: `--all`, `--iface <name>` - `sys ip` flags: `--all` (include link-local), `--iface <name>` (filter by interface)
- `sys route` flags: `--ipv4`, `--ipv6`, `--to <ip>` - `sys route` flags: `--ipv4`, `--ipv6`, `--to <ip>` (filter by destination)
- `sys dns` - `sys dns`: show DNS configuration
## ports ## ports
- `ports listen` flags: `--tcp`, `--udp`, `--port <n>` - `ports listen` flags: `--tcp`, `--udp`, `--port <n>` (filter by port)
- `ports who <port>` - `ports who <port>`: find owning processes for a port
- `ports conns` flags: `--top <n>`, `--by-process` - `ports conns` flags: `--top <n>`, `--by-process` (summaries)
## neigh ## neigh
- `neigh list` flags: `--ipv4`, `--ipv6`, `--iface <name>` - `neigh list` flags: `--ipv4`, `--ipv6`, `--iface <name>`
## cert ## cert
- `cert roots` - `cert roots`: list trusted root certificates
- `cert baseline <path>` - `cert baseline <path>`: write baseline JSON
- `cert diff <path>` - `cert diff <path>`: diff against baseline JSON
## geoip ## geoip
- `geoip lookup <ip>` - `geoip lookup <ip>`: lookup GeoIP
- `geoip status` - `geoip status`: show GeoIP database status
## probe ## probe
- `probe ping <host>` flags: `--count <n>`, `--timeout-ms <n>`, `--interval-ms <n>`, `--no-geoip` - `probe ping <host>` flags: `--count <n>`, `--timeout-ms <n>`, `--interval-ms <n>`, `--no-geoip`
@@ -44,7 +44,7 @@ This document lists CLI commands and supported flags. Output defaults to text; u
- `dns detect <domain>` flags: `--servers <csv>`, `--transport <udp|tcp|dot|doh>`, `--tls-name <name>`, `--socks5 <url>`, `--prefer-ipv4`, `--repeat <n>`, `--timeout-ms <n>` - `dns detect <domain>` flags: `--servers <csv>`, `--transport <udp|tcp|dot|doh>`, `--tls-name <name>`, `--socks5 <url>`, `--prefer-ipv4`, `--repeat <n>`, `--timeout-ms <n>`
- `dns watch` flags: `--duration <Ns|Nms>`, `--iface <name>`, `--filter <pattern>` - `dns watch` flags: `--duration <Ns|Nms>`, `--iface <name>`, `--filter <pattern>`
- `dns leak status` flags: `--profile <full-tunnel|proxy-stub|split>`, `--policy <path>` - `dns leak status` flags: `--profile <full-tunnel|proxy-stub|split>`, `--policy <path>`
- `dns leak watch` flags: `--duration <Ns|Nms>`, `--iface <name>`, `--profile <full-tunnel|proxy-stub|split>`, `--policy <path>`, `--privacy <full|redacted|minimal>`, `--out <path>`, `--summary-only`, `--iface-diag` - `dns leak watch` flags: `--duration <Ns|Nms>`, `--iface <name>`, `--profile <full-tunnel|proxy-stub|split>`, `--policy <path>`, `--privacy <full|redacted|minimal>`, `--out <path>`, `--summary-only`, `--iface-diag` (list capture-capable interfaces)
- `dns leak report` flags: `<path>`, `--privacy <full|redacted|minimal>` - `dns leak report` flags: `<path>`, `--privacy <full|redacted|minimal>`
## http ## http