Repository navigation
Threat Model
This page answers three questions about sipnab:
- what an attacker would want from it,
- where an attacker can reach it,
- what stops them.
It also lists what does not stop them.
- The last section, residual risks, matters as much as the rest.
- An assessment that lists only defenses tells an operator nothing about where to add their own.
SECURITY.md says how
to report a vulnerability. It also says which classes of bug count as one.
- This page is the analysis behind that list.
- The assurance case builds on it.
- It argues that sipnab applies secure design principles.
- It walks the CWE Top 25 weaknesses one by one.
- Asset: something worth protecting, such as a TLS private key or the calls in a capture.
- Trust boundary: a place where data or commands cross into sipnab from something sipnab does not control. Every input an attacker can influence crosses one.
- Threat: a specific thing an attacker could try at a boundary.
-
Mitigation: the code that makes a threat fail or limits its damage.
- Every mitigation below names the file, and usually the function, that implements it.
- So a reader can check the claim instead of trusting it.
- Residual risk: a threat that no mitigation fully covers today.
-
Loopback: the
127.0.0.1or::1address, reachable only from the same machine. -
Bearer token: a secret a client sends in an HTTP
Authorization: Bearerheader. Whoever holds the token has the access it grants. - HMAC: a keyed checksum. Only a holder of the key can produce a value that verifies. So it proves who sent a message, and that nobody changed it.
The assessment covers the sipnab binary built with the full feature set
on Linux. That is the build that has every listener and every hook.
- It walks each trust boundary.
- It names the likely threats there.
- It cites the code that answers each one.
- The authors read each cited function to confirm it does what this page says.
- The code may do less than a reader might assume. Then the gap appears under residual risks.
sipnab is mostly passive: it reads packets and reports on them. Two features act on other systems:
- scanner-kill (sends SIP responses),
- the TFPS ban actions.
Both are off by default.
| Asset | Why an attacker wants it |
|---|---|
| Captured SIP and RTP | Call metadata (who called whom, when), SIP digest credentials, and call audio. |
| Decryption secrets | TLS private keys (--tls-key), TLS key logs (--keylog), SRTP keys, and secrets embedded in pcapng files. Any of these decrypts traffic beyond what sipnab shows. |
| Credentials sipnab checks | REST API keys and signing keys, MCP tokens, metrics Basic-auth credentials, HEP shared secrets, archive passwords. |
| The capture host | sipnab often starts as root to open a network device. Code execution in sipnab before the privilege drop is code execution as root. |
| Integrity of findings | Security alerts, scanner-kill decisions and fail2ban lines drive action elsewhere. Forged findings can ban an innocent address. |
| Other networks | The scanner-kill path transmits. Misused, it could aim traffic at a victim. |
| Evidence files | A capture is often the only copy of an incident. Overwriting it destroys evidence. |
| Boundary | Who is on the other side | Exposure by default |
|---|---|---|
| Packet capture input | Anyone who can send a packet the capture interface sees | Whenever sipnab captures live |
| Capture and archive files | Whoever produced the file | Whenever -I reads a file |
| HEP senders | Any host that can reach the HEP port | Off. --hep-listen turns it on |
| REST API clients | Any host that can reach the API port | Off. --api turns it on |
| MCP clients | An AI agent and whoever controls its prompts | Off. --mcp turns it on |
| Exec hooks | Contents of captured SIP, passed to an operator's command | Off. --on-dialog-exec, --on-quality-exec and --alert-exec turn it on |
| WASM plugins | The author of a plugin file | Not in the default build. The plugins feature adds it |
| TLS and SRTP key material | Other local users, crash dumps, swap | Whenever a key option is present |
| Configuration files and the command line | Anyone who can write a config file or read the process list | Always |
Every packet on a monitored interface is attacker-controlled.
- A remote attacker needs no account and no connection.
- The attacker needs only the ability to send one SIP or RTP packet that crosses the wire sipnab watches.
| Threat | Mitigation | Where |
|---|---|---|
| A malformed packet crashes a parser or corrupts memory. | The parsers are Rust. The project fuzzes every parser that reads untrusted bytes, and a smoke tier runs in ordinary CI. Fault model counts the unsafe blocks and names where they live. |
fuzz/fuzz_targets/, tests/smoke_fuzz_test.rs
|
| A flood of unique Call-IDs or RTP SSRCs grows memory without limit. | The dialog and stream stores cap their size and evict. A regression test floods 50,000 identities into a 1,000-entry store. | tests/resource_bounds_test.rs |
| Oversized header lines, TCP streams or WebSocket frames exhaust memory. | Fixed caps on header-line length, on the reassembly buffer and on WebSocket message size. |
src/sip/parser.rs::DEFAULT_MAX_HEADER_LINE_LEN, src/capture/reassembly.rs::DEFAULT_MAX_TCP_BUFFER, src/capture/websocket.rs::MAX_WS_MESSAGE_SIZE
|
| A parser bug becomes root code execution. | Once the capture thread reports the device open, sipnab drops to an unprivileged user (nobody unless --user names another) and checks that the drop took. See residual risk "libpcap is C, and it runs briefly as root" for the window before the drop. It sets PR_SET_NO_NEW_PRIVS at startup so a later exec cannot regain privilege. |
src/privilege.rs::drop_privileges, src/privilege.rs::verify_dropped, src/privilege.rs::block_privilege_escalation
|
| A forged scanner packet turns scanner-kill into a reflector aimed at a victim. | Responses pass a global per-second cap (default 10, zero refused) and a fixed cap of three per destination per minute that no option raises. Only a live source can create the send sockets: a capture file or a uprobe source cannot. The sockets live in a separate worker process that starts with an emptied environment and clears its Linux capabilities. |
src/cli.rs::DEFAULT_KILL_RATE_LIMIT, src/process_isolation.rs::MAX_PER_DST_PER_MINUTE, src/security/transmit_guard.rs::for_source, src/process_isolation/worker_process.rs::clear_capabilities
|
A capture file is as hostile as the network it came from. An archive adds decompression, and file names chosen by its author.
| Threat | Mitigation | Where |
|---|---|---|
| A record header claims a huge length and triggers an out-of-bounds read. | The reader uses checked arithmetic and a bounds check on every record length. | src/capture/pcap_reader.rs |
| A decompression bomb fills memory or disk. | Every byte that decompression produces, summed over every nested layer, counts against one ceiling (default 1 GiB, set with --max-gunzip-bytes). Nesting stops at four layers and member count at 10,000. |
src/capture/pcap_reader.rs::DEFAULT_MAX_GUNZIP_BYTES, src/capture/archive/mod.rs::MAX_DEPTH, src/capture/archive/mod.rs::MAX_ENTRIES
|
A member named ../../etc/cron.d/x writes outside the extraction directory. |
sipnab never uses a member's name as a path. It writes each member to a name it generates (m00003.pcap) inside a private temporary directory, creates the file exclusively with owner-only permissions, and never materializes links, device nodes or named pipes. |
src/capture/archive/mod.rs::ExtractDir |
| An output option points at an input and destroys the evidence. | sipnab compares canonical paths, after resolving symlinks and .., and refuses before it opens anything for writing. |
src/capture/output_guard.rs::canonical_target |
| A pcapng file embeds TLS secrets that travel with a shared copy. | sipnab reads Decryption Secrets Blocks so it can decrypt, and --strip-secrets writes a copy with every one removed, for use before anyone shares a capture. |
src/capture/pcapng_meta.rs, src/cli.rs (strip_secrets) |
| An archive password leaks through the process list, a URL or a readable file. |
--archive-password prints a warning naming the safer options on every use. sipnab refuses a password file you own that other users can read. The REST API refuses a password in a query string and limits wrong guesses to five per token and archive in 15 minutes. |
src/capture/archive/password.rs::INLINE_WARNING, src/privilege.rs::permission_refusal, src/output/api.rs::refuse_password_in_url_mw, src/output/api.rs::ARCHIVE_WRONG_LIMIT
|
HEP (Homer Encapsulation Protocol) lets a SIP server such as OpenSIPS or Kamailio mirror its traffic to sipnab over the network.
- A HEP packet carries the SIP message and the addresses it claims the message used.
- So a sender can assert any source address it likes.
| Threat | Mitigation | Where |
|---|---|---|
| Anyone on the network injects fake calls. | A listener on a non-loopback address refuses to start unless it has a shared secret or a source allowlist. It classifies loopback from the literal address only, without a DNS lookup, so a hostname counts as non-loopback. | src/capture/hep.rs::enforce_hep_bind_policy |
| An attacker recovers the shared secret byte by byte from response timing. | The shared secret check compares in constant time. |
src/capture/hep.rs::plain_auth_check, src/crypto.rs::constant_time_eq
|
| An attacker replays or edits a captured HEP packet. | The opt-in --hep-auth-mode hmac signs the whole datagram, rejects stale timestamps, and remembers the one-time number (nonce) in each accepted packet to refuse replays. It verifies the signature before touching the nonce cache, so a forged packet cannot poison it. |
src/capture/hep.rs::verify_hmac_datagram |
| A sender forges a source address so sipnab kills a call or bans an innocent host. | Scanner-kill and fail2ban lines act on a HEP-reported address only with --hep-allow-kill, which defaults off. |
src/security/scanner_kill.rs::kill_response_eligible |
| A HEP-over-TLS key file readable by every user lets anyone impersonate the listener. | sipnab refuses a world-readable key. | src/tls_files.rs::pem_private_key |
| One sender floods the listener. | A global packet ceiling (--hep-rate-limit, default 50,000 packets per second) and an optional per-sender cap (--hep-rate-limit-per-peer, off by default). |
src/capture/hep.rs::describe_hep_limiters |
The REST API (--api) serves everything sipnab knows about the capture. The
metrics endpoint (--metrics) serves Prometheus counters.
| Threat | Mitigation | Where |
|---|---|---|
| The API listens on a public address with no credentials. | A non-loopback bind with no API key or signing key refuses to start. The metrics server applies the same rule to its Basic-auth credential. |
src/output/api.rs::enforce_bind_auth_policy, src/output/prometheus_server.rs::start_metrics_server
|
A web page uses DNS rebinding to reach a loopback API with no key through a browser: it points its own name at 127.0.0.1, then reads /v1/dialogs or sends POST /v1/persistence as a same-origin request (CWE-352). |
Before any route, the rate limiter or authentication runs, the Host header must name localhost, 127.0.0.1, ::1, the bound address (any IP address on a wildcard bind) or an --api-allowed-host / [api] allowed_hosts entry. Anything else gets 403, and a request with no Host gets 400. * turns the check off. The MCP transport applies the same rule. |
src/host_allowlist.rs::HostAllowlist, src/output/api.rs::with_host_allowlist
|
| An attacker forges or reuses a token. | Tokens carry an HMAC-SHA256 signature, an expiry, an audience (api or mcp) and an id that a revocation list can name. Verification compares signatures in constant time. A value that starts like a signed token and fails any check gets a refusal, never a second chance as a static key. Authentication describes minting and rotation. |
src/auth.rs::verify_signed, src/auth.rs::verify_static
|
| A token for one surface opens the other. | The audience check is unconditional, so an API token fails on MCP and the reverse. | src/auth.rs::verify_signed |
| An attacker guesses tokens at high speed. | The per-client rate limit runs before authentication, so a wrong guess costs the same budget as a right one. | src/output/api.rs::guard_scoped |
| A read-only credential triggers a ban on another system. | TFPS ban and unban need a token with the actions scope and a server-side setting that enables them. |
src/output/api.rs::action_guard |
| A network observer reads bearer tokens or capture data in transit. | With --api-tls-cert and --api-tls-key the API serves HTTPS only (TLS 1.2 and 1.3), refuses a world-readable key or a key that does not match the certificate at startup, and refuses to start on only one of the two flags rather than serving plain HTTP. HTTP MCP (--mcp-tls-cert / --mcp-tls-key) and the metrics endpoint (--metrics-tls-cert / --metrics-tls-key) apply the same checks through the same reader. |
src/output/api.rs::api_tls_config, src/tls_files.rs::server_config, src/cli.rs::tls_pair_problem
|
| A client that connects and never finishes a TLS handshake holds the listener. | On the API and HTTP MCP, each handshake runs in its own task with a 10-second timeout, at most 256 at once; sipnab closes connections past that. On the metrics endpoint each connection has its own thread with a 5-second read and write timeout, within the --metrics-max-conn limit. |
src/tls_listener.rs::accept_tls, src/output/prometheus_server.rs::start_metrics_server
|
| A slow or huge request ties up the server. | Every route has a 30-second timeout and a 1 MiB body limit. |
src/output/api.rs::build_router, src/output/api.rs::REQUEST_TIMEOUT, src/output/api.rs::MAX_REQUEST_BODY_BYTES
|
MCP (Model Context Protocol) lets an AI agent query sipnab. The agent is a client like any other, with one extra risk:
- Text inside a capture can reach the agent's prompt.
- So a hostile SIP header can try to talk the agent into calling a tool.
The defenses therefore limit what any caller can do. They do not trust the agent's judgment. MCP deployment covers running it safely.
| Threat | Mitigation | Where |
|---|---|---|
| The HTTP transport listens on a public address with no credentials. | A non-loopback bind without a token or signing key refuses to start. | src/mcp/transport.rs::serve_http |
| A web page uses DNS rebinding to reach a loopback MCP server through a browser. | Requests must carry a Host header on the allowlist (localhost, 127.0.0.1, ::1 and the bound address, plus --mcp-allowed-host entries), checked before the bearer guard by the same rule the REST API uses. |
src/host_allowlist.rs::HostAllowlist, src/mcp/transport.rs::host_layer
|
| An agent replaces the capture, installs TLS probes, stops the server or writes findings. | Each of these tools refuses unless the operator started sipnab with its own opt-in flag: --mcp-allow-open-capture, --mcp-allow-tls-capture, --mcp-allow-shutdown and --mcp-allow-save-findings. |
src/mcp/server.rs::open_capture and the allow_* fields beside it |
| An agent writes or reads outside a chosen directory. | File tools accept a bare file name only, resolve symlinks, and refuse any result outside --mcp-file-root. With no root set, the file tools refuse. |
src/mcp/server.rs::resolve_in_root |
| One agent monopolizes the server. | A per-caller cap on tool calls per second (--mcp-rate-limit-per-peer, default 100) and a 2 MiB request body cap. |
src/mcp/server.rs::with_rate_limit_per_peer, src/mcp/transport.rs::serve_http
|
--on-dialog-exec, --on-quality-exec and --alert-exec run an operator's
command when an event fires.
- The event data comes from captured SIP.
- So a caller can choose the From header that reaches the command.
| Threat | Mitigation | Where |
|---|---|---|
| A crafted SIP header injects shell syntax into the command. | sipnab passes event data in SIPNAB_* environment variables and never splices it into the command string. The legacy %from style placeholders become quoted "${SIPNAB_FROM}" references, not text substitution, so the shell neither splits the value into words nor expands * in it. |
src/output/event_exec.rs::spawn_command, src/security/exec_placeholders.rs::quote_placeholders, src/security/alerting.rs
|
| A burst of events forks thousands of processes. | A per-second rate limit and a cap on live child processes (default 100, [limits] exec_queue_depth). sipnab drops and counts events past either cap. |
src/output/event_exec.rs::DEFAULT_QUEUE_DEPTH, src/output/event_exec.rs::check_rate_limit
|
A plugin is a WebAssembly module. It receives one dialog as JSON and returns findings.
- The
pluginsfeature adds it. - The default build leaves it out.
- WASM plugins is the author's guide.
| Threat | Mitigation | Where |
|---|---|---|
| A plugin reads files, opens sockets or runs commands. | The host registers no imports at all, so a module that imports anything fails to load. The interpreter, wasmi, runs no JIT. |
src/plugin/mod.rs::instantiate |
| A plugin loops forever or allocates the host's memory. | A fuel budget per dialog, a 16 MiB memory cap installed before the module's declared memory exists, a 4 MiB output cap and a 16 MiB file-size cap. A failing plugin fails that dialog only. |
src/plugin/mod.rs::FUEL_PER_DIALOG, src/plugin/mod.rs::MAX_MEMORY_PAGES, src/plugin/mod.rs::MAX_OUTPUT_BYTES, src/plugin/mod.rs::MAX_PLUGIN_BYTES
|
sipnab decrypts traffic that other systems encrypted. So it holds keys that decrypt far more than one capture. Capture SIP over TLS covers the options.
| Threat | Mitigation | Where |
|---|---|---|
| A crash writes keys into a core file. | With any key option present, sipnab turns off core dumps for itself (PR_SET_DUMPABLE) and exits if that fails, unless --allow-coredump says otherwise. |
src/privilege.rs::disable_core_dumps, src/app/bootstrap.rs
|
| The kernel writes keys to swap. | sipnab locks its memory with mlockall. If the host's RLIMIT_MEMLOCK forbids that, it logs a warning and continues. |
src/privilege.rs::lock_key_memory |
| Keys linger in freed memory. | Key-log entries, key-log read buffers and derived SRTP session keys wipe themselves on drop. |
src/capture/tls.rs::zeroize_material, src/capture/keylog_source.rs, src/rtp/srtp.rs::DerivedSessionKeys
|
| A private key reaches a log line. | The RSA key type prints as RsaKey(<redacted>), and a parse error never echoes key bytes. |
src/capture/rsa_key.rs |
| A libpcap defect reads another run's key log. | The opt-in Landlock sandbox (--sandbox best-effort or required) limits which paths the process can open after startup. |
src/sandbox.rs::install |
sipnab reads a TOML file. It uses the first it finds of these:
-
--config, -
$SIPNAB_CONFIG, -
$XDG_CONFIG_HOME/sipnab/sipnab.toml(by default~/.config/sipnab/sipnab.toml), -
~/.sipnabrc, -
/etc/sipnab/sipnab.toml.
The file can name commands to run (alert_exec). So write access to it amounts
to running code as sipnab.
| Threat | Mitigation | Where |
|---|---|---|
| A typo in a key silently disables a setting, such as a rate limit. | sipnab warns about every unknown key, and validation refuses unsafe values such as a zero exec queue or a zero kill rate. |
src/config.rs::unknown_keys, src/config.rs (validate) |
| An environment variable in the config expands into more than the config named. | Only the ${NAME} form expands, never recursively, and an unset variable is an error rather than an empty string. |
src/config.rs::expand_env_vars |
A secret on the command line shows up in ps output. |
The listener secrets have file or environment-variable forms, such as --api-signing-key-file, --mcp-token-file, --hep-auth-file, --metrics-auth-file and SIPNAB_API_KEY. |
src/cli.rs |
-
Privilege drop and chroot. These apply during startup
(
src/privilege.rs::do_chroot).-
--usersets the account sipnab drops to. -
--chrootnarrows the filesystem it can see. - Architecture explains the privilege-drop design.
-
-
Landlock path sandbox, opt-in with
--sandbox(src/sandbox.rs). -
Seccomp system-call filter, opt-in with
--seccomp(src/seccomp.rs, syscall sandbox design).- The
logmode records calls and blocks nothing. - The
enforcemode needs an allowlist the operator supplies.
- The
-
Dependency checks.
-
cargo denyandcargo auditrun in CI againstdeny.toml. - Dependabot watches for updates
(
.github/dependabot.yml).
-
Each item below is a threat the code does not fully answer today.
-
Most are choices with a stated reason.
-
Some are open work.
-
An operator who needs protection against one of these has to supply it outside sipnab.
-
TLS is opt-in on every network listener.
- The REST API, HTTP MCP and the metrics endpoint serve HTTPS only when
given a certificate and key. These come from
--api-tls-cert,--mcp-tls-cert,--metrics-tls-certand their key flags, or thetls_cert/tls_keykeys insipnab.toml(src/cli.rs::tls_settings_problem). - Without them, each server logs a warning on a non-loopback bind but still starts.
- Without TLS or a reverse proxy, these cross the network in clear text:
- bearer tokens,
- the metrics endpoint's Basic credential (encoding, not encryption),
- capture data.
- The REST API, HTTP MCP and the metrics endpoint serve HTTPS only when
given a certificate and key. These come from
-
Loopback means no authentication.
- With no key configured, the REST API and HTTP MCP accept every request on
a loopback bind
(
src/output/api.rs::authenticate). - On a shared host, every local user can read the capture through them.
- With no key configured, the REST API and HTTP MCP accept every request on
a loopback bind
(
-
Authenticated clients see real data.
-
--redactreplaces identities with pseudonyms in exported vCon containers only. - The REST API and MCP answer with the real addresses and identities.
Neither calls the redactor
(
src/output/redact.rs).
-
-
Failed MCP logins face no throttle.
- The MCP rate limit counts tool calls after authentication.
- The HTTP bearer check has no limiter of its own
(
src/mcp/transport.rs::auth_layer). - Signed tokens resist guessing through their 256-bit signature. A short
static
--mcp-tokendoes not.
-
Plain HEP authentication is weak.
- In the default
plainmode, each packet carries the shared secret in clear text.- So anyone on the path can read and reuse it.
- Nothing stops replays.
- The HMAC mode fixes both, but only another sipnab sends it.
- A source allowlist alone trusts UDP source addresses. An attacker can forge those.
- In the default
-
Exec hooks inherit the environment.
- The child processes start with sipnab's full environment. That includes
any
SIPNAB_API_KEYor similar secret set there (src/output/event_exec.rs::spawn_command). - Passing data through variables also only helps while the hook script
quotes them. A script that runs
eval $SIPNAB_FROMreintroduces the injection.
- The child processes start with sipnab's full environment. That includes
any
-
No permission check on most secret files or the config file.
- sipnab checks permissions on archive password files and the HEP TLS key only.
- It reads these without checking who else can read or write them:
- signing-key files
(
src/app/servers.rs::read_signing_key_file), -
--tls-key, - the config file.
- signing-key files
(
- Whoever can write the config file can set
alert_exec.
-
The sandbox and system-call filter are off by default.
- Landlock and seccomp both default to
off(src/sandbox.rs::SandboxMode,src/seccomp.rs::SeccompMode). - No enforcing seccomp allowlist ships in the binary.
- Landlock and seccomp both default to
-
Capabilities survive a non-root start.
- After
--setup-caps, a non-root sipnab holdsCAP_NET_RAWandCAP_NET_ADMINfrom the file itself. - The privilege drop does nothing for a process that did not start as root
(
src/privilege.rs::drop_privileges). - Only the scanner-kill worker clears its capability set.
- On macOS the drop also needs an explicit
--user.
- After
-
libpcap is C, and it runs briefly as root.
- It parses every live packet before sipnab's Rust code does. It does this inside the process that holds keys and tokens.
- The capture thread starts reading as soon as it reports the device open.
It does not wait for the privilege drop on the main thread
(
src/capture/live.rs::capture_live,src/app/bootstrap.rs). - So the first packets of a root-started run can reach libpcap before the drop.
- The privilege drop and the opt-in sandbox limit the damage after that. Nothing removes the risk.
-
File-tool path check and file open are separate steps.
- The MCP file tools resolve the path and check it against the root. Then they open it later.
- A local user who can change links inside
--mcp-file-rootbetween those two steps could redirect a write. - Keep the root writable by sipnab alone.
-
Plugins are not signed.
- sipnab loads any module the operator names.
- A plugin can emit misleading findings, even though it cannot touch the host.
-
The metrics endpoint does not check
Host.- The REST API and HTTP MCP refuse a
Hostthat is not on their allowlist. That stops DNS rebinding. - The standalone
--metricsserver does not (src/output/prometheus_server.rs::start_metrics_server). So a web page can read the counters of a loopback metrics endpoint with no credentials, through a browser. - It serves read-only counters and no capture content.
- A non-loopback bind already needs Basic auth.
-
--api-allowed-host '*'and--mcp-allowed-host '*'put the REST API and MCP back in the same position.
- The REST API and HTTP MCP refuse a
tests/openssf_badge_test.rs checks three things:
- this page names every trust boundary above,
- every path it cites exists,
- every
file::namecitation names something defined in that file.
A renamed function turns that test red. So the page cannot quietly point at code that moved.
Website · Repository · Issues · Generated from docs/ — edit there, not here.
Getting started
- Installation
- First CLI Triage
- Glossary
- Cookbook
- Runnable Examples
- Real World Captures
- Troubleshooting
- Tuning Capture
- Encapsulations
- Rtpengine Relays
- Backers
Using the TUI
CLI & automation
- CLI Reference
- Error Messages
- Filter DSL
- Output Formats
- SIP Response Codes
- SIP Methods
- SIP Header Fields
- SIP Parameters
- SIP Lint Rules
- MOS and Codecs
Configuration
Integrations (API & MCP)
- REST API
- Prometheus Metrics
- Authentication
- MCP
- MCP Deployment
- MCP Across an Estate
- MCP Tools
- MCP Tools Core
- MCP Tools Signaling
- MCP Tools Captures
- MCP Tools Security
- MCP Tools Media
- MCP Tools Relay
- MCP Tools TFPS
- MCP Tools Server
- MCP Tools vCon
- MCP Tools TLS
- MCP Protocol
- Uprobe Walkthrough
- Capture SIP over TLS
- WASM Plugins
- vCon Export
- vCon Capture Stack
- G729 Decoding
Your SIP server
- Use OpenSIPS as the SIP Server
- Run sipnab beside OpenSIPS
- Use Kamailio as the SIP Server
- Run sipnab beside Kamailio
- Use Asterisk as the PBX
- Run sipnab beside Asterisk
- Use FreeSWITCH in the Voice Stack
- Run sipnab beside FreeSWITCH
Add to your voice stack
- Add a vCon Server
- Send vCons to a vCon Server
- Send vCons to vcon store
- Add TFPS
- Control TFPS from sipnab
- Ban SIP Scanners with fail2ban
- Feed fail2ban from sipnab
- Add rtpengine
- Name rtpengine Media with sipnab
- Add rtpproxy
- Name rtpproxy Media with sipnab
- Add Homer
- Connect sipnab to Homer
- Add Prometheus and Grafana
- Add sipnab Metrics to Prometheus
Development & internals
- Internals Index
- Internals Subsystem Guide
- Internals Invariants
- Internals Testing
- Internals Walkthroughs
- Internals Build CI Release
- Internals Profiling
- Internals Domain Primer
- Library API
- Benchmarks
- Fault Model
- Threat Model
- Assurance Case
- Architecture
- Internals Threading
- Internals TUI Testing
- Internals Zero Copy Payloads
- Internals Uprobe Capture
- Internals Rtpengine Control Plane
- Internals Relay Control Decoding
- Internals vCon Exporter
- Internals Operator Guide Notes
- Internals Postmortems
- Internals Code Map
- Internals Lint Rules
- Internals Encapsulation Decoding
- Internals MCP Design Notes
- Internals Metrics And Output Notes