mtr is the de facto standard for interactive traceroute but hasn't seen major feature development in years. trippy (Rust) is the main modern alternative but focuses on a different feature set.
Key advantages ttl already has:
- ECMP path enumeration with per-flow/per-packet classification (
--flows) - NAT detection (source port rewrite analysis)
- ICMP rate limit detection (distinguish rate limiting from real loss)
- Route flap and asymmetric routing detection
- TTL manipulation detection (transparent proxies, middleboxes)
- Path MTU discovery (
--pmtud) - IX detection via PeeringDB
- Animated session replay
- Dual-stack
--resolve-all(trace IPv4 and IPv6 simultaneously)
- ICMP Echo probing with TTL sweep
- IPv4 and IPv6 support with extension header handling
- Real-time TUI with ratatui (11 built-in themes)
- Hop statistics (loss, min/avg/max, stddev, jitter, percentiles)
- Reverse DNS resolution (parallel lookups)
- MPLS label detection (RFC 4884/4950 ICMP extensions)
- JSON, CSV, and report export formats
- Session replay from saved JSON
- Multiple simultaneous targets (
ttl 8.8.8.8 1.1.1.1) - NAT detection (source port rewrite analysis)
- Paris/Dublin traceroute (
--flowsfor ECMP path enumeration) - UDP probing (
-p udp) and TCP SYN probing (-p tcp) - Protocol auto-detection (
-p auto, default) - ASN lookup (Team Cymru DNS), GeoIP (MaxMind), IX detection (PeeringDB)
- Terminal injection protection (sanitize external data)
- Terminal state cleanup on error/panic
- Interface binding (
--interface,--recv-any) - Shell completions (
--completions bash/zsh/fish/powershell) - Settings modal (theme, display mode, PeeringDB API key)
- Target list overlay for multi-target mode
- Autosize columns (auto/compact/wide with
wkey cycling) - Linux binary compatibility (musl libc for broad distro support)
- Path MTU discovery (
--pmtud) with binary search - Packet size control (
--size) with DF flag - DSCP/ToS marking (
--dscp) for QoS policy testing - ICMP rate limit detection with TUI indicators
- Route flap detection (primary responder IP changes)
- Asymmetric routing detection (forward vs return path hops)
- TTL manipulation detection (transparent proxies, middleboxes)
- First-hop gateway detection via kernel APIs (netlink/sysctl)
- Rate limiting (
--rate) for slow links - Source IP selection (
--source-ip) - Update notifications (checks GitHub releases, install-method-aware)
- FreeBSD support (experimental, raw sockets)
- Animated replay (
--replay file --animate) with speed control - Probe event recording for replay accuracy
- TUI refresh rate increased to 60fps (#17)
- Jumbo frame support (
--sizeup to 9216,--jumbofor PMTUD) - Immediate sent counting (mtr parity — increments at probe send, not response)
- Dual-stack
--resolve-all(trace IPv4 and IPv6 simultaneously) - FreeBSD ICMP socket fix (RAW sockets, not DGRAM)
- Last RTT column in main table (mtr parity —
Loss% Snt Last Avg Min Max StdDev) - JAvg and JMax columns in Wide display mode
- Wider ASN column for full AS name visibility
- ECMP classification: per-flow vs per-packet detection with primary_ratio heuristic (#46)
- Paths column reflects actual responder count for per-packet ECMP (#46)
-
Eindicator for ECMP detected vs!for route flap (#46) - Effective flow capability:
--flows+ ICMP warns and collapses to single-flow (#46) - Receiver flow attribution hardening: unknown flows only match when unambiguous (#46)
- NetBSD platform support (experimental, raw sockets, IPv6 PMTUD only) (#47)
- NetBSD UDP source IP auto-detection (fixes EHOSTUNREACH on DGRAM sockets) (#47)
- Update checker: non-blocking
try_recv()polling in TUI (replaces blockingrecv_timeout(1s)) - Update checker: first-run immediate network check (
interval(Duration::ZERO)) - Interactive replay controls (seek, speed, progress bar) shipped in v0.19.0
- Pre-commit hooks (
.pre-commit-config.yamlforcargo fmt/clippy/test) - CI:
cargo clippy --all-targets -- -D warningson Linux, macOS, and FreeBSD - hickory-resolver 0.26 upgrade (closes RUSTSEC-2026-0118 and RUSTSEC-2026-0119)
- Trace diffing (
--diff before.json after.json): added/lost hops, path changes, latency shifts;--jsonfor machine-readable output - Streaming JSON output (
--stream-json): line-delimited probe events + per-target summary, composable with jq/grep - Daemon mode (
--daemon) with graceful SIGTERM shutdown (cleandocker stop) - Prometheus/OpenMetrics exporter (
--prometheus :9090) with/healthzfor orchestration - Official Dockerfile + multi-arch (amd64/arm64) GHCR images (
ghcr.io/lance0/ttl) - Interactive target selection:
ttlwith no args opens an empty session;oadds targets mid-session with runtime engine/receiver spawning - IX prefix lookup via binary radix trie (O(prefix_len) instead of O(n) linear scan)
- New
aarch64-unknown-linux-muslrelease artifact
- Opt out of the startup update check (#110):
--no-update-checkflag,DO_NOT_TRACK/TTL_NO_UPDATE_CHECKenv vars,no_update_checkconfig key, a TUI Settings toggle, and a--no-default-featuresbuild that compiles the check (andupdate-informer) out entirely
- TUI renders only on change (#129, #131): a per-tick render fingerprint skips the session snapshot and the redraw when nothing moved — 1.4% → 0.4% of one CPU core on a 9-hop trace, scaling with hop count. Session mutations mark the view dirty through the lock's write guard, so no writer can leave the display stale.
- Published crate excludes the demo GIF/tape, halving the crates.io tarball (1.14 MB → 0.56 MB compressed)
- Security: rkyv 0.8.18 (RUSTSEC-2026-0233/0234/0235) and lru 0.18.2 (RUSTSEC-2026-0253)
- RFC 5837 interface and next-hop identification (#134, #137): Interface Information Objects in ICMP Time Exceeded / Destination Unreachable messages — ifIndex, IP, interface name, MTU for the incoming/outgoing/sub-IP/next-hop roles — parsed alongside RFC 4950 MPLS labels, shown in the hop detail view and JSON export. Validated against Arista EOS captures. Fixed the ICMPv6 RFC 4884 length field, which had blocked all ICMPv6 extensions.
-
scripts/fakertr: a containerised fake RFC 5837 router for end-to-end smoke tests of the ICMP extension path with real packets - Security: rustls 0.23.45 (RUSTSEC-2026-0285), maxminddb 0.31 (MMDB decode DoS hardening)
The macOS single-hop fix (#12) removes the stale-TTL race from the probe send paths, now complete across IPv4 and IPv6 on every platform. IPv4 is unified on IP_HDRINCL (TTL written into a hand-built IP header sent through one raw socket); IPv6 sends each probe from a fresh socket on the BSD-derived platforms (per_probe_send = macOS/FreeBSD/NetBSD). The rapid probe sweeps are race-free, so the interim timing delay is gone; the lone IPv6 PMTUD probe per round still uses the shared socket but is an isolated send. Validated on real Linux, macOS, and FreeBSD kernels in CI.
- Unify the IPv4 send path on
IP_HDRINCL. TTL in the IP header; per-OSip_len/ip_offbyte order handled (host order on macOS/NetBSD, network order on Linux/FreeBSD ≥11); transport (ICMP/UDP/TCP) checksums built in; CI runs a privileged real-kernel send test on Linux/macOS/FreeBSD. Also fixes IPv4 PMTUD on NetBSD (DF set in the header, not via the missingIP_DONTFRAG). - IPv6: deterministic per-packet hop limit on FreeBSD/NetBSD. Extended the per-probe-socket path (previously macOS-only) to FreeBSD/NetBSD via the new
per_probe_sendcfg (build.rs). Linux keeps one shared socket (no race there). - Dropped the 500µs
apply_rate_limitdelay. Redundant now that IPv4 usesIP_HDRINCLand IPv6 uses per-probe sockets on all BSD-derived platforms; only the explicit--ratedelay remains.
Why this matters: Per-packet load balancing (common on Arista, Juniper, Cisco) is undercounted by the current flow-primary model. Users see 8 responders in the detail view but "Paths: 1" in the main table. Related: #46
- Detect per-packet vs per-flow ECMP (primary_ratio heuristic per flow)
- Paths column reflects actual responder count for per-packet ECMP
- Separate indicators:
Efor ECMP detected vs!for route flap - Warn when
--flows > 1with effective ICMP probing (-p icmp, or-p autowhen auto-select resolves to ICMP) - Define
-p autowarning semantics for multi-target/mixed-family runs (warn if any target resolves to effective ICMP, avoid duplicate spam) - Track effective flow capability at runtime (requested
--flowsvs effective protocol) and use it for flap detection + NAT/Paths column visibility - Add CLI/TUI hint that flow-based ECMP detection is meaningful with UDP/TCP probes
- Keep Paths value + highlight + host indicator driven by one shared ECMP classification (avoid count/style drift)
- Handle out-of-range returned src ports as unknown flow (not forced flow 0) to avoid false per-flow attribution behind NAT/CGNAT
- Update indicator/UI budget for new
Emarker (host width autosize currently assumes" !~^") - Update user-facing indicator docs/help (
Evs!) in CLI help + docs pages - Add tests for per-packet ECMP classification,
-p autoICMP warning behavior, and out-of-range src-port flow attribution - #46 acceptance: per-packet ECMP no longer presents as misleading
Paths: 1when many responders are observed - #46 acceptance:
E(ECMP) and!(route flap) are no longer conflated in the same scenario - Paris strategy for UDP (
--strategy paris— fixed 5-tuple, checksum encodes sequence) (follow-on after #46 core fix) - Dublin strategy for UDP (
--strategy dublin— IP ID field encodes sequence) (follow-on after #46 core fix)
Prioritized by effort vs user impact. Quick wins first, then bigger lifts.
- Progress indicator in replay — show position in timeline during animated replay
- Interactive replay — step through events, jump to time, speed control
- Last metric semantics — documented as primary-responder-most-recent; TUI/CSV aligned
- IPv6 RAW payload fallback tests — unit tests for IPv6 Echo Reply and Time Exceeded parsing
- Main table layout tests — verify header/cell/width count parity across Auto/Compact/Wide × single-flow/multi-flow modes
- PCAP export — write probe/response packets to .pcap for Wireshark analysis
- IX lookup performance — radix trie for O(prefix_len) instead of O(n) linear scan
- Customizable columns — choose which stats to display in TUI
- Container image — pre-built multi-arch image on GHCR for CI/monitoring pipelines
- ICMP checksum flow variation — Paris traceroute for ICMP (vary checksum to create distinct flows). Neither ttl nor trippy implements this today. Requires platform-specific raw socket work (kernel checksum offloading on Linux, IP_HDRINCL). Note: Real-world value may be limited — Arista hardware flow-hashing platforms don't use ICMP checksum as entropy, so this approach won't create distinct flows on most switch hardware. TCP/UDP remain the reliable methods for multi-path detection. May still be useful on software load balancers.
- BGP & routing integration — looking glass queries, AS path display, RPKI/ROA validation
- Baseline comparison — save baseline, alert on latency/loss/path deviations
- Continuous logging mode — log path changes over hours/days
- Historical data storage — SQLite/file-based path history
- Custom keybindings — user-configurable key mappings
- World map visualization — ASCII/Unicode geographic path display
- Advanced protocol testing — TCP MSS clamping, ECN, fragmentation testing
- Multi-path validation — verify all ECMP paths are functional
- Library API stabilization (stable
lib.rsfor third-party integrations) - Comprehensive documentation for library consumers
- Semantic versioning commitment
- Integration tests for probe-receive-state pipeline
- Property-based/fuzz tests for packet parsing (correlate.rs)
- RAW payload fallback unit tests (IPv4)
- IPv6 RAW payload fallback unit tests
- Concurrent multi-target stress tests
- Basic ICMP traceroute (Npcap or Winsock raw sockets)
- TUI compatibility with Windows Terminal
- Pre-built binaries
Rationale: Massive Npcap effort. WSL2 works well. Revisit if demand warrants.
- Remote agent for measuring both directions
- One-way delay estimation (detect latency asymmetry)
Rationale: Requires deploying an agent on the remote side, which changes the tool's simplicity model.
- Bandwidth/capacity estimation (pathchar-style probing)
- SNMP integration (query router interface stats)
- Network topology learning (build graph from multiple traces)
Rationale: These push ttl toward being a full network management tool. Better served by purpose-built tools.
| Tool | Language | ECMP | MTU Discovery | Rate Limit Detection | TUI | Active Development |
|---|---|---|---|---|---|---|
| mtr | C | No | No | No | Yes | Maintenance |
| trippy | Rust | Yes (UDP) | No | No | Yes | Active |
| traceroute | C | No | Yes | No | No | Maintenance |
| tracepath | C | No | Yes | No | No | Maintenance |
| ttl | Rust | Yes (per-flow + per-packet) | Yes | Yes | Yes | Active |
ttl is a CLI traceroute tool. The following are explicitly out of scope:
- Web/mobile UI — this is a CLI tool, SSH into a box
- Shareable URLs / hosted trace service — JSON files are the sharing format
- Webhook/event streaming — use
--stream-json | curlinstead - Monitor mode with alerting — use Smokeping/Nagios for long-running monitoring
- Modular output plugins — Unix pipes are the plugin system
- Hop privacy mode (mask IPs for screenshots) — users can redact manually
- Multi-language TUI (i18n) — English-only is fine for CLI tools
- Full packet capture — use tcpdump/wireshark
- Bandwidth testing — use xfr or iperf
- Port scanning — use nmap
- Enterprise collaboration platform — not a SaaS product
If you need these features, combine ttl with purpose-built tools.
See KNOWN_ISSUES.md for documented edge cases and limitations.
- GitHub Actions CI (build, test, clippy, FreeBSD)
- Binary releases (Linux x86_64/aarch64, macOS x86_64/aarch64)
- Homebrew core formula (
brew install ttl) +lance0/tap/ttltap - Curl installer (
install.sh) - Dependabot (Cargo + GitHub Actions)
- AUR package (
ttl-bin, community-maintained) - Gentoo package (
net-analyzer/ttl, official repository) - Container image on GHCR (
ghcr.io/lance0/ttl, multi-arch, published on release) - Docker Hub mirror (optional — needs registry credentials; GHCR covers the use case)
See issues labeled good first issue for entry points. PRs welcome for any roadmap item.