Add: verbose flag to show logs in detail

This commit is contained in:
DaZuo0122
2026-01-17 00:15:46 +08:00
parent 7746511fc4
commit 7e87edb411
11 changed files with 146 additions and 2 deletions

4
Cargo.lock generated
View File

@@ -2851,6 +2851,7 @@ dependencies = [
"tokio",
"tokio-rustls",
"tokio-socks",
"tracing",
"url",
]
@@ -2871,6 +2872,7 @@ dependencies = [
"serde",
"thiserror 2.0.17",
"tokio",
"tracing",
"url",
]
@@ -2927,6 +2929,7 @@ dependencies = [
"thiserror 2.0.17",
"tokio",
"tokio-socks",
"tracing",
"url",
"wtfnet-geoip",
]
@@ -2942,6 +2945,7 @@ dependencies = [
"tokio",
"tokio-rustls",
"tokio-socks",
"tracing",
"url",
"x509-parser",
]

View File

@@ -70,7 +70,7 @@ wtfn calc summarize 10.0.0.0/24 10.0.1.0/24
Global flags:
- `--json` / `--pretty`
- `--no-color` / `--quiet`
- `-v` / `-vv`
- `-v` / `-vv` / `--verbose`
- `--log-level <error|warn|info|debug|trace>`
- `--log-format <text|json>`
- `--log-file <path>`

View File

