Rust library + CLI

Monocle

A BGP data analysis toolkit and CLI for inspecting ASNs/prefixes, searching public archives, validating routes with RPKI, and more.

Quick start

Monocle centers around inspect, plus targeted subcommands for parsing/search and data utilities. These commands map directly to the upstream README.

Common entry points
# Inspect an ASN (unified "whois/prefix/rpki/connectivity" view)
monocle inspect 13335

# Inspect a prefix (shows matching origin and RPKI validation)
monocle inspect 1.1.1.0/24

# Search BGP messages for a prefix in a time window
monocle search -t 2024-01-01T00:00:00Z -T 2024-01-01T00:01:00Z -c rrc00 -p 1.1.1.0/24 -m a

Capabilities

Monocle is designed for reproducible workflows: you can run it interactively, embed it in automation, or access it via server mode.

Unified inspection
Use `monocle inspect` for ASN/prefix/IP/name queries. It consolidates basic info, prefixes, connectivity, and RPKI into a single entry point.
Parse + search pipelines
`parse` decodes a single MRT file (local or remote). `search` finds and parses matching messages across public archives via BGPKIT Broker.
RPKI and relationships
Validate prefix-origin pairs (`rpki validate`), list ROAs/ASPAs, and query AS relationships (`as2rel`) and prefix mappings (`pfx2as`).
Operator-friendly output
All commands support `--format` (table/markdown/json/json-line/psv), plus `--json` for a convenient pretty JSON shortcut.

Install

Install with Cargo/Homebrew/cargo-binstall for local usage. Use Docker to run commands without installing Rust toolchains, or to run server mode with a persistent data directory.

cargo

# Using cargo
cargo install monocle

homebrew

# Using homebrew on macOS
brew install monocle

cargo-binstall

# Using cargo-binstall
cargo install cargo-binstall
cargo binstall monocle

Docker

# Using Docker
# Build locally
docker build -t bgpkit/monocle:latest .

# Or use docker compose
docker compose build

# Run help (default command)
docker run --rm bgpkit/monocle:latest

# Inspect an ASN
docker run --rm bgpkit/monocle:latest inspect 13335

# Persist data directory (recommended)
docker run --rm -v monocle-data:/data bgpkit/monocle:latest inspect 13335

# Start the WebSocket server
docker run --rm -p 8080:8080 -v monocle-data:/data bgpkit/monocle:latest server --address 0.0.0.0 --port 8080

# Using docker compose for server mode
docker compose up -d

Examples

The examples below are aligned with the upstream README and reflect Monocle’s current command set (notably: inspect replaces older “whois/pfx2as” workflows).

inspect

Unified ASN/prefix/IP/name lookup. By default yields multiple sections (basic, prefixes, connectivity, RPKI). Use --show to narrow output or --full to remove limits.

monocle inspect
# Inspect one ASN (by default shows all sections)
monocle inspect 13335

# Inspect multiple ASNs (shows a glance table first)
monocle inspect 13335 15169

# Search by name
monocle inspect -n cloudflare

# Limit output to basic info only
monocle inspect 13335 --show basic

# Show everything without limits
monocle inspect 13335 --full

parse

Parse a single MRT file given a local path or remote URL. Apply filters (prefix/origin/peer/time/elem-type) and optionally write filtered output back to an MRT file.

monocle parse
# Parse a remote MRT file and filter announcements for a prefix
monocle parse https://data.ris.ripe.net/rrc00/2024.01/updates.20240101.0000.gz \
  -p 1.1.1.0/24 -m a | head -5

# Parse a local MRT file with filters
monocle parse updates.20240101.0000.bz2 -o 13335 -m a

# Export filtered output to a new MRT file
monocle parse updates.20240101.0000.bz2 -o 13335 -M cloudflare_routes.mrt.gz

search

Search matching messages across public MRT archives using BGPKIT Broker under the hood. Use --broker-files when you want the file plan without parsing.

monocle search
# Search announcements for a prefix during a time window
monocle search -t 2024-01-01T00:00:00Z -T 2024-01-01T00:01:00Z \
  -c rrc00 -p 1.1.1.0/24 -m a

# Show which MRT files would be queried (without parsing them)
monocle search -t 2024-01-01T00:00:00Z -T 2024-01-01T01:00:00Z \
  -c rrc00 --broker-files

RPKI

