ztunnel-core is early-stage and in active development. The figures on this page are derived from the crate source as it stands today (Cargo.toml, src/lib.rs, src/ffi.rs): version, crate-types, the dotted commands matched in Engine::invoke, and the exported C symbols. The "planned" column lists work that is not yet implemented — it is a roadmap, not a claim of coverage.
Module map
| module | role today | planned |
|---|---|---|
| lib (Engine) | one dotted command surface via Engine::invoke; event sink; connect/disconnect orchestration | on-demand connect triggers driven from the host |
| model | config · backend · connection · status · stats · log · settings types | per-config advanced OpenVPN options matrix |
| config · lint · redact · migrate | parse + import OpenVPN .ovpn, Tunnelblick .tblk bundles (config located inside the bundle), WireGuard .conf; backend auto-detect; inline <ca>/<cert>/<key> block extraction (openvpn.inline_blocks); the security linter and structured diff (config.lint · config.lint_text · config.diff); secret redaction for a shareable copy (config.redact); OpenVPN↔WireGuard translation (config.migrate) | — |
| manager · policy · scheduler · netmonitor | per-config lifecycle state machine; logs; throughput sampling; network-trust policy (auto-connect on untrusted Wi-Fi, per-app decisions — policy.wifi_action · policy.app_decisions); reconnect backoff/jitter/give-up computed as a pure function (vpn.reconnect_schedule); default-path signature monitoring that fires the reconnect (vpn.network_changed) | — |
| openvpn · supervisor · ncp | argv construction + management-interface protocol parser (STATE · BYTECOUNT · PASSWORD · LOG); the net-gated process supervisor that spawns the system openvpn against a private temp config with --management wired; offline data-channel cipher agreement between two configs (openvpn.negotiate) and --push reply modelling | interactive auth prompts (host side) |
| wireguard · wireguard_tunnel · wghandshake · wgcookie · wgprobe · wgrank · x25519 | typed .conf parse with 32-byte key validation; pure-Rust X25519 keygen (wg.genkey · wg.pubkey); offline Noise_IKpsk2 handshake and cookie/MAC models; the wireguard-feature userspace data path over boringtun (tun/utun + UDP + Noise pump); the interface-less handshake probe (wgprobe feature — wg.probe · wg.probe_all) and authenticated peer ranking (wg.rank) | — |
| platform (macos · linux) | typed NetOp set; privilege detection | utun/tun creation, routing, DNS via privileged helper |
| privileged | ordered bring-up PrivilegePlan from a config | SMAppService (macOS) / polkit (Linux) helper execution |
| creds | CredStore trait + session-only in-memory store (no plaintext on disk); the keychain-feature KeychainCreds backend over keyring (macOS Keychain / Linux Secret Service / Windows credential manager), one JSON secret per config id | — |
| log · stats · connlog | bounded per-connection log buffer; throughput rate sampler; fixed-width bandwidth rollups (stats.rollup), session summaries, data budgets and uptime/error-budget SLA (stats.uptime_sla); connection-log analysis (log.analyze) | — |
| store | profile (configs + settings) JSON load/save, plus whole-profile export/import as one bundle (profile.export · profile.import) | — |
| route · killswitch · leakdelta · firewall · impact | Route-table conflict detection and tunnel coverage (route.conflicts · route.coverage), the leak surface and its continuous delta (route.leak_surface · route.leak_delta · vpn.leak_watch), kill-switch firewall planning and its rendered syntax (vpn.killswitch_plan · vpn.killswitch_syntax), NAT/MSS rule generation, and the pre-connect blast-radius preview (vpn.impact_preview) | live rule installation (privileged helper) |
| dns · dnssplit · dnswire | Resolver modelling and leak checks (dns.leak_check · dns.block_match · dns.bootstrap_plan), split-horizon resolver selection by domain suffix (dns.split_horizon), and DNS wire-format / DoH / DoT request building (dns.query_wire) | live resolver installation (privileged helper) |
| netcalc · tcpmeltdown · multihop · proxy · obfs · ipsec | Pure IP/CIDR arithmetic behind split tunnelling and AllowedIPs (net.*), the TCP-over-TCP meltdown-margin solver (net.tcp_meltdown), multi-hop cascade resolution with MTU budget and rekey schedule, proxy-over-tunnel planning, the pluggable-transport catalog, and the IKEv2/IPsec profile model | — |
| servers · pki · forecast | The server catalog with latency, favourites, quality ranking, fastest-server selection and failover plans (servers.*); X.509 analysis of inline certificate material with connect and fleet expiry forecasts (pki.audit_config · pki.connect_forecast · pki.fleet_forecast) | — |
| ffi | C ABI: ztn_init · ztn_invoke · ztn_set_event_callback · ztn_string_free | richer event payloads |
tauri_plugin (feature tauri) | Tauri v2 plugin glue + mountable webui | per-window capability scoping |
Build surfaces
The crate declares crate-type = ["rlib", "staticlib", "cdylib"]. The rlib links natively into Rust/Tauri hosts; the staticlib/cdylib expose the C ABI for non-Rust hosts. The default net feature gates the OS-level transport (OpenVPN management socket, WireGuard UDP), all std-only today; building --no-default-features yields a pure config/model/manager core that compiles in headless CI. The optional wireguard feature adds the boringtun userspace data path (tun/utun device, UDP socket, Noise pump), wgprobe the interface-less handshake probe that needs neither tun nor privilege, keychain the OS-keychain credential backend over keyring, and tauri the GUI plugin layer.
Verification
The crate carries 362 in-source unit tests (356 with --no-default-features) across the engine and its modules: the command surface (version/platform reporting, config add/list/get/remove, a connect-without-privilege honest-error path, log accumulation, bad-WireGuard rejection, unknown-command tagging), plus module-level tests in config, wireguard, openvpn (management-line parsing + argv), manager (state transitions), privileged (plan building), stats, store, log and util. Tests run without root or network access and pass identically in headless Linux CI; the privileged bring-up returns an honest needs_privilege error rather than a faked tunnel.