Skip to content
/ xfr Public

A modern iperf3 alternative with a live TUI, multi-client server, and QUIC support. Built in Rust.

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

lance0/xfr

xfr

xfr logo

A modern iperf3 alternative with a live TUI, multi-client server, and QUIC support. Built in Rust.

Crates.io CI License Ko-fi

Quick Start

# Server
xfr serve

# Client (in another terminal or machine)
xfr 192.168.1.1              # Basic TCP test
xfr 192.168.1.1 -P 4         # 4 parallel streams
xfr 192.168.1.1 -u -b 1G     # UDP at 1 Gbps

See Installation below for setup instructions.

TUI Preview

xfr TUI interface

Features

  • Live TUI with real-time throughput graphs and per-stream stats
  • Server dashboard - xfr serve --tui for monitoring active tests
  • Multi-client server - handle multiple simultaneous tests
  • TCP, UDP, and QUIC with configurable bitrate and parallel streams
  • Single-port TCP - firewall-friendly, only port 5201 needed (no ephemeral data ports)
  • Bidirectional testing - measure upload and download simultaneously
  • Multiple output formats - plain text, JSON, JSON streaming, CSV
  • Result comparison - xfr diff to detect performance regressions
  • LAN discovery - find xfr servers with mDNS (xfr discover)
  • Prometheus metrics - export stats for monitoring dashboards
  • Config file - save defaults in ~/.config/xfr/config.toml
  • Environment variables - XFR_PORT, XFR_DURATION overrides

vs iperf3

Feature iperf3 xfr
Live TUI No Yes (client & server)
Multi-client server No Yes
Single-port TCP No (needs ephemeral ports) Yes (only port 5201)
Output formats Text/JSON Text/JSON/CSV
Prometheus metrics No Yes (optional feature)
Compare runs No xfr diff
LAN discovery No xfr discover
Config file No Yes

Real-World Use Cases

VPN Tunnel Testing

Measure actual throughput through your VPN:

# On VPN server
xfr serve

# From client, through VPN
xfr 10.8.0.1 -t 30s

UDP Congestion Detection

Test UDP at your expected rate to detect packet loss:

xfr <host> -u -b 500M -t 60s    # Watch for loss percentage in TUI

Before/After Comparison

Quantify the impact of network changes:

xfr <host> --json -o before.json
# ... make changes ...
xfr <host> --json -o after.json
xfr diff before.json after.json --threshold 5

Multi-Stream for Bonded Connections

Test aggregate bandwidth across bonded/LACP interfaces:

xfr <host> -P 8 -t 30s          # 8 streams to utilize all links

Prometheus Monitoring

Continuous performance monitoring:

xfr serve --prometheus 9090 --push-gateway http://pushgateway:9091
# Scrape metrics or view in Grafana

Installation

From crates.io (Recommended)

Requires Rust 1.88+:

# Install Rust (if not already installed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

# Install xfr
cargo install xfr

Homebrew (macOS/Linux)

brew install lance0/tap/xfr

Pre-built Binaries

Download from GitHub Releases:

Platform Target
Linux x86_64 xfr-x86_64-unknown-linux-musl.tar.gz
Linux ARM64 xfr-aarch64-unknown-linux-gnu.tar.gz
macOS Apple Silicon xfr-aarch64-apple-darwin.tar.gz
macOS Intel Use cargo install xfr
Android (Termux) xfr-aarch64-linux-android.tar.gz
Windows Use WSL2 (native support is experimental)
# Example: Linux x86_64
curl -LO https://github.com/lance0/xfr/releases/latest/download/xfr-x86_64-unknown-linux-musl.tar.gz
tar xzf xfr-*.tar.gz && sudo mv xfr /usr/local/bin/

From Source

git clone https://github.com/lance0/xfr
cd xfr && cargo build --release
sudo cp target/release/xfr /usr/local/bin/

Quick Install Script

Note: Review scripts before piping to sh. See the install script source.

curl -fsSL https://raw.githubusercontent.com/lance0/xfr/master/install.sh | sh

Termux (Android)

Download the aarch64-linux-android binary from releases, or build from source:

pkg install rust
cargo install xfr

NetBSD

Available via pkgsrc:

pkgin install xfr

Optional Features

Feature Default Description
discovery Yes mDNS LAN discovery (xfr discover)
prometheus No Prometheus metrics endpoint and Push Gateway support
cargo install xfr --features prometheus    # Prometheus support
cargo install xfr --all-features           # All features

Shell Completions

# Bash
xfr --completions bash > ~/.local/share/bash-completion/completions/xfr

# Zsh (add ~/.zfunc to fpath in .zshrc first)
xfr --completions zsh > ~/.zfunc/_xfr

# Fish
xfr --completions fish > ~/.config/fish/completions/xfr.fish

# PowerShell (add to $PROFILE)
xfr --completions powershell >> $PROFILE

# Elvish
xfr --completions elvish > ~/.elvish/lib/xfr.elv

Usage

Server

