# IMPLEMENTATION.md ## 0) Project identity * **Project name:** WTFnet * **Binary name:** `wtfn` * **Tagline:** *“What the f*ck is my networking doing?”* Target OS (first-class): * ✅ Linux (Debian/Ubuntu) * ✅ Windows 10/11 + Windows Server --- ## 1) Workspace layout (Cargo) Recommended workspace structure: keep the CLI thin, keep logic reusable, and isolate OS-specific code. ``` wtfnet/ ├─ Cargo.toml ├─ crates/ │ ├─ wtfnet-cli/ # bin: clap parsing + output formatting │ ├─ wtfnet-core/ # shared types: errors, output schema, config, logging init │ ├─ wtfnet-platform/ # platform traits + OS dispatch │ ├─ wtfnet-platform-linux/ # Linux implementations (netlink/procfs) │ ├─ wtfnet-platform-windows/ # Windows implementations (Win32 APIs) │ ├─ wtfnet-geoip/ # GeoLite2 Country+ASN mmdb │ ├─ wtfnet-probe/ # ping/tcping/trace + geoip enrichment │ ├─ wtfnet-dns/ # query/detect/watch │ ├─ wtfnet-http/ # HTTP/1.1, HTTP/2, optional HTTP/3 │ ├─ wtfnet-tls/ # TLS handshake/cert/verify/alpn │ ├─ wtfnet-discover/ # mdns/ssdp discovery │ └─ wtfnet-diag/ # diag bundle orchestrator └─ docs/ # design/usage docs (optional) ``` ### Root `Cargo.toml` (workspace) ```toml [workspace] resolver = "2" members = [ "crates/wtfnet-cli", "crates/wtfnet-core", "crates/wtfnet-platform", "crates/wtfnet-platform-linux", "crates/wtfnet-platform-windows", "crates/wtfnet-geoip", "crates/wtfnet-probe", "crates/wtfnet-dns", "crates/wtfnet-http", "crates/wtfnet-tls", "crates/wtfnet-discover", "crates/wtfnet-diag", ] [workspace.package] edition = "2021" license = "MIT" ``` --- ## 2) Subcrate responsibilities ### 2.1 `wtfnet-cli` (binary) **Purpose** * Defines `clap` subcommands & global flags (`--json`, `--pretty`, logging flags, timeouts) * Calls into library crates * Converts results → human tables OR JSON **Strict rule** * No OS-specific code here. * No heavy logic here. --- ### 2.2 `wtfnet-core` (shared kernel) **Owns** * Output schema wrapper (`meta`, `command`, `data`, `warnings`, `errors`) * Error taxonomy + exit code mapping * Config loading (flags/env/config.json) * Logging initialization (`tracing`) * Formatting helpers (durations, bytes, IP formatting) * “human table renderer” utilities (optional) --- ### 2.3 `wtfnet-platform` (traits + dispatch) **Purpose** Expose a stable interface for sysadmin-ish data: * sys: interfaces/IP/route/DNS config snapshot * ports: listening sockets + PID/process info * cert roots: enumerate trusted roots * neigh: ARP/NDP cache **Pattern** * Define Rust traits like `SysProvider`, `PortsProvider`, `CertProvider`, `NeighProvider` * Provide a `Platform` object that selects implementation by target OS --- ### 2.4 `wtfnet-platform-linux` Linux implementations: * netlink-based route/IP/neigh: use `rtnetlink` ([Docs.rs][1]) * ports/process mapping: * either use `listeners` (cross-platform) or Linux procfs parsing * DNS snapshot: parse `/etc/resolv.conf` + detect `systemd-resolved` best-effort --- ### 2.5 `wtfnet-platform-windows` Windows implementations: * use `windows` crate / Win32 APIs * interfaces/routes/neigh via IP Helper APIs * ports/process via Windows socket/process APIs * trusted roots via Windows cert store APIs --- ### 2.6 `wtfnet-geoip` * Loads **local** GeoLite2 Country + ASN mmdb * Provides one `GeoIpService` with `lookup(ip)` returning: * country + ISO * ASN + org --- ### 2.7 `wtfnet-probe` Implements: * ping (v4/v6) * tcping (connect latency) * trace (traceroute-like) * optional `--geoip` enrichment For ping, you can start with `surge-ping` ([Crates][2]) or `ping-async` ([Docs.rs][3]) (both async-oriented). --- ### 2.8 `wtfnet-dns` Implements: * `dns query` (dig-like) * `dns detect` (poisoning compare) * `dns watch` (passive, best-effort) Use **Hickory DNS** (Trust-DNS rebrand) ([Docs.rs][4]) for a solid resolver/client base. --- ### 2.9 `wtfnet-http` Implements: * `http head|get` * HTTP/2 support is required (via `reqwest`/`hyper`) * HTTP/3 optional behind feature flag: * `h3` + `h3-quinn` + `quinn` ([GitHub][5]) --- ### 2.10 `wtfnet-tls` Implements: * `tls handshake|cert|verify|alpn` * Use `rustls` for handshake parsing * For system trust verification: * `rustls-native-certs` for loading OS roots ([Crates][6]) * optionally `rustls-platform-verifier` for “verify like the OS” behavior ([GitHub][7]) --- ### 2.11 `wtfnet-discover` Implements bounded local discovery: * mDNS service discovery: `mdns-sd` ([Crates][8]) * SSDP discovery: `ssdp-client` ([Crates][9]) --- ### 2.12 `wtfnet-diag` Orchestrates: * sys snapshot * routes * ports listen * neigh list * optional quick checks: DNS detect, TLS handshake, HTTP head * bundle export to zip --- ## 3) Dependency map (crate graph) **High-level dependency graph:** ``` wtfnet-cli ├─ wtfnet-core ├─ wtfnet-platform │ ├─ wtfnet-platform-linux (cfg linux) │ └─ wtfnet-platform-windows (cfg windows) ├─ wtfnet-geoip ├─ wtfnet-probe ├─ wtfnet-dns ├─ wtfnet-http ├─ wtfnet-tls ├─ wtfnet-discover └─ wtfnet-diag ``` **Rule of thumb** * `wtfnet-core` should not depend on OS crates. * feature crates should depend on `wtfnet-core` + minimal extras. --- ## 4) Shared libraries / crate dependencies (recommended) ### 4.1 Core stack (almost everywhere) * **CLI**: `clap` (+ `clap_complete` optional) * **Async runtime**: `tokio` * **Serialization**: `serde`, `serde_json` * **Errors**: `thiserror` (libs), `anyhow` (CLI glue) * **URLs**: `url` * **Time**: `time` (or `chrono`), `humantime` * **Tables (human output)**: `tabled` or `comfy-table` * **Zip bundles**: `zip` (diag bundle) ### 4.2 Logging / tracing Use `tracing` + `tracing-subscriber`: * `tracing` * `tracing-subscriber` (fmt + env filter) * optional: `tracing-appender` (log file) **Why this choice** * structured logs * spans for timing each probe stage * easy JSON logs to stderr --- ### 4.3 Sys/platform related crates * Interfaces: `network-interface` ([Crates][10]) (good for standardized interface listing) * Linux netlink: `rtnetlink` ([Docs.rs][1]) * Ports: * `listeners` (cross-platform “listening process mapping”) ([GitHub][11]) * fallback: `netstat2` (cross-platform sockets info) ([Docs.rs][12]) * Windows APIs: `windows` crate > Suggestion: start with `listeners` for `ports listen/who` (it directly targets your use-case). ([GitHub][11]) --- ### 4.4 GeoIP * `maxminddb` (read GeoLite2 mmdb) --- ### 4.5 DNS * `hickory-resolver` / Hickory ecosystem ([Docs.rs][4]) Passive `dns watch` (optional): * `pcap` or `pnet` (feature-gated) --- ### 4.6 HTTP / TLS HTTP: * `reqwest` (easy HTTP/1.1 + HTTP/2) * or `hyper` if you want lower-level control HTTP/3 (optional feature): * `h3` + `h3-quinn` + `quinn` ([GitHub][5]) TLS: * `rustls` * `rustls-native-certs` ([Crates][6]) * `rustls-platform-verifier` (optional) ([GitHub][7]) --- ### 4.7 Probing * ping: * `surge-ping` ([Crates][2]) * or `ping-async` ([Docs.rs][3]) * tcping: plain `tokio::net::TcpStream::connect` + `timeout` * trace: start simple (UDP/ICMP-based approaches are trickier & permission-sensitive) --- ### 4.8 Discovery * mDNS: `mdns-sd` ([Crates][8]) * SSDP: `ssdp-client` ([Crates][9]) --- ## 5) Feature flags & compile-time options In root design, define optional features to avoid heavy deps by default. Suggested features: * `http3` → enables `h3`, `h3-quinn`, `quinn` * `pcap` → enables passive DNS watch with packet capture * `discover` → enable mdns/ssdp features (if you want a “minimal build”) Example snippet (in `wtfnet-http/Cargo.toml`): ```toml [features] default = ["http2"] http2 = [] http3 = ["dep:h3", "dep:h3-quinn", "dep:quinn"] [dependencies] reqwest = { version = "*", features = ["rustls-tls", "http2"] } h3 = { version = "*", optional = true } h3-quinn = { version = "*", optional = true } quinn = { version = "*", optional = true } ``` --- ## 6) Core data model + output schema (do this early) ### 6.1 Unified JSON wrapper (recommended) Every command returns: ```rust pub struct CommandEnvelope { pub meta: Meta, pub command: CommandInfo, pub data: T, pub warnings: Vec, pub errors: Vec, } ``` Key principles: * stable keys * additive schema evolution * logs never pollute stdout JSON ### 6.2 Exit code mapping Put this in `wtfnet-core` and make CLI enforce it: ```rust pub enum ExitKind { Ok, Failed, Usage, Permission, Timeout, Partial, } ``` --- ## 7) Logging design (`tracing`) ### 7.1 Init once in `main()` `wtfnet-core::logging::init(...)` should: * respect CLI flags + env vars * print to stderr * support `text|json` formats ### 7.2 Use spans for “timing breakdown” Example: HTTP diagnostics ```rust #[tracing::instrument(skip(client))] async fn http_head(client: &Client, url: &Url) -> Result { let _span = tracing::info_span!("http_head", %url).entered(); // measure dns/connect/tls/ttfb where possible Ok(report) } ``` --- ## 8) Platform abstraction pattern (Rust traits) In `wtfnet-platform`: ```rust pub trait SysProvider { async fn interfaces(&self) -> Result, PlatformError>; async fn routes(&self) -> Result, PlatformError>; async fn dns_config(&self) -> Result; } pub trait PortsProvider { async fn listening(&self) -> Result, PlatformError>; async fn who_owns(&self, port: u16) -> Result, PlatformError>; } pub trait CertProvider { async fn trusted_roots(&self) -> Result, PlatformError>; } pub trait NeighProvider { async fn neighbors(&self) -> Result, PlatformError>; } ``` Then provide: ```rust pub struct Platform { pub sys: Arc, pub ports: Arc, pub cert: Arc, pub neigh: Arc, } ``` OS dispatch: * `cfg(target_os = "linux")` → `wtfnet-platform-linux` * `cfg(target_os = "windows")` → `wtfnet-platform-windows` --- ## 9) Implementation notes per command area ### 9.1 sys (interfaces/routes/dns) **Interfaces** * start with `network-interface` ([Crates][10]) for a normalized list * if you need MTU / gateway details not exposed, add platform-native calls **Linux routes/neigh** * `rtnetlink` can manage links/addresses/ARP/route tables ([Docs.rs][1]) **Windows routes/neigh** * use Win32 IP helper APIs via `windows` crate --- ### 9.2 ports (listen/who) Best path: * use `listeners` crate for cross-platform “listening sockets → process” mapping ([GitHub][11]) Fallback: * `netstat2` provides cross-platform socket information ([Docs.rs][12]) --- ### 9.3 cert roots Use: * `rustls-native-certs` to load roots from OS trust store ([Crates][6]) Filtering: * by subject substring * by fingerprint sha256 * expired/not-yet-valid Diff: * export stable JSON * compare by fingerprint (sha256) --- ### 9.4 geoip (local mmdb) Use: * `maxminddb` Expose: * `GeoIpService::new(country_path, asn_path)` * `lookup(IpAddr) -> GeoInfo` --- ### 9.5 dns (query/detect/watch) Resolver: * Hickory DNS ecosystem ([Docs.rs][4]) Detect logic (keep deterministic): * Query multiple resolvers * Normalize answers (A/AAAA/CNAME) * “suspicious” if major divergence, NXDOMAIN mismatch, private IP injection patterns Watch: * feature-gate packet capture * document privilege needs clearly --- ### 9.6 http (head/get) HTTP/2: * `reqwest` makes this trivial HTTP/3 (optional): * use `h3` + `h3-quinn` + `quinn` ([GitHub][5]) Keep it behind `--http3` and fallback to HTTP/2 when UDP is blocked. Timing breakdown: * you’ll get total time easily * fine-grained DNS/connect/TLS timing may need deeper client hooks (ok to be best-effort) --- ### 9.7 tls (handshake/cert/verify) Handshake: * use `rustls` to connect and extract: * version, cipher suite, ALPN * peer cert chain Verify: * use `rustls-platform-verifier` if you want OS-like verification ([GitHub][7]) * otherwise load roots via `rustls-native-certs` ([Crates][6]) and verify with webpki --- ### 9.8 neigh (ARP/NDP) Linux: * `rtnetlink` includes ARP/neighbor operations ([Docs.rs][1]) Windows: * IP Helper API provides neighbor cache info (implementation detail) --- ### 9.9 discover (mDNS + SSDP) mDNS: * `mdns-sd` ([Crates][8]) Bounded `--duration`, no spam. SSDP: * `ssdp-client` ([Crates][9]) Send M-SEARCH, collect responses, parse location/server/usn. --- ## 10) Testing strategy ### 10.1 Unit tests (fast, pure) * subnet math (`calc`) * parsing/formatting * DNS comparison heuristics (test vectors) ### 10.2 Snapshot tests (JSON stability) Use `insta`: * ensure `--json` schema doesn’t drift accidentally ### 10.3 Integration tests (CI) * run non-privileged commands only: * `sys ifaces` * `calc subnet` * `dns query example.com A` * `http head https://example.com` --- ## 11) Coding conventions * Every command handler returns a structured `CommandEnvelope` * Never `println!` from libs; return data → CLI prints it * `--json` must be clean stdout (no logs mixed in) * Use timeouts everywhere in probe/dns/http/tls * Prefer “best-effort + warnings” over hard failure --- ## 12) Minimal “first coding milestone” plan 1. `wtfnet-core`: envelope + logging init + exit mapping 2. `wtfnet-cli`: clap skeleton + `sys ifaces` 3. `wtfnet-geoip`: load mmdb + `geoip ` 4. `ports listen/who` using `listeners` ([GitHub][11]) 5. `dns query` via Hickory ([Docs.rs][4]) 6. `http head` and `tls handshake` basic success path 7. `diag` orchestration + zip bundle ---