OpenSIPS version you are running
version: opensips 3.6.5 (x86_64/linux)
flags: STATS: On, DISABLE_NAGLE, USE_MCAST, SHM_MMAP, PKG_MALLOC, Q_MALLOC, F_MALLOC, HP_MALLOC, F_PARALLEL_MALLOC, DBG_MALLOC, FAST_LOCK-ADAPTIVE_WAIT
ADAPTIVE_WAIT_LOOPS=1024, MAX_RECV_BUFFER_SIZE 262144, MAX_LISTEN 16, MAX_URI_SIZE 1024, BUF_SIZE 65535
poll method support: poll, epoll, sigio_rt, select.
git revision: 42f57f043
main.c compiled on 05:28:42 May 16 2026 with cc 14
Crash Core Dump
Program terminated with signal SIGSEGV, Segmentation fault.
#0 parse_from_header (msg=msg@entry=0x0) at parser/parse_from.c:50
50 if ( !msg->from && ( parse_headers(msg,HDR_FROM_F,0)==-1 || !msg->from)) {
(gdb) bt full
#0 parse_from_header (msg=msg@entry=0x0) at parser/parse_from.c:50
from_b = <optimized out>
__FUNCTION__ = "parse_from_header"
error = <optimized out>
#1 0x00007f7bd9ddee68 in get_from_tag (_m=0x0, _tag=_tag@entry=0x7ffd7ef01638) at nhelpr_funcs.c:229
__FUNCTION__ = "get_from_tag"
#2 0x00007f7bd9dece29 in rtpproxy_fill_call_args (sess=0x7ffd7ef017d0, args=args@entry=0x7ffd7ef01600, ip=ip@entry=0x0, type=type@entry=0x0,
in_iface=in_iface@entry=0x0, out_iface=out_iface@entry=0x0, global_flags=global_flags@entry=0x0, flags=0x0, extra_flags=0x0) at rtpproxy.c:5079
p = <optimized out>
b = <optimized out>
__FUNCTION__ = "rtpproxy_fill_call_args"
#3 0x00007f7bd9e0be28 in rtpproxy_api_delete (sess=<optimized out>, server=0x7f7bda453660, flags=<optimized out>, extra=<optimized out>) at rtpproxy.c:5300
ret = -1
rset = 0x0
args = {arg1 = 0x0, arg2 = 0x0, offer = 0, body = {s = 0x0, len = 0}, callid = {s = 0x0, len = 0}, from_tag = {s = 0x0, len = 0}, to_tag = {s = 0x0, len = 0},
set = 0x0, node = 0x0, raddr = {s = 0x0, len = 0}}
__FUNCTION__ = "rtpproxy_api_delete"
#4 0x00007f7bd9da81b9 in rtp_relay_delete (info=0x7ffd7ef017d0, ctx=<optimized out>, sess=0x7f7bda453650, leg=<optimized out>) at rtp_relay_ctx.c:1326
ret = <optimized out>
__FUNCTION__ = "rtp_relay_delete"
#5 0x00007f7bd9db58df in rtp_relay_delete_ctx (ctx=0x7f7bda4531d0, sess=0x7f7bda453650, leg=0) at rtp_relay_ctx.c:1475
info = {msg = 0x0, branch = -1, callid = 0x7f7bda4531f8, from_tag = 0x0, to_tag = 0x7f7bda453218, body = 0x0}
#6 rtp_relay_dlg_end (dlg=<optimized out>, type=<optimized out>, params=<optimized out>) at rtp_relay_ctx.c:1515
ltype = 0
ctx = 0x7f7bda4531d0
#7 0x00007f7bd9e7e63f in run_dlg_callbacks (type=type@entry=32, dlg=dlg@entry=0x7f7bda4510b0, msg=msg@entry=0x7f7bdc0a0a60, dir=<optimized out>,
dst_leg=<optimized out>, dlg_data=dlg_data@entry=0x0, locked=locked@entry=0, is_active=is_active@entry=1) at dlg_cb.c:256
cb = 0x7f7bda457f60
__FUNCTION__ = "run_dlg_callbacks"
#8 0x00007f7bd9eb256f in dlg_onroute (req=<optimized out>, route_params=<optimized out>, param=<optimized out>) at dlg_handlers.c:2158
dlg = <optimized out>
val = {
s = 0x55ebe8597fa5 <buf+261> "57e.1e128ca>\r\nCSeq: 2 BYE\r\nContact: sip:sipp@127.0.0.1:5090\r\nMax-Forwards: 69\r\nSubject: Performance Test\r\nContent-Length: 0\r\n\r\n", len = 11}
callid = {
s = 0x55ebe8597f6e <buf+206> "1-82290@127.0.0.1\r\nRoute: <sip:127.0.0.1;lr;ftag=1;did=57e.1e128ca>\r\nCSeq: 2 BYE\r\nContact: sip:sipp@127.0.0.1:5090\r\nMax-Forwards: 69\r\nSubject: Performance Test\r\nContent-Length: 0\r\n\r\n", len = 17}
ftag = {
s = 0x55ebe8597f36 <buf+150> "1\r\nTo: sut <sip:service@127.0.0.1:5060>;tag=1\r\nCall-ID: 1-82290@127.0.0.1\r\nRoute: <sip:127.0.0.1;lr;ftag=1;did=57e.1e128ca>\r\nCSeq: 2 BYE\r\nContact: sip:sipp@127.0.0.1:5090\r\nMax-Forwards: 69\r\nSubject: P"..., len = 1}
ttag = {
s = 0x55ebe8597f62 <buf+194> "1\r\nCall-ID: 1-82290@127.0.0.1\r\nRoute: <sip:127.0.0.1;lr;ftag=1;did=57e.1e128ca>\r\nCSeq: 2 BYE\r\nContact: sip:sipp@127.0.0.1:5090\r\nMax-Forwards: 69\r\nSubject: Performance Test\r\nContent-Length: 0\r\n\r\n", len = 1}
h_entry = <optimized out>
h_id = <optimized out>
new_state = 5
old_state = 4
unref = 2
event = <optimized out>
Describe the traffic that generated the bug
SIPREC call
To Reproduce
- Configure OpenSIPS with SIPREC
- Establish a call with rtp_relay_engage("rtpproxy")
- Add siprec_start_recording in the main route
- A basic SIPREC session established.
- Send a BYE from caller to tear down the dialog.
- OpenSIPS crashes in rtp_relay_delete with ftag=[]
Relevant System Logs
DBG:rtp_relay:rtp_relay_delete: callid=[1-82290@127.0.0.1] ftag=[] ttag=[1] ctx-flags=[] delete-flags=[]
CRITICAL:core:sig_usr: segfault in process pid: 82133, id: 6
DBG:core:restore_segv_handler: restoring SIGSEGV handler...
DBG:core:restore_segv_handler: successfully restored system SIGSEGV handler
OS/environment information
- Operating System:
- OpenSIPS installation:
- other relevant information:
Root Cause Analysis
Looking at rtp_relay_delete_ctx, the fix is straightforward — assign info.from_tag from ctx->from_tag, mirroring how callid and to_tag are handled. The comment in your code already hints at this.
static void rtp_relay_delete_ctx(struct rtp_relay_ctx *ctx, struct rtp_relay_sess *sess, int leg)
{
struct rtp_relay_session info;
memset(&info, 0, sizeof info);
info.callid = &ctx->callid;
if (!info.callid->len)
info.callid = &ctx->dlg_callid;
if (ctx->from_tag.len)
info.from_tag = &ctx->from_tag;
info.to_tag = &ctx->to_tag;
info.branch = RTP_RELAY_ALL_BRANCHES;
rtp_relay_delete(&info, ctx, sess, leg);
}
This avoids the need to pass msg through the call chain. Since rtp_relay_delete_ctx is called on BYE (dialog teardown), ctx->from_tag should already be populated from the initial INVITE flow via rtp_relay_fill_dlg. The from_tag check in rtpproxy_fill_call_args (if (!sess->from_tag)) will then skip the get_from_tag(sess->msg, ...) call that would fail due to info.msg being NULL.
Why info.msg is NULL in rtp_relay_delete_ctx
In rtp_relay_delete_ctx, the info struct is zeroed out with memset(&info, 0, sizeof info), and info.msg is never assigned afterwards. Unlike other call paths (e.g., rtp_relay_indlg_tm_req which sets info.msg = p->req), this function only populates callid, to_tag, and branch — leaving info.msg = NULL.
When rtp_relay_delete is called with this info, it eventually reaches rtpproxy_fill_call_args in the rtpproxy module. There, the check:
if (!sess->from_tag) {
if (get_from_tag(sess->msg, &args->from_tag) == -1 || args->from_tag.len == 0) {
LM_ERR("can't get From tag\n");
return 0;
}
}
tries to extract the from_tag from sess->msg, which is NULL (since info.msg was never set), causing a crash or silent failure.
OpenSIPS version you are running
Crash Core Dump
Describe the traffic that generated the bug
SIPREC call
To Reproduce
Relevant System Logs
OS/environment information
Root Cause Analysis
Looking at rtp_relay_delete_ctx, the fix is straightforward — assign info.from_tag from ctx->from_tag, mirroring how callid and to_tag are handled. The comment in your code already hints at this.
This avoids the need to pass msg through the call chain. Since rtp_relay_delete_ctx is called on BYE (dialog teardown), ctx->from_tag should already be populated from the initial INVITE flow via rtp_relay_fill_dlg. The from_tag check in rtpproxy_fill_call_args (if (!sess->from_tag)) will then skip the get_from_tag(sess->msg, ...) call that would fail due to info.msg being NULL.
Why info.msg is NULL in rtp_relay_delete_ctx
In rtp_relay_delete_ctx, the info struct is zeroed out with memset(&info, 0, sizeof info), and info.msg is never assigned afterwards. Unlike other call paths (e.g., rtp_relay_indlg_tm_req which sets info.msg = p->req), this function only populates callid, to_tag, and branch — leaving info.msg = NULL.
When rtp_relay_delete is called with this info, it eventually reaches rtpproxy_fill_call_args in the rtpproxy module. There, the check:
tries to extract the from_tag from sess->msg, which is NULL (since info.msg was never set), causing a crash or silent failure.