@@ -24,7 +24,7 @@ struct Cli {
no_color: bool,
#[arg(long)]
quiet: bool,
#[arg(short = 'v', action = clap::ArgAction::Count)]
#[arg(short = 'v', long = "verbose", action = clap::ArgAction::Count)]
verbose: u8,
#[arg(long)]
log_level: Option<String>,

View File

@@ -16,6 +16,7 @@ tokio-rustls = "0.24"
tokio-socks = "0.5"
url = "2"
pnet = { version = "0.34", optional = true }
tracing = "0.1"
[features]
pcap = ["dep:pnet"]

View File

@@ -19,6 +19,7 @@ use thiserror::Error;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio_rustls::TlsConnector;
use tokio_socks::tcp::Socks5Stream;
use tracing::debug;
use url::Url;
#[cfg(feature = "pcap")]
@@ -169,6 +170,15 @@ pub async fn query(
timeout_ms: u64,
) -> Result<DnsQueryReport, DnsError> {
let record_type = parse_record_type(record_type)?;
debug!(
domain,
record_type = %record_type,
transport = %transport,
server = ?server.as_ref().map(|value| value.addr),
proxy = ?proxy.as_deref(),
timeout_ms,
"dns query start"
);
if let Some(proxy) = proxy {
let server = server.ok_or_else(|| DnsError::MissingServer(transport.to_string()))?;
return match transport {
@@ -245,6 +255,15 @@ pub async fn detect(
repeat: u32,
timeout_ms: u64,
) -> Result<DnsDetectResult, DnsError> {
debug!(
domain,
transport = %transport,
servers = servers.len(),
proxy = ?proxy.as_deref(),
repeat,
timeout_ms,
"dns detect start"
);
let mut results = Vec::new();
for server in servers {
for _ in 0..repeat.max(1) {
@@ -311,6 +330,12 @@ pub async fn watch(_options: DnsWatchOptions) -> Result<DnsWatchReport, DnsError
#[cfg(feature = "pcap")]
pub async fn watch(options: DnsWatchOptions) -> Result<DnsWatchReport, DnsError> {
debug!(
iface = ?options.iface,
duration_ms = options.duration_ms,
filter = ?options.filter,
"dns watch start"
);
let iface = match select_interface(options.iface.as_deref()) {
Some(value) => value,
None => {
@@ -341,6 +366,15 @@ pub async fn watch(options: DnsWatchOptions) -> Result<DnsWatchReport, DnsError>
match rx.next() {
Ok(frame) => {
if let Some(event) = parse_dns_frame(frame, start, &filter) {
debug!(
src = %event.src,
dst = %event.dst,
query_name = %event.query_name,
query_type = %event.query_type,
rcode = %event.rcode,
is_response = event.is_response,
"dns watch event"
);
events.push(event);
}
}
@@ -435,6 +469,13 @@ async fn doh_query_via_proxy(
timeout_ms: u64,
proxy: String,
) -> Result<DnsQueryReport, DnsError> {
debug!(
domain,
record_type = %record_type,
server = %server.addr,
proxy = %proxy,
"dns doh via proxy"
);
let tls_name = server
.name
.clone()
@@ -530,6 +571,13 @@ async fn dot_query_via_proxy(
timeout_ms: u64,
proxy: String,
) -> Result<DnsQueryReport, DnsError> {
debug!(
domain,
record_type = %record_type,
server = %server.addr,
proxy = %proxy,
"dns dot via proxy"
);
let tls_name = server
.name
.clone()

View File

@@ -9,3 +9,4 @@ serde = { version = "1", features = ["derive"] }
thiserror = "2"
tokio = { version = "1", features = ["net", "time"] }
url = "2"
tracing = "0.1"

View File

@@ -4,6 +4,7 @@ use std::net::{IpAddr, SocketAddr};
use std::time::{Duration, Instant};
use tokio::net::lookup_host;
use thiserror::Error;
use tracing::debug;
use url::Url;
#[derive(Debug, Error)]
@@ -67,6 +68,16 @@ pub struct HttpRequestOptions {
}
pub async fn request(url: &str, opts: HttpRequestOptions) -> Result<HttpReport, HttpError> {
debug!(
url,
method = ?opts.method,
timeout_ms = opts.timeout_ms,
follow_redirects = ?opts.follow_redirects,
http1_only = opts.http1_only,
http2_only = opts.http2_only,
proxy = ?opts.proxy,
"http request start"
);
let parsed = Url::parse(url).map_err(|err| HttpError::Url(err.to_string()))?;
let host = parsed
.host_str()

View File

@@ -14,3 +14,4 @@ wtfnet-geoip = { path = "../wtfnet-geoip" }
libc = "0.2"
tokio-socks = "0.5"
url = "2"
tracing = "0.1"

View File

@@ -21,6 +21,7 @@ use thiserror::Error;
use tokio::net::{TcpStream, lookup_host};
use tokio::time::timeout;
use tokio_socks::tcp::Socks5Stream;
use tracing::debug;
use url::Url;
use wtfnet_geoip::GeoIpRecord;
@@ -114,7 +115,15 @@ pub async fn ping(
timeout_ms: u64,
interval_ms: u64,
) -> Result<PingReport, ProbeError> {
debug!(
target,
count,
timeout_ms,
interval_ms,
"probe ping start"
);
let addr = resolve_one(target).await?;
debug!(ip = %addr, "probe ping resolved");
let mut results = Vec::new();
let mut received = 0u32;
let mut min = None;
@@ -193,6 +202,15 @@ pub async fn tcp_ping(
proxy: Option<&str>,
prefer_ipv4: bool,
) -> Result<TcpPingReport, ProbeError> {
debug!(
target,
port,
count,
timeout_ms,
proxy = ?proxy,
prefer_ipv4,
"probe tcp ping start"
);
let (report_ip, target_host, proxy_addr) = if let Some(proxy) = proxy {
let proxy = parse_socks5_proxy(proxy)?;
if proxy.remote_dns {
@@ -214,6 +232,12 @@ pub async fn tcp_ping(
(Some(addr), addr.to_string(), String::new())
};
let socket_addr = report_ip.map(|addr| SocketAddr::new(addr, port));
debug!(
report_ip = ?report_ip,
target_host = %target_host,
proxy_addr = %proxy_addr,
"probe tcp ping resolved"
);
let timeout_dur = Duration::from_millis(timeout_ms);
let mut results = Vec::new();
let mut received = 0u32;
@@ -285,7 +309,15 @@ pub async fn tcp_trace(
max_hops: u8,
timeout_ms: u64,
) -> Result<TraceReport, ProbeError> {
debug!(
target,
port,
max_hops,
timeout_ms,
"probe tcp trace start"
);
let addr = resolve_one(target).await?;
debug!(ip = %addr, "probe tcp trace resolved");
let socket_addr = SocketAddr::new(addr, port);
let timeout_dur = Duration::from_millis(timeout_ms);
let mut hops = Vec::new();
@@ -341,7 +373,15 @@ pub async fn udp_trace(
max_hops: u8,
timeout_ms: u64,
) -> Result<TraceReport, ProbeError> {
debug!(
target,
port,
max_hops,
timeout_ms,
"probe udp trace start"
);
let addr = resolve_one(target).await?;
debug!(ip = %addr, "probe udp trace resolved");
let timeout_dur = Duration::from_millis(timeout_ms);
let mut hops = Vec::new();

View File

@@ -13,3 +13,4 @@ tokio-rustls = "0.24"
x509-parser = "0.16"
tokio-socks = "0.5"
url = "2"
tracing = "0.1"

View File

@@ -8,6 +8,7 @@ use tokio::net::TcpStream;
use tokio::time::timeout;
use tokio_rustls::TlsConnector;
use tokio_socks::tcp::Socks5Stream;
use tracing::debug;
use url::Url;
use x509_parser::prelude::{FromDer, X509Certificate};
@@ -85,6 +86,15 @@ pub struct TlsOptions {
}
pub async fn handshake(target: &str, options: TlsOptions) -> Result<TlsHandshakeReport, TlsError> {
debug!(
target,
sni = ?options.sni,
alpn = ?options.alpn,
proxy = ?options.socks5,
timeout_ms = options.timeout_ms,
prefer_ipv4 = options.prefer_ipv4,
"tls handshake start"
);
let (host, port, server_name) = parse_target(target, options.sni.as_deref())?;
let connector = build_connector(options.insecure, &options.alpn)?;
let stream = connect(
@@ -115,6 +125,15 @@ pub async fn handshake(target: &str, options: TlsOptions) -> Result<TlsHandshake
}
pub async fn verify(target: &str, options: TlsOptions) -> Result<TlsVerifyReport, TlsError> {
debug!(
target,
sni = ?options.sni,
alpn = ?options.alpn,
proxy = ?options.socks5,
timeout_ms = options.timeout_ms,
prefer_ipv4 = options.prefer_ipv4,
"tls verify start"
);
let (host, port, server_name) = parse_target(target, options.sni.as_deref())?;
let connector = build_connector(false, &options.alpn)?;
match connect(
@@ -159,6 +178,15 @@ pub async fn verify(target: &str, options: TlsOptions) -> Result<TlsVerifyReport
}
pub async fn certs(target: &str, options: TlsOptions) -> Result<TlsCertReport, TlsError> {
debug!(
target,
sni = ?options.sni,
alpn = ?options.alpn,
proxy = ?options.socks5,
timeout_ms = options.timeout_ms,
prefer_ipv4 = options.prefer_ipv4,
"tls certs start"
);
let (host, port, server_name) = parse_target(target, options.sni.as_deref())?;
let connector = build_connector(options.insecure, &options.alpn)?;
let stream = connect(
@@ -180,6 +208,15 @@ pub async fn certs(target: &str, options: TlsOptions) -> Result<TlsCertReport, T
}
pub async fn alpn(target: &str, options: TlsOptions) -> Result<TlsAlpnReport, TlsError> {
debug!(
target,
sni = ?options.sni,
alpn = ?options.alpn,
proxy = ?options.socks5,
timeout_ms = options.timeout_ms,
prefer_ipv4 = options.prefer_ipv4,
"tls alpn start"
);
let (host, port, server_name) = parse_target(target, options.sni.as_deref())?;
let connector = build_connector(options.insecure, &options.alpn)?;
let stream = connect(