Siavash Sameni 23db39a84e
All checks were successful
CI / test (push) Successful in 1m26s
Add CSV output to server mode
Server now writes a CSV row for each completed test with peer IP,
protocol, direction, duration, avg speeds, bytes, and lost packets.

Verified on loopback: TX 35 Gbps, RX 51 Gbps captured in CSV.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 10:19:15 +04:00
2026-04-01 10:19:15 +04:00

btest-rs

A Rust reimplementation of the MikroTik Bandwidth Test (btest) protocol. Both server and client modes, fully compatible with MikroTik RouterOS devices.

Features

  • Full protocol support -- TCP and UDP data transfer, IPv4 and IPv6
  • EC-SRP5 authentication -- modern RouterOS >= 6.43 Curve25519-based auth (server and client)
  • MD5 authentication -- legacy RouterOS < 6.43 challenge-response auth
  • Multi-connection support -- handles MikroTik's multi-connection UDP mode
  • Bidirectional testing -- simultaneous upload and download
  • Syslog logging -- send structured events (auth, test start/end) to a remote syslog server
  • CSV output -- append machine-readable test results to a CSV file
  • Timed tests -- --duration flag to automatically stop after N seconds
  • Quiet mode -- suppress terminal output for scripted/automated use
  • NAT traversal -- probe packet to open firewall holes for UDP receive
  • Single static binary -- ~2 MB, zero runtime dependencies (musl build)
  • Cross-platform -- macOS, Linux (x86_64, ARM64), Docker
  • Async I/O -- tokio-based, handles many concurrent connections efficiently

Performance

Tested over WiFi 6E (MikroTik RouterOS <-> macOS):

Mode Protocol Speed
Server RX (1 conn) UDP 1.05 Gbps
Client TCP download TCP 530 Mbps
Client TCP upload TCP 840 Mbps
Client UDP download UDP 433 Mbps
Client TCP bidirectional TCP 264/264 Mbps
Server bidirectional UDP 280/393 Mbps

On wired gigabit links, expect line-rate performance in both TCP and UDP modes.

Installation

From source

cargo install --path .

Pre-built binary (Linux x86_64)

# Cross-compile from macOS (requires Docker)
scripts/build-linux.sh

# Copy to server
scp dist/btest root@yourserver:/usr/local/bin/btest

Docker

docker compose up -d

See docs/docker.md for full Docker and deployment options.

systemd service

sudo ./scripts/install-service.sh
sudo ./scripts/install-service.sh --auth-user admin --auth-pass secret
sudo ./scripts/install-service.sh --auth-user admin --auth-pass secret --port 2000

The installer creates a dedicated btest system user, installs a hardened systemd unit, and enables the service.

Quick Start

Server mode

MikroTik devices connect to this server to run bandwidth tests.

# No authentication
btest -s

# MD5 authentication (legacy RouterOS)
btest -s -a admin -p password

# EC-SRP5 authentication (RouterOS >= 6.43)
btest -s -a admin -p password --ecsrp5

# Custom port, verbose logging
btest -s -P 3000 -v

# With syslog and CSV logging
btest -s -a admin -p password --syslog 192.168.1.1:514 --csv /var/log/btest.csv

Client mode

Connect to a MikroTik device's built-in btest server.

# TCP download test
btest -c 192.168.88.1 -r

# TCP upload test
btest -c 192.168.88.1 -t

# Bidirectional TCP
btest -c 192.168.88.1 -t -r

# UDP download with bandwidth limit
btest -c 192.168.88.1 -r -u -b 100M

# With authentication
btest -c 192.168.88.1 -r -a admin -p password

# Timed test (30 seconds), results to CSV
btest -c 192.168.88.1 -r -d 30 --csv results.csv

# Quiet mode (no terminal output)
btest -c 192.168.88.1 -r -d 10 --csv results.csv -q

# UDP through NAT
btest -c 192.168.88.1 -r -u -n

Debug logging

btest -s -v       # debug messages
btest -s -vv      # trace messages (hex dumps of status exchange)
btest -s -vvv     # maximum verbosity

CLI Reference

Usage: btest [OPTIONS]