xfr serve                    # Listen on port 5201
xfr serve -p 9000            # Custom port
xfr serve --tui              # Live dashboard showing active tests
xfr serve --one-off          # Exit after one test
xfr serve --max-duration 60s # Limit test duration
xfr serve --push-gateway http://pushgateway:9091  # Push metrics on test complete
xfr serve --psk mysecret     # Require PSK authentication
xfr serve --rate-limit 2     # Max 2 concurrent tests per IP
xfr serve --allow 192.168.0.0/16 --deny 0.0.0.0/0  # IP ACL

Client

xfr 192.168.1.1              # TCP test, 10s, single stream
xfr 192.168.1.1 -t 30s       # 30 second test
xfr 192.168.1.1 -P 4         # 4 parallel streams
xfr 192.168.1.1 -R           # Reverse (download test)
xfr 192.168.1.1 --bidir      # Bidirectional
xfr 192.168.1.1 -6           # Force IPv6 only
xfr ::1 -6                   # IPv6 localhost

UDP Mode

xfr 192.168.1.1 -u           # UDP mode
xfr 192.168.1.1 -u -b 1G     # UDP at 1 Gbps
xfr 192.168.1.1 -u -b 100M   # UDP at 100 Mbps

QUIC Mode

xfr 192.168.1.1 --quic       # QUIC transport (encrypted)
xfr 192.168.1.1 --quic -P 4  # QUIC with 4 parallel streams
xfr 192.168.1.1 --quic -R    # QUIC download test

QUIC provides built-in TLS 1.3 encryption with stream multiplexing over a single connection.

Security Note: QUIC encrypts traffic but does not verify server identity by default. For authenticated connections, use --psk on both client and server to prevent MITM attacks.

Output Formats

xfr <host> --json              # JSON summary
xfr <host> --json-stream       # JSON per interval (for scripting)
xfr <host> --csv               # CSV output
xfr <host> -q                  # Quiet mode (summary only)
xfr <host> -o results.json     # Save to file
xfr <host> --no-tui            # Plain text, no TUI
xfr <host> --timestamp-format iso8601  # ISO 8601 timestamps

Note: Log messages go to stderr, allowing clean JSON/CSV piping: xfr <host> --json 2>/dev/null

Interval Control

xfr <host> -i 2                # Report every 2 seconds
xfr <host> --omit 3            # Skip first 3s of intervals (TCP ramp-up)

Compare Results

xfr diff baseline.json current.json
xfr diff baseline.json current.json --threshold 5

Discovery

xfr discover                 # Find xfr servers on LAN
xfr discover --timeout 10s   # Extended search

Keybindings (Client TUI)

Key Action
q Quit (cancels test)
p Pause/Resume display
s Settings modal
t Cycle color theme
d Toggle per-stream view
? / F1 Help
j Print JSON result
u Dismiss update notification

Keybindings (Server TUI)

Key Action
q Quit server
? / F1 Help
Esc Close help

Themes

xfr includes 11 built-in color themes. Select with --theme or press t during a test:

xfr <host> --theme dracula     # Dark purple theme
xfr <host> --theme matrix      # Green on black hacker style
xfr <host> --theme catppuccin  # Soothing pastels
xfr <host> --theme nord        # Arctic blue tones

Available themes: default, kawaii, cyber, dracula, monochrome, matrix, nord, gruvbox, catppuccin, tokyo_night, solarized

Your theme preference is auto-saved to ~/.config/xfr/prefs.toml.

Configuration

xfr reads defaults from ~/.config/xfr/config.toml:

[client]
duration_secs = 10
parallel_streams = 1
tcp_nodelay = false
json_output = false
no_tui = false
theme = "default"  # or dracula, catppuccin, nord, matrix, etc.
timestamp_format = "relative"  # or "iso8601", "unix"
log_file = "~/.config/xfr/xfr.log"
log_level = "info"

[server]
port = 5201
push_gateway = "http://pushgateway:9091"
log_file = "~/.config/xfr/xfr-server.log"
log_level = "info"
psk = "my-secret-key"
rate_limit = 5
allow = ["192.168.0.0/16", "10.0.0.0/8"]

Environment variables override config file:

export XFR_PORT=9000
export XFR_DURATION=30s

Prometheus Metrics

Enable with --features prometheus:

xfr serve --prometheus 9090

Metrics available at http://localhost:9090/metrics:

  • xfr_bytes_total - Total bytes transferred
  • xfr_throughput_mbps - Current throughput
  • xfr_active_tests - Number of active tests
  • xfr_retransmits_total - TCP retransmissions

See examples/grafana-dashboard.json for a sample Grafana dashboard.

CLI Reference

