-
Notifications
You must be signed in to change notification settings - Fork 2
Home
GABPBX is a GPLv2 open source PBX based on the Asterisk architecture and maintained as the Germán Aracil Boned PBX project.
This wiki documents GABPBX as a system: architecture, modules, configuration, operation and implementation notes taken from the source tree.
The current release is GABPBX 1.5.11. It completes chan_sofia as a broad,
production-grade, drop-in replacement for chan_sip, and delivers reliable
two-way WebRTC media — DTLS-SRTP, an ICE-lite STUN responder, rtcp-mux,
BUNDLE and RTCP keyframe feedback — so a browser can register, call, be called,
hold and resume over secure WebSocket with audio and video, no pjproject and
no libnice in the tree. 1.5.0 adds video bridging between a legacy SIP video
phone and a WebRTC leg (H.264 passthrough), RFC 3264 o= version stickiness,
and DTMF logging.
A modern SIP channel driver built on the Sofia-SIP NUA stack. Drop-in for
chan_sip (same SIP channel, sip show … CLI, SIPpeers AMI, sippeers
realtime), with capabilities chan_sip never had:
- Registration: SIP Outbound (RFC 5626), Path (RFC 3327), Service-Route (RFC 3608), GRUU.
- Presence/voicemail: outbound PUBLISH (RFC 3903), generic outbound SUBSCRIBE, an outbound MWI watcher, solicited and unsolicited MWI, presence/BLF dialog-info.
- Signaling: PRACK/100rel (RFC 3262), in-dialog UPDATE (RFC 3311), Q.850 Reason (RFC 3326), REFER transfer (blind and attended), out-of-dialog MESSAGE.
- Media: SRTP/SDES (RFC 4568), DTLS-SRTP (RFC 5763/5764), WebRTC audio and two-way video, Opus passthrough, T.38 fax with a state machine.
- Security: mutual TLS, TLS hardening, SHA-256 digest auth, a local anti-abuse SIP blacklist.
-
Diagnostics: per-call SIP history with verbose call analysis, plus a
richer
sip …CLI.
Start at Chan-Sofia, then Features for the full catalogue, WebRTC for the browser story, Migrating-from-chan_sip for the swap, and Security for the hardening posture.
-
Local-hold offer direction (experimental, default off). chan_sofia has always answered a local
hold with music-on-hold only, never telling the held peer over SIP. With
[general] hold_reinvite = sendonly(orinactive), a local hold now also re-INVITEs the peer toa=sendonly(peer stops sending and hears our MOH, RFC 6337) ora=inactive, restoringa=sendrecvon UNHOLD; a rejected/unanswered hold re-INVITE rolls back. A typed re-INVITE purpose keeps directmedia, T.38 and local-hold response handling isolated from each other. Defaultno= prior MOH-only behavior. Shipped experimental and off by default — the enabled path is not yet confirmed end to end; validate before enabling.
-
Forked-call early media (experimental, default off). When a call to a peer forks to multiple
registered contacts, chan_sofia keeps the caller muted until one branch answers. With the new
[general] fork_early_media = yes, once the fork narrows to a single live non-WebRTC branch that sends a 180/183 with SDP, the caller hears that branch's early media (receive-only). Conservative by design: never binds while two or more branches are live, never sends media upstream before answer, no-op for WebRTC, and hands media to the winner (or restores silence) on answer/failure. Shipped experimental and off by default — the enabled path is not yet validated end to end; validate before enabling.
Q.850 signaling reaches full chan_sip parity on rejected calls.
-
Q.850 Reason on INVITE rejects. With
use_q850_reason = yes, chan_sofia now stamps an RFC 3326Reason: Q.850;cause=N;text="..."header on INVITE-rejection responses (404, 480, 484, 486, 488, 503, and the in-dialog re-INVITE / UPDATE / T.38 488 rejects), not only on the BYE/CANCEL requests it already handled, so upstream proxies and billing see the real Q.850 cause behind a rejected call. The cause is taken from the channel hangup cause, or mapped from the SIP status via a port of chan_sip'shangup_sip2causefor pre-channel rejects. Gated byuse_q850_reason(default no).
A correctness follow-up to the audit — SDP body sizing, early-media signaling parity with chan_sip,
MWI summary completeness and RTCP report handling.
-
SDP buffer headroom. A WebRTC video answer using BUNDLE with several H.264/VP8 payload types, their
per-payload
a=rtcp-fblines and ICE candidates could exceed the fixed 2048-byte SDP body buffers, making the SDP builder fail closed and emit no SDP. The six response/offer SDP buffers now hold 4096 bytes, and the internal video attribute accumulators hold 2048 bytes (those can fill before the outer buffer on a rich video m-line), so a valid video answer is no longer silently dropped. -
progressinband=novsnever. Withprogressinband=no, a RINGING indication now degrades to in-band ringback once a 183 Session Progress has already been sent (early media exists), matchingchan_sip; previouslynocollapsed ontonever. -
MWI multi-class summaries. The
application/simple-message-summaryparser (RFC 3842) now aggregates the new/old message counts across all message classes (Voice, Fax, Pager, Multimedia, Text), each saturated, with theMessages-Waitingline as the fallback when no per-class counts are present. - RTCP multi-block reports. An RTCP SR/RR carrying more than one reception report block (RFC 3550) now selects the block that concerns our own SSRC for RTT/jitter/loss statistics, instead of always using the first block.
A further audit-hardening batch — correctness, security, concurrency and robustness across chan_sofia,
sofia_sdp, sdp_crypto, res_rtp and the RTP engine.
- RTP codec-map concurrency. The per-instance codec payload map has no lock of its own, so installing a freshly negotiated map on the SIP/SDP thread raced the media threads reading it; every live-map install and every media-thread reader now serialize under the RTP instance lock, and the peer-to-peer bridge takes its two instance locks separately so opposite bridge directions cannot deadlock. The outbound SRTP protect+send is likewise serialized against DTLS-SRTP (re)install and RTCP transmit on the same session.
-
SRTP key hygiene.
sdp_cryptonever logs the local SRTP master key, zeroizes key material before free (RFC 4568 §9.1), rejects an over-long inline key instead of truncating it, and echoes the accepted crypto tag on a re-keying re-INVITE (RFC 4568 §5.1.2). -
BUNDLE answer correctness. A WebRTC answer lists the
a=group:BUNDLEmids in the offered m-line order (RFC 8843 §7.3.1) instead of a fixed audio-first order, and the mid/group buffers are sized end to end for standards-legal long mids (no dropped group line, no truncated mid). -
T.38 and video re-offers. An image-only T.38 re-INVITE is answered with
m=imageonly (no phantomm=audio, RFC 3264 §6); a later re-INVITE on a leg that offered WebRTC video keeps offeringm=video(the emit is gated on the live video capability); and a forked call applies its winning branch's negotiated audio codec to the answered channel instead of relying on transcoding. -
Robustness. A malformed trailing RTCP sub-packet no longer discards a keyframe request latched earlier in the
same compound packet; the native bridge takes the second channel's video/text remote-address baselines from the
video/text instances; a very large
blacklist_banno longer overflows into a permanent ban; a refusedsip reloadno longer mutates the live blacklist window; REGISTER rejects bind their final response to the request; and the per-peer lock is destroyed on teardown.
An audit-hardening batch across chan_sofia, sdp_crypto, sofia_t38 and res_rtp — security, protocol
correctness and concurrency.
-
SRTP key confidentiality.
sdp_cryptono longer echoes the caller-controlleda=cryptoattribute — which carries the inline master key+salt (RFC 4568 §6.1) — at log level; the "lifetime unsupported" and malformed-line paths now log only non-secret fields (RFC 4568 §9.1). -
Per-suite key advertised == installed. In per-suite-fresh-key mode the emitted
a=cryptonow advertises the same key the local SRTP policy actually installed (a single selector feeds both), so the remote no longer decrypts with the wrong key; and the "unchanged crypto" short-circuit compares suite + selected index + key (not the key bytes alone), so a suite switch (…_80↔…_32) with a reused key correctly re-keys. -
RTCP concurrency. The scheduled RTCP SR/RR and the video-update PLI now serialize on the SRTCP session
(they protected+sent on the same libsrtp session concurrently); T.38 parameter interpretation and the
late-offer ACK SDP parse now run under the proper lock; and outbound-call paths no longer read freeable peer
string fields (
host/name) during asip reload. -
Inbound UAS hangup. An unanswered inbound INVITE is now rejected with a final response mapped from the hangup
cause (
chan_sipparity — 403/486/503/… instead ofCANCEL), with a guard so a call already rejected byBusy()/Congestion()never emits a double final response. -
Response binding. In-dialog UPDATE and NOTIFY responses are bound to their server transaction
(
NUTAG_WITH_THIS), so the 500/200 actually reaches the wire instead of being dropped and retransmitted to timeout. - Fork BLF. A forked call's winner now decrements the peer ringing counter on answer, so device state moves RINGING → INUSE instead of staying RINGING for the whole call.
-
fromuseroverrides the outboundFromuser (chan_sip parity). A peer'sfromuserwas only a fallback for the outboundFromURI user — used solely when no caller-ID resolved. chan_sip treats it as an override that wins over the resolved caller-ID (chan_sip.c:12900-12901), so a peer with nocalleridwhose channel carried the inbound SIP username emitted that username in the outboundFrominstead of the configuredfromuser(which some carriers reject).fromuser, when set, now overrides theFromURI user in both allowed and restricted presentation. Only theFromURI user changes — the display name, presentation,Contact, and any RPID/PAI headers are untouched (chan_sip's RPID builder never consumesfromuser). Restricted presentation now matches chan_sip exactly ("Anonymous" <sip:<fromuser>@anonymous.invalid>), andusereqphonetests the finalFromuser so a non-numericfromuserno longer inherits;user=phone. Completes the empty-callerid outbound parity from 1.5.3/1.5.4.
-
Outbound
Fromnever leaks the peer section name;[general] calleriddefault. The outboundFromidentity resolver used the peer/section name as a fallback when no caller-ID could be resolved (no channel/connected-line identity, no peercid_num, nofromuser) — so an anonymous inbound call from a peer with no callerid could leak the peer's account/auth name into theFrom. chan_sip never does this. Thepeer->namefallback is removed, and a new[general] calleridsets the last-resort fallback From identity (chan_sipdefault_calleridparity, defaultgabpbx; shown insip show settingsas "Default callerid"). It is only used when nothing else resolves an identity and does not override a real caller-ID. Completes the empty-callerid parity from 1.5.3 (an inboundFromstill passes through unchanged when the peer callerid is unset). Also silences a pre-existing build warning — chan_sofia now compiles with zero warnings.
-
Peer callerid on the outbound From (chan_sip parity) +
apply_peer_callerid. A peer that authenticates with one SIP username but is configured withcallerid=<number>was leaking its SIP username into the outboundFrominstead of presenting the configured number (which upstream proxies/SBCs may reject). Two-part fix: (1) a peer'scallerid=is now split into thecid_num/cid_namefields the driver actually uses — previously a duplicate config handler shadowed the split in both the static and realtime loaders, so the configured callerid never took effect; (2) new[general] apply_peer_callerid(defaultyes, chan_sip parity) forces the matched peer'scid_num/cid_name/callingpresonto an inbound call when no trusted RPID/PAI was accepted, so the configured callerid appears in the outboundFrom. A trusted RPID/PAI still wins;shrinkcalleridis honored;apply_peer_callerid=nokeeps the inboundFromuser (pass-through). The source of truth is the peercalleridfield; a dialplanSet(CALLERID(num/name))remains an optional later override. Applies onsip reload.
-
auth_qop— chan_sip legacy no-qop MD5 digest challenge. Some legacy handsets only authenticate against chan_sip's exact 401 challenge (the RFC 2069 formDigest algorithm=MD5, realm="…", nonce="…"with noqop); against chan_sofia's RFC 2617/7616qop="auth"form they failed the second REGISTER with403. New[general] auth_qop(defaultno) emits the chan_sip legacy no-qop MD5 challenge — withauth_algorithms=md5it is byte-for-byte chan_sip's — whileauth_qop=yesrestoresqop="auth"withnc/cnoncereplay protection. MD5 only (SHA-256 always keepsqop); applies onsip reload.⚠️ The defaultno(RFC 2069) has no digest replay protection, matching chan_sip — pair it with TLS/WSS, or setauth_qop=yeswhere handsets allow.
-
sip reloadno longer falsely refused ontls_min_version. On a config with no explicittls_min_version=line, the reload check compared the running effective default (TLS 1.2) against an empty scratch default and reported a phantom listener change, refusing everysip reloadwithlistener config changed (tls_min_version)until a full restart. The scratch now seeds the same effective default (shared with the load path so the two cannot drift), while a genuine change such astls_min_version=1.3is still correctly detected as requiring a restart.
-
Video between a legacy SIP video phone and a WebRTC leg. A SIP phone that
offers H.264 (RTP/AVP) can now exchange two-way video with a browser leg, with
no transcoding. The answer sent to the caller is narrowed to the video codec
the far/bridge leg actually negotiated (RFC 3264 §6): codecs the far leg cannot
produce are dropped instead of merely reordered, so the caller does not lock its
video onto a payload type the peer will never send. H.264
a=fmtp(profile-level-id/packetization-mode, RFC 6184 §8.2.2) is relayed and, when the two sides cannot agree, video fails closed to audio rather than sending a stream the peer drops. The intersection is SDP-only — no channel format state is mutated mid-call — and a keyframe request crosses the bridge in both directions (SIP INFOpicture_fast_update⇄ RTCP PLI/FIR, RFC 5168/4585/5104). The INFO answer is now bound to its own transaction (NUTAG_WITH_THIS), removing a ~32-second Timer-F cut. See WebRTC. -
SDP o= version stickiness (RFC 3264 §8). A re-offer that repeats the same
session origin with an unchanged (
<=) version is treated as a no-op, so a learned symmetric-RTP remote address survives anUPDATE/re-INVITE — matchingchan_sipprocess_sdp_oand preserving audio across NAT keepalive re-offers. Theignoresdpversionoption is honoured (defaultno). -
DTMF logging.
sip set debug dtmf on|offlogs every received DTMF digit (RFC 2833/telephone-event, SIP INFO, or inband) to the CLI and the messages log, the waychan_sipdid — useful when diagnosing IVR and feature-code entry. Default off. See Chan-Sofia.
-
WebRTC call hold/resume works end to end. Pressing Hold on a WebRTC phone
no longer tears the call down, and video resumes by itself on unhold, exactly
like audio — in every combination of WebRTC and desk-phone endpoints, on
either side of the call. Five fixes: the SDP answer now mirrors the offered
per-media direction (RFC 3264 §6.1); answers mirror every offered m-line
using the current offer/answer transaction role (RFC 3264 §6); the fork-winner
handover preserves the SDP stream identity (
cname/msid, RFC 7022/8830); negotiated video payload types survive renegotiation (RFC 3264 §8.3.2); and RTCP keyframe feedback (PSFB PLI/FIR, RFC 4585/5104) is implemented end to end — advertised asa=rtcp-fb, relayed across the bridge, and transmitted SRTCP-protected over the ICE-selected tuple. See WebRTC.
- WebRTC fork-winner media fix. When a call forks to an extension registered from both a browser (wss) and a desk phone (udp) and the browser answers first, the call now carries two-way audio and video (previously the winning leg's DTLS never completed because stale media descriptors starved its socket). See WebRTC.
-
Native peer-to-peer SIP text messaging. An out-of-dialog
MESSAGEbetween two registered users is delivered to the recipient's live devices, resolved through the same auto-created hint namespace as BLF and fanned out to every registered contact (RFC 3428). New optionmessage_autorelay(default on); themessage_contextdialplan route remains available as a fallback. See Features.
- Reliable WebRTC audio. The ICE media tuple is now latched on every integrity-authenticated connectivity check, not only the nominated pair, removing intermittent one-way audio and the 10–20 s startup gap and making inbound calls to a browser come up cleanly (RFC 8445 / RFC 7675). See WebRTC.
-
Bundled WebRTC video. A new option
webrtc_video_bundle(per-peer and[general], default off, requireswebrtc=yes) carries audio and video over a single ICE/DTLS transport with payload-type demux and the RTP MID header extension (RFC 8843 max-bundle, RFC 8285). See WebRTC. -
Per-Contact registration. Each Contact in a REGISTER now binds, refreshes
and de-registers independently with its own
;expires(RFC 3261 §10.3), and a call to a peer whose bindings have all expired returnsCHANUNAVAILinstead of routing to a stale binding. See Chan-Sofia. -
DTMF parity with
chan_sip. The negotiated DTMF mode is reflected end to end: telephone-event is advertised only for RFC 2833 modes,dtmfmode=autoresolves at SDP commit with a fax-safe detector reconfigure, and inbound SIP INFO signals are parsed. See Features. -
TLS 1.2 accepted by default.
tls_min_versionnow defaults to TLS 1.2 (1.2 and 1.3) instead of 1.3-only, so endpoints that cap at TLS 1.2 connect. See Security. -
Live decrypted SIP capture.
sip_capture_addressstreams every decrypted SIP message (udp/tcp/tls/ws/wss, with SDP) as HEP to a Homer/sipcapture server,sip_capture_filewrites the same to a text file, andrtp set debug ice/sip set debug forkadd targeted tracers. See Operations.
-
Inbound WebRTC calls now connect. A call placed to a wss-registered
browser (GABPBX as the SDP offerer) comes up with two-way audio, alongside the
already-working browser-originated calls. Two RFC-grounded fixes make it work:
an ICE role-conflict repair (GABPBX replies
487 Role Conflictso the browser flips to controlling and nominates a pair, RFC 8445), and deferring inbound DTLS until the answer'sa=fingerprintis installed instead of failing closed (RFC 5763/8842). Rejected video tears down only its own pre-armed DTLS/ICE and never drops the audio call. See WebRTC. -
SDP/ICE diagnostics.
sip set debug sdp [on|off]traces the generated offer SDP, the WebRTC offer-gate decision, the incoming answer SDP and the offerer answer-apply path — the WSS/TLS signalling already decrypted. EverySofia: …debug line now carries a[from-user|to-user|callid]transaction tag. See Operations.
- WebRTC media is no longer roadmap. Two WSS browsers can hold a real two-way audio call, with two-way video (VP8/H.264) on top. See WebRTC.
- Opus relays without transcoding. Three core fixes (codec selection, the 48 kHz clock rate, and the RTP smoother) let a both-Opus call pass through cleanly. See Features → Opus.
- The full
chan_sofiaSIP and media catalogue is documented one feature at a time in Features.
-
Chan-Sofia - the Sofia-SIP based SIP channel driver and
chan_sipreplacement. -
Features - the complete
chan_sofiacapability catalogue, one by one. - WebRTC - browser SIP over WSS, DTLS-SRTP, ICE-lite, audio and video.
- Migrating-from-chan_sip - the two-line swap and what carries over.
- Security - the security and robustness posture.
- Architecture
- Build-and-Installation
- Module-Families
- Channel-Drivers
- Applications
- Dialplan-Functions
- Codecs-and-Formats
- Realtime-and-Resources
- CDR-CEL
- PBX-and-Bridges
- Operations
Documentation in this wiki follows the source code first. When a behavior is uncertain, the source file and sample configuration are authoritative.
SIP — chan_sofia
Subsystems
Realtime & data
Operations