Add: verbose flag to show logs in detail
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -2851,6 +2851,7 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tokio-socks",
|
"tokio-socks",
|
||||||
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2871,6 +2872,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2927,6 +2929,7 @@ dependencies = [
|
|||||||
"thiserror 2.0.17",
|
"thiserror 2.0.17",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-socks",
|
"tokio-socks",
|
||||||
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
"wtfnet-geoip",
|
"wtfnet-geoip",
|
||||||
]
|
]
|
||||||
@@ -2942,6 +2945,7 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tokio-socks",
|
"tokio-socks",
|
||||||
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
"x509-parser",
|
"x509-parser",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ wtfn calc summarize 10.0.0.0/24 10.0.1.0/24
|
|||||||
Global flags:
|
Global flags:
|
||||||
- `--json` / `--pretty`
|
- `--json` / `--pretty`
|
||||||
- `--no-color` / `--quiet`
|
- `--no-color` / `--quiet`
|
||||||
- `-v` / `-vv`
|
- `-v` / `-vv` / `--verbose`
|
||||||
- `--log-level <error|warn|info|debug|trace>`
|
- `--log-level <error|warn|info|debug|trace>`
|
||||||
- `--log-format <text|json>`
|
- `--log-format <text|json>`
|
||||||
- `--log-file <path>`
|
- `--log-file <path>`
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ struct Cli {
|
|||||||
no_color: bool,
|
no_color: bool,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
#[arg(short = 'v', action = clap::ArgAction::Count)]
|
#[arg(short = 'v', long = "verbose", action = clap::ArgAction::Count)]
|
||||||
verbose: u8,
|
verbose: u8,
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
log_level: Option<String>,
|
log_level: Option<String>,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ tokio-rustls = "0.24"
|
|||||||
tokio-socks = "0.5"
|
tokio-socks = "0.5"
|
||||||
url = "2"
|
url = "2"
|
||||||
pnet = { version = "0.34", optional = true }
|
pnet = { version = "0.34", optional = true }
|
||||||
|
tracing = "0.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
pcap = ["dep:pnet"]
|
pcap = ["dep:pnet"]
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use thiserror::Error;
|
|||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio_rustls::TlsConnector;
|
use tokio_rustls::TlsConnector;
|
||||||
use tokio_socks::tcp::Socks5Stream;
|
use tokio_socks::tcp::Socks5Stream;
|
||||||
|
use tracing::debug;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[cfg(feature = "pcap")]
|
#[cfg(feature = "pcap")]
|
||||||
@@ -169,6 +170,15 @@ pub async fn query(
|
|||||||
timeout_ms: u64,
|
timeout_ms: u64,
|
||||||
) -> Result<DnsQueryReport, DnsError> {
|
) -> Result<DnsQueryReport, DnsError> {
|
||||||
let record_type = parse_record_type(record_type)?;
|
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 {
|
if let Some(proxy) = proxy {
|
||||||
let server = server.ok_or_else(|| DnsError::MissingServer(transport.to_string()))?;
|
let server = server.ok_or_else(|| DnsError::MissingServer(transport.to_string()))?;
|
||||||
return match transport {
|
return match transport {
|
||||||
@@ -245,6 +255,15 @@ pub async fn detect(
|
|||||||
repeat: u32,
|
repeat: u32,
|
||||||
timeout_ms: u64,
|
timeout_ms: u64,
|
||||||
) -> Result<DnsDetectResult, DnsError> {
|
) -> 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();
|
let mut results = Vec::new();
|
||||||
for server in servers {
|
for server in servers {
|
||||||
for _ in 0..repeat.max(1) {
|
for _ in 0..repeat.max(1) {
|
||||||
@@ -311,6 +330,12 @@ pub async fn watch(_options: DnsWatchOptions) -> Result<DnsWatchReport, DnsError
|
|||||||
|
|
||||||
#[cfg(feature = "pcap")]
|
#[cfg(feature = "pcap")]
|
||||||
pub async fn watch(options: DnsWatchOptions) -> Result<DnsWatchReport, DnsError> {
|
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()) {
|
let iface = match select_interface(options.iface.as_deref()) {
|
||||||
Some(value) => value,
|
Some(value) => value,
|
||||||
None => {
|
None => {
|
||||||
@@ -341,6 +366,15 @@ pub async fn watch(options: DnsWatchOptions) -> Result<DnsWatchReport, DnsError>
|
|||||||
match rx.next() {
|
match rx.next() {
|
||||||
Ok(frame) => {
|
Ok(frame) => {
|
||||||
if let Some(event) = parse_dns_frame(frame, start, &filter) {
|
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);
|
events.push(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -435,6 +469,13 @@ async fn doh_query_via_proxy(
|
|||||||
timeout_ms: u64,
|
timeout_ms: u64,
|
||||||
proxy: String,
|
proxy: String,
|
||||||
) -> Result<DnsQueryReport, DnsError> {
|
) -> Result<DnsQueryReport, DnsError> {
|
||||||
|
debug!(
|
||||||
|
domain,
|
||||||
|
record_type = %record_type,
|
||||||
|
server = %server.addr,
|
||||||
|
proxy = %proxy,
|
||||||
|
"dns doh via proxy"
|
||||||
|
);
|
||||||
let tls_name = server
|
let tls_name = server
|
||||||
.name
|
.name
|
||||||
.clone()
|
.clone()
|
||||||
@@ -530,6 +571,13 @@ async fn dot_query_via_proxy(
|
|||||||
timeout_ms: u64,
|
timeout_ms: u64,
|
||||||
proxy: String,
|
proxy: String,
|
||||||
) -> Result<DnsQueryReport, DnsError> {
|
) -> Result<DnsQueryReport, DnsError> {
|
||||||
|
debug!(
|
||||||
|
domain,
|
||||||
|
record_type = %record_type,
|
||||||
|
server = %server.addr,
|
||||||
|
proxy = %proxy,
|
||||||
|
"dns dot via proxy"
|
||||||
|
);
|
||||||
let tls_name = server
|
let tls_name = server
|
||||||
.name
|
.name
|
||||||
.clone()
|
.clone()
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ serde = { version = "1", features = ["derive"] }
|
|||||||
thiserror = "2"
|
thiserror = "2"
|
||||||
tokio = { version = "1", features = ["net", "time"] }
|
tokio = { version = "1", features = ["net", "time"] }
|
||||||
url = "2"
|
url = "2"
|
||||||
|
tracing = "0.1"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use std::net::{IpAddr, SocketAddr};
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use tokio::net::lookup_host;
|
use tokio::net::lookup_host;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use tracing::debug;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
@@ -67,6 +68,16 @@ pub struct HttpRequestOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn request(url: &str, opts: HttpRequestOptions) -> Result<HttpReport, HttpError> {
|
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 parsed = Url::parse(url).map_err(|err| HttpError::Url(err.to_string()))?;
|
||||||
let host = parsed
|
let host = parsed
|
||||||
.host_str()
|
.host_str()
|
||||||
|
|||||||
@@ -14,3 +14,4 @@ wtfnet-geoip = { path = "../wtfnet-geoip" }
|
|||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
tokio-socks = "0.5"
|
tokio-socks = "0.5"
|
||||||
url = "2"
|
url = "2"
|
||||||
|
tracing = "0.1"
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ use thiserror::Error;
|
|||||||
use tokio::net::{TcpStream, lookup_host};
|
use tokio::net::{TcpStream, lookup_host};
|
||||||
use tokio::time::timeout;
|
use tokio::time::timeout;
|
||||||
use tokio_socks::tcp::Socks5Stream;
|
use tokio_socks::tcp::Socks5Stream;
|
||||||
|
use tracing::debug;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use wtfnet_geoip::GeoIpRecord;
|
use wtfnet_geoip::GeoIpRecord;
|
||||||
|
|
||||||
@@ -114,7 +115,15 @@ pub async fn ping(
|
|||||||
timeout_ms: u64,
|
timeout_ms: u64,
|
||||||
interval_ms: u64,
|
interval_ms: u64,
|
||||||
) -> Result<PingReport, ProbeError> {
|
) -> Result<PingReport, ProbeError> {
|
||||||
|
debug!(
|
||||||
|
target,
|
||||||
|
count,
|
||||||
|
timeout_ms,
|
||||||
|
interval_ms,
|
||||||
|
"probe ping start"
|
||||||
|
);
|
||||||
let addr = resolve_one(target).await?;
|
let addr = resolve_one(target).await?;
|
||||||
|
debug!(ip = %addr, "probe ping resolved");
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
let mut received = 0u32;
|
let mut received = 0u32;
|
||||||
let mut min = None;
|
let mut min = None;
|
||||||
@@ -193,6 +202,15 @@ pub async fn tcp_ping(
|
|||||||
proxy: Option<&str>,
|
proxy: Option<&str>,
|
||||||
prefer_ipv4: bool,
|
prefer_ipv4: bool,
|
||||||
) -> Result<TcpPingReport, ProbeError> {
|
) -> 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 (report_ip, target_host, proxy_addr) = if let Some(proxy) = proxy {
|
||||||
let proxy = parse_socks5_proxy(proxy)?;
|
let proxy = parse_socks5_proxy(proxy)?;
|
||||||
if proxy.remote_dns {
|
if proxy.remote_dns {
|
||||||
@@ -214,6 +232,12 @@ pub async fn tcp_ping(
|
|||||||
(Some(addr), addr.to_string(), String::new())
|
(Some(addr), addr.to_string(), String::new())
|
||||||
};
|
};
|
||||||
let socket_addr = report_ip.map(|addr| SocketAddr::new(addr, port));
|
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 timeout_dur = Duration::from_millis(timeout_ms);
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
let mut received = 0u32;
|
let mut received = 0u32;
|
||||||
@@ -285,7 +309,15 @@ pub async fn tcp_trace(
|
|||||||
max_hops: u8,
|
max_hops: u8,
|
||||||
timeout_ms: u64,
|
timeout_ms: u64,
|
||||||
) -> Result<TraceReport, ProbeError> {
|
) -> Result<TraceReport, ProbeError> {
|
||||||
|
debug!(
|
||||||
|
target,
|
||||||
|
port,
|
||||||
|
max_hops,
|
||||||
|
timeout_ms,
|
||||||
|
"probe tcp trace start"
|
||||||
|
);
|
||||||
let addr = resolve_one(target).await?;
|
let addr = resolve_one(target).await?;
|
||||||
|
debug!(ip = %addr, "probe tcp trace resolved");
|
||||||
let socket_addr = SocketAddr::new(addr, port);
|
let socket_addr = SocketAddr::new(addr, port);
|
||||||
let timeout_dur = Duration::from_millis(timeout_ms);
|
let timeout_dur = Duration::from_millis(timeout_ms);
|
||||||
let mut hops = Vec::new();
|
let mut hops = Vec::new();
|
||||||
@@ -341,7 +373,15 @@ pub async fn udp_trace(
|
|||||||
max_hops: u8,
|
max_hops: u8,
|
||||||
timeout_ms: u64,
|
timeout_ms: u64,
|
||||||
) -> Result<TraceReport, ProbeError> {
|
) -> Result<TraceReport, ProbeError> {
|
||||||
|
debug!(
|
||||||
|
target,
|
||||||
|
port,
|
||||||
|
max_hops,
|
||||||
|
timeout_ms,
|
||||||
|
"probe udp trace start"
|
||||||
|
);
|
||||||
let addr = resolve_one(target).await?;
|
let addr = resolve_one(target).await?;
|
||||||
|
debug!(ip = %addr, "probe udp trace resolved");
|
||||||
|
|
||||||
let timeout_dur = Duration::from_millis(timeout_ms);
|
let timeout_dur = Duration::from_millis(timeout_ms);
|
||||||
let mut hops = Vec::new();
|
let mut hops = Vec::new();
|
||||||
|
|||||||
@@ -13,3 +13,4 @@ tokio-rustls = "0.24"
|
|||||||
x509-parser = "0.16"
|
x509-parser = "0.16"
|
||||||
tokio-socks = "0.5"
|
tokio-socks = "0.5"
|
||||||
url = "2"
|
url = "2"
|
||||||
|
tracing = "0.1"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use tokio::net::TcpStream;
|
|||||||
use tokio::time::timeout;
|
use tokio::time::timeout;
|
||||||
use tokio_rustls::TlsConnector;
|
use tokio_rustls::TlsConnector;
|
||||||
use tokio_socks::tcp::Socks5Stream;
|
use tokio_socks::tcp::Socks5Stream;
|
||||||
|
use tracing::debug;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use x509_parser::prelude::{FromDer, X509Certificate};
|
use x509_parser::prelude::{FromDer, X509Certificate};
|
||||||
|
|
||||||
@@ -85,6 +86,15 @@ pub struct TlsOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handshake(target: &str, options: TlsOptions) -> Result<TlsHandshakeReport, TlsError> {
|
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 (host, port, server_name) = parse_target(target, options.sni.as_deref())?;
|
||||||
let connector = build_connector(options.insecure, &options.alpn)?;
|
let connector = build_connector(options.insecure, &options.alpn)?;
|
||||||
let stream = connect(
|
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> {
|
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 (host, port, server_name) = parse_target(target, options.sni.as_deref())?;
|
||||||
let connector = build_connector(false, &options.alpn)?;
|
let connector = build_connector(false, &options.alpn)?;
|
||||||
match connect(
|
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> {
|
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 (host, port, server_name) = parse_target(target, options.sni.as_deref())?;
|
||||||
let connector = build_connector(options.insecure, &options.alpn)?;
|
let connector = build_connector(options.insecure, &options.alpn)?;
|
||||||
let stream = connect(
|
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> {
|
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 (host, port, server_name) = parse_target(target, options.sni.as_deref())?;
|
||||||
let connector = build_connector(options.insecure, &options.alpn)?;
|
let connector = build_connector(options.insecure, &options.alpn)?;
|
||||||
let stream = connect(
|
let stream = connect(
|
||||||
|
|||||||
Reference in New Issue
Block a user