Documentation
Reference for the new-arp-scan CLI and library behavior (from the project README and repository).
Overview
new-arp-scan is an ARP scanning tool written in Rust. On Linux, the scan command performs address resolution protocol discovery across the selected interface’s IPv4 subnet using raw AF_PACKET / SOCK_RAW sockets.
Platform support
- Linux — full support for interfaces and scan.
- Non-Linux — scan and interfaces return an unsupported-platform error without calling Linux-only APIs.
Permissions
Creating the raw packet socket requires Linux capability
CAP_NET_RAW (often available to
the superuser). If opening the socket fails with permission denied, the tool surfaces an explicit
CAP_NET_RAW hint. See Linux
packet(7) and capabilities(7).
Commands
new-arp-scan interfaces
new-arp-scan scan [--interface <NAME>] [--timeout-ms <MILLISECONDS>] [--pacing-ms <MILLISECONDS>] [--attempts <COUNT>]
Built-in help: new-arp-scan --help, new-arp-scan interfaces --help, new-arp-scan scan --help. Running new-arp-scan with no arguments prints the root help and exits successfully.
interfaces
On Linux, lists interfaces usable for ARP scanning: Ethernet hardware type, administratively up, not loopback, not NOARP, with an IPv4 address, netmask, and a non-zero hardware address. Output is a plain aligned table sorted by interface index, then name, with NAME, INDEX, IPV4, NETMASK, and MAC columns. If none qualify, the tool prints no usable interfaces found and exits successfully.
scan
On Linux, reads the interface IPv4 address, netmask, and Ethernet hardware address via ioctl, opens a raw packet socket bound to ARP (ETH_P_ARP), then runs --attempts full rounds (default 1). Each round sends one broadcast ARP request per target address in the subnet (excluding network and broadcast, but always including the interface’s own IPv4 when it falls outside that open range). Between rounds it sleeps --pacing-ms after each round except the last (default 0), then collects replies until --timeout-ms elapses after the last round (default 3000). Millisecond values that exceed what Linux poll(2) accepts are clamped internally.
If scan is run without --interface / --iface, the tool selects an interface automatically only when exactly one usable interface exists; otherwise it exits with an error describing the ambiguity or that no usable interface was found.
Examples
These examples match the CLI help footer and current operator workflows:
# List interfaces usable for ARP scanning on Linux
new-arp-scan interfaces
# Scan a specific local IPv4 subnet
new-arp-scan scan --interface eth0
# Let the tool select the interface when exactly one usable interface exists
new-arp-scan scan
# Use a custom receive window, pacing between scan rounds, and multiple attempts
new-arp-scan scan --interface eth0 --timeout-ms 5000 --pacing-ms 10 --attempts 3
Scan behavior
- Target addresses come from the selected interface’s IPv4 address and netmask. The scanner excludes the network and broadcast addresses, but includes the interface’s own IPv4 address when that address falls outside the open host range.
- Requests are broadcast ARP frames sent through a Linux raw packet socket bound to ETH_P_ARP.
- --attempts is the total number of scan rounds (minimum 1). Each round sends one request per target; the default is 1.
- --pacing-ms sleeps after each full round of target sends except the last round. The default is 0, so the default scan sends all targets back-to-back within each round.
- --timeout-ms is the receive window after the last round. The default is 3000, and values larger than Linux poll(2) accepts are clamped internally.
- Non-fatal send or frame-parse problems are collected as warnings, while fatal interface, socket, receive, or poll failures return an error.
Output
- Discovered hosts: <IPv4> <MAC> on standard output, sorted by ascending IPv4 address. MAC addresses are colon-separated lowercase hex.
- Non-fatal issues (e.g. failed send, malformed frame, conflicting duplicate address resolution reply for the same IPv4): warning: ... on standard error.
- No responses: prints no hosts found and exits successfully.
Library API
The crate exposes the same application surface used by the binary. Call run(ApplicationCommand::Scan { ... }) or run(ApplicationCommand::UsableInterfacesList) and handle ApplicationOutcome or AppError.
- Scan commands take explicit Duration values for timeout and pacing, and std::num::NonZeroU64 for attempts. Use DEFAULT_SCAN_TIMEOUT, DEFAULT_SCAN_PACING, and DEFAULT_SCAN_ATTEMPTS to match CLI defaults.
- ScanOutcome::discovered_hosts contains DiscoveredHost values sorted by IPv4 address. Each host stores the MAC in DiscoveredHost::media_access_control_address as a typed MacAddress.
- UsableInterfacesListOutcome exposes the same interface rows printed by the interfaces command.
- Pure IPv4 helpers Ipv4Cidr and Ipv4HostAddressIterator are public for CIDR parsing and target expansion.
Verification
To verify frames on the wire, run tcpdump or Wireshark on the same interface (for example tcpdump -ni eth0 arp) while scanning. This is optional manual validation and is not part of automated tests.
For a full acceptance check on hardware you control, build the binary and run a privileged scan such as sudo ./target/debug/new-arp-scan scan --interface eth0. Compare default runs with custom --timeout-ms, --pacing-ms, and --attempts values to confirm timing behavior for your network.
Requirements
- Rust toolchain with Cargo (rustc, cargo fmt, cargo clippy)
- GNU Make (optional; recommended for Makefile targets)
Local development
| Command | Description |
|---|---|
| make build | cargo clean then cargo build |
| make test | cargo test then cargo test --tests |
| make lint | cargo fmt --all then cargo clippy --all-targets -- -D warnings |
| make coverage | cargo llvm-cov --all-targets --summary-only (install once with cargo install cargo-llvm-cov; may need rustup component add llvm-tools-preview) |
| make clean | cargo clean |
Run the same commands manually if you prefer not to use Make. Contributing guidelines: CONTRIBUTING.md. Extra notes may live under docs/ in the repository.
License
Copyright © Bizjak Tech OÜ. Licensed under the GNU Affero General Public License v3.0 only.