# sipnab [![CI](https://github.com/NormB/sipnab/actions/workflows/ci.yml/badge.svg)](https://github.com/NormB/sipnab/actions/workflows/ci.yml) [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/13931/badge) ![OpenSSF Baseline](https://www.bestpractices.dev/projects/13931/baseline)](https://www.bestpractices.dev/projects/13931) [![codecov](https://codecov.io/gh/NormB/sipnab/graph/badge.svg)](https://codecov.io/gh/NormB/sipnab) [![Signed build provenance and SBOM](https://img.shields.io/badge/build_provenance-signed_%C2%B7_SBOM-2ea44f)](https://sipnab.com/docs/install/#verify-a-download-is-genuine) [![XERJ Corpus Hub contributor](https://hub.xerj.org/contributors/NormB/badge.svg)](https://hub.xerj.org/contributors/NormB) **Read a SIP call and see why it failed.** SIP is the signaling protocol that sets up and tears down voice calls. - sipnab reads that signaling from one of these sources: - a live network interface, - a pcap (packet capture) file, - a HEP feed that your SIP proxies send. HEP copies each SIP message to a collector over the network. - From an interface or a file, it also reads the RTP audio packets underneath. It grades their quality. - It shows you: - the call flow, - the audio quality, - the security signals around each call. ![sipnab interactive TUI — call-flow ladder of a complete call: INVITE with SDP, 100 Trying, 180 Ringing, 200 OK, ACK, the RTP media line, then BYE and its 200 OK, with the decoded INVITE in the detail pane. One of seven dialogs in the same sample capture the analyze page loads](website/static/demos/hero-static.webp) sipnab is one binary with no database and no web UI to run. - You can point it at one box's traffic. - Or you can have every proxy in a cluster send it HEP. Then one listener sees calls across many nodes, without anything installed on the production hosts. - It keeps what it sees in memory. - It answers through its terminal view, a command line, a REST API, and an MCP server. You can try it without installing anything. [sipnab.com/analyze](https://sipnab.com/analyze/) reads a pcap in your browser without uploading it. The full documentation lives at **[sipnab.com](https://sipnab.com)** and in [docs/](docs/README.md). The [Glossary](docs/glossary.md) defines the terms these pages use. ## Install On Linux (x86_64 or aarch64) or macOS: ```bash curl -fsSL https://sipnab.com/install.sh | sh ``` The script does three things: - It picks the build for your OS, CPU and glibc. - It checks the build against the release's `.sha256` file. - It installs the build to `/usr/local/bin`. It uses `sudo` only if that directory is not writable. You can [read the script](https://sipnab.com/install.sh) first. To confirm the install, run `sipnab --version`. It prints the version and the features compiled in. Other ways in: | You want | Do this | |---|---| | Homebrew on macOS | `brew install NormB/tap/sipnab` | | A `.deb` or `.rpm`, including `-noaudio` builds for headless servers | [Install with your package manager](docs/install.md#install-with-your-package-manager) | | A static Linux binary with no libpcap dependency (musl) | [Release artifacts](docs/install.md#release-artifacts) | | To prove a download is genuine (checksums, build provenance, SBOM) | [Verify a download is genuine](docs/install.md#verify-a-download-is-genuine) | | To build it yourself | [Build from source](#build-from-source), below | ## Your first ten minutes Here are four common starting points. Each one ends with a link to the page that goes further. ### Triage a capture file Reading a file needs no root and no network interface. So it is the easiest place to start. This sample holds one completed call and four failed ones: ```bash curl -LO https://github.com/NormB/sipnab/raw/main/tests/pcap-samples/sip-problem-call.pcap ``` Open it in the TUI (text user interface), the interactive full-screen view. - Press `F1` for the keys each view accepts. - To quit, press `q` and then `y` to confirm. - Or press `Ctrl-C` to quit at once. ```bash sipnab -I sip-problem-call.pcap ``` Or stay on the command line. `-N` skips the TUI and prints to the terminal. List every call in the file, with its final status code, as a report table: ```bash sipnab -N -I sip-problem-call.pcap --report --no-cli-print ``` Print only the messages of calls that failed or sounded poor. The output is JSON that you can pipe into `jq`: ```bash sipnab -N --json -I sip-problem-call.pcap --problems ``` Explain one call. A Call-ID is the SIP header that names a call. The report table above lists them: ```bash sipnab -N -I sip-problem-call.pcap --call-report 'busy-3a2b1c@192.0.2.30' --no-cli-print ``` Next: - [Triage a capture from the command line](docs/first-cli-triage.md) walks through these commands with their output. - [Your first analysis in the TUI](docs/tui-walkthrough.md) does the same interactively. ### Watch live traffic Live capture on Linux needs raw-socket access. Instead of running sipnab as root, grant the binary the two capabilities once. Then run it as yourself: ```bash sudo sipnab --setup-caps ``` Then capture on an interface. Replace `eth0` with your interface. `ip link` lists them: ```bash sipnab -d eth0 ``` For a stream of JSON, one SIP message per line, add `-N --json`: ```bash sipnab -N -d eth0 --json ``` - Re-run `--setup-caps` after each upgrade. Replacing the binary clears its capabilities. - On macOS, run live capture with `sudo` instead. - [Capture live traffic without root](docs/install.md#capture-live-traffic-without-root) explains the privilege model. - [Tune capture on a busy server](docs/tuning-capture.md) covers packet loss. ### Receive HEP from your proxies Kamailio, OpenSIPS and Asterisk can each mirror their SIP traffic over HEP. Then one sipnab listener sees the calls of every node. You install nothing on the production hosts. A listener on a routable address must do one of two things: - name the senders it accepts (`--hep-allow`), - or share a secret with them (`--hep-auth-file`). Otherwise sipnab refuses to start it: ```bash sipnab -N -L 0.0.0.0:9060 --hep-allow 192.0.2.10 ``` To try it on one machine, bind to loopback. Then replay a capture into it from a second terminal with `-H` (HEP send): ```bash sipnab -N -L 127.0.0.1:9060 ``` ```bash sipnab -N -I sip-problem-call.pcap -H 127.0.0.1:9060 ``` A proxy's HEP feed carries its SIP signaling, not the call audio. For audio quality, run sipnab where the media flows as well. These guides set this up end to end, TLS transport included: - [Run sipnab beside OpenSIPS](docs/opensips-sipnab.md) - [Run sipnab beside Kamailio](docs/kamailio-sipnab.md) - [Connect sipnab to Homer](docs/homer-sipnab.md) ### Serve the REST API, metrics and MCP sipnab can answer other programs while it captures. Choose an API key and keep it in the environment. sipnab reads it there, and `ps` cannot see it there: ```bash export SIPNAB_API_KEY="$(openssl rand -hex 32)" ``` Serve the REST API and Prometheus metrics on loopback. The process keeps serving until you press `Ctrl-C`: ```bash sipnab -N -I sip-problem-call.pcap --api 127.0.0.1:8080 --metrics 127.0.0.1:9100 ``` ```bash curl -H "Authorization: Bearer $SIPNAB_API_KEY" http://127.0.0.1:8080/v1/dialogs ``` MCP (Model Context Protocol) lets an AI agent, such as Claude Code, call sipnab's analysis as tools. - Over stdio, the default transport, the agent starts sipnab itself. So this is the command you register with your MCP client. - `--mcp-transport http` serves remote agents instead. ```bash sipnab --mcp -N -I sip-problem-call.pcap --mcp-tools core ``` The server offers 76 tools. Every tool costs the agent context before it asks anything. - `--mcp-tools core` loads a small set that still answers a whole call. - Named bundles such as `signaling` and `media` load other sets. - Bundles of your own in the config file also load other sets. - See [Choosing which tools load](docs/mcp-tools.md#choosing-which-tools-load). Next: - [REST API and metrics](docs/rest-api.md) - [Prometheus metrics](docs/prometheus-metrics.md) - [MCP server](docs/mcp.md) - [Connect an AI agent to sipnab](docs/mcp-deploy.md) ## Security basics - **Privileges.** Reading files needs none. - For live capture, prefer `sudo sipnab --setup-caps` to running as root. - Started as root, sipnab opens the capture device. Then it drops to an unprivileged user (`nobody`, or `--user`). - `--chroot` confines it further. - **Listeners bind to loopback by default.** On a routable address, these refuse to start without an option: - the REST API, without `--api-key` or `--api-signing-key`, - MCP over HTTP, without `--mcp-token` or `--mcp-signing-key`, - the metrics endpoint, without `--metrics-auth`. - [Set up authentication](docs/auth.md) covers signed tokens, rotation and revocation. - **TLS.** The REST API, MCP over HTTP and the metrics endpoint each serve HTTPS themselves when given a certificate and key: - `--api-tls-cert` / `--api-tls-key` ([API TLS](docs/rest-api.md#api-tls)), - `--mcp-tls-cert` / `--mcp-tls-key` ([MCP TLS](docs/mcp-deploy.md#mcp-tls)), - `--metrics-tls-cert` / `--metrics-tls-key` ([Metrics TLS](docs/prometheus-metrics.md#metrics-tls)), - or the matching `tls_cert` / `tls_key` keys in `sipnab.toml`. - HEP can use TLS in both directions (`--hep-listen-transport tls`, `--hep-send-transport tls`). The sender does one of two things: - it trusts only a named CA (`--hep-tls-ca`), - or it adds one to the host's bundle (`--hep-tls-extra-ca`). - **Sending.** Capture is passive. The features that send are off until you ask for them. For example: - HEP forwarding (`-H`), - reverse DNS (`--reverse-dns`), - `--kill-scanner` and `-K`. On a live interface, these answer scanners with SIP responses. `--kill-scanner-detect-only` detects scanners and never answers them. - When sipnab reads a capture file, it sends no scanner responses. - **The threat model.** [Threat model and security assessment](docs/threat-model.md) lists the assets, trust boundaries, mitigations and known gaps. ## What it does - **Several ways to read the results.** - the interactive TUI, - the non-interactive CLI (`-N`), - JSON (`--json`, one message per line), - reports, - the REST API, - the MCP server. - **Call analysis.** - dialog state, - PDD (post-dial delay, the wait before ringing), - SIP header matching (`--from`, `--to` and the rest), - a [filter language](docs/filter-dsl.md) of 42 fields, 8 operators and boolean logic. - **Diagnostic aliases.** - As flags: `--problems`, `--slow-setup`, `--short-calls`, `--one-way` and `--nat-issues`. - Through `--filter`: `codec-asym`, `ptime-asym`, `payload-asym`, `duration-asym` and `late-media`. For example: `sipnab -N -I capture.pcap --filter codec-asym`. - **RTP quality.** - jitter, - loss, - MOS (mean opinion score). This is an estimate of how the call sounded, from the ITU-T G.107 E-model ([where it comes from](docs/mos-and-codecs.md)). - RTCP XR ([RFC 3611](https://www.rfc-editor.org/rfc/rfc3611.html)) reports, - one-way audio. - **Security analysis.** - Scanner detection, registration floods, digest credential leaks, STIR/SHAKEN, and fraud heuristics. - It sends alerts to syslog, JSON or a command of your own (`--alert`, `--alert-exec`). - It can write fail2ban input (`--fail2ban`). - It can ask [TFPS](docs/tfps-sipnab.md) to ban a source. That action stays off until `--allow-action` enables it. - **HEP v3** send over UDP, TCP or TLS, and HEP v1/v2/v3 receive. - **TLS and SRTP decryption.** It decrypts from these sources: - an SSLKEYLOGFILE (TLS 1.2 and 1.3), - an RSA private key (`--tls-key`, TLS 1.2 RSA key exchange only), - SRTP keys. These are the SDES `a=crypto` keys in the SDP, or a master-keys file with `--srtp-keys`. - DTLS-SRTP (`--dtls-keylog`, [RFC 5764](https://www.rfc-editor.org/rfc/rfc5764.html)). - [Capture SIP over TLS](docs/tls-capture.md) helps you choose. - **TLS capture with uprobes.** This does not break TLS. - It works on a host where you already have root. - Kernel uprobes read the SIP plaintext inside OpenSSL or wolfSSL, before the library encrypts it (`--uprobe-tls`). - So it needs no key, certificate or restart. - Every Linux build has it. Its default tracefs backend needs no BTF. - The eBPF backend also recovers the peer addresses. - It is in the released Linux gnu tarballs, `.deb` and `.rpm`. - It is not in the static musl builds. - It needs a kernel with BTF. - **SIPREC metadata.** Reads the recording metadata ([RFC 7866](https://www.rfc-editor.org/rfc/rfc7866.html)) that a session recording client sends. sipnab is not a recording client or server. - **Relay correlation.** - It ties media on a relay back to its call. The relay can be an rtpengine relay ([rtpengine](docs/rtpengine.md)) or an rtpproxy relay (`--rtpproxy-control`). - It reads rtpengine's own counters over its control port (`--rtpengine-control`). sipnab labels them as the relay's report, not sipnab's measurement. - **vCon export and delivery.** - It writes each observed call as a vCon, a conversation container (`--export-vcon`, [Export a call as a vCon](docs/vcon.md)). - `--vcon-forward`, a separate process, delivers them to a vCon store. Two examples are vcon.store and a self-hosted conserver. - It is in the gnu and macOS builds. The static musl builds lack the `vcon` feature. - `--vcon-forward-kind vcon-store` adds vcon.store's ingest path and header. - It changes only the copy it sends. - The reason: vcon.store's validator rejects the string-array `extensions` that both vCon drafts define ([Send sipnab's vCons to vcon.store](docs/vcon-store.md)). - Export rules (`[[vcon.rule]]`) pick calls by filter. They write them per leg or per call. - A call can go to your own transcriber first (`[[vcon.enrich]]`). - You can follow and hear live calls while they are in progress. - A rule with `encrypt_to` writes the signed and encrypted form. - **Export formats.** pcap and pcapng, TXT, JSON, NDJSON, CSV, an HTML page of the call flow, Markdown, WAV audio, SIPp XML scenarios and RTP JSON. - **Tunnels and transports.** It reads SIP in these forms: - inside VLAN and QinQ tags, MPLS, GRE, GTP-U, VXLAN, GENEVE and other tunnels, - SIP over WebSocket, - SIP split across IP fragments or TCP segments. - Some need an option on a live capture. [Encapsulations](docs/encapsulations.md) lists which. - **Ranked analysis and conformance.** - `--analyze` lists every problem in a capture, worst first. - `--yang-analyze` writes it as [RFC 7951](https://www.rfc-editor.org/rfc/rfc7951.html) JSON against a published YANG module. - `--lint` checks RFC conformance. Each finding has a rule ID and RFC section. - **pcap in and out.** - It reads and writes pcap and pcapng, with rotation and splitting. - It reads directories, tar archives and password-protected ZIP and 7z archives. - It reads stored vCon containers as the SIP messages they hold. - **vCons with pseudonyms, and a hardened process.** - `--redact` replaces identities, addresses and hostnames in exported vCons with keyed pseudonyms. - `--redact-map` writes the reverse map to a file only you can read. - A capture started as root drops to `--user` after opening its devices. - It can confine itself with a Landlock sandbox (`--sandbox`) and a seccomp allowlist (`--seccomp`). - **MCP server.** 76 tools over stdio or HTTP. - 63 only read. - The 13 that write each say what they change. - File writes stay inside `--mcp-file-root`. - These stay off until you enable them: - swapping the capture (`--mcp-allow-open-capture`), - shutting the server down (`--mcp-allow-shutdown`), - recording findings (`--mcp-allow-save-findings`), - asking TFPS to ban a source (`--allow-action`). - [MCP server](docs/mcp.md) has a first working example. ## The TUI - **Call list** with sortable columns, multi-select, inline search and filters - **Call flow ladder** with color-coded arrows, SDP codecs, and PDD - **Four timestamp modes:** absolute, delta from the previous message, delta from the first, and scaled to time - **Split view:** the raw SIP message beside the ladder, resized with `+`/`-` - **Message diff:** select two messages with `Space` to compare them - **Extended flow:** merge the legs of one call through a proxy or B2BUA into one ladder (`x` or `F4`) - **RTP streams** with jitter, loss and MOS (`Tab`), audio playback, and WAV export (`F2`) - **Quality views:** a live MOS dashboard, a loss map and a call timeline; **carrier views:** ASR, NER and ACD, top talkers and a call-volume histogram - **Operator notes** on messages, saved as pcapng packet comments, and names for hosts from hosts files and DNS [Keybindings](docs/keybindings.md) lists every key, per view. ## Build from source sipnab is Rust everywhere except the OS boundary. - It has 113 `unsafe` blocks, all of them FFI. - The build rejects any block that does not state its own soundness argument. You need **Rust 1.99+** (edition 2024) and the libpcap headers: - macOS: included with the Xcode Command Line Tools (`xcode-select --install`) - Debian/Ubuntu: `apt install libpcap-dev` - Fedora/RHEL: `dnf install libpcap-devel` ```bash cargo build --release ``` The binary is at `target/release/sipnab`. [Install with cargo](docs/install.md#install-with-cargo) installs the published crate instead. At run time, sipnab loads the system libpcap (`libpcap.so.1` on Linux). Only the static musl release binary carries its own. Audio playback in the TUI also needs `libasound` (ALSA). - It loads it only when you press play. - Playback lives in a separate plugin, `libsipnab_audio.so`. - So a binary built with audio starts fine on a host without libasound. - WAV export still works there. ### Feature flags | Flag | What it adds | Default | |---|---|---| | `native` | Live and file capture, output writers, the CLI. Needed by every feature below except `tls`, `audio` and `wasm` | yes | | `tui` | The interactive terminal UI | yes | | `audio` | RTP audio playback in the TUI, through the lazily loaded `sipnab-audio` plugin, and WAV export | yes | | `metrics` | Standalone Prometheus metrics server (`--metrics`) | yes | | `tls` | TLS and DTLS decryption, SRTP key extraction | no | | `hep` | HEP v3 send, HEP v1/v2/v3 receive | no | | `api` | REST API and its Prometheus endpoint, over HTTP or HTTPS | no | | `mcp` | MCP server, stdio transport | no | | `mcp-http` | MCP server over HTTP (Streamable HTTP). Implies `mcp` and `api` | no | | `plugins` | WASM plugin host (`--plugin`): sandboxed third-party detections | no | | `vcon` | vCon export of one observed call | no | | `opus` | Ogg Opus recordings in vCon containers. Compiles libopus from source, so building it needs `cmake` and a C compiler | no | | `archive` | Password-protected ZIP and 7z input | no | | `g729` | G.729 decoding in audio exports, once `sipnab g729 install` has installed the codebook tables on the host ([G.729 decoding](docs/g729.md)) | no | | `bpf` | eBPF TLS capture (`--uprobe-backend bpf`). Needs a nightly toolchain and `bpf-linker` to build, and a kernel with BTF to run. Outside `full` | no | | `wasm` | WebAssembly build for in-browser pcap analysis | no | | `full` | `native`, `tui`, `audio`, `metrics`, `tls`, `hep`, `api`, `mcp`, `mcp-http`, `plugins`, `vcon`, `opus`, `archive`, `g729` | no | Every feature: ```bash cargo build --release --features full ``` A headless capture host has the HEP listener, REST API and MCP over HTTP. It has no TUI or audio: ```bash cargo build --release --no-default-features --features native,hep,api,mcp,mcp-http ``` [Installation](docs/install.md#build-it-from-source) covers the other builds. That includes [cross-compilation](docs/install.md#cross-compilation). ## Add it to your voice stack These are step-by-step guides. - Each guide installs your SIP server: OpenSIPS, Kamailio, Asterisk or FreeSWITCH. - It installs each piece beside it. - Then it connects sipnab to it. - Every command in each guide ran on fresh virtual machines. Each page names them. - **SIP proxy.** OpenSIPS and Kamailio carry your calls. Every other guide builds on them. - [Use OpenSIPS](docs/opensips.md) and [run sipnab beside it](docs/opensips-sipnab.md) - [Use Kamailio](docs/kamailio.md) and [run sipnab beside it](docs/kamailio-sipnab.md) - **PBX.** Asterisk answers calls and places them on to the callee, as two legs. - [Use Asterisk](docs/asterisk.md) and [run sipnab beside it](docs/asterisk-sipnab.md) - **Softswitch.** FreeSWITCH answers each call. It bridges the call to the callee as a second call. The audio of both passes through it. - [Use FreeSWITCH](docs/freeswitch.md) and [run sipnab beside it](docs/freeswitch-sipnab.md) - **Call records.** A vCon server keeps every call as a vCon. - OpenSIPS records calls into it over SIPREC. - sipnab can send its own vCons, built from what it saw on the wire. - The command `sipnab --vcon-forward` delivers them, to the server or to vcon.store. It is in the gnu and macOS builds, which carry the `vcon` feature. - [Use a vCon server](docs/vcon-server.md), [run sipnab beside it](docs/vcon-sipnab.md), [send to vcon.store](docs/vcon-store.md) - **Attack blocking.** TFPS stops SIP scanners and fraud in the kernel with XDP. fail2ban bans them with an nftables rule. - [Use TFPS](docs/tfps.md) and [run sipnab beside it](docs/tfps-sipnab.md) - [Use fail2ban](docs/fail2ban.md) and [run sipnab beside it](docs/fail2ban-sipnab.md) - **Media relay.** rtpengine or rtpproxy anchors every call's audio. sipnab matches the media on the relay with the call it belongs to. - [Use rtpengine](docs/rtpengine-relay.md) and [run sipnab beside it](docs/rtpengine-sipnab.md) - [Use rtpproxy](docs/rtpproxy-relay.md) and [run sipnab beside it](docs/rtpproxy-sipnab.md) - **Call history.** Homer keeps a searchable history of every call your proxy sends it over HEP. sipnab can join the same feed. - [Use Homer](docs/homer.md) and [run sipnab beside it](docs/homer-sipnab.md) - **Metrics.** Prometheus and Grafana graph your SIP proxy's statistics. sipnab adds its own call and media series beside them. - [Use Prometheus and Grafana](docs/prometheus.md) and [run sipnab beside it](docs/prometheus-sipnab.md) ## Where to read next [docs/README.md](docs/README.md) indexes every page by what you are trying to do. Here are the ones most people need: | When you want to | Read | |---|---| | Find out why calls fail, drop, or carry one-way audio | [Troubleshooting](docs/troubleshooting.md) | | Copy a recipe for a common task | [Examples and recipes](docs/examples.md) | | Narrow to the calls that matter | [Filter DSL](docs/filter-dsl.md) | | Look up a flag | [CLI reference](docs/cli-reference.md) | | Write a config file | [Config reference](docs/config-reference.md), starting from [contrib/sipnabrc.example](contrib/sipnabrc.example) | | Parse sipnab's JSON or export pcap | [Output formats](docs/output-formats.md) | | Use sipnab as a Rust library | [Library API](docs/library.md) | | Understand how it works inside | [Architecture](docs/architecture.md) and [Fault model](docs/fault-model.md) | ## Getting help - Ask usage questions in [Discussions](https://github.com/NormB/sipnab/discussions). - Report bugs in [Issues](https://github.com/NormB/sipnab/issues/new/choose). - [SUPPORT.md](SUPPORT.md) explains which is which. - [MAINTAINERS.md](MAINTAINERS.md) says who answers and how fast. ## Contributing We welcome contributions. - [CONTRIBUTING.md](CONTRIBUTING.md) covers the build and test workflow, the git hooks, and the pull request checklist. - Before we can merge a pull request, you sign the [Contributor License Agreement](CONTRIBUTING.md#contributor-license-agreement) once. - A pull request cannot merge until the `license/cla` check passes. - If your change adds a dependency, read [Dependencies](CONTRIBUTING.md#dependencies) first. - This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). - [ROADMAP.md](ROADMAP.md) says what we intend to work on over the next year. It also says what we have decided not to build. ## Security Found a vulnerability? **Do not open a public issue.** [SECURITY.md](SECURITY.md) gives: - the private reporting address, - the response timeline, - what is in scope. Examples: - parser crashes, - key-material leaks, - privilege-drop and chroot escapes, - API and MCP authentication bypass, - command injection through the `--alert-exec` family. ## Support the project [![Patreon](https://img.shields.io/badge/Patreon-support-f96854?logo=patreon&logoColor=white)](https://www.patreon.com/c/NormB975) [![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-db61a2?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/NormB) [![CLA assistant](https://cla-assistant.io/readme/badge/NormB/sipnab)](https://cla-assistant.io/NormB/sipnab) ## License Licensed under either of - [Apache License, Version 2.0](LICENSE-APACHE) - [MIT License](LICENSE-MIT) at your option. Copyright 2024-2026 Norm Brandinger