Module: kamailio
Branch: master
Commit: 51886cf6994131aaa90233d59c7ab119e76ba380
URL: 
https://github.com/kamailio/kamailio/commit/51886cf6994131aaa90233d59c7ab119e76ba380

Author: Vladimir Kuznichenkov <[email protected]>
Committer: Daniel-Constantin Mierla <[email protected]>
Date: 2026-07-13T16:16:03+02:00

tm: skip dns failover for msg-less local UAC

A locally generated transaction can have uas.request==NULL when the
outgoing buffer cannot be parsed back into a synthetic SIP message. On
FR timeout with another DNS destination available, the failover path
dereferenced the missing request and could crash the tm timer process.

Disable DNS failover for such transactions when t_uac_prepare() cannot
build the synthetic request. Also decline DNS failover when
add_uac_dns_fallback() receives no originating request, and keep
defensive NULL checks in the lower-level UAC builders.

Fixes GH #4799.

---

Modified: src/modules/tm/t_fwd.c
Modified: src/modules/tm/uac.c

---

Diff:  
https://github.com/kamailio/kamailio/commit/51886cf6994131aaa90233d59c7ab119e76ba380.diff
Patch: 
https://github.com/kamailio/kamailio/commit/51886cf6994131aaa90233d59c7ab119e76ba380.patch

---

diff --git a/src/modules/tm/t_fwd.c b/src/modules/tm/t_fwd.c
index 756b0ec015e..e235ade0584 100644
--- a/src/modules/tm/t_fwd.c
+++ b/src/modules/tm/t_fwd.c
@@ -342,6 +342,11 @@ static int prepare_new_uac(struct cell *t, struct sip_msg 
*i_req, int branch,
        memset(&bbak, 0, sizeof(tm_branch_bak_t));
        dst = &t->uac[branch].request.dst;
 
+       if(unlikely(i_req == NULL)) {
+               LM_BUG("null input sip msg\n");
+               return E_BUG;
+       }
+
        /* ... we calculate branch ... */
        if(!t_calc_branch(
                           t, branch, i_req->add_to_branch_s, 
&i_req->add_to_branch_len)) {
@@ -709,6 +714,11 @@ static char *print_uac_request_from_buf(struct cell *t, 
struct sip_msg *i_req,
 
        shbuf = 0;
 
+       if(unlikely(i_req == NULL)) {
+               LM_BUG("null input sip msg\n");
+               goto error00;
+       }
+
        /* ... we calculate branch ... */
        if(!t_calc_branch(
                           t, branch, i_req->add_to_branch_s, 
&i_req->add_to_branch_len)) {
@@ -921,6 +931,12 @@ static int add_uac_from_buf(struct cell *t, struct sip_msg 
*request, str *uri,
        char *shbuf;
        unsigned int len;
 
+       if(unlikely(request == NULL)) {
+               LM_BUG("null input sip msg\n");
+               ret = ser_error = E_BUG;
+               goto error;
+       }
+
        branch = t->nr_of_outgoings;
        if(branch == sr_dst_max_branches) {
                LM_ERR("maximum number of branches exceeded\n");
@@ -1076,6 +1092,18 @@ int add_uac_dns_fallback(struct cell *t, struct sip_msg 
*msg,
        int ret;
 
        ret = -1;
+       /* The failover paths require the originating request: with
+        * reparse_on_dns_failover print_uac_request_from_buf() and
+        * add_uac_from_buf() dereference it, otherwise add_uac() ->
+        * prepare_new_uac() does; msg->rcv is also read when
+        * dns_reuse_rcv_socket is set. msg is NULL for a locally generated
+        * transaction (t_uac(), uac module, ...) when its uas.request could
+        * not be built from the outgoing buffer - decline dns failover. */
+       if(unlikely(msg == NULL)) {
+               LM_DBG("no originating request - skipping dns failover for a"
+                          " locally generated transaction\n");
+               return ret;
+       }
        if(cfg_get(core, core_cfg, use_dns_failover)
                        && !((t->flags & (T_DONT_FORK | T_DISABLE_FAILOVER))
                                        || uac_dont_fork(old_uac))
diff --git a/src/modules/tm/uac.c b/src/modules/tm/uac.c
index 6d280e474f2..f239bdceee0 100644
--- a/src/modules/tm/uac.c
+++ b/src/modules/tm/uac.c
@@ -627,7 +627,9 @@ static inline int t_uac_prepare(
                if(likely(t_build_msg_from_buf(&lreq, buf, buf_len, uac_r, &dst)
                                   == 0)) {
                        if(parse_headers(&lreq, HDR_EOH_F, 0) == -1) {
-                               LM_ERR("failed to parse headers on uas for 
failover\n");
+                               LM_ERR("failed to parse headers on uas for 
failover - dns"
+                                          " failover disabled for this 
transaction\n");
+                               new_cell->flags |= T_DISABLE_FAILOVER;
                        } else {
                                new_cell->uas.request = sip_msg_cloner(&lreq, 
&sip_msg_len);
                                lreq.buf = 0;
@@ -640,7 +642,9 @@ static inline int t_uac_prepare(
                                                ((char *)new_cell->uas.request) 
+ sip_msg_len;
                        }
                } else {
-                       LM_WARN("failed to build uas for failover\n");
+                       LM_WARN("failed to build uas for failover - dns 
failover"
+                                       " disabled for this transaction\n");
+                       new_cell->flags |= T_DISABLE_FAILOVER;
                }
        }
 #endif /* USE_DNS_FAILOVER */

_______________________________________________
Kamailio - Development Mailing List -- [email protected]
To unsubscribe send an email to [email protected]
Important: keep the mailing list in the recipients, do not reply only to the 
sender!

Reply via email to