MAnycastR (Measure Anycast Routing) performs synchronized Internet measurements from a distributed set of anycast Points of Presence (PoPs).
Measuring your own anycast infrastructure
- Mapping catchments using an improved version of Verfploeter
- Anycast latency (RTT between the anycast infrastructure and the Internet)
- Optimal deployment ('best' deployment inferred from unicast latencies from all PoPs)
- Multi-deployment probing (measure multiple anycast prefixes simultaneously)
- Site flipping (network regions experiencing anycast site flipping)
- Anycast routing stability and BGP convergence time
Measuring external anycast infrastructure
- LACeS — anycast-based detection of anycast, and latency-based detection using Great-Circle-Distance.
IPv4 and IPv6 are both supported, over ICMP, UDP (DNS), and TCP (can be mixed within a single measurement).
This README is the manual for installing and running MAnycastR. Documentation of the code itself is available via rustdoc.
- Installation
- Quick start
- How it works
- Measurement types
- Targets and hitlists
- Configuration files
- Output formats
- Running a shared deployment
- Options reference
- Contributing
- Citation
Further documentation lives in docs/: deployment · output formats · traceroute internals
All three components are subcommands of a single manycastr binary.
curl -L -o manycastr https://github.com/rhendriks/MAnycastR/releases/latest/download/manycastr
chmod +x manycastr
sudo setcap cap_net_raw+ep manycastrdocker pull ghcr.io/rhendriks/manycastr:latestRun with --network host, so probes use the anycast/unicast addresses of the host:
docker run -it --init --network host --cap-drop=ALL --cap-add=NET_RAW --read-only manycastrRequires rustup, protobuf-compiler, gcc, and musl-tools. Building against a musl target produces a statically linked binary (recommended for distribution to Workers).
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh && source $HOME/.cargo/env
apt-get install -y protobuf-compiler gcc musl-tools
git clone https://github.com/rhendriks/MAnycastR.git && cd MAnycastR
cargo build --release
sudo setcap cap_net_raw+ep target/release/manycastrWorkers send and receive probes over raw sockets (SOCK_RAW),
which require the CAP_NET_RAW capability (or sudo).
For reference, the standard ping utility also has CAP_NET_RAW capabilities.
The Orchestrator and CLI run unprivileged and require no capabilities.
A raw socket is required as MAnycastR is an anycast measurement tool:
replies to probes sent by one Worker may be received by another Worker.
Permissionless sockets such as SOCK_DGRAM would drop such replies.
DNS NOTE: the kernel answers DNS replies with ICMP port-unreachable as raw sockets do not register a UDP listener on the source port.
Grant the capability as a file capability (setcap, above), under systemd, or in Docker:
[Service]
User=manycastr
AmbientCapabilities=CAP_NET_RAW
CapabilityBoundingSet=CAP_NET_RAW
NoNewPrivileges=yesdocker run --cap-drop=ALL --cap-add=NET_RAW --read-only --network host manycastr worker ...If raw-socket privileges are a concern, bound the process further with nftables/tc egress policies and rate-limits.
1. Start the Orchestrator (Workers and CLIs share --port by default):
manycastr orchestrator -p 500012. Start one or more Workers. The Orchestrator address is address:port, where the address may
be IPv4, IPv6, or a hostname (resolved at connect time):
manycastr worker -a 10.0.0.0:50001
manycastr worker -a [2001::1]:50001
manycastr worker -a orchestrator.example.net:500013. Confirm the Workers are connected:
manycastr cli -a [::1]:50001 worker-list4. Run a measurement:
manycastr cli -a [::1]:50001 start -m catchment --hitlist hitlist.txt -p icmp -a 10.0.0.0 -r 1000All Workers probe the targets in hitlist.txt over ICMPv4 from source address 10.0.0.0,
at 1,000 packets per second per Worker.
The hitlist is divided amongst the Workers, each target receiving a single probe;
catchment is inferred from which PoP receives the reply.
Results are written to a timestamped .csv.gz file in the working directory (see Output formats).
A deployment consists of three components:
| Component | Role |
|---|---|
| Orchestrator | Central controller orchestrating measurements |
| CLI | Schedules measurements at the Orchestrator and collects results |
| Worker | Deployed on anycast PoPs, sends and receives probes |
The CLI sends a measurement definition built from the arguments of its start command.
The Orchestrator instructs the Workers to begin, and the Workers stream results back to it.
The Orchestrator aggregates them (and may create follow-up tasks for some measurement types)
and forwards them to the CLI, which writes the output file.
Probes can be sent as ICMP ECHO requests (-p icmp), UDP DNS A record requests (-p dns),
TCP SYN/ACK probes (-p tcp), or UDP DNS TXT CHAOS requests (-p chaos).
An origin is the flow 5-tuple a probe is sent with:
protocol, source address, source port, destination address, and destination port.
Every field except the destination address — which comes from the target being probed — is
configured, either directly with -p, -a, -s, and -d,
or several at a time in a configuration file.
A measurement may use more than one origin, in which case each target is probed once per origin,
and replies carry an origin_id column identifying the origin that produced them.
This is what makes multi-protocol, multi-prefix, and mixed IPv4/IPv6 measurements possible.
Selected with -m.
manycastr cli -a [::1]:50001 start -m catchment --hitlist hitlist.txt -p icmp -a 10.0.0.0Simple catchment mapping to see which PoP catches each target. The hitlist is divided amongst the Workers (round-robin), so each target receives a single probe, and the receiving PoP is its catchment.
manycastr cli -a [::1]:50001 start -m laces --hitlist hitlist.txt -p icmp -a 10.0.0.0 --responsiveEvery Worker probes every target, so a target is probed once per Worker.
Used to perform anycast censuses, with an extended version of MAnycast2:
a target whose replies end are received at several Worker PoPs is inferred to be anycast.
With --responsive, targets are first probed from a single Worker to confirm probe responsiveness
before being probed from all Workers
Anycast latency measures the RTT between each target and the anycast deployment:
manycastr cli -a [::1]:50001 start -m latency --hitlist hitlist.txt -p tcp -a 10.0.0.0Each target receives two probes: a discovery probe establishing which PoP catches it,
then a measurement probe from that catching Worker, so that sender and receiver are the same PoP.
Measurement probes respect the per-Worker probing rate (-r).
This means that the measurement time is non-deterministic as they are distributed based on the catchment distribution.
The measurement will finish when the Worker with the largest catchment share finishes sending its measurement probes.
Unicast latency instead measures each target's RTT from every PoP:
manycastr cli -a [::1]:50001 start -m latency --hitlist hitlistv6.txt -p icmp -a unicastv6 --responsive-a unicastv4/-a unicastv6 creates an origin where each Worker probes
from its own local unicast address of that IP version.
Every Worker probes every target (like -m laces) which can also be combined with --responsive
to avoid unnecessary probes for probe unresponsive targets.
This allows for anycast-detection using Great-Circle-distance
and for inferring 'optimal' routing.
We identify the Worker with the lowest unicast RTT as 'optimal'
which can be used to identify catchment/latency improvements when
compared against the catchment/latency experienced by the target using anycast.
manycastr cli -a [::1]:50001 start -m anycast-traceroute --hitlist hitlist.txt -p icmp
manycastr cli -a [::1]:50001 start -m anycast-traceroute -t 1.1.1.1 -p dnsMeasures the path from the catching PoP to a target.
Uses discovery probes (like Anycast latency) to establish the catching PoP,
which then sends traceroute probes to measure the path.
Each intermediate router returns an ICMP Time Exceeded towards the anycast IP address
which may return at different PoPs.
This allows for troubleshooting targets reaching a distant anycast PoP
and catchment mapping of networks that e.g., do not respond to ping but send ICMP Time Exceeded replies.
Traceroute works over ICMP, DNS, and TCP using Paris traceroute. When using multi-origin configurations (e.g., multiple protocols, or different port/src address combinations) multi-paths can be measured to e.g., assess anycast routing differences amongst protocols.
See docs/traceroute.md for a more detailed description.
manycastr cli -a [::1]:50001 start -m tracemap --hitlist unresponsives.txt -a 10.0.0.1 -p icmpExperimental feature to map the catchment of probe unresponsive targets by soliciting an ICMP Time Exceeded reply from routers near the target. This method uses a binary-search implementation to find a hop near to the target whilst sending as little traceroute probes as possible.
manycastr cli -a [::1]:50001 start -m feed -p icmp -a 10.0.0.0Allows for feeding targets over stdin as NDJSON (or bare addresses).
{"dst":"192.0.2.1"}
{"dst":"203.0.113.7","worker":"ams01"}
{"dst":"198.51.100.9","origin":2,"worker":"all"}
192.0.2.1
| Field | Values | Default |
|---|---|---|
dst |
target address | required |
worker |
"any" (round-robin), a Worker ID (1) or hostname ("ams01"), a hostname glob ("us-*"), or "all" |
"any" |
origin |
an origin ID (2), or "all" |
first origin of the target's IP version |
nprobes |
measurement probes to send per selected Worker (1–255) | 1 |
session |
session ID for attribution with shared CLI set-ups (e.g., multiple web-interfaces connecting to the same CLI) | none |
Adding --responsive gates tasks involving multiple probes to a discovery probe first.
Use cases include reactive measurements. For instance, to measure the catchment and latency of a target after observing a routing change in BGP. Or to verify the catchment of a target when receiving potentially spoofed traffic.
bgp-monitor | manycastr cli -a [::1]:50001 start -m feed -p icmp -a 10.0.0.0Notes:
- Results are written as LACeS rows (
rx,addr,ttl,tx,rtt), plussessionwith--sessions. - Session attribution is supported only for ICMP.
- Origins must be shared among all Workers (live mode does not support Worker-specific origins).
manycastr cli -a [::1]:50001 start -m feed-trace -p icmp -a 10.0.0.0Similar to -m feed except it adds TTL level control to the user using an additional ttl field (default 255).
This is added a separate measurement type as it requires Workers to also listen for ICMP Time Exceeded replies
which increases resource usage as there are no measurement hashes encoded in such replies for easy filtering.
{"dst":"192.0.2.1","ttl":4}
{"dst":"192.0.2.1","ttl":5}
Notes:
- Results are written as traceroute rows, with
probe_ttlrecording the TTL each probe was sent with. - Unrelated ICMP Time Exceeded are filtered by the Orchestrator that tracks ongoing tasks.
Targets come either from a file (--hitlist, one IP address or number per line, optionally gzip- or
bzip2-compressed) or directly on the command line (-t 1.1.1.1,8.8.8.8) for ad-hoc measurements.
Exactly one of the two must be given.
USC/ISI ANT hitlists are created specifically for catchment mappings: they list one to several addresses per /24 prefix, ranked by ping responsiveness over time. MAnycastR detects and parses them automatically.
Default behavior is to probe every target address (i.e. multiple targets per /24).
Combined with --responsive, candidates are instead tried in rank order until one replies,
so at most one responsive target per prefix is measured -
maximizing coverage at prefix granularity while keeping probing costs low.
manycastr cli -a [::1]:50001 start -m latency --hitlist isi-hitlist.fsdb.bz2 -p icmp -a 10.0.0.0 --responsiveWe use the USC/ISI ANT format, extended for IPv6.
IPv4 — candidates are last-octets in hex:
#fsdb -F t block octets
01000400 01,04,09
01000500 01
01001100 -
Row 1 lists 1.0.4.1, 1.0.4.4, and 1.0.4.9 (in rank order) for 1.0.4.0/24; row 2 lists 1.0.5.1 for 1.0.5.0/24.
IPv6 — candidates are hex suffixes within the 80 host bits of the /48 (no colons, no leading zeros needed):
#fsdb -F t block suffixes
20010db80001 1
20010db81234 1,2a3f,ec4a01
Row 1 lists 2001:db8:1::1 for 2001:db8:1::/48; row 2 lists 2001:db8:1234::1, 2001:db8:1234::2a3f, and 2001:db8:1234::ec4a01 for 2001:db8:1234::/48.
A configuration file (-f) defines several origins at once,
and may vary them per Worker:
# Worker, src_addr, src_port, dst_port, protocol
ALL, 10.0.0.0, 62321, 63853, icmp
ALL, unicastv4, 62321, 63853, icmp
The Worker field is ALL, a Worker ID, a hostname, or a hostname glob (us-*);
Workers listen for every anycast origin defined, regardless of which they probe with.
See example.conf for the full syntax.
Replies are tagged with an origin_id column identifying the origin that produced them.
Multi-origin probing allows for measuring two anycast prefixes side-by-side (e.g., a control and test prefix) to e.g., compare routing differences. One use-case could be to measure the impact of a site outage, or a Traffic Engineering policy (e.g., a community or prepend).
manycastr cli -a [::1]:50001 start -m catchment --hitlist hitlist.txt -p icmp,tcp,dns -a 10.0.0.0Each protocol given to -p becomes its own origin, and every target is probed with all of them.
This measures whether targets route to a different PoP depending on the protocol used.
This feature also enables for measuring routing differences when varying the protocol (e.g., when networks route TCP/UDP differently than ICMP).
Multiple origins can be defined with varied port values or anycast source addresses. This enables measuring routing differences when varying the flow-header of packets (e.g., when hash based load-balancers may cause packets to reach different PoPs).
Configurations can mix anycast and unicast source addresses.
With -m laces this allows for measuring the anycast catchment/latency and per-PoP unicast latencies in a single run.
A configuration file can declare IPv4 and IPv6 origins side by side. Hitlist can also mix IPv4 and IPv6 targets. Targets are only probed by the origin matching its IP version.
# Worker, src_addr, src_port, dst_port, protocol
ALL, 10.0.0.0, 62321, 63853, icmp
ALL, 2001:db8::1, 62321, 63853, icmp
ALL, unicastv4, 62321, 63853, icmp
ALL, unicastv6, 62321, 63853, icmp
manycastr cli -a [::1]:50001 start -m catchment --hitlist mixed_hitlist.txt -f mixed.confThis allows for measuring the IP version differences for dual-stack anycast deployments. E.g., to compare how resolvers reach your authoritative nameserver using both IPv4 and IPv6.
Results are written to the path given by -o as gzip-compressed CSV (.csv.gz) by default,
or as parquet with --parquet.
Which columns are present depends on the measurement type.
See docs/output.md for the full column reference, the Parquet file metadata and IP address encoding, and snippets for reading results with pandas and DuckDB.
For infrastructure shared between users, the Orchestrator can cap the probing rate (--max_rate)
and restrict the origins a CLI may use (--origins).
This can be used to provide CLI access to external parties.
We run such a set-up using TANGLED, please contact me if you are interested in running measurements.
For security considerations we support
CLI and Worker connections on separate ports (--cli_port).
The inter-component gRPC connections also support TLS (--tls, --tls_system).
See docs/deployment.md for configuring these, generating certificates, using an internal CA, and keeping Workers connected across restarts.
Also available as manycastr <orchestrator|worker|cli> --help and manycastr cli start --help.
| Option | Default | Description |
|---|---|---|
-p, --port <PORT> |
50001 |
Port to listen on |
--cli_port <PORT> |
shares --port |
Separate port for CLI connections |
-c, --config <FILE> |
Static Worker hostname to ID mapping (see example.map) | |
--max_rate <RATE> |
unlimited | Maximum probing rate allowed for measurements (per second, per Worker) |
--origins <FILE> |
all allowed | Origin allow-list restricting the origins CLIs may use |
--tls <CERT> |
off | Enable TLS with the certificate at this path |
--tls_key <KEY> |
--tls path with .key |
Path to the TLS private key |
| Option | Default | Description |
|---|---|---|
-a, --orchestrator <ADDR> |
required | address:port of the Orchestrator |
-n, --hostname <NAME> |
$HOSTNAME |
Hostname for this Worker (Worker only) |
--tls <CERT> |
off | Enable TLS, authenticating the Orchestrator against this certificate |
--tls_system |
off | Enable TLS, authenticating against the host's system trust store |
--tls_domain <NAME> |
host in -a |
Name to authenticate the Orchestrator as |
The CLI takes a subcommand: worker-list (list connected Workers) or start (run a measurement).
Targets and origins
| Option | Default | Description |
|---|---|---|
--hitlist <PATH> |
Hitlist file (.gz/.bz2 supported; ISI fsdb detected automatically) |
|
-t, --target <TARGETS> |
Comma-separated target address(es), instead of --hitlist |
|
-a, --address <ADDR> |
required | Anycast source address, or unicastv4/unicastv6 |
-p, --p_type <TYPE> |
icmp |
Protocol(s): icmp, dns, tcp, chaos (comma-separated for several) |
-f, --configuration <CONF> |
Config file defining origins; conflicts with -a, -s, -d, -p |
|
-s, --sport <PORT> |
62321 |
Source port (DNS, TCP) |
-d, --dport <PORT> |
63853; 53 for dns/chaos |
Destination port |
-q, --query <QUERY> |
example.org; hostname.bind for chaos |
DNS record to request |
-u, --url <URL> |
URL encoded in the probe payload (e.g. opt-out information) |
Measurement
| Option | Default | Description |
|---|---|---|
-m, --m_type <MODE> |
laces |
laces, catchment, latency, anycast-traceroute, tracemap, feed, feed-trace |
-r, --rate <RATE> |
1000; 10 for traceroute/tracemap |
Probing rate per Worker (packets per second) |
-x, --selective <IDS> |
all Workers | Workers that send probes, as IDs, hostnames, or globs (us-*); all Workers still listen |
-w, --worker_interval <N> |
1 |
Seconds between different Workers' probes to the same target |
-i, --probe_interval <N> |
1 |
Seconds between probes from one Worker to the same target |
-c, --nprobes <N> |
1 |
Probes per origin,target pair (not counted against the probing rate) |
--responsive |
off | Screen targets for responsiveness before probing from all Workers; with ISI hitlists, try candidates in rank order until one replies |
--shuffle |
off | Shuffle the hitlist |
--sessions |
off | Enable feed sessions (-m feed only): report a per-reply session column |
Traceroute (anycast-traceroute, tracemap, feed-trace)
| Option | Default | Description |
|---|---|---|
--trace_initial_hop <N> |
4 |
Starting TTL (skips hops within the PoP's own network) |
--trace_max_hop <N> |
25 |
Maximum TTL (covers >99% of Internet path lengths) |
--trace_timeout <N> |
3 |
Per-hop timeout in seconds |
--trace_max_failures <N> |
5; 3 for tracemap |
Consecutive failures before advancing (tracemap: confirmation window past a silent midpoint) |
--trace_star <BOOL> |
true |
Emit a * row for unresponsive hops |
Output
| Option | Default | Description |
|---|---|---|
-o, --out <PATH> |
./ |
Output file, or directory (trailing /) for a generated filename |
--parquet |
off | Write .parquet instead of .csv.gz |
--stream |
off | Stream results to stdout |
Issues and pull requests are welcome.
MAnycastR as a tool for anycast censuses was developed for the following paper.
Please cite it when using MAnycastR to perform anycast censuses — -m laces.
@inproceedings{10.1145/3730567.3764484,
author = {Hendriks, Remi and Luckie, Matthew and Jonker, Mattijs and Sommese, Raffaele and van Rijswijk-Deij, Roland},
title = {LACeS: An Open, Fast, Responsible and Efficient Longitudinal Anycast Census System},
year = {2025},
isbn = {9798400718601},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3730567.3764484},
doi = {10.1145/3730567.3764484},
booktitle = {Proceedings of the 2025 ACM Internet Measurement Conference},
pages = {445–461},
numpages = {17},
keywords = {internet measurement, anycast, internet topology, routing, ip},
location = {USA},
series = {IMC '25}
}
MAnycastR as a tool for detecting networks experiencing anycast site flipping was used for the following paper. Please cite it when using MAnycastR to detect anycast site flipping.
@ARTICLE{11268317,
author={Hendriks, Remi and Jonker, Mattijs and van Rijswijk-Deij, Roland and Sommese, Raffaele},
journal={IEEE Transactions on Network and Service Management},
title={Load-Balancing Versus Anycast: A First Look at Operational Challenges},
year={2025},
volume={},
number={},
pages={1-1},
keywords={Routing;Internet;Routing protocols;Probes;IP networks;Costs;Tunneling;Time measurement;Source address validation;Servers;Anycast;Load Balancing;Routing Stability},
doi={10.1109/TNSM.2025.3636785}
}
We are currently working on a paper describing MAnycastR as a tool itself. For now, we kindly ask you to cite the LACeS paper (first listed) when using MAnycastR for non-listed goals.