From f349d4b4fa58361bf83b7f5326f07557311a19cb Mon Sep 17 00:00:00 2001 From: DaZuo0122 <1085701449@qq.com> Date: Sat, 17 Jan 2026 19:49:53 +0800 Subject: [PATCH] Add: description in help message --- README.md | 37 +---- crates/wtfnet-cli/src/main.rs | 256 +++++++++++++++++++++------------- docs/COMMANDS.md | 38 ++--- 3 files changed, 183 insertions(+), 148 deletions(-) diff --git a/README.md b/README.md index ead2bb9..86aa6fd 100644 --- a/README.md +++ b/README.md @@ -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 ` -- `--log-format ` -- `--log-file ` -- `NETTOOL_LOG_FILTER` or `RUST_LOG` can override log filters (ex: `maxminddb::decoder=debug`) - -Command flags (implemented): -- `sys ip`: `--all`, `--iface ` -- `sys route`: `--ipv4`, `--ipv6`, `--to ` -- `ports listen`: `--tcp`, `--udp`, `--port ` -- `neigh list`: `--ipv4`, `--ipv6`, `--iface ` -- `ports conns`: `--top `, `--by-process` -- `cert baseline`: `` -- `cert diff`: `` -- `probe ping`: `--count `, `--timeout-ms `, `--interval-ms `, `--no-geoip` -- `probe tcping`: `--count `, `--timeout-ms `, `--socks5 `, `--prefer-ipv4`, `--no-geoip` -- `probe trace`: `--max-hops `, `--per-hop `, `--timeout-ms `, `--udp`, `--port `, `--rdns`, `--no-geoip` -- `dns query`: `--server `, `--transport `, `--tls-name `, `--socks5 `, `--prefer-ipv4`, `--timeout-ms ` -- `dns detect`: `--servers `, `--transport `, `--tls-name `, `--socks5 `, `--prefer-ipv4`, `--repeat `, `--timeout-ms ` -- `dns watch`: `--duration `, `--iface `, `--filter ` -- `dns leak status`: `--profile `, `--policy ` -- `dns leak watch`: `--duration `, `--iface `, `--profile `, `--policy `, `--privacy `, `--out `, `--summary-only` -- `dns leak watch`: `--iface-diag` (prints capture-capable interfaces) -- `dns leak report`: ``, `--privacy ` -- `http head|get`: `--timeout-ms `, `--follow-redirects `, `--show-headers`, `--show-body`, `--max-body-bytes `, `--http1-only`, `--http2-only`, `--http3` (feature `http3`), `--http3-only` (feature `http3`), `--geoip`, `--socks5 ` -- `tls handshake|cert|verify|alpn`: `--sni `, `--alpn `, `--timeout-ms `, `--insecure`, `--socks5 `, `--prefer-ipv4`, `--show-extensions`, `--ocsp` -- `discover mdns`: `--duration `, `--service ` -- `discover ssdp`: `--duration ` -- `discover llmnr`: `--duration `, `--name ` -- `discover nbns`: `--duration ` -- `diag`: `--out `, `--bundle `, `--dns-detect `, `--dns-timeout-ms `, `--dns-repeat ` +## 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/`. diff --git a/crates/wtfnet-cli/src/main.rs b/crates/wtfnet-cli/src/main.rs index 22de166..ed9be0b 100644 --- a/crates/wtfnet-cli/src/main.rs +++ b/crates/wtfnet-cli/src/main.rs @@ -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, - #[arg(long)] + #[arg(long, help = "Set log format (text|json)")] log_format: Option, - #[arg(long)] + #[arg(long, help = "Write logs to a file")] log_file: Option, #[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, } #[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, } #[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, } #[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, - #[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, } #[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, - #[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, - #[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, - #[arg(long)] + #[arg(long, help = "SOCKS5 proxy URL")] socks5: Option, - #[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, - #[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, - #[arg(long)] + #[arg(long, help = "SOCKS5 proxy URL")] socks5: Option, - #[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, - #[arg(long)] + #[arg(long, help = "Filter by domain substring")] filter: Option, } #[derive(Parser, Debug, Clone)] struct DnsLeakStatusArgs { - #[arg(long)] + #[arg(long, help = "Policy profile (full-tunnel|proxy-stub|split)")] profile: Option, - #[arg(long)] + #[arg(long, help = "Path to policy JSON")] policy: Option, } #[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, - #[arg(long)] + #[arg(long, help = "Policy profile (full-tunnel|proxy-stub|split)")] profile: Option, - #[arg(long)] + #[arg(long, help = "Path to policy JSON")] policy: Option, - #[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, - #[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, } #[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, } #[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, - #[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, } #[derive(Parser, Debug, Clone)] struct TlsArgs { + #[arg(help = "Target host:port")] target: String, - #[arg(long)] + #[arg(long, help = "Override SNI")] sni: Option, - #[arg(long)] + #[arg(long, help = "ALPN protocols (comma-separated)")] alpn: Option, - #[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, - #[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, } #[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, } #[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, - #[arg(long)] + #[arg(long, help = "Write zip bundle to file")] bundle: Option, - #[arg(long)] + #[arg(long, help = "Run DNS detect on domain")] dns_detect: Option, - #[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, } diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index bed8870..e6f5f41 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -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 ` -- `--log-format ` -- `--log-file ` +- `--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 `: set log level +- `--log-format `: set log format +- `--log-file `: 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 ` -- `sys route` flags: `--ipv4`, `--ipv6`, `--to ` -- `sys dns` +- `sys ifaces`: list network interfaces +- `sys ip` flags: `--all` (include link-local), `--iface ` (filter by interface) +- `sys route` flags: `--ipv4`, `--ipv6`, `--to ` (filter by destination) +- `sys dns`: show DNS configuration ## ports -- `ports listen` flags: `--tcp`, `--udp`, `--port ` -- `ports who ` -- `ports conns` flags: `--top `, `--by-process` +- `ports listen` flags: `--tcp`, `--udp`, `--port ` (filter by port) +- `ports who `: find owning processes for a port +- `ports conns` flags: `--top `, `--by-process` (summaries) ## neigh - `neigh list` flags: `--ipv4`, `--ipv6`, `--iface ` ## cert -- `cert roots` -- `cert baseline ` -- `cert diff ` +- `cert roots`: list trusted root certificates +- `cert baseline `: write baseline JSON +- `cert diff `: diff against baseline JSON ## geoip -- `geoip lookup ` -- `geoip status` +- `geoip lookup `: lookup GeoIP +- `geoip status`: show GeoIP database status ## probe - `probe ping ` flags: `--count `, `--timeout-ms `, `--interval-ms `, `--no-geoip` @@ -44,7 +44,7 @@ This document lists CLI commands and supported flags. Output defaults to text; u - `dns detect ` flags: `--servers `, `--transport `, `--tls-name `, `--socks5 `, `--prefer-ipv4`, `--repeat `, `--timeout-ms ` - `dns watch` flags: `--duration `, `--iface `, `--filter ` - `dns leak status` flags: `--profile `, `--policy ` -- `dns leak watch` flags: `--duration `, `--iface `, `--profile `, `--policy `, `--privacy `, `--out `, `--summary-only`, `--iface-diag` +- `dns leak watch` flags: `--duration `, `--iface `, `--profile `, `--policy `, `--privacy `, `--out `, `--summary-only`, `--iface-diag` (list capture-capable interfaces) - `dns leak report` flags: ``, `--privacy ` ## http