Validate prefix-origin pairs and list ROAs/ASPAs. Monocle caches current data locally; some subcommands also support historical sources.

monocle rpki
# Validate a prefix-ASN pair (RFC 6811 semantics)
monocle rpki validate 1.1.1.0/24 13335

# List ROAs for an ASN (current cached data)
monocle rpki roas 13335

# List ROAs for a prefix
monocle rpki roas 1.1.1.0/24

# Historical ROAs on a date (source: RIPE)
monocle rpki roas 13335 --date 2024-01-01 --source ripe

# ASPAs (current or historical)
monocle rpki aspas --customer 13335
monocle rpki aspas --provider 174

as2rel

Query AS-level relationships. For multiple ASNs, relationships are shown for all pairs (asn1 < asn2).

monocle as2rel
# Relationship between two ASNs
monocle as2rel 13335 174

# Show all relationships for an ASN (with names)
monocle as2rel 13335 --show-name | head -10

# Find single-homed ASNs to an upstream (example: AS2914)
monocle as2rel 2914 --single-homed --min-visibility 10 --show-name

pfx2as

Prefix-to-ASN mapping lookup. Results include RPKI validation status for the prefix-ASN pair.

monocle pfx2as
# Lookup a prefix (origin ASN + RPKI validation)
monocle pfx2as 1.1.1.0/24

# Include sub-prefixes / super-prefixes
monocle pfx2as 8.8.0.0/16 --include-sub --limit 5 --show-name
monocle pfx2as 1.1.1.0/24 --include-super

# Lookup by ASN (announced prefixes; limit output)
monocle pfx2as 13335 --limit 5 --show-name

# JSON output
monocle pfx2as 13335 --limit 3 --json

Utilities

Operator-quality utilities for time conversion, country lookups, and IP metadata.

time / country / ip
# Time conversion (Unix <-> RFC3339 <-> human)
monocle time 1704067200
monocle time "2024-01-01T00:00:00Z"
monocle time "yesterday" "last week"

# Country lookup
monocle country US
monocle country germany

# IP lookup (specific IP or your public IP)
monocle ip 1.1.1.1
monocle ip

Output formats

All commands share common output controls. If you are integrating Monocle into pipelines, prefer --format json-line (one JSON object per line) or --format json.

--format / --json
# Supported output formats (global option)
# table (default), markdown, json, json-pretty, json-line, psv
monocle inspect 13335 --format table
monocle inspect 13335 --format markdown
monocle inspect 13335 --format json
monocle inspect 13335 --format json-pretty
monocle inspect 13335 --format json-line
monocle inspect 13335 --format psv

# Shortcut
monocle inspect 13335 --json

Server mode (WebSocket)

Monocle can run as a WebSocket server for programmatic access. The server is DB-first and reads from a local SQLite cache; long-running operations can stream progress and support cancellation.

monocle server
# Start the WebSocket server
monocle server
monocle server --address 0.0.0.0 --port 3000

# Endpoints:
#   WebSocket: ws://<address>:<port>/ws
#   Health:    http://<address>:<port>/health

For protocol details and supported methods, refer to the upstream repository documentation in src/server/README.md.

Library usage (Rust)

Monocle can be used as a library, with feature tiers for minimal dependency footprint. This is useful when you want the same business logic as the CLI/server inside your own service or batch job.

Cargo features

Cargo.toml
# Cargo.toml
[dependencies]
# Full library with CLI argument support (default)
monocle = "1.0"

# Minimal database access only
monocle = { version = "1.0", default-features = false, features = ["database"] }

# BGP operations without CLI overhead
monocle = { version = "1.0", default-features = false, features = ["lens-bgpkit"] }

# Full functionality without CLI
monocle = { version = "1.0", default-features = false, features = ["lens-full"] }

Example: Inspect lens

Rust
use monocle::database::MonocleDatabase;
use monocle::lens::inspect::{InspectLens, InspectQueryOptions};

fn main() -> anyhow::Result<()> {
    // Open the monocle database (local cache)
    let db = MonocleDatabase::open_in_dir("~/.monocle")?;

    // Create a lens (business logic reusable across CLI/server)
    let lens = InspectLens::new(&db);

    // Query AS information
    let options = InspectQueryOptions::default();
    let results = lens.query_asn(13335, &options)?;

    println!("AS{}: {}", results.asn, results.name.unwrap_or_default());
    Ok(())
}