Siavash Sameni 751a9d5f13
All checks were successful
CI / test (push) Successful in 1m27s
Add --duration, --csv, --quiet flags for automated testing
- --duration N: run client test for N seconds then exit
- --csv <file>: append results to CSV (creates with headers if new)
- --quiet/-q: suppress terminal output (for scripted/machine use)

CSV columns: timestamp, host, port, protocol, direction, duration_s,
  tx_avg_mbps, rx_avg_mbps, tx_bytes, rx_bytes, lost_packets, auth_type

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 09:30:58 +04:00
2026-03-31 18:28:48 +04:00

btest-rs

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

Based on

This project is a clean-room Rust reimplementation based on the protocol reverse-engineering work done by Alex Samorukov in btest-opensource. The original C implementation and protocol documentation were invaluable in making this project possible. Full credit to Alex and all contributors to that project.

The original btest-opensource project is included as a git submodule for reference and protocol documentation.

Why Rust?

  • Single static binary - 2 MB, zero dependencies, runs anywhere
  • Cross-platform - macOS, Linux (x86_64, ARM64), Docker
  • Async I/O - tokio-based, handles many concurrent connections efficiently
  • Memory safe - no buffer overflows, no use-after-free, no data races
  • Easy deployment - scp one file, done. Or use the systemd installer.

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

Installation

Pre-built binary

# Build for Linux x86_64 from macOS (requires Docker)
scripts/build-linux.sh

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

From source

cargo install --path .

Docker

docker compose up -d    # Server on port 2000

systemd service

# On the target Linux server:
sudo ./scripts/install-service.sh
sudo ./scripts/install-service.sh --auth-user admin --auth-pass secret

Usage

Server mode

MikroTik devices connect to this server to run bandwidth tests.

# Basic server (no auth)
btest -s

# With authentication
btest -s -a admin -p password

# Custom port with verbose logging
btest -s -P 2000 -v

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
btest -c 192.168.88.1 -t -r

# UDP 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

Debug logging

btest -s -v      # info + debug
btest -s -vv     # info + debug + trace (hex dumps of status exchange)

MikroTik Setup

Enable btest server on MikroTik (for client mode)

/tool/bandwidth-server set enabled=yes

Run btest from MikroTik (connecting to our server)

Important: Set Connection Count to 1 — multi-connection mode is not supported.

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

Protocol

The MikroTik btest protocol uses:

  • TCP port 2000 for control (handshake, auth, status exchange)
  • UDP ports 2001+ for data transfer
  • MD5 challenge-response authentication (RouterOS < 6.43)
  • 1-second status interval with dynamic speed adjustment

See the original protocol documentation for wire-format details.

Authentication

Both MD5 (legacy) and EC-SRP5 (RouterOS >= 6.43) authentication are supported:

# Server with MD5 auth (legacy clients)
btest -s -a admin -p password

# Server with EC-SRP5 auth (modern RouterOS clients)
btest -s -a admin -p password --ecsrp5

# Client auto-detects auth type
btest -c 192.168.88.1 -r -a admin -p password

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 fine. IPv6 is disabled by default.
  • Multi-connection UDP is supported. MikroTik's multi-connection mode sends from multiple source ports which are all accepted by the server.

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 original license and copyright notice 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%