# ADR-0001 β€” SIP strategy: native Rust core behind a Kamailio + rtpengine edge - **Status:** ~~Accepted~~ **Superseded** (2026-06) - **Date:** 2026-06 - **Supersedes:** the `πŸ”Œ Edge/FFI (pjproject)` disposition in PORT_PLAN.md Β§1 (historical) - **Superseded by:** [ADR-0003](0003-sip-rust-native-trunk.md) β€” Rust-native trunk SIP, no SBC shield > **Superseded.** Kept as the historical record of the layered "own the Rust parser, front with > Kamailio + rtpengine" plan. Reversed under the AI-era contact-center scope (the device interop > tail collapses to a few documented trunk providers). See [ADR-0003](0003-sip-rust-native-trunk.md). ## Context SIP is rutster's highest-risk subsystem. Three forces pull against each other: 1. **The security thesis.** rutster's headline is "memory-safe by construction, fuzzed parsers, no buffer-overflow/RCE class." The SIP parser is the *first* thing hostile internet packets touch β€” the most exposed surface in the whole system. 2. **The interop tail.** The hard, *unbounded* part of SIP isn't RFC 3261 β€” it's 20 years of device/carrier/NAT quirks. Owning that tail forever is what killed `chan_sip` and drove Asterisk to retreat to pjproject. It is a permanent tax, not a one-time cost. 3. **Time-to-first-call.** We want interoperable SIP trunking early, without blocking on a young stack maturing. These don't resolve as a single build-vs-buy call, because they live at *different layers* of SIP: | Layer | CVE-class risk | Interop-tail cost | Verdict | |---|---|---|---| | Parser (bytes off the wire) | **Highest** | Low | **Own in Rust** β€” cheap, and the thesis depends on it | | Transaction / dialog / timers | Medium | Medium (bounded by RFCs) | Own over time; sans-IO Rust fits | | Interop tail (UA quirks, NAT, carrier glare) | Low | **Unbounded, forever** | **Rent** β€” this is what a mature edge is for | Pure FFI to pjproject was rejected: it pays the interop cost *and* puts C at the most exposed seam, gutting the memory-safety headline at the one place it matters most. It is the right default for a generic PBX and the wrong one for a security-first platform. ## Decision A **layered** strategy: 1. **Own the SIP parser in Rust, from day one.** Build on `rsip` (message types/parsing) and the `ezk-sip` family (sans-IO transaction/dialog core). No hostile bytes ever hit a C parser. This is non-negotiable β€” the security story requires it. 2. **Front the public SIP edge with Kamailio + rtpengine.** Kamailio handles signaling (proxy, registrar, TLS termination, topology hiding, rate-limiting, anti-scan); **rtpengine** handles the media leg (kernel-forwarded RTP relay, SRTP/DTLS-SRTP bridging, ICE, NAT). This is the most-proven, most-scaled FOSS SIP edge β€” carrier-grade on the open internet. It absorbs the interop tail and gives us a hardened edge in weeks. 3. **Grow the native Rust transaction/dialog core *behind* that shield.** It matures in production where its early bugs aren't customer-facing outages. As it hardens, Kamailio's role shrinks from "does all the SIP" β†’ "just the public edge" β†’ optionally nothing. **Chosen edge: Kamailio + rtpengine** (over OpenSIPS and drachtio). Rationale: largest proven deployment pedigree and max-scale proxy track record; rtpengine is the canonical media companion. OpenSIPS and drachtio remain valid alternatives (drachtio noted for a future *programmable* edge once rutster's API model is solid). ## Topology ``` hostile internet trusted core ───────────────► Kamailio ──signaling──► rutster control plane (SIP trunks, + rtpengine ──media─────► rutster media plane far-end UAs) (edge SBC) (native Rust SIP core grows here, behind the shield) ``` WebRTC ingress is unaffected and ships *first* (WebRTC signaling is app-defined, not SIP), so first-call does not block on any of this. ## Consequences - **Positive:** security headline holds (Rust parser at the edge of *our* trust boundary); interoperable SIP trunking available early; native stack de-risked by maturing behind a proven shield; no pjproject license/threading/`unsafe` entanglement. - **Negative / costs:** an operational dependency on Kamailio + rtpengine (config, deployment, expertise) for the foreseeable future; two media-handling points during the shield phase (rtpengine at the edge, rutster media plane inside) to reason about. - **Open follow-ups:** Kamailio↔rutster control-plane integration (KEMI vs. dispatcher vs. a custom control channel); how far inward rtpengine relays vs. rutster terminating media directly; the graduation criteria for retiring the shield.