Flag Short Default Description
--port -p 5201 Server/client port
--time -t 10s Test duration (use 0 for infinite)
--udp -u false UDP mode
--quic -Q false QUIC mode (encrypted, multiplexed streams)
--bitrate -b 1G Target bitrate for UDP (e.g., 1G, 100M). Use -b 0 for unlimited
--parallel -P 1 Parallel streams
--reverse -R false Reverse direction (download)
--bidir false Bidirectional test
--ipv4 -4 false Force IPv4 only
--ipv6 -6 false Force IPv6 only
--bind none Local address to bind (e.g., 192.168.1.100)
--json false JSON output
--json-stream false JSON per interval
--csv false CSV output
--quiet -q false Summary only
--interval -i 1.0 Report interval (seconds)
--omit 0 Omit first N seconds
--output -o stdout Output file
--no-tui false Disable TUI
--theme default Color theme (dracula, nord, matrix, etc.)
--tcp-nodelay false Disable Nagle algorithm
--window OS default TCP window size
--congestion OS default TCP congestion control algorithm (e.g. cubic, bbr, reno)
--timestamp-format relative Timestamp format (relative, iso8601, unix)
--log-file none Log file path (e.g., ~/.config/xfr/xfr.log)
--log-level info Log level (error, warn, info, debug, trace)
--push-gateway none Prometheus Push Gateway URL (server)
--prometheus none Prometheus metrics port (server, requires feature)
--psk none Pre-shared key for authentication
--psk-file none Read PSK from file
--rate-limit none Max concurrent tests per IP (server)
--rate-limit-window 60s Rate limit time window (server)
--completions none Generate shell completions (bash, zsh, fish, powershell, elvish)
--allow none Allow IP/subnet, repeatable (server)
--deny none Deny IP/subnet, repeatable (server)
--acl-file none ACL rules file (server)
--max-duration none Maximum test duration, server-side limit (server)
--tui false Enable live dashboard (server)
--one-off false Exit after one test (server, works with TCP and QUIC)

Security Considerations

Transport Encryption

Mode Encryption Certificate Verification
TCP None N/A
UDP None N/A
QUIC TLS 1.3 Disabled by default

QUIC mode (-Q/--quic) provides TLS 1.3 encryption but does not verify server certificates, making it vulnerable to MITM attacks without additional authentication. Always use --psk with QUIC on untrusted networks. Alternatively, use a VPN or SSH tunnel.

Authentication

PSK authentication (--psk) verifies client identity but does not encrypt TCP/UDP traffic. For encrypted + authenticated connections, use QUIC with PSK:

# Server
xfr serve --psk "secretkey"

# Client (encrypted + authenticated)
xfr <host> -Q --psk "secretkey"

Network Considerations

  • Single-port TCP: TCP uses single-port mode by default -- control and data connections share port 5201. Data connections are validated against the control connection's IP address, preventing unauthorized access.
  • UDP on untrusted networks: UDP mode may be susceptible to reflection attacks from spoofed source addresses. Use TCP or QUIC on public networks.
  • Rate limiting: Use --rate-limit on public servers to prevent abuse.
  • ACLs: Use --allow/--deny to restrict client access.

DoS Protections

  • Slow-loris resistance: New connections must send their first message within 5 seconds, preventing slow-loris attacks from blocking the accept loop.
  • DataHello flood protection: DataHello messages for unknown test IDs are rejected immediately without allocating resources.
  • Bounded reads: All control messages are limited to 8KB, preventing memory exhaustion from oversized messages.
  • Capability negotiation: Client and server exchange capabilities during the Hello handshake (protocol version 1.1), enabling safe feature evolution.
  • Concurrent connection limits: Server limits concurrent handlers (default 100) to prevent connection floods.

Server Resource Usage

Each stream allocates 128KB-4MB for buffers depending on speed mode. Memory usage scales with concurrent clients:

Streams per client Memory per client 10 clients
1 (-P 1) 128KB - 4MB 1.3MB - 40MB
8 (-P 8) 1MB - 32MB 10MB - 320MB
128 (-P 128) 16MB - 512MB 160MB - 5GB

The server limits concurrent handlers (default 100) to prevent resource exhaustion. Use --rate-limit to restrict tests per IP.

Platform Support

Platform Status
Linux x86_64/ARM64 Full support, pre-built binaries
macOS Apple Silicon Full support, pre-built binaries
macOS Intel Full support, build from crate: cargo install xfr
Android (Termux) Full support, pre-built binaries
NetBSD Full support, via pkgsrc: pkgin install xfr
Windows Experimental (WSL2 recommended). Native builds work but lack TCP_INFO metrics.

Troubleshooting

Permission denied on port 5201

Use a port above 1024 or run with elevated privileges:

xfr serve -p 9000

Connection refused

Ensure the server is running and the port is not blocked by a firewall. TCP only requires port 5201 (or your custom port) to be open -- no additional ephemeral data ports are needed. For UDP, each stream uses a separate port allocated by the server.

Low throughput

  • Try multiple parallel streams: -P 4
  • Disable Nagle's algorithm: --tcp-nodelay
  • Increase TCP window size: --window 4M

UDP packet loss

  • Reduce bitrate: -b 500M
  • Check for network congestion or firewall issues

Documentation

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

About

A modern iperf3 alternative with a live TUI, multi-client server, and QUIC support. Built in Rust.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published