ransack

August 18, 2026 · View on GitHub

Multi-RAT cellular survey and recon for DragonOS. ransack fuses what several different sensors see — an SDR, a rooted Qualcomm phone, a Rayhunter — into a single SQLite database with a versioned REST/SSE API. LTE, 5G NR, 2G/GSM, and NB-IoT cells all land in the same cells table, merged on PLMN and cell identity, so a GSM sighting and an LTE decode of one tower become one row instead of two. The name is RAN (radio access network) + ransack.

Survey is passive, receive-only. A separate, human-driven plane captures subscriber identities (IMSI/TMSI/IMEI) and is for your own network, a licensed engagement, or a shielded lab only.

ransack is a thin control plane: a daemon (ransackd) that owns the database, the API, and radio arbitration, plus a set of small sensors that each wrap one proven tool (srsRAN, gr-gsm, Sni5Gect, QCSuper, LTESniffer, FALCON, Rayhunter) and feed the shared DB. It does not reimplement the DSP — it drives the tools the box already ships.

Status

CapabilityStatusNotes
LTE survey (cell_search + MIB)Validated OTALimeSDR Mini 2, live cells on bands 5 and 71
LTE SIB1 identity (PLMN/TAC/cell-id)Link-margin limitedMIB decodes on weak signal; SIB1 needs a few dB more
5G NR survey + SIB1Validated OTALive NR cell on n25
2G/GSM survey — gr-gsm on SDRValidated OTAParse confirmed against a live osmo-nid cell
2G/GSM survey — OsmocomBB phoneValidated OTAcell_log through a Motorola C118
NB-IoT find (cell_search_nbiot)ValidatedSyncs to anchors; --decode (SIB1-NB) needs signal margin
Modem DIAG ingest (QCSuper)ValidatedCaptures 2G/3G/4G/5G; ransack parses LTE SIB1 today (3G/UMTS not yet)
Rayhunter connectorTestedFirmware v0.6.1 - v0.11.2
LTE identity (LTESniffer DL/UL)Parser validatedSelf-test passes; live TMSI/IMSI pending decodable coverage
LTE activity (FALCON PDCCH)File-validatedReal O2-DE recording; live capture pending
REST/SSE API + daemonValidatedCrash recovery, idempotent operations, socket activation
Sensor fusion + gpsd geotagValidatedCross-RAT merge on PLMN + cell-id; RSRP-weighted tower estimate

Built for DragonOS Resolute (26.04)

ransack assumes the heavy pieces are already on the box, and the supported platform is DragonOS Resolute (Ubuntu 26.04), where the cellular toolchain it orchestrates is pre-installed: srsRAN 4G, gr-gsm, Sni5Gect, QCSuper, LTESniffer / ltesniffer-dl, FALCON, the LimeSuite stack, and gpsd.

ransack does not bundle these — it drives them. Every sensor is fail-soft: a missing tool degrades that one sensor and reports why, rather than breaking the rest. You can run it off DragonOS, but you have to provide those tools yourself (see Install). Treat 26.04 Resolute as the target.

Sensors

RATSurveyWrapsIdentity / deeper
2G / GSMransack-gsmgr-gsm grgsm_scanner, or OsmocomBB on a Calypso phoneransack-imsi (IMSI/TMSI)
LTE / 4Gransack, ransack-sweepsrsRAN cell_search + srsue, tshark SIB decoderansack-lte-ue (LTESniffer), ransack-pdcch (FALCON)
NB-IoTransack-nbiotsrsRAN cell_search_nbiot + npdsch_ue
5G NRransack-nrSni5Gect scanner (SSB, then MIB/SIB1)
modem (2G-5G)ransack-modemQCSuper reading a Qualcomm DIAG stream
recordedransack-rayhunterEFF Rayhunter recordings + its alerts

Coverage notes: QCSuper logs the full 2G/3G/4G/5G DIAG stream, so the 3G/UMTS signalling is in the pcap — ransack just doesn't parse it into cells yet. Today ransack-modem extracts LTE (E-UTRA) SIB1 cell identity from that capture; UMTS has a schema column but no decoder wired to it. 5G here is survey only; Sni5Gect's transmit/effect side is out of scope for this repo.

Radios

Use the classic LimeSuite driver=lime for the srsRAN LTE path — limesuiteng rejects the mid-stream sample-rate changes cell_search makes.

SDRLTE / NB-IoTGSM5G NRLTE identity
LimeSDR (driver=lime)yesyes
USRP B210 / X310yesyesyes (UHD only)downlink 1 SDR; uplink needs 2x B210 + GPSDO
bladeRFyesyes
Pluto / HackRF / RTL-SDRNB-IoT: experimentalvia SoapySDR

The modem sensor needs a rooted Qualcomm phone (adb) or a USB DIAG modem; the phone-based 2G path needs a Calypso handset (Motorola C1xx and similar) running OsmocomBB.

Usage

ransack -b 12                                  # survey LTE band 12 into the DB
ransack-sweep --preset us                      # fan every common US band across all SDRs at once
ransack-cells                                  # list what's been found
ransack-gsm  scan --band PCS1900               # survey 2G
ransack-nr   scan                              # survey 5G NR (SSB -> SIB1)
ransack-nbiot scan --decode                    # find NB-IoT anchors and decode SIB1-NB
ransack-menu                                   # interactive TUI over all of the above

Example run:

$ ransack -b 12
[ransack] cell_search band 12 ...
[ransack] EARFCN 5035 PCI 493: PLMN 001-01 TAC 1 CID 100
[ransack] EARFCN 5110 PCI 288: PLMN 001-01 TAC 1 CID 101
[ransack] done. 2 cells in ~/.ransack/cells.sqlite