Options:
  -s, --server                Run in server mode
  -c, --client <HOST>         Run in client mode, connect to HOST
  -t, --transmit              Client transmits data (upload test)
  -r, --receive               Client receives data (download test)
  -u, --udp                   Use UDP instead of TCP
  -b, --bandwidth <BW>        Target bandwidth limit (e.g., 100M, 1G, 500K)
  -P, --port <PORT>           Listen/connect port [default: 2000]
      --listen <ADDR>         IPv4 listen address [default: 0.0.0.0] (use "none" to disable)
      --listen6 [<ADDR>]      Enable IPv6 listener [default: ::] (experimental)
  -a, --authuser <USER>       Authentication username
  -p, --authpass <PASS>       Authentication password
      --ecsrp5                Use EC-SRP5 authentication (RouterOS >= 6.43)
  -n, --nat                   NAT traversal mode (send UDP probe packet)
  -d, --duration <SECS>       Test duration in seconds (client mode, 0=unlimited) [default: 0]
      --csv <FILE>            Output results to CSV file (appends if file exists)
  -q, --quiet                 Suppress terminal output (use with --csv)
      --syslog <HOST:PORT>    Send logs to remote syslog server (UDP, RFC 3164)
  -v, --verbose               Increase log verbosity (-v, -vv, -vvv)
  -h, --help                  Show help
  -V, --version               Show version

MikroTik Configuration

Enable btest server on MikroTik (for client mode)

/tool/bandwidth-server set enabled=yes

Run btest from MikroTik (connecting to our server)

/tool/bandwidth-test address=<server-ip> direction=both protocol=udp \
    user=admin password=password

Protocol

The MikroTik btest protocol uses:

  • TCP port 2000 for control (handshake, authentication, status exchange)
  • UDP ports 2001+ for data transfer (server side)
  • UDP ports 2257+ for data transfer (client side, offset +256)
  • MD5 double-hash challenge-response authentication (RouterOS < 6.43)
  • EC-SRP5 Curve25519 Weierstrass authentication (RouterOS >= 6.43)
  • 1-second status interval with dynamic speed adjustment

See docs/protocol.md for the full wire-format specification.

Authentication

Both legacy and modern MikroTik authentication schemes are supported:

Scheme RouterOS Version Flag
None Any (no flags)
MD5 challenge-response < 6.43 -a USER -p PASS
EC-SRP5 (Curve25519) >= 6.43 -a USER -p PASS --ecsrp5

In server mode, --ecsrp5 advertises EC-SRP5 to connecting clients. Without it, MD5 is advertised. In client mode, the authentication type is auto-detected from the server's response.

Known Limitations

  • IPv6 support is experimental (--listen6). TCP over IPv6 works fully. UDP over IPv6 has issues on macOS due to kernel ENOBUFS limitations with send_to(). On Linux, IPv6 UDP works correctly.
  • Multi-connection UDP is supported. MikroTik's multi-connection mode sends from multiple source ports, all accepted by the server.

Documentation

Testing

cargo test                           # Unit + integration tests
scripts/test-local.sh                # Loopback self-test
scripts/test-mikrotik.sh <ip>        # Test against MikroTik device
scripts/test-docker.sh               # Docker container test

Credits

  • btest-opensource by Alex Samorukov -- original C implementation and protocol reverse-engineering. Licensed under MIT.
  • Margin Research -- EC-SRP5 authentication reverse-engineering (Curve25519 Weierstrass, SRP key exchange). Licensed under Apache 2.0.
  • MikroTik -- creator of the bandwidth test protocol and RouterOS.

License

MIT License -- see LICENSE.

This project is derived from btest-opensource (MIT License, Copyright 2016 Alex Samorukov). The EC-SRP5 implementation is based on research by Margin Research (Apache License 2.0). Original license and copyright notices are preserved as required.

Description
A high-performance MikroTik Bandwidth Test (btest) server and client written in Rust. Fully compatible with MikroTik RouterOS devices. Supports TCP/UDP, IPv4/IPv6, EC-SRP5 and MD5 authentication, multi-connection mode, syslog logging, CSV output, and CPU monitoring. Single static binary, zero dependencies.
Readme MIT 1.1 MiB
2026-04-18 07:51:46 +00:00
Languages
Rust 80.4%
Shell 13.5%
HTML 4.2%
Python 1.3%
Makefile 0.4%
Other 0.2%