use anyhow::Context;
use clap::Parser;
use tracing::level_filters::LevelFilter;
use tracing_subscriber::EnvFilter;
use crate::capture::interfaces::list_interfaces;
pub const DEFAULT_BPF: &str = "tcp port 443";
#[derive(Debug, Parser)]
#[command(
name = "seehandshake",
version,
about = "Visualize TLS handshakes in your terminal, in real time.",
long_about = None,
)]
pub struct Args {
#[arg(short, long, value_name = "NAME")]
pub interface: Option<String>,
#[arg(long)]
pub list_interfaces: bool,
#[arg(long, value_name = "FILTER", default_value = DEFAULT_BPF)]
pub bpf: String,
#[arg(long, value_name = "LEVEL", default_value = "warn")]
pub log_level: String,
}
pub fn init_logging(level: impl AsRef<str>) -> anyhow::Result<()> {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
EnvFilter::builder()
.with_default_directive(LevelFilter::WARN.into())
.parse_lossy(level.as_ref())
});
tracing_subscriber::fmt()
.with_env_filter(filter)
.with_writer(std::io::stderr)
.with_target(false)
.try_init()
.map_err(|e| anyhow::anyhow!("{e}"))?;
Ok(())
}
pub fn run(args: Args) -> anyhow::Result<()> {
if args.list_interfaces {
return print_interfaces();
}
crate::ui::run_live(&args).context("running the terminal UI")
}
fn print_interfaces() -> anyhow::Result<()> {
let interfaces = list_interfaces().context("enumerating network interfaces")?;
for iface in interfaces {
println!("{}\t{}", iface.name, iface.description.unwrap_or_default());
}
Ok(())
}