How sipnab turns captured packets into calls, media streams and findings, and
where each answer surface reads them from. Read this to understand what a
setting such as --cores, --limit or --no-reassembly changes.
Contributors changing the code want the code map: the module layout, the design decisions and where to add things.
sipnab is a single binary. It runs in one of two modes:
- as a TUI, an interactive terminal interface (the default),
- or in batch mode with
-N: read, print or export, then exit.
Both modes run the same analysis.
The run mode decides who drives the capture. It does not decide who can ask about it. The same analysis is readable over four surfaces at once:
| Surface | Flag | Who asks |
|---|---|---|
| Terminal | default | A person at a TUI, or a script reading text/JSON/NDJSON |
| REST API | --api |
Another program, over HTTP |
| MCP | --mcp, plus --mcp-transport http to serve it over HTTP |
An AI agent, calling Model Context Protocol tools |
| Prometheus | --metrics |
A scraper |
- All four read the same dialog and stream tables, so they report the same calls.
- An MCP client or REST client can query a live capture while it is still running.
- No MCP tool changes the analysis.
capture sources per-packet path tables
─────────────── ─────────────── ──────
live device (-d) ─┐
capture file (-I)─┼──► decapsulation, IP fragment and ──► SIP, RTCP ──► dialogs ◄── SDP ──► RTP streams
HEP listener (-L)─┘ TCP reassembly, SIP framing or RTP ▲ ▲
└── terminal, REST, MCP, Prometheus
Each packet goes through these steps:
- Capture. A live interface (
-d), one or more capture files (-I), or a HEP listener (-L) that receives copies from Kamailio, OpenSIPS, Asterisk or rtpengine. - Decapsulation. sipnab strips the link layer, VLAN tags and the tunnels
listed in Encapsulations. A frame it cannot decode is
counted in the
NOT DECODEDline at the end of the run. - Reassembly. sipnab joins IP fragments and TCP segments, so a SIP message
split across packets reads as one message.
--no-reassemblyturns this off. - Classification. sipnab unwraps SIP over WebSocket, then reads the payload as SIP, RTCP or RTP.
- Tables. SIP messages join dialogs by Call-ID. RTP packets join streams by SSRC. The SDP in a dialog links its streams to it. An RTP stream with no SIP in the capture still appears as a stream.
- Readers. The terminal, the REST API, MCP and Prometheus read the two tables.
The dialog and stream tables have fixed ceilings, so a flood of unique Call-IDs or SSRCs cannot exhaust memory:
| Setting | Default | At the ceiling |
|---|---|---|
--limit |
100000 dialogs over the run | sipnab evicts the oldest dialog. With --no-rotate, it drops new dialogs instead. |
--max-streams |
50000 streams | sipnab evicts the oldest stream. |
--limit counts every dialog the run has seen, completed ones included, so a
long-running capture reaches it even at low call volume.
Fault model lists every bound.
With -I and --cores N, sipnab reads the capture once and splits the
packets across N worker threads by host pair. Each worker builds its own
tables, and sipnab merges them at the end of the file. That mode prints the
whole-capture views (--report, --json-dialogs, --analyze,
--call-report) and no per-message lines. Benchmarks
measures how it scales.
Live capture and a file read without --cores use one processing thread.
- sipnab sets
PR_SET_NO_NEW_PRIVSat startup in every run mode, so no child process it starts can gain privileges. - When started as root, it drops root right after opening the capture socket.
--usernames the account it drops to. - It disables core dumps whenever it holds decryption keys.
--chrootconfines a long-running daemon to one directory.- The scanner-kill response runs in a separate process that holds the only sockets it sends through.
- The REST API and MCP servers run inside the main process, which also holds the capture data, TLS key material and bearer tokens. Treat the API bind address and key accordingly.
A malformed packet or capture file never stops the run: sipnab marks the message as a parse error and continues. The project fuzzes the parsers that read captured bytes, with 20 targets. Fault model describes each failure class and how sipnab behaves under it.