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
```
## Supported flags
Global flags:
- `--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>`
## Command reference
See `docs/COMMANDS.md` for the full list of commands and flags (with descriptions).
## GeoIP data files
GeoLite2 mmdb files should live in `data/`.

View File

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