DOCUMENTATION / PART 2 — GETTING IT RUNNING2.1

Part 2 — Getting it running

Part 1 described the toolkit in the abstract. This part is concrete: what must be installed, what the radios can and cannot do, and one worked session from an empty machine to a case that contains evidence. §2.1 is the bench, §2.2 is the radio, §2.3 is the first hour.

2.1 The bench: dependencies and pre-flight

IMSISting is a shell toolkit wrapped around external programs. It does not vendor decoders, drivers or protocol stacks, and it does not pretend to work without them: a module that needs tshark and cannot find it refuses, names the binary, and exits 2. That behaviour is only pleasant if you can see the whole dependency picture before you are in the middle of a survey, which is what the dependency module exists for.

00_deps — Dependency Manager

modules/00_deps.sh --preflight        # radio, gates and capture state in one page
modules/00_deps.sh --status-tsv       # one row per registered tool, 6 TSV fields
modules/00_deps.sh --missing-only     # only what is not usable
modules/00_deps.sh --check-versions   # present / absent / broken, with versions
modules/00_deps.sh --report           # write loot/deps/deps_report.tsv

Start with --preflight. It answers three questions in one screen: is there a radio, are the capture paths usable, and are the gates clean. The order matters — a broken capture path makes every later result suspect, and it is cheaper to find that now than after an hour of survey.

--status-tsv is the machine-readable form and the one to use in a script. Each row describes one tool with six fields: the tool name, its class (sdr, decode, protocol, sim, net, …), whether it is usable, the package that provides it on Debian, the package that provides it on Arch, and a note. "Usable" is not the same as "installed": a binary that exists but cannot run is reported as broken, because a toolkit that counts a broken decoder as present is a toolkit that reports empty results as findings.

--install-missing installs what is absent through the distribution's package manager, and asks before it does. --install-pip covers the Python protocol libraries that are not packaged. Neither is required to use the toolkit: most modules degrade in a stated way rather than failing, and the ones that cannot degrade refuse.

05_field_kit — Field Kit

The field kit is the answer to a specific bad habit: claiming a capability because a binary was on $PATH. It performs two things.

--capability reports what radio hardware is present and what that implies for the work you might do next — receive only, transmit capable, full duplex, both directions but one chain at a time. This is a stronger statement than 01_radio --list-tsv, which lists what answered a probe; the field kit maps the answer onto consequences.

--guard-check is the honesty test the rest of the tree leans on. It runs every radio-gated verb in the toolkit and verifies that each one fails correctly when no radio is present: refusing with a named missing clause, or handing off, never succeeding with empty output. If any gated verb returns 0 with no radio, the field kit reports it as a defect. That is the mechanism which keeps loot/ honest when the hardware is unplugged, and it is why the modules can be trusted in a lab.

--emit writes synthetic GSMTAP onto the loopback interface (or into a pcap) from a set of built-in scenarios, and --scenarios lists them. This exists so that the decoders, the stores and the interfaces can be exercised end to end on a machine with no radio and no live network — and so that a reader of this manual can reproduce every GSMTAP example in Part 5 without radiating anything. The synthetic frames are labelled synthetic in the store's source column: a scenario is evidence about the decoder, never about the air.

tools/fetch-reference-data.sh — the public reference tables

A capture tells you what the air carried. It does not tell you who owns it. The MCC/MNC register, the ITU's ISPC register and the IANA enterprise numbers are what turn an identity into an operator, and they are public but not shipped: they are hundreds of thousands of rows, they are revised, and a stale copy that looks authoritative is worse than no copy at all.

tools/fetch-reference-data.sh                 # all three tables
tools/fetch-reference-data.sh --only ispc     # one
tools/fetch-reference-data.sh --check         # present / silent, no download
Table Source Rows Read by
data/public/plmn.tsv the full public MCC/MNC register ~2 500 02_cell_recon, 04_tower_map, 16_sim
data/public/ispc.tsv ITU Operational Bulletin, Q.708 annex ~6 300 26_ss7_map --ispc
data/public/pen.tsv IANA enterprise numbers ~67 000 Diameter vendor ids

Everything lands under data/public/, which is gitignored. Nothing is committed and nothing is fetched at module run time: a module either finds a table or says it did not.

The lookups report three states, and the difference is the point:

State Means What a caller does
ok the row was found print the operator
absent the table was read and holds no such row that is the finding
silent the table is not on this machine report unobserved, never "absent"

silent and absent are routinely confused and they never mean the same thing. A PLMN that resolves to nothing in a downloaded register is an operator missing from the public record; a PLMN that resolves to nothing because nobody ran the fetch is a hole in the analyst's bench. Collapsing the second into the first manufactures findings, which is the one failure this toolkit exists to avoid.

data/opops/ — the operator's own tables

data/opops/ is the private half: tables an operator supplies about its own network. The toolkit ships the loader and the schema, never the contents — which is also the reason it is useful, because the private numbers a core network runs on are exactly the ones that must not be in a git repository.

File Header Answers
gt.tsv gt_prefix, plmn, stp_type, note which PLMN and which STP a global-title prefix belongs to
cellblock.tsv plmn, range_lo, range_hi, kind, note whether a cell identity sits inside the block an operator was allocated
iprange.tsv plmn, cidr, role, note which core function owns an address
smsc.tsv plmn, smsc_gt, note the SMSC a home network routes short messages through

Validation is an operator-internal binary: a subscriber who watches a spoofed command from their handset will accept the command when the SMSC is approved, and the SMSC identity is core-internal. These are not exported by any public registry, published by any SIM vendor, or in any OEM code. A GT table is the only thing that turns op=470012000001 into a statement about the operator whose HLR is being queried.

With data/opops/ empty the toolkit is correct and shallow: it decodes, it correlates, and it reports the store's contents as unobserved where an operator table would have answered. That is the honest floor, not a bug.

Each table ships as a tracked *.dist template in the same directory. Copy the one you need, drop the .dist, and replace the example rows:

cp data/opops/iprange.tsv.dist data/opops/iprange.tsv
tools/lib/refdata.sh            # source, not run: refdata_status_line

The templates carry the schema and one obvious example row each — never a real operator's numbers, which is the whole reason the directory is private.

Screening an interconnect peer

iprange.tsv is what turns a source address into a statement about a peer. 11_lte_core reads it for two questions that a border either answers or does not, and answers both in the same three states the rest of the toolkit uses:

modules/11_lte_core.sh --gtp-screen-peer 198.51.100.5 32
modules/11_lte_core.sh --diameter-screen 16777251 316

The first asks two things in order. Is this address inside a prefix a contracted peer was granted, and — the half a peer-level allow rule never asks — may a peer originate this GTP-C message type at all. A message can come from the right address and still be wrong: MBMS Session Start, or any node-initiated procedure, is not something a roaming partner sends.

The second asks whether a Diameter (application, command) pair is one a roaming peer may originate, or whether it belongs to an interface that only ever traverses one operator's domain. S6a Update-Location arriving over an interconnect is the identity-theft shape, not a protocol error, and it is named as such.

Two things both verbs refuse to do. They do not resolve longest-prefix — the first matching row wins, so put narrow prefixes above broad ones. And with no iprange.tsv installed they answer unknown, not deny: a missing file must never manufacture a blocked-peer finding.