$ ransack-cells
 earfcn  band   pci      plmn    tac      cell_id  last_seen
   5035    12   493   001-01   1    100  2026-08-17T20:41:05Z
   5110    12   288   001-01   1     101  2026-08-17T20:41:52Z

Survey, then engage

One shared table means you survey once and target anything you found. For LTE a single --earfcn resolves the frequency, band, PCI, and PRB (and the uplink frequency) from the survey row:

ransack -b 12                                          # survey
ransack-lte-ue monitor --earfcn 5035 --mode 0          # downlink: TMSI/paging, one SDR
ransack-lte-ue monitor --earfcn 5035 --mode 1 \        # uplink+downlink: IMSI/IMEI/UE-capability
    --serial-a <dl-serial> --serial-b <ul-serial>      #   2x B210 + GPSDO

For 2G: ransack-gsm scan, then ransack-imsi catch --auto points the catcher at the strongest GSM cell found. That chain uses a bound UDP socket, not a raw sniff, so it needs no sudo.

API

ransackd serves a versioned REST/SSE API on 127.0.0.1:8082.

POST /v1/scans   {"bands":[12,71]}            start a scan            -> {"scan_id": 42}
GET  /v1/cells?band=12&seen_within=2h         discovered cells (filtered)
GET  /v1/events                               live SSE: cell_found, scan_progress, scan_done, ...
GET  /v1/map                                  estimated tower positions + observations as GeoJSON
GET  /v1/export?format=csv                    bulk pull

Also: health, version, ready, describe, sdrs, cells/<id>, cells/<id>/measurements, observations, plmns, scans, scans/<id>, plus POST /v1/monitor and DELETE /v1/scans/<id>. The SSE journal is durable, so a client (or the daemon after a restart) can replay from the last event id it saw.

MCP

ransack ships a Contract 1.0 capability descriptor (share/dragon-agent/providers.d/ransack.json) rather than its own MCP server. DragonOS's dragon-mcp-gateway reads that descriptor, renders each capability as an MCP tool, and routes calls to ransackd's /v1. It is pure stdlib over stdio, opens no port, and needs no key of its own.

claude mcp add dragon -- dragon-mcp-gateway

ransack then appears as ransack__scan_band, ransack__list_cells, ransack__list_plmns, ransack__geolocate_cells, plus the lifecycle tools (operation_status, operation_results, operation_cancel, ready).

Two properties worth stating plainly:

  • The API key lives with the agent, not with ransack. Claude Code uses your own Anthropic login or ANTHROPIC_API_KEY; DragonOS's dragon-rf-agent reads dragon-brain's key from /etc/dragon-brain.conf, then ~/.config/dragon-brain.conf, then the environment. Without a key the CLIs, TUI, and API still work fully.
  • The descriptor exposes only the passive survey. The identity-capture tools are not in it, so an agent driving the gateway cannot trigger a subscriber-identity capture — that plane is CLI-only.

Runs as you, not root

ransack writes your ~/.ransack/cells.sqlite and runs the survey without sudo. SDR realtime priority comes from the usrp group, not root; the GSM catcher listens on a bound UDP socket instead of raw-sniffing, so it never needs CAP_NET_RAW. If a tool genuinely does need sudo, ransackd still resolves ~ to your home via SUDO_USER, so the database never forks into /root.

Install

On DragonOS Resolute the whole toolchain is already on the image:

sudo apt install ./ransack_*.deb

The daemon is socket-activated: systemd holds 127.0.0.1:8082 and starts ransackd on the first request. Config lives at /etc/ransack/config.yml.

Off DragonOS, install the runtime and add only the tools for the sensors you want:

sudo apt install python3 python3-flask python3-yaml python3-jsonschema sqlite3 tshark iproute2 curl
sudo dpkg -i ransack_*.deb        # or run bin/ransack* out of the repo
SensorNeeds
LTE / NB-IoTsrsRAN 4G (cell_search, srsue, cell_search_nbiot, npdsch_ue)
5G NRSni5Gect
GSM / identitygr-gsm, OsmocomBB, an IMSI-catcher
modemQCSuper + a rooted Qualcomm phone or DIAG modem
LTE identityLTESniffer (uplink: 2x B210 + GPSDO) and/or ltesniffer-dl (downlink, one SDR)
LTE activityFALCON
geotagginggpsd (optional; positions are null without a fix)

SDR drivers: UHD for USRP, SoapySDR classic driver=lime for LimeSDR, the respective Soapy/UHD modules for bladeRF/HackRF/RTL.

Configuration

/etc/ransack/config.yml (or ~/.ransack/config.yml). Everything is optional:

api:     { host: 127.0.0.1, port: 8082 }
db:      ~/.ransack/cells.sqlite
device:  { driver: lime, args: "driver=lime,rxant=LNAW" }
scan:    { default_bands: [2, 4, 5, 12, 13, 71], gain: 55, secs: 25, recurse: true }
gps:     { enabled: auto, host: 127.0.0.1, port: 2947, max_age_s: 5 }

Most sensors also take an environment override for the radio (RANSACK_NBIOT_ARGS, RANSACK_GSM_SDR_ARGS, RANSACK_NR_DEV, ...) so you can point one at a second SDR.

The survey plane is passive receive-only — it reads the broadcast SIBs and SSBs cells already transmit. The identity plane (IMSI/TMSI/IMEI) is different: run it only against a network you own, under a licensed engagement, or in a shielded enclosure with a test SIM. Every run is logged to the scans table. You are responsible for compliance with local law.

License

GPL-2.0-or-later, Copyright 2025-2026 CEMAXECUTER LLC. See LICENSE.