An educational security research proof-of-concept (PoC) and bandwidth management tool for local networks, written in Rust.
Harper demonstrates the inherent protocol design limitations of legacy IPv4 networks—specifically the lack of authentication in the Address Resolution Protocol (ARP)—and highlights why modern architectures must move away from implicit local trust toward strict device registration, network segmentation, and Zero Trust principles.
harper sits between managed endpoints on your local network and the internet, giving network operators control over bandwidth allocation. It can throttle a connection to a specific speed, block it entirely, or leave it untouched on a per-device basis.
It operates in two modes:
- MITM mode — harper positions itself between a target host and the gateway using ARP cache coordination, without requiring router administrative access.
- Gateway mode — If you operate the router or access point, harper shapes traffic directly without any ARP manipulation.
- Linux
- Root privileges (for raw sockets, tc, nftables)
- A wired or wireless network interface
- Kernel modules:
ifb,act_mirred,sch_htb,sch_sfq,cls_fw
# Enter the Nix development shell
nix-shell
# Build release binary
build
# or: cargo build --release
# Binary at: target/release/harper# Run unit + integration (+ declarative mock) tests (no root needed)
cargo nextest run
# or: cargo testUnit tests live inline in each src/**/*.rs module's #[cfg(test)] mod tests;
cross-module behavioural tests live in tests/bdd_*.rs and only use the public
API exposed by src/lib.rs.
Harper features a declarative testing architecture combining:
NetBackendTrait &MockBackend: In-process mock routing and state simulation running in milliseconds duringcargo test.- TOML Topologies & Scenarios: Declarative specs under
tests/topologies/*.tomlandtests/scenarios/*.tomlparsed withserde+tomland asserted viainstasnapshots andproptestinvariants. - Network Namespaces (
scripts/netns-test.sh): Isolated network topology testing usingip netnsand veth pairs.# Enter Nix shell (includes iperf3, jq, etc.) nix-shell # Run all topology tests sudo ./scripts/netns-test.sh run all # Run a specific topology test (e.g. gateway pool) sudo ./scripts/netns-test.sh run gateway_pool # Interactive MITM setup sudo ./scripts/netns-test.sh setup_mitm
- NixOS VM Integration Tests (
nixos/vm.nix): VM-level end-to-end TC/XDP validation withiperf3.
# Run all 9 integration scenarios (MITM + Gateway in netns)
sudo ./scripts/netns-test.sh run all
# Run a specific scenario
sudo ./scripts/netns-test.sh run gateway_pool| Option | Description |
|---|---|
-i, --interface <IFACE> |
Network interface to use (auto-selected if omitted) |
-g, --gateway <IP> |
Gateway IP (MITM mode only, auto-detected if omitted) |
-t, --target <IP|CIDR|RANGE> |
Target IP(s) — skips full scan (can repeat) |
-u, --upload <KBPS> |
Upload bandwidth cap per host (omit = unlimited) |
-d, --download <KBPS> |
Download bandwidth cap per host (omit = unlimited) |
-b, --bandwidth <KBPS> |
Bandwidth cap (both upload/download, overridden by -u/-d) |
--pool <KBPS> |
Shared upload/download bandwidth pool per host |
--pool-upload <KBPS> |
Shared upload bandwidth pool |
--pool-download <KBPS> |
Shared download bandwidth pool |
--gateway-mode |
Shape clients on a network you host (no ARP poisoning) |
--all |
Auto-select every discovered client; dynamically add/evict (MITM) / shape every client (Gateway) |
--one-sided |
Use gratuitous ARP takeover instead of bidirectional poisoning |
--uplink <IP|MAC> |
Explicitly name the bottleneck uplink device to exclude from shaping |
The packet relay (victim ↔ gateway) has three backends. The kernel eBPF relay (tc redirect) is the default; userspace is opt-in or an automatic fallback.
| Option | Description |
|---|---|
--kernel |
In-kernel eBPF tc redirect relay (default; TCX on kernel ≥ 6.6, netlink below) |
--xdp |
Prefer the XDP eBPF relay (fastest; falls back to tc). Note: XDP cannot stamp skb->mark, so relayed flows are not shaped — use --kernel when throttling |
--userland |
Use the userspace PacketForwarder instead of the kernel relay |
--check-ebpf |
Verify eBPF programs are compiled, loadable and verified, then exit |
# Interactive: scan → pick targets → set bandwidth
sudo harper
# Non-interactive: throttle specific targets at 500 kbps
sudo harper -t 192.168.1.10 -t 192.168.1.20 -b 500
# Block a target entirely
sudo harper -t 192.168.1.5 -b 0
# CIDR range
sudo harper -t 10.0.0.0/24 -b 1024
# Last-octet range
sudo harper -t 192.168.1.10-20 -b 512
# Dynamic MITM: auto-select every discovered host, then keep watching —
# new devices are auto-added, stale ones evicted
sudo harper --all -b 500# Shape all discovered clients at 1 Mbps each
sudo harper --gateway-mode --all -b 1024
# Shape specific targets only (skips scan)
sudo harper --gateway-mode -t 10.0.0.5 -t 10.0.0.10 -b 500
# Pool mode: all shaped clients share ONE bandwidth pool
# Unshaped traffic (the local host / uplink) keeps the rest of the line
sudo harper --gateway-mode --all --pool 2048
# Exclude a repeater/uplink by MAC or IP from the managed endpoint pool
sudo harper --gateway-mode --all --uplink AA:BB:CC:DD:EE:FF| Aspect | MITM mode | Gateway mode |
|---|---|---|
| ARP spoofing | Yes (bidirectional or one-sided) | No |
| Requires being gateway | No | Yes |
| Target discovery | ARP scan + passive sniff | Kernel ARP cache (instant) + scan fallback |
--target |
Skips scan, resolves only those IPs | Same; skips cache lookup |
--all |
Dynamic MITM: auto-select + watch the wire, auto-add new devices, evict stale ones | Shape every discovered client |
--pool |
N/A | Shared bandwidth class for all managed hosts |
--uplink |
Excludes from ARP synchronization | Excludes from managed endpoint pool |
| Format | Example | Expands to |
|---|---|---|
| Single IP | 192.168.1.10 |
192.168.1.10 |
| CIDR | 10.0.0.0/24 |
10.0.0.1 – 10.0.0.254 |
| Last-octet range | 192.168.1.10-20 |
192.168.1.10 – 192.168.1.20 |
| Multiple | -t 10.0.0.1 -t 10.0.0.5-10 |
Combined, deduped, sorted |
After the scan completes, you'll see a table:
==============================================================
ARP Spoof — Target Selection
==============================================================
ID IP MAC Status Vendor
[1] 192.168.1.10 AA:BB:CC:DD:EE:01 Discovered Intel
[2] 192.168.1.11 AA:BB:CC:DD:EE:02 Discovered Unknown
[3] 192.168.1.12 AA:BB:CC:DD:EE:03 Discovered Apple
==============================================================
Gateway [4] 192.168.1.1 is excluded from selection.
Formats: "3" "1-5" "1,3,5" "all"
Select target(s) [1-3] or 'q' to quit:
Input formats:
3— single host1-5— inclusive range (skips unavailable IDs)1,3,5— comma-separated list (deduped, sorted)all/ALL/All— all available hosts
Then you'll be prompted for bandwidth (blank = unlimited).
Press Ctrl-C or q + Enter at any time. harper will:
- Stop packet forwarding
- Stop ARP cache synchronization
- Send ARP restore packets (600 ms per host) to restore normal endpoint caches
- Remove tc qdiscs and nftables rules
- Restore kernel sysctl settings (ip_forward, rp_filter, etc.)
Never kill -9 the process — managed endpoints will temporarily lose connectivity until their ARP caches expire (typically 30–60 s).
This software is provided for educational and research purposes only. You are solely responsible for ensuring your use complies with all applicable laws. Only use harper on networks you own or have explicit written permission to test.
See LICENSE for the full MIT license terms. Also see Legal Notice for a statement from the author.
MIT © 2026 Masrkai