A portable CLI tool for real-world network testing—measures both throughput and connection quality (latency/loss/jitter/route), not just a single “speed” number. It fully automates data collection and prints a simple, human-readable summary.
It has two goals:
- Measure your machine’s link end-to-end, including under-load impact (bufferbloat).
- Pick the best route/egress/target when you have multiple options, using per-target results plus a Scorecard.
Works on macOS, Linux, OpenWrt, and most Unix-like systems.
Need public iperf3 endpoints? See: https://github.com/R0GGER/public-iperf3-servers
- Throughput: iperf3 upload + download (reverse mode)
- Latency / Loss / Jitter / Hops: mtr (ICMP/UDP/TCP probes)
- Under-load quality (bufferbloat indicator):
- ping + jitter while iperf is running
- ΔPing and ΔJitter vs idle baseline
- IPv4 + IPv6
- test IPv4 / IPv6 literals directly
- test domains with
--ipv4/--ipv6(A/AAAA)
- Port spec for iperf3: single port, ranges, or comma lists
Example:-p 5201-5210or-p 5201,5203,5205-5207
The script will fallback across ports until it gets a valid result and will report which port was used. - Multiple targets via
--ips <file>- one per line
- supports inline
# notesthat show up in output and Scorecard
- Multiple egress interfaces
-I eth0 -I eth1or-I "eth0,eth1"- if multiple interfaces are set, each target is tested across all of them
- Scorecard (when testing more than 1 target)
- best upload, best download, best ping, minimum hops (ties supported)
- Logging:
--log [dir]writes a single consolidated log - Optional auto-install:
--install-missing(brew/apt/yum/dnf/pacman/opkg where available)
curl -O https://raw.githubusercontent.com/russellgrapes/ifspeedtest-cli/main/ifspeedtest.sh
chmod +x ifspeedtest.shIf you don’t specify --mtr or --iperf3, it runs both by default.
./ifspeedtest.sh -i 1.1.1.1
./ifspeedtest.sh -i 2606:4700:4700::1111
./ifspeedtest.sh -i example.com --mtr --iperf3 30./ifspeedtest.sh [options]-i, --ip <IPv4|IPv6|domain>: target to test--ips <file>: file with targets (one per line; supports# comments)--ipv4: for domain targets, resolve/use IPv4 only (A)--ipv6: for domain targets, resolve/use IPv6 only (AAAA)-I <iface>[,<iface>...]: egress interface/device to use (repeatable)--mtr [count]: run mtr (default:MTR_COUNTor 10)--iperf3 [time]: run iperf3 (default:IPERF3_TIMEor 10 seconds)-P, --iperf3-parallel <n>: iperf3 parallel streams (default:IPERF3_PARALLELor 10)-p, --iperf3-port <spec>: iperf3 server port or range/list Examples:5201,5201-5210,5201,5202-5204--mtr-probe <icmp|udp|tcp>: mtr probe type (default:icmp)--mtr-port <port>: destination port fortcp/udpprobes--mtr-interval <seconds>: seconds between probes (default:1)--log [directory]: write a log file (default: OS-specific; OpenWrt uses/tmp)--install-missing: attempt to install missing tools--sudo: force sudo for mtr (prompt once up front where supported)--no-sudo: never use sudo for mtr (mtr may be skipped if it needs privileges)-h, --help: help
Single target (defaults: mtr + iperf3):
./ifspeedtest.sh -i 10.1.1.1Domain + force IPv6 + longer tests:
./ifspeedtest.sh -i example.com --ipv6 --mtr 30 --iperf3 30Test the same target across two egress interfaces:
./ifspeedtest.sh -i example.com -I "enp0s3,enp0s8" --mtr --iperf3 20Use iperf3 port range fallback:
./ifspeedtest.sh -i iperf.example.com --iperf3 20 -p 5201-5210Targets from file + notes + logs:
./ifspeedtest.sh --ips ips.txt --mtr 30 --iperf3 30 --log ./logs- One target per line: IPv4, IPv6, or domain
- Empty lines ignored
- Lines starting with
#ignored - Inline notes after
#are preserved and shown in the output + Scorecard
Example ips.txt:
1.1.1.1 # route A (ISP1)
2606:4700:4700::1111 # route A (IPv6)
example.com # route B (ISP2)
9.9.9.9This script is a client. Your targets must have an iperf3 server reachable.
Default server (port 5201):
iperf3 -sCustom port (must match -p on the client):
iperf3 -s -p 5202If you use a port range/list on the client, you need servers/listeners available on those ports (or a load balancer / port-forwarding that makes them work).
All defaults can be overridden with env vars:
MTR_COUNT(default 10)MTR_PROBE(icmp|udp|tcp, defaulticmp)MTR_INTERVAL(default 1)MTR_LOAD_COUNT(optional; probes during iperf load; if unset it auto-derives from iperf time)MTR_PORT(for tcp/udp probes; tcp defaults to 443 if unset)IPERF3_TIME(default 10)IPERF3_PARALLEL(default 10)IPERF3_PORTS(same format as--iperf3-port)CONNECT_TIMEOUT(ms; only used if your iperf3 supports--connect-timeout)ADDR_FAMILY(auto|4|6; affects domain resolution only)NO_COLOR=1disables colored output
Example:
NO_COLOR=1 ./ifspeedtest.sh -i example.comYou can install dependencies manually, or run with --install-missing and let the script try.
brew install mtr iperf3
# if you test domains and don’t already have dig/host/nslookup:
brew install bindsudo apt update
sudo apt install -y iperf3 mtr-tiny dnsutils
# optional (enables XML parsing when supported by your mtr):
sudo apt install -y libxml2-utilssudo dnf install -y iperf3 mtr bind-utils
# optional:
sudo dnf install -y libxml2sudo pacman -S --needed iperf3 mtr bind libxml2sudo apk add iperf3 mtr bind-tools libxml2-utilsopkg update
opkg install iperf3 mtr
# if you test domains and BusyBox nslookup isn’t available/usable:
opkg install bind-dig # or: opkg install bind-host-
mtr on macOS often needs sudo for ICMP. Use
--sudo, or switch to TCP probes:./ifspeedtest.sh -i example.com --mtr --mtr-probe tcp --mtr-port 443
-
If a network blocks ICMP, try
--mtr-probe tcporudp. -
iperf3 can saturate links (especially with high
-P). Don’t run this on production links without knowing the impact.
⭐ Star this repo if it helps.
Then fork it and open a pull request, or create an issue tagged enhancement.
Distributed under the MIT License. See LICENSE for more information.
I write loops to skip out on life's hoops.
Russell Grapes - www.grapes.team
Project Link: https://github.com/russellgrapes/bash-ifspeedtest
