From 75ff8a6bdd87466f44a5c8dbeac417cf82493ae4 Mon Sep 17 00:00:00 2001 From: David Trihy Date: Mon, 27 Apr 2026 13:34:52 +0300 Subject: [PATCH 1/8] Refactoring logic into dialog, no dialog and common files No functionality changes just refactor for ease of diff viewing --- modules/topology_hiding/th_common_logic.c | 437 +++++++ modules/topology_hiding/th_common_logic.h | 82 ++ modules/topology_hiding/th_no_dlg_logic.c | 723 +++++++++++ modules/topology_hiding/th_no_dlg_logic.h | 35 + modules/topology_hiding/topo_hiding_logic.c | 1275 +------------------ modules/topology_hiding/topo_hiding_logic.h | 8 +- modules/topology_hiding/topology_hiding.c | 1 + 7 files changed, 1281 insertions(+), 1280 deletions(-) create mode 100644 modules/topology_hiding/th_common_logic.c create mode 100644 modules/topology_hiding/th_common_logic.h create mode 100644 modules/topology_hiding/th_no_dlg_logic.c create mode 100644 modules/topology_hiding/th_no_dlg_logic.h diff --git a/modules/topology_hiding/th_common_logic.c b/modules/topology_hiding/th_common_logic.c new file mode 100644 index 00000000000..ffa791c9023 --- /dev/null +++ b/modules/topology_hiding/th_common_logic.c @@ -0,0 +1,437 @@ +/* + * + * Copyright (C) 2026 Genesys Cloud Services, Inc. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "th_common_logic.h" +#include "../../mem/mem.h" +#include "../../parser/hf.h" +#include "../../parser/parse_rr.h" +#include "../../msg_translator.h" + +struct th_ct_params *th_param_list = NULL; +struct th_ct_params *th_hdr_param_list = NULL; + +#define init_new_ct_node(start,len,list) \ + do { \ + el = pkg_malloc(sizeof(struct th_ct_params));\ + if (!el) { \ + LM_ERR("No more pkg mem\n"); \ + return -1; \ + } \ + el->param_name.len = len; \ + el->param_name.s = start; \ + el->next = *list; \ + *list = el; \ + } while (0) + +static int topo_parse_passed_params(str *params, struct th_ct_params **lst) { + char *p,*s,*end; + struct th_ct_params* el; + int len; + + p = params->s; + end = p+params->len; + while (1) { + s = memchr(p,';',end-p); + if (!s) { + len = end-p; + if (len > 0) + init_new_ct_node(p,len,lst); + break; + } + + len = s-p; + if (len > 0) + init_new_ct_node(p,len,lst); + p=s+1; + } + + return 0; +} + +int topo_parse_passed_ct_params(str *params) +{ + return topo_parse_passed_params(params, &th_param_list); +} + +int topo_parse_passed_hdr_ct_params(str *params) +{ + return topo_parse_passed_params(params, &th_hdr_param_list); +} + +int topo_delete_record_routes(struct sip_msg *req) { + struct lump* lump, *crt, *prev_crt =0, *a, *foo; + struct hdr_field *it; + char* buf; + + /* FIXME - we will be losing uac_replace_from/to in case of no dialog */ + + /* delete also the added record route and the did param */ + for(crt = req->add_rm; crt;) { + if ((crt->type == HDR_RECORDROUTE_T) && (crt->op == LUMP_NOP) ) { + /* lump found */ + lump = crt; + crt = crt->next; + a = lump->before; + while(a) { + foo = a; a = a->before; + if (!(foo->flags & LUMPFLAG_SHMEM)) + free_lump(foo); + if (!(foo->flags & LUMPFLAG_SHMEM)) + pkg_free(foo); + } + + a = lump->after; + while(a) { + foo = a; a = a->after; + if (!(foo->flags & LUMPFLAG_SHMEM)) + free_lump(foo); + if (!(foo->flags & LUMPFLAG_SHMEM)) + pkg_free(foo); + } + if (lump == req->add_rm) { + if (lump->flags & LUMPFLAG_SHMEM) { + /* + * if the chunk is in shm, we cannot remove it, because + * it be in the middle of the big shm chunk + * therefore we simply mark it as false and move on + */ + if (lump->after) + insert_cond_lump_after(lump, COND_FALSE, 0); + if (lump->before) + insert_cond_lump_before(lump, COND_FALSE, 0); + } else { + req->add_rm = lump->next; + } + prev_crt = lump; + } else + prev_crt->next = lump->next; + if (!(lump->flags & LUMPFLAG_SHMEM)) + free_lump(lump); + if (!(lump->flags & LUMPFLAG_SHMEM)) + pkg_free(lump); + continue; + } + prev_crt = crt; + crt = crt->next; + } + + buf = req->buf; + + /* delete record-route headers */ + for (it = req->record_route; it; it = it->sibling) { + if (del_lump(req,it->name.s - buf,it->len, 0) == 0) { + LM_ERR("del_lump failed - while deleting record-route\n"); + return -1; + } + } + + return 0; +} + +int topo_delete_vias(struct sip_msg *req) { + struct hdr_field *it; + char *buf; + + /* parse all headers to be sure that all VIAs are found */ + if (parse_headers(req, HDR_EOH_F, 0)< 0) { + LM_ERR("Failed to parse reply\n"); + return -1; + } + + buf = req->buf; + it = req->h_via1; + if (it) { + /* delete first via1 to set the type (the build_req_buf_from_sip_req will know not to add lump in via1)*/ + if (del_lump(req,it->name.s - buf,it->len, 0) == 0) { + LM_ERR("del_lump failed\n"); + return -1; + } + LM_DBG("Delete via [%.*s]\n", it->len, it->name.s); + for (it = it->sibling; it; it = it->sibling) { + if (del_lump(req,it->name.s - buf,it->len, 0) == 0) { + LM_ERR("del_lump failed\n"); + return -1; + } + LM_DBG("Delete via [%.*s]\n", it->len, it->name.s); + } + } + + return 0; +} + +struct lump* delete_existing_contact(struct sip_msg *msg, int del_hdr) { + int offset; + int len; + struct lump* lump, *crt; + + offset = msg->contact->body.s - msg->buf; + len = msg->contact->body.len; + + for (crt = msg->add_rm; crt; crt = crt->next) { + if (crt->type == HDR_CONTACT_T && crt->op == LUMP_DEL && + crt->u.offset >= offset && crt->u.offset <= offset + len) { + /* + * we do not delete the lump because there might be pointers (such + * as contact->uri from the fix_nated_contact() function pointing + * to the lump's buffer; instead we simply replace the lump with a + * conditional false one + */ + /* mark DEL lump as NOP and add COND_FALSE for before and after */ + crt->op = LUMP_NOP; + + if (crt->after) + insert_cond_lump_after(crt, COND_FALSE, 0); + if (crt->before) + insert_cond_lump_before(crt, COND_FALSE, 0); + } + } + + if (del_hdr) { + /* we were asked to delete the entire header */ + offset = msg->contact->name.s - msg->buf; + len = msg->contact->len; + } else { + /* delete only the contact */ + offset = msg->contact->body.s - msg->buf; + len = msg->contact->body.len; + } + + if ((lump = del_lump(msg, offset, len, HDR_CONTACT_T)) == 0) { + LM_ERR("del_lump failed\n"); + return NULL; + } + + return lump; +} + +struct lump* restore_vias_from_req(struct sip_msg *req,struct sip_msg *rpl) { + struct lump* lmp; + struct hdr_field *it; + str via_str; + char *p,*buf = rpl->buf; + char *received_buf=0,*rport_buf=0; + unsigned int rport_len=0,received_len=0; + int size; + + lmp = anchor_lump(rpl,rpl->headers->name.s - buf,0); + if (lmp == 0) + { + LM_ERR("failed anchoring new lump\n"); + return NULL; + } + + if ((req->msg_flags&FL_FORCE_RPORT)||(req->via1->rport)) { + if ((received_buf=received_builder(req,&received_len))==0){ + LM_ERR("received_builder failed\n"); + return NULL; + } + + if ((rport_buf=rport_builder(req, &rport_len))==0){ + LM_ERR("rport_builder failed\n"); + return NULL; + } + + /* take care of via1 + rest of VIA headers in h_via1 */ + via_str.len = rport_len + received_len + req->h_via1->len; + LM_DBG("via len = %d\n",via_str.len); + if (req->via1->received) { + via_str.len -= req->via1->received->size+1; + LM_DBG(" have received will remove %d \n",req->via1->received->size+1); + } + if (req->via1->rport) { + via_str.len -= req->via1->rport->size+1; + LM_DBG(" have rport will remove %d \n",req->via1->rport->size+1); + } + + /* copy rest of VIA headers */ + it = req->h_via1->sibling; + while (it) { + via_str.len += it->len; + it = it->sibling; + } + + via_str.s = pkg_malloc(via_str.len); + if (!via_str.s) { + LM_ERR("No more pkg mem\n"); + goto err_free_rport; + } + + /* take care of via1 + rest of VIA headers in h_via1 */ + if (req->via1->params.s){ + size= req->via1->params.s-req->via1->hdr.s-1; /*compensate for ';' */ + }else{ + size= req->via1->host.s-req->via1->hdr.s+req->via1->host.len; + if (req->via1->port!=0){ + size += req->via1->port_str.len + 1; /* +1 for ':'*/ + } + } + + p = via_str.s; + memcpy(p,req->via1->hdr.s,size); + p += size; + memcpy(p,received_buf,received_len); + p += received_len; + memcpy(p,rport_buf,rport_len); + p += rport_len; + + int bytes_before = 0; + int bytes_after = 0; + int bytes_between = 0; + char *between = NULL; + char *after = NULL; + + if (req->via1->received) { + if (!req->via1->rport) { + bytes_before = req->via1->received->start-req->via1->hdr.s-size-1; + memcpy(p, + req->via1->hdr.s+size, + bytes_before); + p += bytes_before; + + bytes_after = req->h_via1->len - size - req->via1->received->size - + bytes_before - 1; + memcpy(p, + req->via1->received->start+req->via1->received->size, + bytes_after); + p += bytes_after; + } else { + /* we have both :( */ + if (req->via1->rport->start > req->via1->received->start) { + bytes_before = req->via1->received->start-req->via1->hdr.s-size-1; + bytes_between = req->via1->rport->start - req->via1->received->start - req->via1->received->size - 1; + between = req->via1->received->start + req->via1->received->size; + after = req->via1->rport->start+req->via1->rport->size; + + bytes_after = req->h_via1->len - size - req->via1->rport->size - + bytes_before - 1 - bytes_between - req->via1->received->size - 1; + LM_DBG("1 both , before = %d, between = %d, after = %d\n",bytes_before,bytes_between,bytes_after); + } else { + bytes_before = req->via1->rport->start-req->via1->hdr.s-size-1; + bytes_between = req->via1->received->start - req->via1->rport->start - req->via1->rport->size - 1; + between = req->via1->rport->start + req->via1->rport->size; + + after = req->via1->received->start+req->via1->received->size; + + bytes_after = req->h_via1->len - size - req->via1->rport->size - + bytes_before - 1 - bytes_between - req->via1->received->size -1 ; + LM_DBG("2 both , before = %d, between = %d, after = %d\n",bytes_before,bytes_between,bytes_after); + } + + memcpy(p, + req->via1->hdr.s+size, + bytes_before); + p += bytes_before; + + memcpy(p, + between, + bytes_between); + p += bytes_between; + + memcpy(p, + after, + bytes_after); + p += bytes_after; + } + } else if (req->via1->rport) { + if (!req->via1->received) { + bytes_before = req->via1->rport->start-req->via1->hdr.s-size-1; + memcpy(p, + req->via1->hdr.s+size, + bytes_before); + p += bytes_before; + + bytes_after = req->h_via1->len - size - req->via1->rport->size - + bytes_before - 1; + memcpy(p, + req->via1->rport->start+req->via1->rport->size, + bytes_after); + p += bytes_after; + } + } else { + /* no rport or received already present */ + memcpy(p,req->via1->hdr.s+size,req->h_via1->len-size); + p+= req->h_via1->len-size; + } + + /* copy rest of VIA headers */ + it = req->h_via1->sibling; + while (it) { + memcpy(p,it->name.s,it->len); + p+=it->len; + it = it->sibling; + } + + LM_DBG("built [%.*s], %d %d\n",(int)(p-via_str.s),via_str.s,(int)(p-via_str.s),via_str.len); + + if ((lmp = insert_new_lump_after(lmp, via_str.s, via_str.len, 0)) == 0) { + LM_ERR("failed inserting new old vias\n"); + pkg_free(via_str.s); + goto err_free_rport; + } + + pkg_free(rport_buf); + pkg_free(received_buf); + } else { + /* no need to add received/rport , just copy the headers altogether */ + it = req->h_via1; + via_str.len = 0; + + while (it) { + via_str.len += it->len; + it = it->sibling; + } + + LM_DBG("via len = %d\n",via_str.len); + + if (via_str.len == 0) + return lmp; + + via_str.s = pkg_malloc(via_str.len); + if (!via_str.s) { + LM_ERR("no more pkg mem\n"); + return NULL; + } + + LM_DBG("allocated via_str %p\n",via_str.s); + + it = req->h_via1; + p = via_str.s; + while (it) { + memcpy(p,it->name.s,it->len); + p+=it->len; + it = it->sibling; + } + + LM_DBG("inserting via headers - [%.*s]\n",via_str.len,via_str.s); + + if ((lmp = insert_new_lump_after(lmp, via_str.s, via_str.len, 0)) == 0) { + LM_ERR("failed inserting new old vias\n"); + pkg_free(via_str.s); + return NULL; + } + } + + return lmp; + +err_free_rport: + pkg_free(rport_buf); + pkg_free(received_buf); + return NULL; +} diff --git a/modules/topology_hiding/th_common_logic.h b/modules/topology_hiding/th_common_logic.h new file mode 100644 index 00000000000..18a6ada4e34 --- /dev/null +++ b/modules/topology_hiding/th_common_logic.h @@ -0,0 +1,82 @@ +/* + * + * Copyright (C) 2026 Genesys Cloud Services, Inc. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef _TOPOH_COMMON_LOGIC_H +#define _TOPOH_COMMON_LOGIC_H + +#include "../../str.h" +#include "../../data_lump.h" +#include "../../mem/shm_mem.h" +#include "../../parser/contact/parse_contact.h" + +#define RECORD_ROUTE "Record-Route: " +#define RECORD_ROUTE_LEN (sizeof(RECORD_ROUTE)-1) + +struct th_params { + str ct_caller_user; + str ct_callee_user; +}; + +struct th_ct_params { + str param_name; + struct th_ct_params *next; +}; + +int topo_delete_record_routes(struct sip_msg *req); +int topo_delete_vias(struct sip_msg *req); +struct lump* delete_existing_contact(struct sip_msg *msg, int del_hdr); +struct lump* restore_vias_from_req(struct sip_msg *req,struct sip_msg *rpl); + +static inline int topo_ct_param_len(str *name, str *val, int should_quote) +{ + int len = 1 /* ; */ + name->len; + if (val->len) { + if (should_quote && should_quote_contact_param_value(val)) + len += 2; /* quotes */ + len += 1 /* = */ + val->len; + } + + return len; +} + +static inline char *topo_ct_param_copy(char *buf, str *name, str *val, int should_quote) { + *buf++ = ';'; + memcpy(buf, name->s, name->len); + buf += name->len; + if (val->len) { + *buf++ = '='; + if (should_quote) + should_quote = should_quote_contact_param_value(val); + if (should_quote) + *buf++ = '"'; + memcpy(buf, val->s, val->len); + buf += val->len; + if (should_quote) + *buf++ = '"'; + } + return buf; +} + +static void shm_free_wrap(void *param) { + if (param) + shm_free(param); +} + +#endif \ No newline at end of file diff --git a/modules/topology_hiding/th_no_dlg_logic.c b/modules/topology_hiding/th_no_dlg_logic.c new file mode 100644 index 00000000000..5c42356fee6 --- /dev/null +++ b/modules/topology_hiding/th_no_dlg_logic.c @@ -0,0 +1,723 @@ +/* + * + * Copyright (C) 2026 Genesys Cloud Services, Inc. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "th_no_dlg_logic.h" +#include "../dialog/dlg_hash.h" +#include "../tm/tm_load.h" +#include "../rr/loose.h" + +struct th_no_dlg_param { + str routes; + str username; +}; + +extern struct tm_binds tm_api; +extern struct th_ct_params *th_param_list; +extern struct th_ct_params *th_hdr_param_list; +extern str topo_hiding_ct_encode_pw; +extern str th_contact_encode_param; +extern int th_ct_enc_scheme; + +/* We encode the RR headers, the actual Contact and the socket str for this leg */ +/* Via headers will be restored using the TM module, no need to save anything for them */ +static char* build_encoded_contact_suffix(struct sip_msg* msg, str *routes, int *suffix_len, int flags) +{ + short rr_len,ct_len,addr_len,flags_len,enc_len; + char *suffix_plain,*suffix_enc,*p,*s; + str rr_set = {NULL, 0}; + str contact; + str flags_str; + int i,total_len; + struct sip_uri ctu; + struct th_ct_params* el; + param_t *it; + int is_req = (msg->first_line.type==SIP_REQUEST)?1:0; + int local_len = sizeof(short) /* RR length */ + + sizeof(short) /* Contact length */ + + sizeof(short) /* Flags length */ + + sizeof(short) /* bind addr */; + + /* parse all headers as we can have multiple + RR headers in the same message */ + if( parse_headers(msg,HDR_EOH_F,0)<0 ){ + LM_ERR("failed to parse all headers\n"); + return NULL; + } + + if (routes && routes->len) { + rr_set = *routes; + rr_len = (short)routes->len; + } else if(msg->record_route){ + if(print_rr_body(msg->record_route, &rr_set, !is_req, 0, NULL) != 0){ + LM_ERR("failed to print route records \n"); + return NULL; + } + rr_len = (short)rr_set.len; + } else { + rr_len = 0; + } + + if ( parse_contact(msg->contact)<0 || + ((contact_body_t *)msg->contact->parsed)->contacts==NULL || + ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { + LM_ERR("bad Contact HDR\n"); + goto error; + } else { + contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri; + ct_len = (short)contact.len; + } + + flags_str.s = int2str(flags, &flags_str.len); + flags_len = (short)flags_str.len; + + addr_len = (short)msg->rcv.bind_address->sock_str.len; + local_len += rr_len + ct_len + flags_len + addr_len; + enc_len = th_ct_enc_scheme == ENC_BASE64 ? + calc_word64_encode_len(local_len) : calc_word32_encode_len(local_len); + total_len = enc_len + + 1 /* ; */ + + th_contact_encode_param.len + + 1 /* = */ + + 1 /* > */; + + if (th_param_list) { + if ( parse_contact(msg->contact)<0 || + ((contact_body_t *)msg->contact->parsed)->contacts==NULL || + ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { + LM_ERR("bad Contact HDR\n"); + } else { + contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri; + if(parse_uri(contact.s, contact.len, &ctu) < 0) { + LM_ERR("Bad Contact URI\n"); + } else { + for (el=th_param_list;el;el=el->next) { + /* we just iterate over the unknown params */ + for (i=0;iparam_name, &ctu.u_name[i])) + total_len += topo_ct_param_len(&ctu.u_name[i], &ctu.u_val[i], 0); + } + } + } + } + } + + if (th_hdr_param_list) { + if ( parse_contact(msg->contact)<0 || + ((contact_body_t *)msg->contact->parsed)->contacts==NULL || + ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { + LM_ERR("bad Contact HDR\n"); + } else { + for (el=th_hdr_param_list;el;el=el->next) { + for (it=((contact_body_t *)msg->contact->parsed)->contacts->params;it;it=it->next) { + if (str_match(&el->param_name, &it->name)) + total_len += topo_ct_param_len(&it->name, &it->body, 1); + } + } + } + } + + suffix_enc = pkg_malloc(total_len+1); + if (!suffix_enc) { + LM_ERR("no more pkg\n"); + goto error; + } + suffix_plain = pkg_malloc(local_len+1); + if (!suffix_plain) { + LM_ERR("no more pkg\n"); + goto error; + } + + p = suffix_plain; + memcpy(p,&rr_len,sizeof(short)); + p+= sizeof(short); + if (rr_len) { + memcpy(p,rr_set.s,rr_set.len); + p+= rr_set.len; + } + memcpy(p,&ct_len,sizeof(short)); + p+= sizeof(short); + if (ct_len) { + memcpy(p,contact.s,contact.len); + p+= contact.len; + } + memcpy(p,&flags_len,sizeof(short)); + p+= sizeof(short); + memcpy(p,flags_str.s, flags_str.len); + p+= flags_str.len; + memcpy(p,&addr_len,sizeof(short)); + p+= sizeof(short); + memcpy(p,msg->rcv.bind_address->sock_str.s,msg->rcv.bind_address->sock_str.len); + p+= msg->rcv.bind_address->sock_str.len; + for (i=0;i<(int)(p-suffix_plain);i++) + suffix_plain[i] ^= topo_hiding_ct_encode_pw.s[i%topo_hiding_ct_encode_pw.len]; + + s = suffix_enc; + *s++ = ';'; + memcpy(s,th_contact_encode_param.s,th_contact_encode_param.len); + s+= th_contact_encode_param.len; + *s++ = '='; + if (th_ct_enc_scheme == ENC_BASE64) + word64encode((unsigned char*)s,(unsigned char *)suffix_plain,p-suffix_plain); + else + word32encode((unsigned char*)s,(unsigned char *)suffix_plain,p-suffix_plain); + s = s+enc_len; + + if (th_param_list) { + for (el=th_param_list;el;el=el->next) { + /* we just iterate over the unknown params */ + for (i=0;iparam_name, &ctu.u_name[i])) + s = topo_ct_param_copy(s, &ctu.u_name[i], &ctu.u_val[i], 0); + } + } + } + *s++ = '>'; + if (th_hdr_param_list) { + if ( parse_contact(msg->contact)<0 || + ((contact_body_t *)msg->contact->parsed)->contacts==NULL || + ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { + LM_ERR("bad Contact HDR\n"); + } else { + for (el=th_hdr_param_list;el;el=el->next) { + for (it=((contact_body_t *)msg->contact->parsed)->contacts->params;it;it=it->next) { + if (str_match(&el->param_name, &it->name)) + s = topo_ct_param_copy(s, &it->name, &it->body, 1); + } + } + } + } + + if (rr_set.s && !routes) + pkg_free(rr_set.s); + pkg_free(suffix_plain); + *suffix_len = total_len; + return suffix_enc; +error: + if (rr_set.s) + pkg_free(rr_set.s); + return NULL; +} + + +static void _th_no_dlg_onreply(struct cell* t, int type, struct tmcb_params *param,int flags, int do_rr) +{ + struct lump* lmp; + str rr_set; + struct th_no_dlg_param *p = *(param->param); + struct sip_msg *req = param->req; + struct sip_msg *rpl = param->rpl; + char *route; + int size; + + /* parse all headers to be sure that all RR and Contact hdrs are found */ + if (parse_headers(rpl, HDR_EOH_F, 0)< 0) { + LM_ERR("Failed to parse reply\n"); + return; + } + + if (topo_delete_record_routes(rpl) < 0) { + LM_ERR("Failed to remove Record Route header \n"); + return; + } + + if(topo_delete_vias(rpl) < 0) { + LM_ERR("Failed to remove via headers\n"); + return; + } + + if ( !(rpl->REPLY_STATUS>=300 && rpl->REPLY_STATUS<400) ) { + if (topo_no_dlg_encode_contact(rpl,flags, + (p?&p->routes:NULL),(p?&p->username:NULL)) < 0) { + LM_ERR("Failed to encode contact header \n"); + return; + } + } + + if (!(lmp = restore_vias_from_req(req,rpl))) { + LM_ERR("Failed to restore VIA headers from request \n"); + return ; + } + + /* pass record route headers */ + if(do_rr && req->record_route){ + if(print_rr_body(req->record_route, &rr_set, 0, 1, NULL) != 0 ){ + LM_ERR("failed to print route records \n"); + return; + } + + size = rr_set.len + RECORD_ROUTE_LEN + CRLF_LEN; + route = pkg_malloc(size); + if (route == NULL) { + LM_ERR("no more pkg memory\n"); + pkg_free(rr_set.s); + return; + } + + memcpy(route, RECORD_ROUTE, RECORD_ROUTE_LEN); + memcpy(route+RECORD_ROUTE_LEN, rr_set.s, rr_set.len); + memcpy(route+RECORD_ROUTE_LEN+rr_set.len, CRLF, CRLF_LEN); + /* put after Via */ + if ((lmp = insert_new_lump_after(lmp, route, size, HDR_RECORDROUTE_T)) == 0) { + LM_ERR("failed inserting new route set\n"); + pkg_free(route); + pkg_free(rr_set.s); + return; + } + + LM_DBG("Added record route [%.*s]\n", size, route); + pkg_free(rr_set.s); + } + return; +} + +static void th_no_dlg_onreply(struct cell* t, int type, struct tmcb_params *param) +{ + _th_no_dlg_onreply(t,type,param,0,1); +} + +static void th_no_dlg_user_onreply(struct cell* t, int type, struct tmcb_params *param) +{ + _th_no_dlg_onreply(t,type,param,TOPOH_KEEP_USER,1); +} + +static void th_no_dlg_onreply_within(struct cell* t, int type, struct tmcb_params *param) +{ + _th_no_dlg_onreply(t,type,param,0,0); +} + +static void th_no_dlg_user_onreply_within(struct cell* t, int type, struct tmcb_params *param) +{ + _th_no_dlg_onreply(t,type,param,TOPOH_KEEP_USER,0); +} + +int topology_hiding_match(struct sip_msg *msg) +{ + struct sip_uri *r_uri; + int i; + + if (parse_sip_msg_uri(msg)<0) { + LM_ERR("Failed to parse request URI\n"); + return -1; + } + + if (parse_headers(msg, HDR_ROUTE_F, 0) == -1) { + LM_ERR("failed to parse route headers\n"); + } + + r_uri = &msg->parsed_uri; + + if (check_self(&r_uri->host,r_uri->port_no ? r_uri->port_no : SIP_PORT, 0) == 1 && msg->route == NULL) { + /* Seems we are in the topo hiding case : + * we are in the R-URI and there are no other route headers */ + for (i=0;iu_params_no;i++) + if (r_uri->u_name[i].len == th_contact_encode_param.len && + memcmp(th_contact_encode_param.s,r_uri->u_name[i].s,th_contact_encode_param.len)==0) { + LM_DBG("We found param in R-URI with value of %.*s\n", + r_uri->u_val[i].len,r_uri->u_val[i].s); + /* pass the param value to the matching funcs */ + return topo_no_dlg_seq_handling(msg,&r_uri->u_val[i]); + } + } + + return -1; +} + +int topo_hiding_no_dlg(struct sip_msg *req, + struct cell* t,int extra_flags,struct th_params *params) { + transaction_cb* used_cb; + struct th_no_dlg_param *p = NULL; + + /* parse all headers to be sure that all RR and Contact hdrs are found */ + if (parse_headers(req, HDR_EOH_F, 0)< 0) { + LM_ERR("Failed to parse reply\n"); + return -1; + } + + if (topo_delete_record_routes(req) < 0) { + LM_ERR("Failed to remove Record Route header \n"); + return -1; + } + + if(topo_delete_vias(req) < 0) { + LM_ERR("Failed to remove via headers\n"); + return -1; + } + + if (topo_no_dlg_encode_contact(req,extra_flags,NULL, ¶ms->ct_caller_user) < 0) { + LM_ERR("Failed to encode contact header \n"); + return -1; + } + + if (extra_flags & TOPOH_KEEP_USER) { + used_cb = th_no_dlg_user_onreply; + } else { + used_cb = th_no_dlg_onreply; + if (params && params->ct_callee_user.len) { + p = shm_malloc(sizeof *p + params->ct_callee_user.len); + if (p) { + memset(p, 0, sizeof *p); + p->username.s = (char *)(p + 1); + p->username.len = params->ct_callee_user.len; + memcpy(p->username.s, params->ct_callee_user.s, + params->ct_callee_user.len); + } + } + } + + if (extra_flags & TOPOH_HIDE_CALLID) + LM_WARN("Cannot hide callid when dialog support is not engaged!\n"); + if (extra_flags & TOPOH_DID_IN_USER) + LM_WARN("Cannot store DID in user when dialog support is not engaged!\n"); + + if (tm_api.register_tmcb( req, 0, TMCB_RESPONSE_FWDED, + used_cb,p, (p?shm_free_wrap:NULL))<0 ) { + LM_ERR("failed to register TMCB\n"); + return -1; + } + + return 1; +} + +#define ROUTE_STR "Route: " +#define ROUTE_LEN (sizeof(ROUTE_STR) - 1) +#define ROUTE_PREF "Route: <" +#define ROUTE_PREF_LEN (sizeof(ROUTE_PREF) -1) +#define ROUTE_SUFF ">\r\n" +#define ROUTE_SUFF_LEN (sizeof(ROUTE_SUFF) -1) + +int topo_no_dlg_seq_handling(struct sip_msg *msg,str *info) +{ + int max_size,dec_len,i,size,flags; + char *dec_buf,*p,*route=NULL,*hdrs,*remote_contact; + struct hdr_field *it; + str rr_buf,ct_buf,flags_buf,bind_buf; + rr_t *head = NULL, *rrp; + int next_strict=0; + struct sip_uri fru; + char* buf = msg->buf; + struct lump* lmp = NULL; + str host; + int port,proto; + const struct socket_info *sock; + str route_buf = {0, 0}; + struct th_no_dlg_param *param = NULL; + transaction_cb* used_cb; + + /* parse all headers to be sure that all RR and Contact hdrs are found */ + if (parse_headers(msg, HDR_EOH_F, 0)< 0) { + LM_ERR("Failed to parse reply\n"); + return -1; + } + + /* delete vias */ + if(topo_delete_vias(msg) < 0) { + LM_ERR("Failed to remove via headers\n"); + return -1; + } + + /* delete record route */ + for (it=msg->record_route;it;it=it->sibling) { + if (del_lump(msg, it->name.s - buf, it->len, 0) == 0) { + LM_ERR("del_lump failed\n"); + return -1; + } + } + + max_size = th_ct_enc_scheme == ENC_BASE64 ? + calc_max_word64_decode_len(info->len) : + calc_max_word32_decode_len(info->len); + dec_buf = pkg_malloc(max_size); + if (dec_buf==NULL) { + LM_ERR("No more pkg\n"); + return -1; + } + + if (th_ct_enc_scheme == ENC_BASE64) + dec_len = word64decode((unsigned char *)dec_buf, + (unsigned char *)info->s,info->len); + else + dec_len = word32decode((unsigned char *)dec_buf, + (unsigned char *)info->s,info->len); + for (i=0;i_len) {\ + LM_ERR("bad length %d in encoded contact\n", (_s).len);\ + goto err_free_buf;\ + }\ + (_s).s = _p + sizeof(short);\ + _p += sizeof(short) + (_s).len;\ + _len -= sizeof(short) + (_s).len;\ + } while(0) + + p = dec_buf; + size = dec_len; + __extract_len_and_buf(p, size, rr_buf); + __extract_len_and_buf(p, size, ct_buf); + __extract_len_and_buf(p, size, flags_buf); + __extract_len_and_buf(p, size, bind_buf); + + LM_DBG("extracted routes [%.*s] , ct [%.*s] , flags [%.*s] and bind [%.*s]\n", + rr_buf.len,rr_buf.s,ct_buf.len,ct_buf.s,flags_buf.len,flags_buf.s,bind_buf.len,bind_buf.s); + + if (rr_buf.len) { + if (parse_rr_body(rr_buf.s,rr_buf.len,&head) != 0) { + LM_ERR("failed parsing route set\n"); + goto err_free_buf; + } + + if(parse_uri(head->nameaddr.uri.s, head->nameaddr.uri.len, &fru) < 0) { + LM_ERR("Failed to parse SIP uri\n"); + goto err_free_head; + } + if(is_strict(&fru.params)) + next_strict = 1; + } + + if (msg->dst_uri.s && msg->dst_uri.len) { + /* reset dst_uri if previously set + * either by loose route or manually */ + pkg_free(msg->dst_uri.s); + msg->dst_uri.s = NULL; + msg->dst_uri.len = 0; + } + + if (!next_strict) { + LM_DBG("Fixing message. Next hop is Loose router\n"); + if (ct_buf.len && ct_buf.s) { + LM_DBG("Setting new URI to <%.*s> \n",ct_buf.len, + ct_buf.s); + + if (set_ruri(msg,&ct_buf) != 0) { + LM_ERR("failed setting ruri\n"); + goto err_free_head; + } + } + if( parse_headers( msg, HDR_EOH_F, 0)<0 ) { + LM_ERR("failed to parse headers when looking after ROUTEs\n"); + goto err_free_head; + } + + if (msg->route) { + for (it=msg->route;it;it=it->sibling) { + if (it->parsed && ((rr_t*)it->parsed)->deleted) + continue; + if ((lmp = del_lump(msg,it->name.s - buf,it->len,HDR_ROUTE_T)) == 0) { + LM_ERR("del_lump failed \n"); + goto err_free_head; + } + } + } + + if ( rr_buf.len !=0 && rr_buf.s) { + + lmp = anchor_lump(msg,msg->headers->name.s - buf,0); + if (lmp == 0) { + LM_ERR("failed anchoring new lump\n"); + goto err_free_head; + } + + size = rr_buf.len + ROUTE_LEN + CRLF_LEN; + route = pkg_malloc(size+1); + if (route == 0) { + LM_ERR("no more pkg memory\n"); + goto err_free_head; + } + + memcpy(route,ROUTE_STR,ROUTE_LEN); + memcpy(route+ROUTE_LEN,rr_buf.s,rr_buf.len); + memcpy(route+ROUTE_LEN+rr_buf.len,CRLF,CRLF_LEN); + + route[size] = 0; + + if ((lmp = insert_new_lump_after(lmp,route,size,HDR_ROUTE_T)) == 0) { + LM_ERR("failed inserting new route set\n"); + goto err_free_route; + } + msg->msg_flags |= FL_HAS_ROUTE_LUMP; + route_buf = rr_buf; + + LM_DBG("Setting route header to <%s> \n",route); + LM_DBG("setting dst_uri to <%.*s> \n",head->nameaddr.uri.len, + head->nameaddr.uri.s); + + if (set_dst_uri(msg,&head->nameaddr.uri) !=0 ) { + goto err_free_head; + } + } + } else { + LM_DBG("Fixing message. Next hop is Strict router\n"); + if (msg->route) { + for (it=msg->route;it;it=it->sibling) { + if (it->parsed && ((rr_t*)it->parsed)->deleted) + continue; + if ((lmp = del_lump(msg,it->name.s - buf,it->len,HDR_ROUTE_T)) == 0) { + LM_ERR("del_lump failed \n"); + goto err_free_head; + } + } + } + + if ( rr_buf.len !=0 && rr_buf.s) { + if (set_ruri(msg,&head->nameaddr.uri) !=0 ) { + LM_ERR("failed setting new dst uri\n"); + goto err_free_head; + } + i=0; + rrp = head; + while (rrp) { + i++; + rrp=rrp->next; + } + + /* If there are more routes other than the first, add them */ + if (i > 1) { + lmp = anchor_lump(msg,msg->headers->name.s - buf,0); + if (lmp == 0) { + LM_ERR("failed anchoring new lump\n"); + goto err_free_head; + } + + hdrs = rr_buf.s + head->len + 1; + + size = rr_buf.len - head->len - 1 + ROUTE_LEN + CRLF_LEN; + route = pkg_malloc(size); + if (route == 0) { + LM_ERR("no more pkg memory\n"); + goto err_free_head; + } + + memcpy(route,ROUTE_STR,ROUTE_LEN); + memcpy(route+ROUTE_LEN,hdrs,rr_buf.len - head->len-1); + memcpy(route+ROUTE_LEN+rr_buf.len - head->len-1,CRLF,CRLF_LEN); + + LM_DBG("Adding Route header : [%.*s] \n",size,route); + + if ((lmp = insert_new_lump_after(lmp,route,size,HDR_ROUTE_T)) == 0) { + LM_ERR("failed inserting new route set\n"); + goto err_free_route; + } + msg->msg_flags |= FL_HAS_ROUTE_LUMP; + route_buf.s = route; + route_buf.len = rr_buf.len - head->len - 1; + } + + if (lmp == NULL) { + lmp = anchor_lump(msg,msg->headers->name.s - buf,0); + if (lmp == 0) + { + LM_ERR("failed anchoring new lump\n"); + return -1; + } + } + + if (ct_buf.len && ct_buf.s) { + size = ct_buf.len + ROUTE_PREF_LEN + ROUTE_SUFF_LEN; + remote_contact = pkg_malloc(size); + if (remote_contact == NULL) { + LM_ERR("no more pkg \n"); + goto err_free_head; + } + + memcpy(remote_contact,ROUTE_PREF,ROUTE_PREF_LEN); + memcpy(remote_contact+ROUTE_PREF_LEN,ct_buf.s,ct_buf.len); + memcpy(remote_contact+ROUTE_PREF_LEN+ct_buf.len, + ROUTE_SUFF,ROUTE_SUFF_LEN); + + LM_DBG("Adding remote contact route header : [%.*s]\n", + size,remote_contact); + + if (insert_new_lump_after(lmp,remote_contact,size,HDR_ROUTE_T) == 0) { + LM_ERR("failed inserting remote contact route\n"); + pkg_free(remote_contact); + goto err_free_head; + } + msg->msg_flags |= FL_HAS_ROUTE_LUMP; + } + } + } + if (route_buf.s && route_buf.len) { + param = shm_malloc(sizeof *param + route_buf.len); + if (param) { + memset(param, 0, sizeof *param); + param->routes.s = (char *)(param + 1); + param->routes.len = route_buf.len; + memcpy(param->routes.s, route_buf.s, route_buf.len); + } + } + + if (flags_buf.len && flags_buf.s) { + if (str2int(&flags_buf, (unsigned int*) &flags) < 0) { + LM_WARN("Failed to convert string to integer, default to no flags\n"); + flags = 0; + } + } else { + flags = 0; + } + + if (flags & TOPOH_KEEP_USER) + used_cb = th_no_dlg_user_onreply_within; + else + used_cb = th_no_dlg_onreply_within; + + /* register tm callback for response in */ + if (tm_api.register_tmcb( msg, 0, TMCB_RESPONSE_FWDED, + used_cb,param,(param?shm_free_wrap:NULL))<0 ) { + LM_ERR("failed to register TMCB\n"); + } + + if (bind_buf.len && bind_buf.s) { + LM_DBG("forcing send socket for req to [%.*s]\n",bind_buf.len,bind_buf.s); + if (parse_phostport( bind_buf.s, bind_buf.len, &host.s, &host.len, + &port, &proto)!=0) { + LM_ERR("bad socket <%.*s>\n", bind_buf.len, bind_buf.s); + } else { + sock = grep_sock_info( &host, (unsigned short)port, proto); + if (!sock) { + LM_WARN("non-local socket <%.*s>...ignoring\n", bind_buf.len, bind_buf.s); + } + msg->force_send_socket = sock; + } + } + + if (rr_buf.len) + free_rr(&head); + pkg_free(dec_buf); + + if (topo_no_dlg_encode_contact(msg,flags,NULL,NULL) < 0) { + LM_ERR("Failed to encode contact header \n"); + return -1; + } + + return 1; + +err_free_route: + if (route) + pkg_free(route); +err_free_head: + if (rr_buf.len) + free_rr(&head); +err_free_buf: + pkg_free(dec_buf); + return -1; +} diff --git a/modules/topology_hiding/th_no_dlg_logic.h b/modules/topology_hiding/th_no_dlg_logic.h new file mode 100644 index 00000000000..f7125c7e5e9 --- /dev/null +++ b/modules/topology_hiding/th_no_dlg_logic.h @@ -0,0 +1,35 @@ +/* + * + * Copyright (C) 2026 Genesys Cloud Services, Inc. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef _TH_NO_DLG_LOGIC_H +#define _TH_NO_DLG_LOGIC_H + +#include "../../str.h" +#include "../tm/t_hooks.h" +#include "th_common_logic.h" +#include "../../context.h" + +enum encode_scheme {ENC_BASE64, ENC_BASE32}; + + +int topo_hiding_no_dlg(struct sip_msg *req, struct cell* t, int extra_flags, struct th_params *params); +int topo_hiding_match_no_dlg(struct sip_msg *msg); + +#endif \ No newline at end of file diff --git a/modules/topology_hiding/topo_hiding_logic.c b/modules/topology_hiding/topo_hiding_logic.c index 5b9d8c58db6..65b81fe64e2 100644 --- a/modules/topology_hiding/topo_hiding_logic.c +++ b/modules/topology_hiding/topo_hiding_logic.c @@ -28,43 +28,25 @@ #include "topo_hiding_logic.h" extern int force_dialog; -extern struct tm_binds tm_api; extern struct rr_binds rr_api; +extern struct tm_binds tm_api; extern struct dlg_binds dlg_api; extern str topo_hiding_prefix; extern str topo_hiding_seed; -extern str topo_hiding_ct_encode_pw; -extern str th_contact_encode_param; -extern int th_ct_enc_scheme; -extern int th_loop_protection; - -struct th_ct_params { - str param_name; - struct th_ct_params *next; -}; + static struct th_ct_params *th_param_list=NULL; static struct th_ct_params *th_hdr_param_list=NULL; static int topo_hiding_with_dlg(struct sip_msg *req,struct cell* t, struct dlg_cell* dlg,int extra_flags,struct th_params *params); -static int topo_hiding_no_dlg(struct sip_msg *req, - struct cell* t,int extra_flags,struct th_params *params); static int topo_dlg_replace_contact(struct sip_msg* msg, struct dlg_cell* dlg, int leg, str *ct_user); -static int topo_delete_vias(struct sip_msg* req); -static int topo_delete_record_routes(struct sip_msg *req); -static struct lump* delete_existing_contact(struct sip_msg *msg, int del_hdr); -static int topo_parse_passed_params(str *params,struct th_ct_params **lst); static void topo_dlg_onroute (struct dlg_cell* dlg, int type, struct dlg_cb_params * params); static void topo_dlg_initial_reply (struct dlg_cell* dlg, int type, struct dlg_cb_params * params); static void th_down_onreply(struct cell* t, int type,struct tmcb_params *param); static void th_up_onreply(struct cell* t, int type, struct tmcb_params *param); -static void th_no_dlg_onreply(struct cell* t, int type, struct tmcb_params *param); -static void th_no_dlg_user_onreply(struct cell* t, int type, struct tmcb_params *param); -static int topo_no_dlg_encode_contact(struct sip_msg *req,int flags,str *routes,str *ct_user); -static int topo_no_dlg_seq_handling(struct sip_msg *msg,str *info); static int dlg_th_onreply(struct dlg_cell *dlg, struct sip_msg *rpl, struct sip_msg *req, int init_req, int dir, int dst_leg); @@ -124,278 +106,7 @@ int topology_hiding(struct sip_msg *req,int extra_flags, struct th_params *param return topo_hiding_no_dlg(req,t,extra_flags,params); } -int topo_parse_passed_ct_params(str *params) -{ - return topo_parse_passed_params(params,&th_param_list); -} - -int topo_parse_passed_hdr_ct_params(str *params) -{ - return topo_parse_passed_params(params,&th_hdr_param_list); -} - -int topology_hiding_match(struct sip_msg *msg) -{ - struct sip_uri *r_uri; - int i; - - if (parse_sip_msg_uri(msg)<0) { - LM_ERR("Failed to parse request URI\n"); - return -1; - } - - if (parse_headers(msg, HDR_ROUTE_F, 0) == -1) { - LM_ERR("failed to parse route headers\n"); - } - - r_uri = &msg->parsed_uri; - - if (check_self(&r_uri->host,r_uri->port_no ? r_uri->port_no : SIP_PORT, 0) == 1 && msg->route == NULL) { - /* Seems we are in the topo hiding case : - * we are in the R-URI and there are no other route headers */ - for (i=0;iu_params_no;i++) - if (r_uri->u_name[i].len == th_contact_encode_param.len && - memcmp(th_contact_encode_param.s,r_uri->u_name[i].s,th_contact_encode_param.len)==0) { - LM_DBG("We found param in R-URI with value of %.*s\n", - r_uri->u_val[i].len,r_uri->u_val[i].s); - /* pass the param value to the matching funcs */ - return topo_no_dlg_seq_handling(msg,&r_uri->u_val[i]); - } - } - - return -1; -} - /* internal functionality */ - -#define init_new_ct_node(start,len,list) \ - do { \ - el = pkg_malloc(sizeof(struct th_ct_params));\ - if (!el) { \ - LM_ERR("No more pkg mem\n"); \ - return -1; \ - } \ - el->param_name.len = len; \ - el->param_name.s = start; \ - el->next = *list; \ - *list = el; \ - } while (0) - -static int topo_parse_passed_params(str *params,struct th_ct_params **lst) -{ - char *p,*s,*end; - struct th_ct_params* el; - int len; - - p = params->s; - end = p+params->len; - while (1) { - s = memchr(p,';',end-p); - if (!s) { - len = end-p; - if (len > 0) - init_new_ct_node(p,len,lst); - break; - } - - len = s-p; - if (len > 0) - init_new_ct_node(p,len,lst); - p=s+1; - } - - return 0; -} - -static int topo_delete_record_routes(struct sip_msg *req) -{ - struct lump* lump, *crt, *prev_crt =0, *a, *foo; - struct hdr_field *it; - char* buf; - - /* FIXME - we will be losing uac_replace_from/to in case of no dialog */ - - /* delete also the added record route and the did param */ - for(crt=req->add_rm; crt;) { - if ((crt->type==HDR_RECORDROUTE_T) && (crt->op==LUMP_NOP) ) { - /* lump found */ - lump = crt; - crt = crt->next; - a=lump->before; - while(a) { - foo=a; a=a->before; - if (!(foo->flags&LUMPFLAG_SHMEM)) - free_lump(foo); - if (!(foo->flags&LUMPFLAG_SHMEM)) - pkg_free(foo); - } - - a=lump->after; - while(a) { - foo=a; a=a->after; - if (!(foo->flags&LUMPFLAG_SHMEM)) - free_lump(foo); - if (!(foo->flags&LUMPFLAG_SHMEM)) - pkg_free(foo); - } - if (lump == req->add_rm) { - if (lump->flags&LUMPFLAG_SHMEM) { - /* - * if the chunk is in shm, we cannot remove it, because - * it be in the middle of the big shm chunk - * therefore we simply mark it as false and move on - */ - if (lump->after) - insert_cond_lump_after(lump, COND_FALSE, 0); - if (lump->before) - insert_cond_lump_before(lump, COND_FALSE, 0); - } else { - req->add_rm = lump->next; - } - prev_crt = lump; - } else - prev_crt->next = lump->next; - if (!(lump->flags&LUMPFLAG_SHMEM)) - free_lump(lump); - if (!(lump->flags&LUMPFLAG_SHMEM)) - pkg_free(lump); - continue; - } - prev_crt = crt; - crt= crt->next; - } - - buf = req->buf; - - /* delete record-route headers */ - for (it=req->record_route;it;it=it->sibling) { - if (del_lump(req,it->name.s - buf,it->len, 0) == 0) { - LM_ERR("del_lump failed - while deleting record-route\n"); - return -1; - } - } - - return 0; -} - -static int topo_delete_vias(struct sip_msg* req) -{ - struct hdr_field *it; - char *buf; - - /* parse all headers to be sure that all VIAs are found */ - if (parse_headers(req, HDR_EOH_F, 0)< 0) { - LM_ERR("Failed to parse reply\n"); - return -1; - } - - buf = req->buf; - it = req->h_via1; - if(it) { - /* delete first via1 to set the type (the build_req_buf_from_sip_req will know not to add lump in via1)*/ - if (del_lump(req,it->name.s - buf,it->len, 0) == 0) { - LM_ERR("del_lump failed\n"); - return -1; - } - LM_DBG("Delete via [%.*s]\n", it->len, it->name.s); - for (it=it->sibling; it; it=it->sibling) { - if (del_lump(req,it->name.s - buf,it->len, 0) == 0) { - LM_ERR("del_lump failed\n"); - return -1; - } - LM_DBG("Delete via [%.*s]\n", it->len, it->name.s); - } - } - - return 0; -} - -static struct lump* delete_existing_contact(struct sip_msg *msg, int del_hdr) -{ - int offset; - int len; - struct lump* lump, *crt; - - offset = msg->contact->body.s - msg->buf; - len = msg->contact->body.len; - - for (crt = msg->add_rm; crt; crt = crt->next) { - if (crt->type == HDR_CONTACT_T && crt->op == LUMP_DEL && - crt->u.offset >= offset && crt->u.offset <= offset + len) { - /* - * we do not delete the lump because there might be pointers (such - * as contact->uri from the fix_nated_contact() function pointing - * to the lump's buffer; instead we simply replace the lump with a - * conditional false one - */ - /* mark DEL lump as NOP and add COND_FALSE for before and after */ - crt->op = LUMP_NOP; - - if (crt->after) - insert_cond_lump_after(crt, COND_FALSE, 0); - if (crt->before) - insert_cond_lump_before(crt, COND_FALSE, 0); - } - } - - if (del_hdr) { - /* we were asked to delete the entire header */ - offset = msg->contact->name.s - msg->buf; - len = msg->contact->len; - } else { - /* delete only the contact */ - offset = msg->contact->body.s - msg->buf; - len = msg->contact->body.len; - } - - if ((lump = del_lump(msg, offset, len, HDR_CONTACT_T)) == 0) { - LM_ERR("del_lump failed\n"); - return NULL; - } - - return lump; -} - -static inline int topo_ct_param_len(str *name, str *val, int should_quote) -{ - int len = 1 /* ; */ + name->len; - if (val->len) { - if (should_quote && should_quote_contact_param_value(val)) - len += 2; /* quotes */ - len += 1 /* = */ + val->len; - } - return len; -} - -static char * topo_ct_param_copy(char *buf, str *name, str *val, int should_quote) -{ - *buf++ = ';'; - memcpy(buf, name->s, name->len); - buf += name->len; - if (val->len) { - *buf++ = '='; - if (should_quote) - should_quote = should_quote_contact_param_value(val); - if (should_quote) - *buf++ = '"'; - memcpy(buf, val->s, val->len); - buf += val->len; - if (should_quote) - *buf++ = '"'; - } - return buf; -} - -static inline int topo_ct_short_len(int len, short *out, const char *field) -{ - if (len < 0 || len > SHRT_MAX) { - LM_ERR("%s too long for encoded contact (%d)\n", field, len); - return -1; - } - *out = (short)len; - return 0; -} - static int topo_dlg_replace_contact(struct sip_msg* msg, struct dlg_cell* dlg, int leg, str *ct_user) { @@ -643,384 +354,6 @@ static int topo_dlg_replace_contact(struct sip_msg* msg, struct dlg_cell* dlg, return -1; } -struct lump* restore_vias_from_req(struct sip_msg *req,struct sip_msg *rpl) -{ - struct lump* lmp; - struct hdr_field *it; - str via_str; - char *p,*buf = rpl->buf; - char *received_buf=0,*rport_buf=0; - unsigned int rport_len=0,received_len=0; - int size; - - lmp = anchor_lump(rpl,rpl->headers->name.s - buf,0); - if (lmp == 0) - { - LM_ERR("failed anchoring new lump\n"); - return NULL; - } - - if ((req->msg_flags&FL_FORCE_RPORT)||(req->via1->rport)) { - if ((received_buf=received_builder(req,&received_len))==0){ - LM_ERR("received_builder failed\n"); - return NULL; - } - - if ((rport_buf=rport_builder(req, &rport_len))==0){ - LM_ERR("rport_builder failed\n"); - return NULL; - } - - /* take care of via1 + rest of VIA headers in h_via1 */ - via_str.len = rport_len + received_len + req->h_via1->len; - LM_DBG("via len = %d\n",via_str.len); - if (req->via1->received) { - via_str.len -= req->via1->received->size+1; - LM_DBG(" have received will remove %d \n",req->via1->received->size+1); - } - if (req->via1->rport) { - via_str.len -= req->via1->rport->size+1; - LM_DBG(" have rport will remove %d \n",req->via1->rport->size+1); - } - - /* copy rest of VIA headers */ - it = req->h_via1->sibling; - while (it) { - via_str.len += it->len; - it = it->sibling; - } - - via_str.s = pkg_malloc(via_str.len); - if (!via_str.s) { - LM_ERR("No more pkg mem\n"); - goto err_free_rport; - } - - /* take care of via1 + rest of VIA headers in h_via1 */ - if (req->via1->params.s){ - size= req->via1->params.s-req->via1->hdr.s-1; /*compensate for ';' */ - }else{ - size= req->via1->host.s-req->via1->hdr.s+req->via1->host.len; - if (req->via1->port!=0){ - size += req->via1->port_str.len + 1; /* +1 for ':'*/ - } - } - - p = via_str.s; - memcpy(p,req->via1->hdr.s,size); - p += size; - memcpy(p,received_buf,received_len); - p += received_len; - memcpy(p,rport_buf,rport_len); - p += rport_len; - - int bytes_before = 0; - int bytes_after = 0; - int bytes_between = 0; - char *between = NULL; - char *after = NULL; - - if (req->via1->received) { - if (!req->via1->rport) { - bytes_before = req->via1->received->start-req->via1->hdr.s-size-1; - memcpy(p, - req->via1->hdr.s+size, - bytes_before); - p += bytes_before; - - bytes_after = req->h_via1->len - size - req->via1->received->size - - bytes_before - 1; - memcpy(p, - req->via1->received->start+req->via1->received->size, - bytes_after); - p += bytes_after; - } else { - /* we have both :( */ - if (req->via1->rport->start > req->via1->received->start) { - bytes_before = req->via1->received->start-req->via1->hdr.s-size-1; - bytes_between = req->via1->rport->start - req->via1->received->start - req->via1->received->size - 1; - between = req->via1->received->start + req->via1->received->size; - after = req->via1->rport->start+req->via1->rport->size; - - bytes_after = req->h_via1->len - size - req->via1->rport->size - - bytes_before - 1 - bytes_between - req->via1->received->size - 1; - LM_DBG("1 both , before = %d, between = %d, after = %d\n",bytes_before,bytes_between,bytes_after); - } else { - bytes_before = req->via1->rport->start-req->via1->hdr.s-size-1; - bytes_between = req->via1->received->start - req->via1->rport->start - req->via1->rport->size - 1; - between = req->via1->rport->start + req->via1->rport->size; - - after = req->via1->received->start+req->via1->received->size; - - bytes_after = req->h_via1->len - size - req->via1->rport->size - - bytes_before - 1 - bytes_between - req->via1->received->size -1 ; - LM_DBG("2 both , before = %d, between = %d, after = %d\n",bytes_before,bytes_between,bytes_after); - } - - memcpy(p, - req->via1->hdr.s+size, - bytes_before); - p += bytes_before; - - memcpy(p, - between, - bytes_between); - p += bytes_between; - - memcpy(p, - after, - bytes_after); - p += bytes_after; - } - } else if (req->via1->rport) { - if (!req->via1->received) { - bytes_before = req->via1->rport->start-req->via1->hdr.s-size-1; - memcpy(p, - req->via1->hdr.s+size, - bytes_before); - p += bytes_before; - - bytes_after = req->h_via1->len - size - req->via1->rport->size - - bytes_before - 1; - memcpy(p, - req->via1->rport->start+req->via1->rport->size, - bytes_after); - p += bytes_after; - } - } else { - /* no rport or received already present */ - memcpy(p,req->via1->hdr.s+size,req->h_via1->len-size); - p+= req->h_via1->len-size; - } - - /* copy rest of VIA headers */ - it = req->h_via1->sibling; - while (it) { - memcpy(p,it->name.s,it->len); - p+=it->len; - it = it->sibling; - } - - LM_DBG("built [%.*s], %d %d\n",(int)(p-via_str.s),via_str.s,(int)(p-via_str.s),via_str.len); - - if ((lmp = insert_new_lump_after(lmp, via_str.s, via_str.len, 0)) == 0) { - LM_ERR("failed inserting new old vias\n"); - pkg_free(via_str.s); - goto err_free_rport; - } - - pkg_free(rport_buf); - pkg_free(received_buf); - } else { - /* no need to add received/rport , just copy the headers altogether */ - it = req->h_via1; - via_str.len = 0; - - while (it) { - via_str.len += it->len; - it = it->sibling; - } - - LM_DBG("via len = %d\n",via_str.len); - - if (via_str.len == 0) - return lmp; - - via_str.s = pkg_malloc(via_str.len); - if (!via_str.s) { - LM_ERR("no more pkg mem\n"); - return NULL; - } - - LM_DBG("allocated via_str %p\n",via_str.s); - - it = req->h_via1; - p = via_str.s; - while (it) { - memcpy(p,it->name.s,it->len); - p+=it->len; - it = it->sibling; - } - - LM_DBG("inserting via headers - [%.*s]\n",via_str.len,via_str.s); - - if ((lmp = insert_new_lump_after(lmp, via_str.s, via_str.len, 0)) == 0) { - LM_ERR("failed inserting new old vias\n"); - pkg_free(via_str.s); - return NULL; - } - } - - return lmp; - -err_free_rport: - pkg_free(rport_buf); - pkg_free(received_buf); - return NULL; -} - -struct th_no_dlg_param { - str routes; - str username; -}; - - -#define RECORD_ROUTE "Record-Route: " -#define RECORD_ROUTE_LEN (sizeof(RECORD_ROUTE)-1) -static void _th_no_dlg_onreply(struct cell* t, int type, struct tmcb_params *param,int flags, int do_rr) -{ - struct lump* lmp; - str rr_set; - struct th_no_dlg_param *p = *(param->param); - struct sip_msg *req = param->req; - struct sip_msg *rpl = param->rpl; - char *route; - int size; - - /* parse all headers to be sure that all RR and Contact hdrs are found */ - if (parse_headers(rpl, HDR_EOH_F, 0)< 0) { - LM_ERR("Failed to parse reply\n"); - return; - } - - if (topo_delete_record_routes(rpl) < 0) { - LM_ERR("Failed to remove Record Route header \n"); - return; - } - - if(topo_delete_vias(rpl) < 0) { - LM_ERR("Failed to remove via headers\n"); - return; - } - - if ( !(rpl->REPLY_STATUS>=300 && rpl->REPLY_STATUS<400) ) { - if (topo_no_dlg_encode_contact(rpl,flags, - (p?&p->routes:NULL),(p?&p->username:NULL)) < 0) { - LM_ERR("Failed to encode contact header \n"); - return; - } - } - - if (!(lmp = restore_vias_from_req(req,rpl))) { - LM_ERR("Failed to restore VIA headers from request \n"); - return ; - } - - /* pass record route headers */ - if(do_rr && req->record_route){ - if(print_rr_body(req->record_route, &rr_set, 0, 1, NULL) != 0 ){ - LM_ERR("failed to print route records \n"); - return; - } - - size = rr_set.len + RECORD_ROUTE_LEN + CRLF_LEN; - route = pkg_malloc(size); - if (route == NULL) { - LM_ERR("no more pkg memory\n"); - pkg_free(rr_set.s); - return; - } - - memcpy(route, RECORD_ROUTE, RECORD_ROUTE_LEN); - memcpy(route+RECORD_ROUTE_LEN, rr_set.s, rr_set.len); - memcpy(route+RECORD_ROUTE_LEN+rr_set.len, CRLF, CRLF_LEN); - /* put after Via */ - if ((lmp = insert_new_lump_after(lmp, route, size, HDR_RECORDROUTE_T)) == 0) { - LM_ERR("failed inserting new route set\n"); - pkg_free(route); - pkg_free(rr_set.s); - return; - } - - LM_DBG("Added record route [%.*s]\n", size, route); - pkg_free(rr_set.s); - } - return; -} - -static void th_no_dlg_onreply(struct cell* t, int type, struct tmcb_params *param) -{ - _th_no_dlg_onreply(t,type,param,0,1); -} - -static void th_no_dlg_user_onreply(struct cell* t, int type, struct tmcb_params *param) -{ - _th_no_dlg_onreply(t,type,param,TOPOH_KEEP_USER,1); -} - -static void th_no_dlg_onreply_within(struct cell* t, int type, struct tmcb_params *param) -{ - _th_no_dlg_onreply(t,type,param,0,0); -} - -static void th_no_dlg_user_onreply_within(struct cell* t, int type, struct tmcb_params *param) -{ - _th_no_dlg_onreply(t,type,param,TOPOH_KEEP_USER,0); -} - -static void shm_free_wrap(void *param) -{ - if (param) - shm_free(param); -} - -static int topo_hiding_no_dlg(struct sip_msg *req, - struct cell* t,int extra_flags,struct th_params *params) -{ - transaction_cb* used_cb; - struct th_no_dlg_param *p = NULL; - - /* parse all headers to be sure that all RR and Contact hdrs are found */ - if (parse_headers(req, HDR_EOH_F, 0)< 0) { - LM_ERR("Failed to parse reply\n"); - return -1; - } - - if (topo_delete_record_routes(req) < 0) { - LM_ERR("Failed to remove Record Route header \n"); - return -1; - } - - if(topo_delete_vias(req) < 0) { - LM_ERR("Failed to remove via headers\n"); - return -1; - } - - if (topo_no_dlg_encode_contact(req,extra_flags,NULL, ¶ms->ct_caller_user) < 0) { - LM_ERR("Failed to encode contact header \n"); - return -1; - } - - if (extra_flags & TOPOH_KEEP_USER) { - used_cb = th_no_dlg_user_onreply; - } else { - used_cb = th_no_dlg_onreply; - if (params && params->ct_callee_user.len) { - p = shm_malloc(sizeof *p + params->ct_callee_user.len); - if (p) { - memset(p, 0, sizeof *p); - p->username.s = (char *)(p + 1); - p->username.len = params->ct_callee_user.len; - memcpy(p->username.s, params->ct_callee_user.s, - params->ct_callee_user.len); - } - } - } - - if (extra_flags & TOPOH_HIDE_CALLID) - LM_WARN("Cannot hide callid when dialog support is not engaged!\n"); - if (extra_flags & TOPOH_DID_IN_USER) - LM_WARN("Cannot store DID in user when dialog support is not engaged!\n"); - - if (tm_api.register_tmcb( req, 0, TMCB_RESPONSE_FWDED, - used_cb,p, (p?shm_free_wrap:NULL))<0 ) { - LM_ERR("failed to register TMCB\n"); - return -1; - } - - return 1; -} - static struct th_params *th_params_dup(struct th_params *params) { struct th_params *ret; @@ -1755,607 +1088,3 @@ int topo_callid_post_raw(str *data, struct sip_msg* foo) free_sip_msg(&msg); return -1; } - -/* We encode the RR headers, the actual Contact and the socket str for this leg */ -/* Via headers will be restored using the TM module, no need to save anything for them */ -static char* build_encoded_contact_suffix(struct sip_msg* msg, str *routes, int *suffix_len, int flags) -{ - short rr_len,ct_len,addr_len,flags_len; - char *suffix_plain,*suffix_enc,*p,*s; - str rr_set = {NULL, 0}; - str contact; - str flags_str; - int i,total_len,enc_len; - struct sip_uri ctu; - struct th_ct_params* el; - param_t *it; - int free_rr_set = 0; - int is_req = (msg->first_line.type==SIP_REQUEST)?1:0; - int local_len = sizeof(short) /* RR length */ + - sizeof(short) /* Contact length */ + - sizeof(short) /* Flags length */ + - sizeof(short) /* bind addr */; - - /* parse all headers as we can have multiple - RR headers in the same message */ - if( parse_headers(msg,HDR_EOH_F,0)<0 ){ - LM_ERR("failed to parse all headers\n"); - return NULL; - } - - if (routes && routes->len) { - rr_set = *routes; - if (topo_ct_short_len(routes->len, &rr_len, "route set") < 0) - return NULL; - } else if(msg->record_route){ - if(print_rr_body(msg->record_route, &rr_set, !is_req, 0, NULL) != 0){ - LM_ERR("failed to print route records \n"); - return NULL; - } - free_rr_set = 1; - if (topo_ct_short_len(rr_set.len, &rr_len, "route set") < 0) - goto error; - } else { - rr_len = 0; - } - - if ( parse_contact(msg->contact)<0 || - ((contact_body_t *)msg->contact->parsed)->contacts==NULL || - ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { - LM_ERR("bad Contact HDR\n"); - goto error; - } else { - contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri; - if (topo_ct_short_len(contact.len, &ct_len, "contact") < 0) - goto error; - } - - flags_str.s = int2str(flags, &flags_str.len); - if (topo_ct_short_len(flags_str.len, &flags_len, "flags") < 0) - goto error; - - if (topo_ct_short_len(msg->rcv.bind_address->sock_str.len, - &addr_len, "bind address") < 0) - goto error; - local_len += rr_len + ct_len + flags_len + addr_len; - enc_len = th_ct_enc_scheme == ENC_BASE64 ? - calc_word64_encode_len(local_len) : calc_word32_encode_len(local_len); - total_len = enc_len + - 1 /* ; */ + - th_contact_encode_param.len + - 1 /* = */ + - 1 /* > */; - - if (th_param_list) { - if ( parse_contact(msg->contact)<0 || - ((contact_body_t *)msg->contact->parsed)->contacts==NULL || - ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { - LM_ERR("bad Contact HDR\n"); - } else { - contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri; - if(parse_uri(contact.s, contact.len, &ctu) < 0) { - LM_ERR("Bad Contact URI\n"); - } else { - for (el=th_param_list;el;el=el->next) { - /* we just iterate over the unknown params */ - for (i=0;iparam_name, &ctu.u_name[i])) - total_len += topo_ct_param_len(&ctu.u_name[i], &ctu.u_val[i], 0); - } - } - } - } - } - - if (th_hdr_param_list) { - if ( parse_contact(msg->contact)<0 || - ((contact_body_t *)msg->contact->parsed)->contacts==NULL || - ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { - LM_ERR("bad Contact HDR\n"); - } else { - for (el=th_hdr_param_list;el;el=el->next) { - for (it=((contact_body_t *)msg->contact->parsed)->contacts->params;it;it=it->next) { - if (str_match(&el->param_name, &it->name)) - total_len += topo_ct_param_len(&it->name, &it->body, 1); - } - } - } - } - - suffix_enc = pkg_malloc(total_len+1); - if (!suffix_enc) { - LM_ERR("no more pkg\n"); - goto error; - } - suffix_plain = pkg_malloc(local_len+1); - if (!suffix_plain) { - LM_ERR("no more pkg\n"); - goto error; - } - - p = suffix_plain; - memcpy(p,&rr_len,sizeof(short)); - p+= sizeof(short); - if (rr_len) { - memcpy(p,rr_set.s,rr_set.len); - p+= rr_set.len; - } - memcpy(p,&ct_len,sizeof(short)); - p+= sizeof(short); - if (ct_len) { - memcpy(p,contact.s,contact.len); - p+= contact.len; - } - memcpy(p,&flags_len,sizeof(short)); - p+= sizeof(short); - memcpy(p,flags_str.s, flags_str.len); - p+= flags_str.len; - memcpy(p,&addr_len,sizeof(short)); - p+= sizeof(short); - memcpy(p,msg->rcv.bind_address->sock_str.s,msg->rcv.bind_address->sock_str.len); - p+= msg->rcv.bind_address->sock_str.len; - for (i=0;i<(int)(p-suffix_plain);i++) - suffix_plain[i] ^= topo_hiding_ct_encode_pw.s[i%topo_hiding_ct_encode_pw.len]; - - s = suffix_enc; - *s++ = ';'; - memcpy(s,th_contact_encode_param.s,th_contact_encode_param.len); - s+= th_contact_encode_param.len; - *s++ = '='; - if (th_ct_enc_scheme == ENC_BASE64) - word64encode((unsigned char*)s,(unsigned char *)suffix_plain,p-suffix_plain); - else - word32encode((unsigned char*)s,(unsigned char *)suffix_plain,p-suffix_plain); - s = s+enc_len; - - if (th_param_list) { - for (el=th_param_list;el;el=el->next) { - /* we just iterate over the unknown params */ - for (i=0;iparam_name, &ctu.u_name[i])) - s = topo_ct_param_copy(s, &ctu.u_name[i], &ctu.u_val[i], 0); - } - } - } - *s++ = '>'; - if (th_hdr_param_list) { - if ( parse_contact(msg->contact)<0 || - ((contact_body_t *)msg->contact->parsed)->contacts==NULL || - ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { - LM_ERR("bad Contact HDR\n"); - } else { - for (el=th_hdr_param_list;el;el=el->next) { - for (it=((contact_body_t *)msg->contact->parsed)->contacts->params;it;it=it->next) { - if (str_match(&el->param_name, &it->name)) - s = topo_ct_param_copy(s, &it->name, &it->body, 1); - } - } - } - } - - if (rr_set.s && free_rr_set) - pkg_free(rr_set.s); - pkg_free(suffix_plain); - *suffix_len = total_len; - return suffix_enc; -error: - if (rr_set.s && free_rr_set) - pkg_free(rr_set.s); - return NULL; -} - -static int topo_no_dlg_encode_contact(struct sip_msg *msg,int flags, str *routes, str *ct_user) -{ - struct lump* lump; - char *prefix=NULL,*suffix=NULL,*ct_username=NULL; - int prefix_len,suffix_len,ct_username_len=0; - struct sip_uri ctu; - str contact; - - if(!msg->contact) { - if(parse_headers(msg, HDR_CONTACT_F, 0)< 0) { - LM_ERR("Failed to parse headers\n"); - return -1; - } - if(!msg->contact) - return 0; - } - - if (!(lump = delete_existing_contact(msg, 0))) { - LM_ERR("Failed to delete existing contact \n"); - goto error; - } - - LM_DBG("Flags '%d' passed for encoding Contact\n", flags); - - prefix_len = 5; /* len) { - ct_username = ct_user->s; - ct_username_len = ct_user->len; - prefix_len += 1 + /* @ */ + ct_username_len; - } else if (flags & TOPOH_KEEP_USER) { - if ( parse_contact(msg->contact)<0 || - ((contact_body_t *)msg->contact->parsed)->contacts==NULL || - ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { - LM_ERR("bad Contact HDR\n"); - } else { - contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri; - if(parse_uri(contact.s, contact.len, &ctu) < 0) { - LM_ERR("Bad Contact URI\n"); - } else { - ct_username = ctu.user.s; - ct_username_len = ctu.user.len; - LM_DBG("Trying to propagate username [%.*s]\n",ct_username_len, - ct_username); - if (ct_username_len > 0) - prefix_len += 1 + /* @ */ + ct_username_len; - } - } - } - - prefix = pkg_malloc(prefix_len); - if (!prefix) { - LM_ERR("no more pkg\n"); - goto error; - } - memcpy(prefix," 0) { - memcpy(prefix+5,ct_username,ct_username_len); - prefix[prefix_len-1] = '@'; - } - - if (!(lump = insert_new_lump_after(lump,prefix,prefix_len,0))) { - LM_ERR("failed inserting '\r\n" -#define ROUTE_SUFF_LEN (sizeof(ROUTE_SUFF) -1) - -static int topo_no_dlg_seq_handling(struct sip_msg *msg,str *info) -{ - int max_size,dec_len,i,size,flags; - char *dec_buf,*p,*route=NULL,*hdrs,*remote_contact; - struct hdr_field *it; - str rr_buf,ct_buf,flags_buf,bind_buf; - rr_t *head = NULL, *rrp; - int next_strict=0; - struct sip_uri fru; - char* buf = msg->buf; - struct lump* lmp = NULL; - str host; - int port,proto; - const struct socket_info *sock; - str route_buf = {0, 0}; - struct th_no_dlg_param *param = NULL; - transaction_cb* used_cb; - - /* parse all headers to be sure that all RR and Contact hdrs are found */ - if (parse_headers(msg, HDR_EOH_F, 0)< 0) { - LM_ERR("Failed to parse reply\n"); - return -1; - } - - /* delete vias */ - if(topo_delete_vias(msg) < 0) { - LM_ERR("Failed to remove via headers\n"); - return -1; - } - - /* delete record route */ - for (it=msg->record_route;it;it=it->sibling) { - if (del_lump(msg, it->name.s - buf, it->len, 0) == 0) { - LM_ERR("del_lump failed\n"); - return -1; - } - } - - max_size = th_ct_enc_scheme == ENC_BASE64 ? - calc_max_word64_decode_len(info->len) : - calc_max_word32_decode_len(info->len); - dec_buf = pkg_malloc(max_size); - if (dec_buf==NULL) { - LM_ERR("No more pkg\n"); - return -1; - } - - if (th_ct_enc_scheme == ENC_BASE64) - dec_len = word64decode((unsigned char *)dec_buf, - (unsigned char *)info->s,info->len); - else - dec_len = word32decode((unsigned char *)dec_buf, - (unsigned char *)info->s,info->len); - for (i=0;i_len) {\ - LM_ERR("bad length %d in encoded contact\n", (_s).len);\ - goto err_free_buf;\ - }\ - (_s).s = _p + sizeof(short);\ - _p += sizeof(short) + (_s).len;\ - _len -= sizeof(short) + (_s).len;\ - } while(0) - - p = dec_buf; - size = dec_len; - __extract_len_and_buf(p, size, rr_buf); - __extract_len_and_buf(p, size, ct_buf); - __extract_len_and_buf(p, size, flags_buf); - __extract_len_and_buf(p, size, bind_buf); - - LM_DBG("extracted routes [%.*s] , ct [%.*s] , flags [%.*s] and bind [%.*s]\n", - rr_buf.len,rr_buf.s,ct_buf.len,ct_buf.s,flags_buf.len,flags_buf.s,bind_buf.len,bind_buf.s); - - if (rr_buf.len) { - if (parse_rr_body(rr_buf.s,rr_buf.len,&head) != 0) { - LM_ERR("failed parsing route set\n"); - goto err_free_buf; - } - - if(parse_uri(head->nameaddr.uri.s, head->nameaddr.uri.len, &fru) < 0) { - LM_ERR("Failed to parse SIP uri\n"); - goto err_free_head; - } - if(is_strict(&fru.params)) - next_strict = 1; - } - - if (msg->dst_uri.s && msg->dst_uri.len) { - /* reset dst_uri if previously set - * either by loose route or manually */ - pkg_free(msg->dst_uri.s); - msg->dst_uri.s = NULL; - msg->dst_uri.len = 0; - } - - if (!next_strict) { - LM_DBG("Fixing message. Next hop is Loose router\n"); - if (ct_buf.len && ct_buf.s) { - LM_DBG("Setting new URI to <%.*s> \n",ct_buf.len, - ct_buf.s); - - if (set_ruri(msg,&ct_buf) != 0) { - LM_ERR("failed setting ruri\n"); - goto err_free_head; - } - } - if( parse_headers( msg, HDR_EOH_F, 0)<0 ) { - LM_ERR("failed to parse headers when looking after ROUTEs\n"); - goto err_free_head; - } - - if (msg->route) { - for (it=msg->route;it;it=it->sibling) { - if (it->parsed && ((rr_t*)it->parsed)->deleted) - continue; - if ((lmp = del_lump(msg,it->name.s - buf,it->len,HDR_ROUTE_T)) == 0) { - LM_ERR("del_lump failed \n"); - goto err_free_head; - } - } - } - - if ( rr_buf.len !=0 && rr_buf.s) { - - lmp = anchor_lump(msg,msg->headers->name.s - buf,0); - if (lmp == 0) { - LM_ERR("failed anchoring new lump\n"); - goto err_free_head; - } - - size = rr_buf.len + ROUTE_LEN + CRLF_LEN; - route = pkg_malloc(size+1); - if (route == 0) { - LM_ERR("no more pkg memory\n"); - goto err_free_head; - } - - memcpy(route,ROUTE_STR,ROUTE_LEN); - memcpy(route+ROUTE_LEN,rr_buf.s,rr_buf.len); - memcpy(route+ROUTE_LEN+rr_buf.len,CRLF,CRLF_LEN); - - route[size] = 0; - - if ((lmp = insert_new_lump_after(lmp,route,size,HDR_ROUTE_T)) == 0) { - LM_ERR("failed inserting new route set\n"); - goto err_free_route; - } - msg->msg_flags |= FL_HAS_ROUTE_LUMP; - route_buf = rr_buf; - - LM_DBG("Setting route header to <%s> \n",route); - LM_DBG("setting dst_uri to <%.*s> \n",head->nameaddr.uri.len, - head->nameaddr.uri.s); - - if (set_dst_uri(msg,&head->nameaddr.uri) !=0 ) { - goto err_free_head; - } - } - } else { - LM_DBG("Fixing message. Next hop is Strict router\n"); - if (msg->route) { - for (it=msg->route;it;it=it->sibling) { - if (it->parsed && ((rr_t*)it->parsed)->deleted) - continue; - if ((lmp = del_lump(msg,it->name.s - buf,it->len,HDR_ROUTE_T)) == 0) { - LM_ERR("del_lump failed \n"); - goto err_free_head; - } - } - } - - if ( rr_buf.len !=0 && rr_buf.s) { - if (set_ruri(msg,&head->nameaddr.uri) !=0 ) { - LM_ERR("failed setting new dst uri\n"); - goto err_free_head; - } - i=0; - rrp = head; - while (rrp) { - i++; - rrp=rrp->next; - } - - /* If there are more routes other than the first, add them */ - if (i > 1) { - lmp = anchor_lump(msg,msg->headers->name.s - buf,0); - if (lmp == 0) { - LM_ERR("failed anchoring new lump\n"); - goto err_free_head; - } - - hdrs = rr_buf.s + head->len + 1; - - size = rr_buf.len - head->len - 1 + ROUTE_LEN + CRLF_LEN; - route = pkg_malloc(size); - if (route == 0) { - LM_ERR("no more pkg memory\n"); - goto err_free_head; - } - - memcpy(route,ROUTE_STR,ROUTE_LEN); - memcpy(route+ROUTE_LEN,hdrs,rr_buf.len - head->len-1); - memcpy(route+ROUTE_LEN+rr_buf.len - head->len-1,CRLF,CRLF_LEN); - - LM_DBG("Adding Route header : [%.*s] \n",size,route); - - if ((lmp = insert_new_lump_after(lmp,route,size,HDR_ROUTE_T)) == 0) { - LM_ERR("failed inserting new route set\n"); - goto err_free_route; - } - msg->msg_flags |= FL_HAS_ROUTE_LUMP; - route_buf.s = route; - route_buf.len = rr_buf.len - head->len - 1; - } - - if (lmp == NULL) { - lmp = anchor_lump(msg,msg->headers->name.s - buf,0); - if (lmp == 0) - { - LM_ERR("failed anchoring new lump\n"); - return -1; - } - } - - if (ct_buf.len && ct_buf.s) { - size = ct_buf.len + ROUTE_PREF_LEN + ROUTE_SUFF_LEN; - remote_contact = pkg_malloc(size); - if (remote_contact == NULL) { - LM_ERR("no more pkg \n"); - goto err_free_head; - } - - memcpy(remote_contact,ROUTE_PREF,ROUTE_PREF_LEN); - memcpy(remote_contact+ROUTE_PREF_LEN,ct_buf.s,ct_buf.len); - memcpy(remote_contact+ROUTE_PREF_LEN+ct_buf.len, - ROUTE_SUFF,ROUTE_SUFF_LEN); - - LM_DBG("Adding remote contact route header : [%.*s]\n", - size,remote_contact); - - if (insert_new_lump_after(lmp,remote_contact,size,HDR_ROUTE_T) == 0) { - LM_ERR("failed inserting remote contact route\n"); - pkg_free(remote_contact); - goto err_free_head; - } - msg->msg_flags |= FL_HAS_ROUTE_LUMP; - } - } - } - if (route_buf.s && route_buf.len) { - param = shm_malloc(sizeof *param + route_buf.len); - if (param) { - memset(param, 0, sizeof *param); - param->routes.s = (char *)(param + 1); - param->routes.len = route_buf.len; - memcpy(param->routes.s, route_buf.s, route_buf.len); - } - } - - if (flags_buf.len && flags_buf.s) { - if (str2int(&flags_buf, (unsigned int*) &flags) < 0) { - LM_WARN("Failed to convert string to integer, default to no flags\n"); - flags = 0; - } - } else { - flags = 0; - } - - if (flags & TOPOH_KEEP_USER) - used_cb = th_no_dlg_user_onreply_within; - else - used_cb = th_no_dlg_onreply_within; - - /* register tm callback for response in */ - if (tm_api.register_tmcb( msg, 0, TMCB_RESPONSE_FWDED, - used_cb,param,(param?shm_free_wrap:NULL))<0 ) { - LM_ERR("failed to register TMCB\n"); - } - - if (bind_buf.len && bind_buf.s) { - LM_DBG("forcing send socket for req to [%.*s]\n",bind_buf.len,bind_buf.s); - if (parse_phostport( bind_buf.s, bind_buf.len, &host.s, &host.len, - &port, &proto)!=0) { - LM_ERR("bad socket <%.*s>\n", bind_buf.len, bind_buf.s); - } else { - sock = grep_sock_info( &host, (unsigned short)port, proto); - if (!sock) { - LM_WARN("non-local socket <%.*s>...ignoring\n", bind_buf.len, bind_buf.s); - } - msg->force_send_socket = sock; - } - } - - if (rr_buf.len) - free_rr(&head); - pkg_free(dec_buf); - - if (topo_no_dlg_encode_contact(msg,flags,NULL,NULL) < 0) { - LM_ERR("Failed to encode contact header \n"); - return -1; - } - - return 1; - -err_free_route: - if (route) - pkg_free(route); -err_free_head: - if (rr_buf.len) - free_rr(&head); -err_free_buf: - pkg_free(dec_buf); - return -1; -} diff --git a/modules/topology_hiding/topo_hiding_logic.h b/modules/topology_hiding/topo_hiding_logic.h index b26252c79e9..6f9dbf72e0f 100644 --- a/modules/topology_hiding/topo_hiding_logic.h +++ b/modules/topology_hiding/topo_hiding_logic.h @@ -40,21 +40,15 @@ #include "../rr/api.h" #include "../dialog/dlg_load.h" -struct th_params { - str ct_caller_user; - str ct_callee_user; -}; +#include "th_common_logic.h" extern str th_contact_caller_var; extern str th_contact_callee_var; enum encode_scheme {ENC_BASE64, ENC_BASE32}; -int topo_parse_passed_ct_params(str *params); -int topo_parse_passed_hdr_ct_params(str *params); int topology_hiding(struct sip_msg *req,int extra_flags, struct th_params *params); int topo_callid_pre_raw(str *data, struct sip_msg* req); int topo_callid_post_raw(str *data, struct sip_msg* req); -int topology_hiding_match(struct sip_msg *req); void th_loaded_callback(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params); char *th_get_encoded_callid(struct sip_msg *msg, str *tag, int *enc_len); diff --git a/modules/topology_hiding/topology_hiding.c b/modules/topology_hiding/topology_hiding.c index 5a540fc7c14..c5dcf84d42b 100644 --- a/modules/topology_hiding/topology_hiding.c +++ b/modules/topology_hiding/topology_hiding.c @@ -29,6 +29,7 @@ #include "topo_hiding_logic.h" +#include "th_common_logic.h" struct tm_binds tm_api; struct dlg_binds dlg_api; From 44b86215d8bc06137e4e7a44ad549f645576d21b Mon Sep 17 00:00:00 2001 From: David Trihy Date: Mon, 27 Apr 2026 13:37:19 +0300 Subject: [PATCH 2/8] thinfo compact binary codec --- modules/topology_hiding/thinfo_codec.c | 657 +++++++++++++++++++++++++ modules/topology_hiding/thinfo_codec.h | 254 ++++++++++ 2 files changed, 911 insertions(+) create mode 100644 modules/topology_hiding/thinfo_codec.c create mode 100644 modules/topology_hiding/thinfo_codec.h diff --git a/modules/topology_hiding/thinfo_codec.c b/modules/topology_hiding/thinfo_codec.c new file mode 100644 index 00000000000..0537aa6a66f --- /dev/null +++ b/modules/topology_hiding/thinfo_codec.c @@ -0,0 +1,657 @@ +#include + +#include "thinfo_codec.h" + +#include "../../parser/msg_parser.h" +#include "../../socket_info.h" + +#define SCHEME_MASK 0x0007 +#define SCHEME_SIP 0x0000 +#define SCHEME_SIPS 0x0001 +#define SCHEME_TEL 0x0002 +#define SCHEME_TELS 0x0003 +#define SCHEME_URN_S 0x0004 +#define SCHEME_URN_N 0x0005 +#define SCHEME_M1 0x0006 // Magic bit 1 - must be 0 (invalid/garbage detection) +#define SCHEME_M2 0x0007 // Magic bit 2 - must be 0 (invalid/garbage detection) + +#define TRANSPORT_MASK 0x0038 +#define TRANSPORT_UDP 0x0000 +#define TRANSPORT_TCP 0x0008 +#define TRANSPORT_TLS 0x0010 +#define TRANSPORT_SCTP 0x0018 +#define TRANSPORT_WS 0x0020 +#define TRANSPORT_WSS 0x0028 +#define TRANSPORT_M1 0x0030 // Magic bit 1 - must be 0 (invalid/garbage detection) +#define TRANSPORT_M2 0x0038 // Magic bit 2 - must be 0 (invalid/garbage detection) + +#define DOMAIN_MASK 0x00C0 +#define DOMAIN_IPV4 0x0000 +#define DOMAIN_IPV6 0x0040 +#define DOMAIN_FQDN 0x0080 +#define DOMAIN_M1 0x00C0 // Magic bit - must be 0 (invalid/garbage detection) + +#define HAS_USERNAME 0x0100 +#define HAS_PASSWORD 0x0200 +#define HAS_PORT 0x0400 +#define HAS_PARAMS 0x0800 // Now means "has OTHER params" (not lr/r2) +#define HAS_HEADERS 0x1000 +#define HAS_LR 0x2000 // lr or lr=on present +#define IS_DUAL_URI 0x4000 // Dual URI encoding flag +#define RESERVED_BIT 0x8000 // Reserved for future use + +#define SOCKET_PROTO_MASK 0x07 // 3 bits for protocol (bits 0-2) +#define SOCKET_IP_MASK 0x18 // 2 bits for IP type (bits 3-4) +#define SOCKET_IPV4 0x00 +#define SOCKET_IPV6 0x08 +#define SOCKET_HAS_PORT 0x20 // Bit 5: port is present + + +// URI2 properties byte (1 byte following URI1 data) +#define URI2_SCHEME_MASK 0x07 // Bits 0-2: scheme for URI2 +#define URI2_TRANSPORT_MASK 0x38 // Bits 3-5: transport for URI2 +#define URI2_TRANSPORT_SHIFT 3 +#define URI2_HAS_PORT 0x40 // Bit 6: URI2 has port +#define URI2_HAS_R2 0x80 // Bit 7: r2 flag for both URIs in dual encoding + +static str r2_on_uri_param = str_init("r2=on"); +static str lr_uri_param = str_init("lr"); +static str lr_on_uri_param = str_init("lr=on"); +static str transport_uri_param = str_init("transport"); + +#define MAX_THINFO_BUFFER_SIZE 4096 + +static const uint8_t SCHEMES[] = { + [ERROR_URI_T] = 0, + [SIP_URI_T] = SCHEME_SIP, + [SIPS_URI_T] = SCHEME_SIPS, + [TEL_URI_T] = SCHEME_TEL, + [TELS_URI_T] = SCHEME_TELS, + [URN_SERVICE_URI_T] = SCHEME_URN_N, + [URN_NENA_SERVICE_URI_T] = SCHEME_URN_S +}; + +static const enum _uri_type SCHEME_TO_ENUM[] = { + [SCHEME_SIP] = SIP_URI_T, + [SCHEME_SIPS] = SIPS_URI_T, + [SCHEME_TEL] = TEL_URI_T, + [SCHEME_TELS] = TELS_URI_T, + [SCHEME_URN_N] = URN_SERVICE_URI_T, + [SCHEME_URN_S] = URN_NENA_SERVICE_URI_T +}; + +static const str SCHEME_STRINGS[] = { + [SCHEME_SIP] = str_init("sip"), + [SCHEME_SIPS] = str_init("sips"), + [SCHEME_TEL] = str_init("tel"), + [SCHEME_TELS] = str_init("tels"), + [SCHEME_URN_N] = str_init("urn:service"), + [SCHEME_URN_S] = str_init("urn:nena:service") +}; + +static const uint8_t TRANSPORTS[] = { + [PROTO_NONE] = 0, + [PROTO_UDP] = TRANSPORT_UDP, + [PROTO_TCP] = TRANSPORT_TCP, + [PROTO_TLS] = TRANSPORT_TLS, + [PROTO_SCTP] = TRANSPORT_SCTP, + [PROTO_WS] = TRANSPORT_WS, + [PROTO_WSS] = TRANSPORT_WSS +}; + +static const enum sip_protos TRANSPORT_TO_ENUM[] = { + [TRANSPORT_UDP] = PROTO_UDP, + [TRANSPORT_TCP] = PROTO_TCP, + [TRANSPORT_TLS] = PROTO_TLS, + [TRANSPORT_SCTP] = PROTO_SCTP, + [TRANSPORT_WS] = PROTO_WS, + [TRANSPORT_WSS] = PROTO_WSS +}; + +static const char *TRANSPORT_STRINGS[] = { + [TRANSPORT_UDP] = "transport=udp", + [TRANSPORT_TCP] = "transport=tcp", + [TRANSPORT_TLS] = "transport=tls", + [TRANSPORT_SCTP] = "transport=sctp", + [TRANSPORT_WS] = "transport=ws", + [TRANSPORT_WSS] = "transport=wss" +}; + +static str dual_uri_skip_params[] = { + str_init("r2") +}; + +static int dual_uri_skip_params_count = sizeof(dual_uri_skip_params) / sizeof(dual_uri_skip_params[0]); + +static uint8_t encode_params(unsigned char *p, uint16_t *uri_properties, str *params, int param_count, str params_to_skip[static param_count]) { + char *src, *end; + int remaining, param_len_current; + uint8_t param_len = 0; + int skip_encode = 0; + + if (!params || params->len == 0 || params->len > UINT8_MAX) { + return 0; + } + + src = params->s; + remaining = params->len; + + if (remaining > 0 && *src == ';') { + src++; + remaining--; + } + + while (remaining > 0) { + if (*src == ';') { + src++; + remaining--; + if (remaining == 0) break; + } + + skip_encode = 0; + end = memchr(src, ';', remaining); + param_len_current = end ? (end - src) : remaining; + + for (int i = 0; i < param_count; i++) { + LM_DBG("Checking param [%.*s]\n", params_to_skip[i].len, params_to_skip[i].s); + if (param_len_current >= params_to_skip[i].len && strncmp(src, params_to_skip[i].s, params_to_skip[i].len) == 0) { + if ((param_len_current == lr_uri_param.len && memcmp(src, lr_uri_param.s, lr_uri_param.len) == 0) || + (param_len_current == lr_on_uri_param.len && memcmp(src, lr_on_uri_param.s, lr_on_uri_param.len) == 0)) { + *uri_properties |= HAS_LR; + } + + src += param_len_current; + remaining -= param_len_current; + skip_encode = 1; + break; + } + } + + if (skip_encode) { + continue; + } + + if (param_len > 0) { + *p++ = ';'; + param_len++; + } + memcpy(p, src, param_len_current); + p += param_len_current; + param_len += param_len_current; + + src += param_len_current; + remaining -= param_len_current; + } + + return param_len; +} + +#define ENCODE_URI_FIELD(_uri, _field, _flag_expr, _props, _p) \ + do { \ + if ((_uri)->_field.len > 0 && (_uri)->_field.len <= UINT8_MAX) { \ + (_props) = (_flag_expr); \ + *(_p)++ = (uint8_t)(_uri)->_field.len; \ + memcpy((_p), (_uri)->_field.s, (_uri)->_field.len); \ + (_p) += (_uri)->_field.len; \ + } else if ((_uri)->_field.len > UINT8_MAX) { \ + LM_WARN("URI " #_field " length '%d' larger than 255\n", (_uri)->_field.len); \ + } \ + } while(0) + +static int encode_uris(thinfo_encoded_t *thinfo, struct sip_uri *uri1, struct sip_uri *uri2, int param_count, str *params_to_skip, int encode_user) { + unsigned char *p, *props_ptr, *param_len_ptr, *uri2_props_ptr; + uint16_t props = 0; + uint8_t uri2_props; + char tmp[256]; + uint8_t param_len; + size_t start_pos; + str extra_params[param_count + 2]; + int extra_param_count = param_count; + + if (thinfo->len + MAX_ENCODED_URI_SIZE * 2 > MAX_THINFO_BUFFER_SIZE) { + return -1; + } + + if (thinfo->len == 0) { + p = thinfo->buf + 3; + thinfo->len = 3; + thinfo->pos = 0; + } else { + p = thinfo->buf + thinfo->len; + } + + start_pos = p - thinfo->buf; + + if (uri2 != NULL) { + props = IS_DUAL_URI; + } + + props_ptr = p; + p += 2; + props |= SCHEMES[uri1->type]; + if (uri1->proto >= PROTO_UDP && uri1->proto <= PROTO_WSS) { + props = (props & ~TRANSPORT_MASK) | TRANSPORTS[uri1->proto]; + } else { + props = (props & ~TRANSPORT_MASK) | TRANSPORTS[PROTO_UDP]; + } + + if (encode_user) { + ENCODE_URI_FIELD(uri1, user, props | HAS_USERNAME, props, p); + ENCODE_URI_FIELD(uri1, passwd, props | HAS_PASSWORD, props, p); + } + + if (uri1->host.len > 0 && uri1->host.len < sizeof(tmp)) { + memcpy(tmp, uri1->host.s, uri1->host.len); + tmp[uri1->host.len] = '\0'; + + if (inet_pton(AF_INET, tmp, p) == 1) { + props = (props & ~DOMAIN_MASK) | DOMAIN_IPV4; + p += 4; + } else if (inet_pton(AF_INET6, tmp, p) == 1) { + props = (props & ~DOMAIN_MASK) | DOMAIN_IPV6; + p += 16; + } else if (uri1->host.len <= UINT8_MAX) { + ENCODE_URI_FIELD(uri1, host, (props & ~DOMAIN_MASK) | DOMAIN_FQDN, props, p); + } else { + return -1; + } + } else { + return -1; + } + + if (uri1->port_no > 0) { + props |= HAS_PORT; + *p++ = (uri1->port_no >> 8) & 0xFF; + *p++ = uri1->port_no & 0xFF; + } + + if (uri2 != NULL) { + uri2_props = 0; + uri2_props_ptr = p; + p += 1; + + uri2_props |= SCHEMES[uri2->type] & URI2_SCHEME_MASK; + if (uri2->proto >= PROTO_UDP && uri2->proto <= PROTO_WSS) { + // TRANSPORTS values are already in bits 3-5 format (0x00, 0x08, 0x10, 0x18, 0x20, 0x28) + // Just mask to fit in URI2 byte + uri2_props |= TRANSPORTS[uri2->proto] & URI2_TRANSPORT_MASK; + } + + if (uri2->port_no > 0) { + uri2_props |= URI2_HAS_PORT; + *p++ = (uri2->port_no >> 8) & 0xFF; + *p++ = uri2->port_no & 0xFF; + } + uri2_props |= URI2_HAS_R2; + *uri2_props_ptr = uri2_props; + } + + if (uri1->params.len > 0 && uri1->params.len <= UINT8_MAX) { + if (params_to_skip != NULL && param_count > 0) { + memcpy(extra_params, params_to_skip, param_count * sizeof(params_to_skip[0])); + } else if (params_to_skip == NULL && param_count > 0) { + LM_WARN("params_to_skip is null but param_count is greater than 0\n"); + extra_param_count = 0; + } + + extra_params[extra_param_count++] = transport_uri_param; + extra_params[extra_param_count++] = lr_uri_param; + + param_len_ptr = p++; + param_len = encode_params(p, &props, &uri1->params, extra_param_count, extra_params); + + if (param_len > 0) { + *param_len_ptr = param_len; + props |= HAS_PARAMS; + p += param_len; + } else { + p = param_len_ptr; + } + } + + ENCODE_URI_FIELD(uri1, headers, props | HAS_HEADERS, props, p); + + props_ptr[0] = (props >> 8) & 0xFF; + props_ptr[1] = props & 0xFF; + + thinfo->len = p - thinfo->buf; + return p - (thinfo->buf + start_pos); +} + +int thinfo_encode_dual_uri(thinfo_encoded_t *thinfo, struct sip_uri *uri1, struct sip_uri *uri2) { + return encode_uris(thinfo, uri1, uri2, dual_uri_skip_params_count, dual_uri_skip_params, 1); +} + +int thinfo_encode_uri(thinfo_encoded_t *thinfo, struct sip_uri *uri, int param_count, str *params_to_skip, int encode_user) { + return encode_uris(thinfo, uri, NULL, param_count, params_to_skip, encode_user); +} + +int thinfo_encode_socket(thinfo_encoded_t *thinfo, const struct socket_info *si) { + unsigned char *p; + uint8_t flags = 0; + int has_port = 0; + + if (si == NULL) { + LM_ERR("Socket is null\n"); + return -1; + } + + if (thinfo->len + MAX_ENCODED_URI_SIZE > MAX_THINFO_BUFFER_SIZE) { + return -1; + } + + if (thinfo->len == 0) { + thinfo->len = 3; + } + + p = thinfo->buf + thinfo->len; + + if (si->proto >= PROTO_UDP && si->proto <= PROTO_WSS) { + flags |= (TRANSPORTS[si->proto] >> 3) & SOCKET_PROTO_MASK; + } else { + return -1; + } + + if (si->address.af == AF_INET) { + flags |= SOCKET_IPV4; + } else if (si->address.af == AF_INET6) { + flags |= SOCKET_IPV6; + } else { + return -1; + } + + has_port = (si->port_no > 0) ? 1 : 0; + if (has_port) { + flags |= SOCKET_HAS_PORT; + } + + *p++ = flags; + + if (si->address.af == AF_INET) { + memcpy(p, si->address.u.addr, 4); + p += 4; + } else if (si->address.af == AF_INET6) { + memcpy(p, si->address.u.addr, 16); + p += 16; + } + + if (has_port) { + *p++ = (si->port_no >> 8) & 0xFF; + *p++ = si->port_no & 0xFF; + } + + int bytes_written = p - (thinfo->buf + thinfo->len); + thinfo->len = p - thinfo->buf; + + return bytes_written; +} + +int thinfo_decode_socket(thinfo_encoded_t *thinfo, int *proto, str *ip, unsigned short *port) { + static char ip_str[INET6_ADDRSTRLEN]; + unsigned char *p; + uint8_t flags, proto_bits, ip_type; + int remaining, has_port; + + if (!thinfo || thinfo->pos >= thinfo->len) return -1; + + if (thinfo->pos == 0) { + thinfo->pos = 3; + } + + p = thinfo->buf + thinfo->pos; + remaining = thinfo->len - thinfo->pos; + + if (remaining < 5) return -1; // Minimum: 1 byte flags + 4 bytes IPv4 + + flags = *p++; + remaining--; + + proto_bits = (flags & SOCKET_PROTO_MASK) << 3; + switch (proto_bits) { + case TRANSPORT_UDP: *proto = PROTO_UDP; break; + case TRANSPORT_TCP: *proto = PROTO_TCP; break; + case TRANSPORT_TLS: *proto = PROTO_TLS; break; + case TRANSPORT_SCTP: *proto = PROTO_SCTP; break; + case TRANSPORT_WS: *proto = PROTO_WS; break; + case TRANSPORT_WSS: *proto = PROTO_WSS; break; + default: return -1; + } + + ip_type = flags & SOCKET_IP_MASK; + has_port = (flags & SOCKET_HAS_PORT) ? 1 : 0; + + if (ip_type == SOCKET_IPV4) { + if (remaining < (4 + (has_port ? 2 : 0))) return -1; // Need 4 bytes for IP + optional 2 for port + inet_ntop(AF_INET, p, ip_str, INET_ADDRSTRLEN); + ip->s = ip_str; + ip->len = strlen(ip_str); + p += 4; + } else if (ip_type == SOCKET_IPV6) { + if (remaining < (16 + (has_port ? 2 : 0))) return -1; // Need 16 bytes for IP + optional 2 for port + inet_ntop(AF_INET6, p, ip_str, INET6_ADDRSTRLEN); + ip->s = ip_str; + ip->len = strlen(ip_str); + p += 16; + } else { + return -1; + } + + if (has_port) { + *port = (p[0] << 8) | p[1]; + p += 2; + } else { + *port = 0; + } + + thinfo->pos = p - thinfo->buf; + + return 1; +} + +#define BUILD_URI_STRING(scheme_val, transport_val, port_val) \ + do { \ + *s++ = '<'; \ + uri_start = s; \ + memcpy(s, SCHEME_STRINGS[scheme_val].s, SCHEME_STRINGS[scheme_val].len); \ + s += SCHEME_STRINGS[scheme_val].len; \ + *s++ = ':'; \ + if (username.len > 0) { \ + memcpy(s, username.s, username.len); \ + s += username.len; \ + if (password.len > 0) { \ + *s++ = ':'; \ + memcpy(s, password.s, password.len); \ + s += password.len; \ + } \ + *s++ = '@'; \ + } \ + if (domain_type == DOMAIN_IPV6) *s++ = '['; \ + memcpy(s, host.s, host.len); \ + s += host.len; \ + if (domain_type == DOMAIN_IPV6) *s++ = ']'; \ + if (port_val > 0) { \ + s += sprintf(s, ":%u", port_val); \ + } \ + if (transport_val != TRANSPORT_UDP) { \ + if (transport_val < sizeof(TRANSPORT_STRINGS)/sizeof(TRANSPORT_STRINGS[0]) && \ + TRANSPORT_STRINGS[transport_val] != NULL) { \ + *s++ = ';'; \ + t_len = strlen(TRANSPORT_STRINGS[transport_val]); \ + memcpy(s, TRANSPORT_STRINGS[transport_val], t_len); \ + s += t_len; \ + } \ + } \ + if (props & HAS_LR) { \ + memcpy(s, ";lr", 3); \ + s += 3; \ + } \ + if (has_r2) { \ + memcpy(s, ";r2=on", 6); \ + s += 6; \ + } \ + if (params.len > 0) { \ + *s++ = ';'; \ + memcpy(s, params.s, params.len); \ + s += params.len; \ + } \ + if (headers.len > 0) { \ + *s++ = '?'; \ + memcpy(s, headers.s, headers.len); \ + s += headers.len; \ + } \ + *s++ = '>'; \ + uris[uri_idx].s = uri_start - 1; \ + uris[uri_idx].len = s - uris[uri_idx].s; \ + if (uri_idx < uri_count - 1) { \ + *s++ = ','; \ + if (is_dual) *s++ = ' '; \ + } \ + } while(0) + +#define DECODE_STR_FIELD(field, flag) \ + do { \ + field.len = 0; \ + if (props & flag) { \ + field.len = *p++; \ + memcpy(field.s, p, field.len); \ + p += field.len; \ + } \ + } while(0) + +static char host_buf[UINT8_MAX], params_buf[UINT8_MAX], username_buf[UINT8_MAX], password_buf[UINT8_MAX], headers_buf[UINT8_MAX]; + +int thinfo_decode_uris(thinfo_encoded_t *thinfo, char decoded_uri_str[static MAX_ENCODED_URI_SIZE * 3], uint16_t uri_count, str uris[static uri_count]) { + uint8_t domain_type, len, uri2_props = 0; + uint8_t scheme1 = 0, scheme2 = 0, transport1 = 0, transport2 = 0; + uint16_t port1 = 0, port2 = 0; + int has_r2 = 0; + int is_dual = 0; + unsigned char *p; + uint16_t props; + char *s, *uri_start; + int t_len; + int uri_idx; + str username = {username_buf, 0}; + str password = {password_buf, 0}; + str host = {host_buf, 0}; + str params = {params_buf, 0}; + str headers = {headers_buf, 0}; + + if (!thinfo || thinfo->len < 3 || uri_count == 0) return -1; + + if (thinfo->pos == 0) { + thinfo->pos = 3; + } + + p = thinfo->buf + thinfo->pos; + s = decoded_uri_str; + + uri_idx = 0; + while (uri_idx < uri_count) { + if ((p - thinfo->buf) >= thinfo->len) return -1; + + has_r2 = 0; + port1 = 0; + port2 = 0; + is_dual = 0; + + props = (p[0] << 8) | p[1]; + p += 2; + + // Validate magic bits - detect garbage data + scheme1 = props & SCHEME_MASK; + transport1 = props & TRANSPORT_MASK; + domain_type = props & DOMAIN_MASK; + + if (scheme1 > SCHEME_URN_N || transport1 > TRANSPORT_WSS || domain_type > DOMAIN_FQDN) { + LM_ERR("Invalid properties detected: props=0x%04x, scheme=0x%02x, transport=0x%02x, domain=0x%02x (garbage data)\n", + props, scheme1, transport1, domain_type); + return -1; + } + + is_dual = (props & IS_DUAL_URI) ? 1 : 0; + + DECODE_STR_FIELD(username, HAS_USERNAME); + + DECODE_STR_FIELD(password, HAS_PASSWORD); + + domain_type = (props & DOMAIN_MASK); + host.len = 0; + if (domain_type == DOMAIN_IPV4) { + inet_ntop(AF_INET, p, host.s, UINT8_MAX); + host.len = strlen(host.s); + p += 4; + } else if (domain_type == DOMAIN_IPV6) { + inet_ntop(AF_INET6, p, host.s, UINT8_MAX); + host.len = strlen(host.s); + p += 16; + } else { + len = *p++; + host.len = len; + memcpy(host.s, p, len); + p += len; + } + + if (props & HAS_PORT) { + port1 = (p[0] << 8) | p[1]; + p += 2; + } + + if (is_dual) { + uri2_props = *p++; + scheme2 = uri2_props & URI2_SCHEME_MASK; + transport2 = uri2_props & URI2_TRANSPORT_MASK; + has_r2 = (uri2_props & URI2_HAS_R2) ? 1 : 0; + + if (uri2_props & URI2_HAS_PORT) { + port2 = (p[0] << 8) | p[1]; + p += 2; + } + } + + DECODE_STR_FIELD(params, HAS_PARAMS); + + DECODE_STR_FIELD(headers, HAS_HEADERS); + + BUILD_URI_STRING(scheme1, transport1, port1); + + LM_DBG("uri[%d]: s=%p, len=%d, content=[%.*s]\n", + uri_idx, uris[uri_idx].s, uris[uri_idx].len, + uris[uri_idx].len, uris[uri_idx].s); + + uri_idx++; + + if (is_dual && uri_idx < uri_count) { + BUILD_URI_STRING(scheme2, transport2, port2); + + LM_DBG("Dual uri[%d]: s=%p, len=%d, content=[%.*s]\n", + uri_idx, uris[uri_idx].s, uris[uri_idx].len, + uris[uri_idx].len, uris[uri_idx].s); + + uri_idx++; + } + } + + thinfo->pos = p - thinfo->buf; + + return s - decoded_uri_str; +} + +void thinfo_buffer_reset(thinfo_encoded_t *thinfo) { + thinfo->len = 0; + thinfo->pos = 0; +} + +void thinfo_buffer_finalize(thinfo_encoded_t *thinfo, uint16_t flags, uint8_t count) { + thinfo->buf[0] = (flags >> 8) & 0xFF; + thinfo->buf[1] = flags & 0xFF; + thinfo->buf[2] = count; +} + +uint8_t thinfo_get_uri_count(thinfo_encoded_t *thinfo) { + return thinfo->buf[2]; +} + +uint16_t thinfo_get_flags(thinfo_encoded_t *thinfo) { + return (thinfo->buf[0] << 8) | thinfo->buf[1]; +} \ No newline at end of file diff --git a/modules/topology_hiding/thinfo_codec.h b/modules/topology_hiding/thinfo_codec.h new file mode 100644 index 00000000000..22420d62308 --- /dev/null +++ b/modules/topology_hiding/thinfo_codec.h @@ -0,0 +1,254 @@ +/* + * + * Copyright (C) 2026 Genesys Cloud Services, Inc. + * + * opensips is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * opensips is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/** + * @file thinfo_codec.h + * @brief Compact binary codec for thinfo encoding and decoding + * @author David Trihy + * @date 2026 + * + * This file provides a compact binary format for encoding and decoding thinfo param, + * achieving significant size reduction compared to string representation. + */ +#ifndef _THINFO_CODEC_H +#define _THINFO_CODEC_H + +#include + +#include "../../parser/msg_parser.h" +#include "../../socket_info.h" + +/** + * @def MAX_ENCODED_URI_SIZE + * @brief Maximum size of an encoded URI in the compact binary format. + * + * @section encoding_format ENCODING FORMAT + * + * @subsection uri_properties 1. URI Properties (2 bytes, uint16_t) - Always present + * Bit layout: + * - Bits 0-2: Scheme (sip, sips, tel, tels, urn:service, urn:nena:service) + * - Bits 3-5: Transport (udp, tcp, tls, sctp, ws, wss) + * - Bits 6-7: Domain type (IPv4, IPv6, FQDN) + * - Bit 8: HAS_USERNAME flag + * - Bit 9: HAS_PASSWORD flag + * - Bit 10: HAS_PORT flag + * - Bit 11: HAS_PARAMS flag (other params, not lr/transport and r2 if dual URI) + * - Bit 12: HAS_HEADERS flag + * - Bit 13: HAS_LR flag (lr or lr=on present) + * - Bit 14: IS_DUAL_URI flag + * - Bit 15: Reserved + * + * @subsection username 2. Username (optional, if HAS_USERNAME set) + * - Encoded Length: 1 byte length + variable data (2-256 bytes) + * - Length byte: uint8_t indicating username length + * - Data: username string (length specified by length byte) + * + * @subsection password 3. Password (optional, if HAS_PASSWORD set) + * - Encoded Length: 1 byte length + variable data (2-256 bytes) + * - Length byte: uint8_t indicating password length + * - Data: password string (length specified by length byte) + * + * @subsection domain 4. Domain (variable size based on domain type) + * - IPv4: 4 bytes (raw binary IP address) + * - IPv6: 16 bytes (raw binary IP address) + * - FQDN: 1 byte length + variable data (2-255 bytes) + * - Length byte: uint8_t indicating hostname length + * - Data: hostname string (length specified by length byte) + * + * @subsection port 5. Port (optional, if HAS_PORT set) + * - 2 bytes (uint16_t, network byte order) + * + * @subsection params 6. Params (optional, if HAS_PARAMS set) + * - Length: 1 byte (uint8_t) + * - Data: variable length (0-255 bytes) + * - @note lr and r2 params are encoded in flags, not here + * + * @subsection headers 7. Headers (optional, if HAS_HEADERS set) + * - Length: 1 byte (uint8_t) + * - Data: variable length (0-255 bytes) + * + * @subsection uri2_properties 8. Second URI Properties (optional, if IS_DUAL_URI set) + * - 1 byte with scheme, transport, HAS_PORT, and HAS_R2 flags + * + * @subsection uri2_port 9. Second URI Port (optional, if IS_DUAL_URI and URI2_HAS_PORT set) + * - 2 bytes (uint16_t, network byte order) + * + * @section examples ENCODING EXAMPLES + * + * @par Best case scenario - single URI: + * - Input URI: 40 bytes + * @code + * + * @endcode + * - Scheme, transport and lr param are encoded into the URI properties + * - Largest IPv4 as a string (15 bytes) encoded into 4 byte octets + * - No port needed to be encoded + * - Params of transport and lr are already encoded so no params set + * - Output: 6 byte binary representation of the URI + * + * @par Best case scenario - r2=on dual URI: + * - Input URI: 96 bytes + * @code + * URI1: + * URI2: + * @endcode + * - Scheme, transport, lr and r2 param are encoded into the URI properties + * - Largest IPv4 as a string (15 bytes) encoded into 4 byte octets + * - No port needed to be encoded + * - Params of transport, lr and r2 are already encoded so no params set + * - Second URI properties encoded with HAS_R2 flag, no port so not encoded + * - Output: 7 byte binary representation of the URI + * + * @note when using thinfo_encode_dual_uri it is up to the caller of the + * function to verify the host and params match before encoding. + * + * @par Worst case scenario: + * - 1,277 bytes encoded size (extremely unlikely) + * - Requires having the largest variable data possible: username, password, hostname, etc. + * - In this scenario the input string will still be larger than the encoded string + * but the savings are negligible at that point + */ +#define MAX_ENCODED_URI_SIZE ( \ + sizeof(uint16_t) + /* uri_properties */ \ + sizeof(uint8_t) + UINT8_MAX + /* username */ \ + sizeof(uint8_t) + UINT8_MAX + /* password */ \ + sizeof(uint8_t) + UINT8_MAX + /* domain */ \ + sizeof(uint16_t) + /* port */ \ + sizeof(uint8_t) + UINT8_MAX + /* params */ \ + sizeof(uint8_t) + UINT8_MAX + /* headers */ \ + sizeof(uint8_t) + /* second associated uri flags */ \ + sizeof(uint16_t) /* second associated uri port */ \ +) + +#define MAX_THINFO_BUFFER_SIZE 4096 + +/** + * @struct thinfo_encoded_t + * @brief Buffer structure for encoded thinfo data + */ +typedef struct { + unsigned char buf[MAX_THINFO_BUFFER_SIZE]; /**< Buffer holding encoded binary data */ + uint16_t len; /**< Current length of encoded data */ + int pos; /**< Current read/write position */ +} thinfo_encoded_t; + +/** + * @brief Encode a single SIP URI into compact binary format + * + * @param thinfo Pointer to the encoded buffer structure (updates len and pos on success) + * @param uri Pointer to the parsed SIP URI to encode + * @param param_count Number of parameters to skip during encoding + * @param params_to_skip Array of parameter names to exclude from encoding + * @param encode_user boolean to toggle whether to encode the username/password + * + * @return 0 on success, -1 on error + */ +int thinfo_encode_uri(thinfo_encoded_t *thinfo, struct sip_uri *uri, int param_count, str *params_to_skip, int encode_user); + +/** + * @brief Encode two related SIP URIs (dual URI encoding for r2 scenarios) + * + * Dual encoding is more efficient when two URIs share functionally similar URIs. + * The main areas they can differ in is scheme, port and transport. + * This is an optimization if record_route() with dual recording routing is in the SIP message. + * The caller must verify that the URIs are compatible for dual encoding. + * + * @param thinfo Pointer to the encoded buffer structure (updates len and pos on success) + * @param uri1 Pointer to the first parsed SIP URI + * @param uri2 Pointer to the second parsed SIP URI + * + * @return 0 on success, -1 on error + */ +int thinfo_encode_dual_uri(thinfo_encoded_t *thinfo, struct sip_uri *uri1, struct sip_uri *uri2); + +/** + * @brief Encode socket information into the buffer + * + * @param thinfo Pointer to the encoded buffer structure (updates len and pos on success) + * @param socket Pointer to the socket_info structure to encode + * + * @return 0 on success, -1 on error + */ +int thinfo_encode_socket(thinfo_encoded_t *thinfo, const struct socket_info *socket); + +/** + * @brief Decode URIs from the encoded buffer into string representations + * + * @param thinfo Pointer to the encoded buffer structure (updates pos on success) + * @param decode_buf Character buffer to hold decoded URI strings + * @param uri_count Number of URIs to decode + * @param uris Array of str structures to receive decoded URI references + * + * @return 0 on success, -1 on error + */ +int thinfo_decode_uris(thinfo_encoded_t *thinfo, char decode_buf[static MAX_ENCODED_URI_SIZE * 3], uint16_t uri_count, str uris[static uri_count]); + +/** + * @brief Decode socket information from the encoded buffer + * + * @param thinfo Pointer to the encoded buffer structure (updates pos on success) + * @param proto Pointer to receive the decoded protocol + * @param ip Pointer to str structure to receive the decoded IP address + * @param port Pointer to receive the decoded port number + * + * @return 0 on success, -1 on error + */ +int thinfo_decode_socket(thinfo_encoded_t *thinfo, int *proto, str *ip, unsigned short *port); + +/** + * @brief Get the number of URIs encoded in the buffer + * + * @param thinfo Pointer to the encoded buffer structure (read-only, does not modify) + * + * @return Number of encoded URIs (uint8_t) + */ +uint8_t thinfo_get_uri_count(thinfo_encoded_t *thinfo); + +/** + * @brief Get the flags from the encoded buffer + * + * @param thinfo Pointer to the encoded buffer structure (read-only, does not modify) + * + * @return Flags value (uint16_t) + */ +uint16_t thinfo_get_flags(thinfo_encoded_t *thinfo); + +/** + * @brief Finalize the encoded buffer by writing header information + * + * This should be called after all encoding operations are complete to write + * the final flags and URI count to the buffer header. + * + * @param thinfo Pointer to the encoded buffer structure (updates buf with header) + * @param flags Flags value to write to the header + * @param uri_count Number of URIs encoded in the buffer + */ +void thinfo_buffer_finalize(thinfo_encoded_t *thinfo, uint16_t flags, uint8_t uri_count); + +/** + * @brief Reset the encoded buffer to initial state + * + * Clears the buffer and resets position and length counters. + * + * @param thinfo Pointer to the encoded buffer structure (resets len and pos to 0) + */ +void thinfo_buffer_reset(thinfo_encoded_t *thinfo); + +#endif \ No newline at end of file From ac6d588b96741d6aaf6597528b56d2abc6462889 Mon Sep 17 00:00:00 2001 From: David Trihy Date: Mon, 27 Apr 2026 13:40:29 +0300 Subject: [PATCH 3/8] Added TH_decoded_* pseudovars --- modules/topology_hiding/topo_hiding_logic.h | 1 - modules/topology_hiding/topology_hiding.c | 221 ++++++++++++++++++-- 2 files changed, 206 insertions(+), 16 deletions(-) diff --git a/modules/topology_hiding/topo_hiding_logic.h b/modules/topology_hiding/topo_hiding_logic.h index 6f9dbf72e0f..f97c636b39b 100644 --- a/modules/topology_hiding/topo_hiding_logic.h +++ b/modules/topology_hiding/topo_hiding_logic.h @@ -44,7 +44,6 @@ extern str th_contact_caller_var; extern str th_contact_callee_var; -enum encode_scheme {ENC_BASE64, ENC_BASE32}; int topology_hiding(struct sip_msg *req,int extra_flags, struct th_params *params); int topo_callid_pre_raw(str *data, struct sip_msg* req); diff --git a/modules/topology_hiding/topology_hiding.c b/modules/topology_hiding/topology_hiding.c index c5dcf84d42b..3b0f66fbdbf 100644 --- a/modules/topology_hiding/topology_hiding.c +++ b/modules/topology_hiding/topology_hiding.c @@ -27,9 +27,8 @@ #include #include - #include "topo_hiding_logic.h" -#include "th_common_logic.h" +#include "th_no_dlg_logic.h" struct tm_binds tm_api; struct dlg_binds dlg_api; @@ -45,8 +44,30 @@ str th_contact_encode_param = str_init("thinfo"); str th_contact_encode_scheme = str_init("base64"); str th_contact_caller_var = str_init("_th_contact_caller_username_var_"); str th_contact_callee_var = str_init("_th_contact_callee_username_var_"); +str topo_hiding_ct_encode_pw_legacy = str_init("ToPoCtPaSS"); +str th_contact_encode_param_legacy = str_init("thinfol"); +str th_contact_encode_scheme_legacy = str_init("base64"); +str th_internal_trusted_tag = STR_EMPTY; +str th_external_socket_tag = STR_EMPTY; +int auto_route_on_trusted_socket = 1; +int th_compact_encoding = 0; int th_ct_enc_scheme; +int th_ct_enc_scheme_legacy; + +/* Global buffer for decoded routes */ +str decoded_uris[12]; +int decoded_uris_count = 0; + +/* Context flag to track if decoded routes are valid for current message */ +int ctx_decoded_routes_valid_idx = -1; + +/* Route field IDs for nested property access */ +#define TH_ROUTE_FULL 0 // Full URI (default) +#define TH_ROUTE_HOST 1 // Host part +#define TH_ROUTE_PORT 2 // Port part +#define TH_ROUTE_USER 3 // User part +#define TH_ROUTE_PARAMS 4 // Parameters static int mod_init(void); static void mod_destroy(void); @@ -55,6 +76,11 @@ static int fixup_th_params(void **param); int w_topology_hiding(struct sip_msg *req, str *flags_s, struct th_params *params); int w_topology_hiding_match(struct sip_msg *req, void *seq_match_mode_val); static int pv_topo_callee_callid(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); +static int pv_topo_decoded_routes(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); +static int pv_topo_decoded_routes_count(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); +static int pv_topo_decoded_contact(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); +static int pv_parse_nameaddr_part(pv_spec_p sp, const str *in); +static int pv_parse_idx_th_route(pv_spec_p sp, const str *in); static const cmd_export_t cmds[]={ {"topology_hiding",(cmd_function)w_topology_hiding, { @@ -69,23 +95,36 @@ static const cmd_export_t cmds[]={ /* Exported parameters */ static const param_export_t params[] = { - { "force_dialog", INT_PARAM, &force_dialog }, - { "th_passed_contact_uri_params",STR_PARAM, &topo_hiding_ct_params.s }, - { "th_passed_contact_params", STR_PARAM, &topo_hiding_ct_hdr_params.s }, - { "th_callid_passwd", STR_PARAM, &topo_hiding_seed.s }, - { "th_callid_prefix", STR_PARAM, &topo_hiding_prefix.s }, - { "th_contact_encode_passwd", STR_PARAM, &topo_hiding_ct_encode_pw.s }, - { "th_contact_encode_param", STR_PARAM, &th_contact_encode_param.s }, - { "th_contact_encode_scheme", STR_PARAM, &th_contact_encode_scheme.s }, - { "th_contact_caller_username_var", STR_PARAM, &th_contact_caller_var.s }, - { "th_contact_callee_username_var", STR_PARAM, &th_contact_callee_var.s }, - { "th_callid_loop_protection", INT_PARAM, &th_loop_protection }, + { "force_dialog", INT_PARAM, &force_dialog }, + { "th_passed_contact_uri_params", STR_PARAM, &topo_hiding_ct_params.s }, + { "th_passed_contact_params", STR_PARAM, &topo_hiding_ct_hdr_params.s }, + { "th_callid_passwd", STR_PARAM, &topo_hiding_seed.s }, + { "th_callid_prefix", STR_PARAM, &topo_hiding_prefix.s }, + { "th_contact_encode_passwd", STR_PARAM, &topo_hiding_ct_encode_pw.s }, + { "th_contact_encode_param", STR_PARAM, &th_contact_encode_param.s }, + { "th_contact_encode_scheme", STR_PARAM, &th_contact_encode_scheme.s }, + { "th_contact_caller_username_var", STR_PARAM, &th_contact_caller_var.s }, + { "th_contact_callee_username_var", STR_PARAM, &th_contact_callee_var.s }, + { "th_contact_encode_passwd_legacy", STR_PARAM, &topo_hiding_ct_encode_pw_legacy.s }, + { "th_contact_encode_param_legacy", STR_PARAM, &th_contact_encode_param_legacy.s }, + { "th_contact_encode_scheme_legacy", STR_PARAM, &th_contact_encode_scheme_legacy.s }, + { "th_internal_trusted_tag", STR_PARAM, &th_internal_trusted_tag.s }, + { "th_external_socket_tag", STR_PARAM, &th_external_socket_tag.s }, + { "th_auto_route_on_trusted_socket", INT_PARAM, &auto_route_on_trusted_socket }, + { "th_compact_encoding", INT_PARAM, &th_compact_encoding }, + { "th_callid_loop_protection", INT_PARAM, &th_loop_protection }, {0, 0, 0} }; static const pv_export_t pvars[] = { { str_const_init("TH_callee_callid"), 1000, pv_topo_callee_callid,0,0, 0, 0, 0}, + { str_const_init("TH_decoded_routes"), 1001, + pv_topo_decoded_routes, 0, pv_parse_nameaddr_part, pv_parse_idx_th_route, 0, 0}, + { str_const_init("TH_decoded_routes_count"), 1002, + pv_topo_decoded_routes_count, 0, 0, 0, 0, 0}, + { str_const_init("TH_decoded_contact"), 1003, + pv_topo_decoded_contact, 0, pv_parse_nameaddr_part, 0, 0, 0}, { {0, 0}, 0, 0, 0, 0, 0, 0, 0 } }; @@ -101,7 +140,7 @@ static module_dependency_t *get_deps_dialog(const param_export_t *param) static const dep_export_t deps = { { /* OpenSIPS module dependencies */ - { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, + { MOD_TYPE_DEFAULT, "tm", DEP_ABORT }, { MOD_TYPE_DEFAULT, "dialog", DEP_SILENT }, { MOD_TYPE_NULL, NULL, 0 }, }, @@ -138,11 +177,16 @@ static int mod_init(void) { LM_INFO("initializing...\n"); + /* Register context for decoded routes validity flag */ + ctx_decoded_routes_valid_idx = context_register_int(CONTEXT_GLOBAL, NULL); + /* param handling */ topo_hiding_prefix.len = strlen(topo_hiding_prefix.s); topo_hiding_seed.len = strlen(topo_hiding_seed.s); th_contact_encode_param.len = strlen(th_contact_encode_param.s); topo_hiding_ct_encode_pw.len = strlen(topo_hiding_ct_encode_pw.s); + th_contact_encode_param_legacy.len = strlen(th_contact_encode_param_legacy.s); + topo_hiding_ct_encode_pw_legacy.len = strlen(topo_hiding_ct_encode_pw_legacy.s); if (topo_hiding_ct_params.s) { topo_hiding_ct_params.len = strlen(topo_hiding_ct_params.s); topo_parse_passed_ct_params(&topo_hiding_ct_params); @@ -163,7 +207,25 @@ static int mod_init(void) "Use 'base64' or 'base32'\n"); goto error; } + + th_contact_encode_scheme_legacy.len = strlen(th_contact_encode_scheme_legacy.s); + if (!str_strcmp(&th_contact_encode_scheme_legacy, const_str("base64"))) + th_ct_enc_scheme_legacy = ENC_BASE64; + else if (!str_strcmp(&th_contact_encode_scheme_legacy, const_str("base32"))) + th_ct_enc_scheme_legacy = ENC_BASE32; + else { + LM_ERR("Unsupported value for 'th_contact_encode_scheme_legacy' modparam!" + "Use 'base64' or 'base32'\n"); + goto error; + } + if (th_internal_trusted_tag.s) { + th_internal_trusted_tag.len = strlen(th_internal_trusted_tag.s); + } + + if (th_external_socket_tag.s) { + th_external_socket_tag.len = strlen(th_external_socket_tag.s); + } /* loading dependencies */ if (load_tm_api(&tm_api)!=0) { @@ -197,7 +259,6 @@ static int mod_init(void) "restart\n"); - return 0; error: return -1; @@ -339,6 +400,8 @@ int w_topology_hiding_match(struct sip_msg *req, void *seq_match_mode_val) } static char *callid_buf=NULL; +static int callid_buf_len=0; + static int pv_topo_callee_callid(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { struct dlg_cell *dlg; @@ -367,3 +430,131 @@ static int pv_topo_callee_callid(struct sip_msg *msg, pv_param_t *param, pv_valu return 0; } + +static int pv_parse_idx_th_route(pv_spec_p sp, const str *in) +{ + if (!in || in->len == 0) { + LM_ERR("invalid index\n"); + return -1; + } + + return pv_parse_index(sp, in); +} + + +static int pv_parse_nameaddr_part(pv_spec_p sp, const str *in) +{ + if (sp == NULL || in == NULL || in->s == NULL || in->len == 0) + return -1; + + sp->pvp.pvn.type = PV_NAME_INTSTR; + sp->pvp.pvn.u.isname.type = 0; + + if (in->len == 4 && strncasecmp(in->s, "host", 4) == 0) { + sp->pvp.pvn.u.isname.name.n = TH_ROUTE_HOST; + } else if (in->len == 4 && strncasecmp(in->s, "port", 4) == 0) { + sp->pvp.pvn.u.isname.name.n = TH_ROUTE_PORT; + } else if (in->len == 4 && strncasecmp(in->s, "user", 4) == 0) { + sp->pvp.pvn.u.isname.name.n = TH_ROUTE_USER; + } else if (in->len == 6 && strncasecmp(in->s, "params", 6) == 0) { + sp->pvp.pvn.u.isname.name.n = TH_ROUTE_PARAMS; + } else { + LM_ERR("unsupported route field <%.*s>\n", in->len, in->s); + return -1; + } + + return 0; +} + +static int pv_topo_decoded_uri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res, int index) +{ + int field_id = 0; + struct sip_uri uri; + + if (msg == NULL || res == NULL) + return -1; + + if (!ctx_decoded_routes_is_valid()) { + return pv_get_null(msg, param, res); + } + + if (param->pvn.type == PV_NAME_INTSTR) { + field_id = param->pvn.u.isname.name.n; + } + + if (field_id == TH_ROUTE_FULL) { + return pv_get_strval(msg, param, res, &decoded_uris[index]); + } + + if (parse_uri(decoded_uris[index].s + 1, decoded_uris[index].len - 1, &uri) < 0) { + LM_ERR("Bad Contact URI\n"); + return -1; + } + + switch (field_id) { + case TH_ROUTE_HOST: + if (uri.host.len == 0) + return pv_get_null(msg, param, res); + return pv_get_strval(msg, param, res, &uri.host); + + case TH_ROUTE_PORT: + return pv_get_uintval(msg, param, res, uri.port_no); + + case TH_ROUTE_USER: + if (uri.user.len == 0) + return pv_get_null(msg, param, res); + return pv_get_strval(msg, param, res, &uri.user); + + case TH_ROUTE_PARAMS: + if (uri.params.len == 0) + return pv_get_null(msg, param, res); + return pv_get_strval(msg, param, res, &uri.params); + + default: + LM_ERR("unknown route field %d\n", field_id); + return pv_get_null(msg, param, res); + } +} + +static int pv_topo_decoded_routes_count(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) +{ + if (msg == NULL || res == NULL) + return -1; + + /* Check if decoded routes are valid for this message context */ + if (!ctx_decoded_routes_is_valid()) { + return pv_get_sintval(msg, param, res, 0); + } + + return pv_get_sintval(msg, param, res, decoded_uris_count - 1); +} + +static int pv_topo_decoded_routes(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) +{ + int idx, idxf; + + if (pv_get_spec_index(msg, param, &idx, &idxf) != 0) { + LM_ERR("invalid index\n"); + return -1; + } + + if (idx < 0) { + idx = (decoded_uris_count - 1) + idx; + } + + if (idx < 0 || idx >= (decoded_uris_count - 1)) + return pv_get_null(msg, param, res); + + /* Adjust index: route 0 is at decoded_uris[1], contact is at [0] */ + idx = idx + 1; + + return pv_topo_decoded_uri(msg, param, res, idx); +} + +static int pv_topo_decoded_contact(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) +{ + if (decoded_uris_count == 0) + return pv_get_null(msg, param, res); + + return pv_topo_decoded_uri(msg, param, res, 0); +} From 11783c1c4faa561541e7b0e26ee4bffa9adb88a0 Mon Sep 17 00:00:00 2001 From: David Trihy Date: Fri, 5 Jun 2026 12:33:03 +0100 Subject: [PATCH 4/8] Major logic rework of one way hiding and compact thinfo --- modules/rr/loose.c | 82 - modules/rr/loose.h | 80 + modules/topology_hiding/th_common_logic.c | 84 +- modules/topology_hiding/th_common_logic.h | 12 +- modules/topology_hiding/th_no_dlg_logic.c | 2127 +++++++++++++++---- modules/topology_hiding/th_no_dlg_logic.h | 14 +- modules/topology_hiding/thinfo_codec.c | 37 +- modules/topology_hiding/thinfo_codec.h | 4 +- modules/topology_hiding/topo_hiding_logic.c | 2 + modules/topology_hiding/topology_hiding.c | 6 +- parser/parse_rr.c | 47 + parser/parse_rr.h | 6 + 12 files changed, 1939 insertions(+), 562 deletions(-) diff --git a/modules/rr/loose.c b/modules/rr/loose.c index 81ad3667211..c512f2f1a09 100644 --- a/modules/rr/loose.c +++ b/modules/rr/loose.c @@ -138,88 +138,6 @@ static inline int find_first_route(struct sip_msg* _m) } -/* - * Find out if a URI contains r2 parameter which indicates - * that we put 2 record routes - */ -static inline int is_2rr(str* _params) -{ - str s; - int i, state = 0; - - if (_params->len == 0) return 0; - s = *_params; - - for(i = 0; i < s.len; i++) { - switch(state) { - case 0: - switch(s.s[i]) { - case ' ': - case '\r': - case '\n': - case '\t': break; - case 'r': - case 'R': state = 1; break; - default: state = 4; break; - } - break; - - case 1: - switch(s.s[i]) { - case '2': state = 2; break; - default: state = 4; break; - } - break; - - case 2: - switch(s.s[i]) { - case ';': return 1; - case '=': return 1; - case ' ': - case '\r': - case '\n': - case '\t': state = 3; break; - default: state = 4; break; - } - break; - - case 3: - switch(s.s[i]) { - case ';': return 1; - case '=': return 1; - case ' ': - case '\r': - case '\n': - case '\t': break; - default: state = 4; break; - } - break; - - case 4: - switch(s.s[i]) { - case '\"': state = 5; break; - case ';': state = 0; break; - default: break; - } - break; - - case 5: - switch(s.s[i]) { - case '\\': state = 6; break; - case '\"': state = 4; break; - default: break; - } - break; - - case 6: state = 5; break; - } - } - - if ((state == 2) || (state == 3)) return 1; - else return 0; -} - - /* * Check if URI is myself */ diff --git a/modules/rr/loose.h b/modules/rr/loose.h index 88f9214ad02..9b7b2690dc4 100644 --- a/modules/rr/loose.h +++ b/modules/rr/loose.h @@ -159,5 +159,85 @@ static inline int is_strict(str* _params) else return 1; } +/* + * Find out if a URI contains r2 parameter which indicates + * that we put 2 record routes + */ +static inline int is_2rr(str* _params) +{ + str s; + int i, state = 0; + + if (_params->len == 0) return 0; + s = *_params; + + for(i = 0; i < s.len; i++) { + switch(state) { + case 0: + switch(s.s[i]) { + case ' ': + case '\r': + case '\n': + case '\t': break; + case 'r': + case 'R': state = 1; break; + default: state = 4; break; + } + break; + + case 1: + switch(s.s[i]) { + case '2': state = 2; break; + default: state = 4; break; + } + break; + + case 2: + switch(s.s[i]) { + case ';': return 1; + case '=': return 1; + case ' ': + case '\r': + case '\n': + case '\t': state = 3; break; + default: state = 4; break; + } + break; + + case 3: + switch(s.s[i]) { + case ';': return 1; + case '=': return 1; + case ' ': + case '\r': + case '\n': + case '\t': break; + default: state = 4; break; + } + break; + + case 4: + switch(s.s[i]) { + case '\"': state = 5; break; + case ';': state = 0; break; + default: break; + } + break; + + case 5: + switch(s.s[i]) { + case '\\': state = 6; break; + case '\"': state = 4; break; + default: break; + } + break; + + case 6: state = 5; break; + } + } + + if ((state == 2) || (state == 3)) return 1; + else return 0; +} #endif /* LOOSE_H */ diff --git a/modules/topology_hiding/th_common_logic.c b/modules/topology_hiding/th_common_logic.c index ffa791c9023..d12d63311e5 100644 --- a/modules/topology_hiding/th_common_logic.c +++ b/modules/topology_hiding/th_common_logic.c @@ -75,6 +75,81 @@ int topo_parse_passed_hdr_ct_params(str *params) return topo_parse_passed_params(params, &th_hdr_param_list); } +static inline int topo_delete_record_route_or_route_uris(struct sip_msg *msg, hdr_types_t hdr_type, int uris_to_delete) { + struct hdr_field *it = NULL; + rr_t *curr_rr = NULL, *next_rr = NULL; + unsigned int offset; + int total_delete_count = 0; + int delete_count = uris_to_delete > 0 ? uris_to_delete : 64; + + if (hdr_type != HDR_RECORDROUTE_T && hdr_type != HDR_ROUTE_T) { + LM_ERR("Header type has to be one of Route or Record-Route\n"); + return -1; + } + + LM_DBG("Attempting to delete %d '%s' headers\n", delete_count, hdr_type == HDR_RECORDROUTE_T ? "Record-Route" : "Route"); + + if (parse_headers(msg, HDR_EOH_F, 0) == -1) { + LM_ERR("Failed to parse '%s' headers\n", hdr_type == HDR_RECORDROUTE_T ? "Record-Route" : "Route"); + return -1; + } + + it = hdr_type == HDR_RECORDROUTE_T ? msg->record_route : msg->route; + while (it != NULL) { + if (parse_rr(it) < 0) { + LM_ERR("Failed to parse '%.*s' headers\n", it->name.len, it->name.s); + return -1; + } + + curr_rr = (rr_t*) it->parsed; + next_rr = NULL; + offset = 0; + while (curr_rr) { + next_rr = curr_rr->next; + + if (next_rr != NULL) { + offset += next_rr->nameaddr.name.s - curr_rr->nameaddr.name.s; + } + + curr_rr = next_rr; + + if (++total_delete_count == delete_count) { + break; + } + } + + if (curr_rr == NULL) { + if (del_lump(msg, it->name.s - msg->buf, it->len, hdr_type) == NULL) { + LM_ERR("del_lump failed \n"); + return -1; + } + } else { + if (del_lump(msg, it->body.s - msg->buf, offset, 0) == NULL) { + LM_ERR("Failed to remove '%.*s' header\n", it->name.len, it->name.s); + return -1; + } + } + + if (total_delete_count == delete_count) { + break; + } + + it = it->sibling; + } + + LM_DBG("Deleted %d '%s' headers\n", total_delete_count, hdr_type == HDR_RECORDROUTE_T ? "Record-Route" : "Route"); + + return 1; +} + +int topo_delete_route_uris(struct sip_msg *msg, int delete_count) { + return topo_delete_record_route_or_route_uris(msg, HDR_ROUTE_T, delete_count); +} + +int topo_delete_record_route_uris(struct sip_msg *msg, int delete_count) { + return topo_delete_record_route_or_route_uris(msg, HDR_RECORDROUTE_T, delete_count); +} + int topo_delete_record_routes(struct sip_msg *req) { struct lump* lump, *crt, *prev_crt =0, *a, *foo; struct hdr_field *it; @@ -221,7 +296,8 @@ struct lump* delete_existing_contact(struct sip_msg *msg, int del_hdr) { return lump; } -struct lump* restore_vias_from_req(struct sip_msg *req,struct sip_msg *rpl) { +struct lump* restore_vias_from_req(struct sip_msg *req, struct sip_msg *rpl) +{ struct lump* lmp; struct hdr_field *it; str via_str; @@ -378,14 +454,14 @@ struct lump* restore_vias_from_req(struct sip_msg *req,struct sip_msg *rpl) { it = it->sibling; } - LM_DBG("built [%.*s], %d %d\n",(int)(p-via_str.s),via_str.s,(int)(p-via_str.s),via_str.len); + LM_DBG("built [%.*s], %d %d\n",(int)(p-via_str.s), via_str.s, (int)(p-via_str.s), via_str.len); if ((lmp = insert_new_lump_after(lmp, via_str.s, via_str.len, 0)) == 0) { LM_ERR("failed inserting new old vias\n"); pkg_free(via_str.s); goto err_free_rport; } - + pkg_free(rport_buf); pkg_free(received_buf); } else { @@ -434,4 +510,4 @@ struct lump* restore_vias_from_req(struct sip_msg *req,struct sip_msg *rpl) { pkg_free(rport_buf); pkg_free(received_buf); return NULL; -} +} \ No newline at end of file diff --git a/modules/topology_hiding/th_common_logic.h b/modules/topology_hiding/th_common_logic.h index 18a6ada4e34..b4dcb3bbe08 100644 --- a/modules/topology_hiding/th_common_logic.h +++ b/modules/topology_hiding/th_common_logic.h @@ -26,24 +26,30 @@ #include "../../mem/shm_mem.h" #include "../../parser/contact/parse_contact.h" -#define RECORD_ROUTE "Record-Route: " -#define RECORD_ROUTE_LEN (sizeof(RECORD_ROUTE)-1) - struct th_params { str ct_caller_user; str ct_callee_user; }; +#define RECORD_ROUTE "Record-Route: " +#define RECORD_ROUTE_LEN (sizeof(RECORD_ROUTE)-1) + struct th_ct_params { str param_name; struct th_ct_params *next; }; +int topo_delete_route_uris(struct sip_msg *msg, int delete_count); +int topo_delete_record_route_uris(struct sip_msg *msg, int delete_count); int topo_delete_record_routes(struct sip_msg *req); int topo_delete_vias(struct sip_msg *req); struct lump* delete_existing_contact(struct sip_msg *msg, int del_hdr); struct lump* restore_vias_from_req(struct sip_msg *req,struct sip_msg *rpl); +int topo_parse_passed_ct_params(str *params); + +int topo_parse_passed_hdr_ct_params(str *params); + static inline int topo_ct_param_len(str *name, str *val, int should_quote) { int len = 1 /* ; */ + name->len; diff --git a/modules/topology_hiding/th_no_dlg_logic.c b/modules/topology_hiding/th_no_dlg_logic.c index 5c42356fee6..1c55418b65b 100644 --- a/modules/topology_hiding/th_no_dlg_logic.c +++ b/modules/topology_hiding/th_no_dlg_logic.c @@ -19,64 +19,689 @@ */ #include "th_no_dlg_logic.h" +#include "thinfo_codec.h" +#include "../../parser/parse_rr.h" +#include "../../parser/parse_uri.h" +#include "../../forward.h" #include "../dialog/dlg_hash.h" #include "../tm/tm_load.h" #include "../rr/loose.h" +#include "../rr/api.h" +#include "../../data_lump.h" + +#include +#include + +#define START_THINFO_BUF_SZ 1000 +#define THINFO_MAX_BUFFER_SIZE 10000 +#define MAX_ENCODED_SIP_URIS 12 + +#define TOPOH_MATCH_TAG_MATCH 2 +#define TOPOH_MATCH_SUCCESS 1 +#define TOPOH_MATCH_FAILURE -1 +#define TOPOH_MATCH_UNSUPPORTED_METHOD -2 + +#define ROUTE_STR "Route: " +#define ROUTE_LEN (sizeof(ROUTE_STR) - 1) +#define ROUTE_PREF "Route: <" +#define ROUTE_PREF_LEN (sizeof(ROUTE_PREF) -1) +#define ROUTE_SUFF ">\r\n" +#define ROUTE_SUFF_LEN (sizeof(ROUTE_SUFF) -1) + +#define ROUTE_SUCCESS (1<<0) +#define ROUTE_LOOSE (1<<1) +#define ROUTE_SELF (1<<2) +#define ROUTE_DOUBLE_RR (1<<3) +#define ROUTE_STRICT (1<<4) +#define ROUTE_FAILURE (1<<5) + +#define RR_PREFIX "Record-Route: " +#define RR_PREFIX_LEN (sizeof(RR_PREFIX)-1) + +#define RR_URI_PREFIX "" +#define RR_TERM_LEN (sizeof(RR_TERM)-1) + +#define RR_SEPARATOR "," +#define RR_SEPARATOR_LEN (sizeof(RR_SEPARATOR)-1) + +#define BUILD_RR_HEADER_BUFFER(hdr_buf, hdr_len, uri_str) \ + do { \ + hdr_len = RR_PREFIX_LEN + (uri_str).len + CRLF_LEN; \ + hdr_buf = pkg_malloc(hdr_len); \ + if (hdr_buf) { \ + memcpy(hdr_buf, RR_PREFIX, RR_PREFIX_LEN); \ + memcpy(hdr_buf + RR_PREFIX_LEN, (uri_str).s, (uri_str).len); \ + memcpy(hdr_buf + RR_PREFIX_LEN + (uri_str).len, CRLF, CRLF_LEN); \ + } \ + } while(0) + +extern struct tm_binds tm_api; + +static thinfo_encoded_t encoded_uri_buf = { 0 }; +static thinfo_encoded_t decoded_uri_buf = { 0 }; struct th_no_dlg_param { str routes; str username; + uint16_t flags; }; -extern struct tm_binds tm_api; -extern struct th_ct_params *th_param_list; -extern struct th_ct_params *th_hdr_param_list; +static char decoded_uri_str[MAX_ENCODED_URI_SIZE * 3]; +static char dec_buf_legacy[4096]; + +extern int th_ct_enc_scheme; extern str topo_hiding_ct_encode_pw; extern str th_contact_encode_param; -extern int th_ct_enc_scheme; +extern int th_ct_enc_scheme_legacy; +extern str topo_hiding_ct_encode_pw_legacy; +extern str th_contact_encode_param_legacy; +extern str th_internal_trusted_tag; +extern str th_external_socket_tag; +extern str th_is_self_socket_tag; +extern int auto_route_on_trusted_socket; +extern int th_compact_encoding; + +extern struct th_ct_params *th_param_list; +extern struct th_ct_params *th_hdr_param_list; + +typedef struct { + unsigned int delete_count; + unsigned int skip_encode_count; +} route_count_t; + +enum info_buffer_state { + HAS_CONTACT = 1 << 0, + HAS_ROUTES = 1 << 1, + HAS_SOCK = 1 << 2, + INVALID_BUF = 1 << 3, +}; + +typedef struct { + str routes; + str contact; + const struct socket_info *sock; + uint16_t flags; + enum info_buffer_state state; +} decoded_info_buffer_t; + +#define FINALIZE_DECODED_BUF_STATE(db) \ + do { \ + if ((db).contact.s && (db).contact.len > 0) \ + (db).state |= HAS_CONTACT; \ + if ((db).routes.s && (db).routes.len > 0) \ + (db).state |= HAS_ROUTES; \ + if ((db).sock) \ + (db).state |= HAS_SOCK; \ + } while(0) + +typedef decoded_info_buffer_t (*decode_info_fn)(str *); +static decoded_info_buffer_t decode_info_buffer(str *); +static decoded_info_buffer_t decode_info_buffer_legacy(str *); + +static int th_no_dlg_encode_contact(struct sip_msg *, uint16_t, str, str *); + +static inline int th_no_dlg_onrequest(struct sip_msg *, uint16_t, str *); +static void th_no_dlg_onreply(struct cell *, int, struct tmcb_params *); +static int th_no_dlg_seq_handling(struct sip_msg *, str *, decode_info_fn); +static inline int th_no_dlg_one_way_hiding(const struct socket_info *); +static struct lump* th_no_dlg_add_auto_record_route(struct sip_msg *, uint16_t, struct lump *); +static route_count_t th_no_dlg_match_record_route_or_route_uris(struct sip_msg *, struct sip_msg *, hdr_types_t, int); + +static char* build_encoded_thinfo_suffix(struct sip_msg *, str, int *, uint16_t, int); + +int topo_hiding_no_dlg(struct sip_msg *req, struct cell* t, unsigned int extra_flags, struct th_params *params) { + struct th_no_dlg_param *p = NULL; + str *username = NULL; + size_t param_size = 0; + + if (extra_flags & TOPOH_HIDE_CALLID) + LM_WARN("Cannot hide callid when dialog support is not engaged!\n"); + if (extra_flags & TOPOH_DID_IN_USER) + LM_WARN("Cannot store DID in user when dialog support is not engaged!\n"); + + if (!(extra_flags & TOPOH_KEEP_USER) && params && params->ct_callee_user.len) { + param_size = sizeof *p + params->ct_callee_user.len + sizeof(uint16_t); + } else { + param_size = sizeof *p; + } + + p = shm_malloc(param_size); + if (p == NULL) { + LM_ERR("Failed to allocate params\n"); + return -1; + } + + memset(p, 0, sizeof *p); + + if (!(extra_flags & TOPOH_KEEP_USER)) { + p->username.s = (char *)(p + 1); + p->username.len = params->ct_callee_user.len; + memcpy(p->username.s, params->ct_callee_user.s, + params->ct_callee_user.len); + + username = ¶ms->ct_caller_user; + } + + p->flags = extra_flags; + + if (th_no_dlg_onrequest(req, extra_flags, username) < 0) { + LM_ERR("Failed to do topology_hiding on request\n"); + goto error; + } + + if (tm_api.register_tmcb(req, 0, TMCB_RESPONSE_FWDED, th_no_dlg_onreply, p, shm_free_wrap) < 0) { + LM_ERR("failed to register TMCB\n"); + goto error; + } + + return 1; +error: + shm_free_wrap(p); + return -1; +} + +static int th_no_dlg_auto_route_seq_handling(struct sip_msg *msg, rr_t auto_route[static 1], str thinfo[static 1], int self_route) { + struct th_no_dlg_param *p = NULL; + rr_t *after_auto = NULL; + const struct socket_info *sock = NULL; + str host = STR_NULL; + str route_s = STR_NULL; + char *route_free_str = NULL; + int max_size = 0, dec_len = 0, proto = 0, i = 0; + uint16_t flags; + unsigned short port = 0; + + max_size = th_ct_enc_scheme == ENC_BASE64 ? + calc_max_word64_decode_len(thinfo->len) : + calc_max_word32_decode_len(thinfo->len); + + if (max_size > MAX_THINFO_BUFFER_SIZE) { + return -1; + } + + if (th_ct_enc_scheme == ENC_BASE64) + dec_len = word64decode(decoded_uri_buf.buf, (unsigned char *) thinfo->s, thinfo->len); + else + dec_len = word32decode(decoded_uri_buf.buf, (unsigned char *) thinfo->s, thinfo->len); + + if (dec_len <= 0) { + LM_ERR("Failed to decode\n"); + return TOPOH_MATCH_FAILURE; + } + + LM_DBG("Size of base64 decoded length %d and size of param len %d\n", dec_len, thinfo->len); + + for (i = 0; i < dec_len; i++) + decoded_uri_buf.buf[i] ^= topo_hiding_ct_encode_pw.s[i % topo_hiding_ct_encode_pw.len]; + + if (thinfo_get_uri_count(&decoded_uri_buf) != 0) { + LM_ERR("Encoded URI count is invalid, can only be 0 in auto Route\n"); + return TOPOH_MATCH_FAILURE; + } + + flags = thinfo_get_flags(&decoded_uri_buf); + + decoded_uri_buf.len = dec_len; + decoded_uri_buf.pos = 0; + + if (thinfo_decode_socket(&decoded_uri_buf, &proto, &host, &port) <= 0) { + LM_ERR("Failed to decode socket 0\n"); + return -1; + } + + LM_DBG("Decoded socket host [%.*s] - Port - %d - Proto %d\n", host.len, host.s, port, proto); + + if (self_route) { + sock = grep_sock_info(&host, port, proto); + } else if (th_external_socket_tag.len > 0) { + sock = grep_internal_sock_info(&th_external_socket_tag, 0, proto); + } else { + LM_ERR("No external socket tag defined\n"); + return TOPOH_MATCH_FAILURE; + } + + if (sock != NULL) { + msg->force_send_socket = sock; + } else if (sock == NULL) { + LM_ERR("No socket found encoded in the auto Route\n"); + return TOPOH_MATCH_FAILURE; + } + + if (topo_delete_record_route_uris(msg, 0) < 0) { + LM_ERR("Failed to remove Record Route header \n"); + return TOPOH_MATCH_FAILURE; + } + + if (topo_delete_vias(msg) < 0) { + LM_ERR("Failed to remove via headers\n"); + return TOPOH_MATCH_FAILURE; + } + + if (msg->record_route) { + if (print_rr_body(msg->record_route, &route_s, 0, 0, NULL) != 0){ + LM_ERR("failed to print route records \n"); + if (route_s.s != NULL) { + pkg_free(route_s.s); + } + return TOPOH_MATCH_FAILURE; + } + route_free_str = route_s.s; + } + + if (th_no_dlg_encode_contact(msg, flags, route_s, NULL) < 0) { + LM_ERR("Failed to encode contact header\n"); + if (route_free_str != NULL) { + pkg_free(route_free_str); + } + return TOPOH_MATCH_FAILURE; + } + + if (route_free_str != NULL) { + pkg_free(route_free_str); + } + + after_auto = auto_route->next; + + if (topo_delete_route_uris(msg, 1) < 0) { + LM_ERR("Failed to Auto Route URI\n"); + return -1; + } + + if (after_auto != NULL && set_dst_uri(msg, &after_auto->nameaddr.uri) !=0) { + LM_ERR("Error set_dst_uri\n"); + return TOPOH_MATCH_FAILURE; + } + + p = shm_malloc(sizeof *p); + if (p == NULL) { + LM_ERR("Failed to allocate params\n"); + return -1; + } + + memset(p, 0, sizeof *p); + + p->flags = flags; + + if (tm_api.register_tmcb(msg, 0, TMCB_RESPONSE_FWDED, th_no_dlg_onreply, p, shm_free_wrap) < 0) { + LM_ERR("failed to register TMCB\n"); + shm_free(p); + return TOPOH_MATCH_FAILURE; + } + + p = NULL; + + return TOPOH_MATCH_SUCCESS; +} + +int topo_hiding_match_no_dlg(struct sip_msg *msg) { + struct sip_uri *request_uri; + struct sip_uri route_uri = { 0 }; + str *thinfo = NULL; + rr_t *auto_route = NULL; + int i, self_route, tag_match; + + if (parse_sip_msg_uri(msg) < 0) { + LM_ERR("Failed to parse request URI\n"); + return -1; + } + + if (parse_headers(msg, HDR_EOH_F, 0) == -1) { + LM_ERR("failed to parse route headers\n"); + } + + request_uri = &msg->parsed_uri; + + if (msg->route == NULL && check_self(&request_uri->host, request_uri->port_no ? request_uri->port_no : SIP_PORT, 0)) { + /* topology_hiding_match with thinfo and request domain is us + * needs to have a thinfo to continue otherwise we cannot match */ + for (i = 0; i < request_uri->u_params_no; i++) { + if (request_uri->u_name[i].len == th_contact_encode_param.len && + memcmp(th_contact_encode_param.s, request_uri->u_name[i].s, th_contact_encode_param.len) == 0) { + LM_DBG("We found param in R-URI with value of %.*s\n", + request_uri->u_val[i].len, request_uri->u_val[i].s); + return th_no_dlg_seq_handling(msg, &request_uri->u_val[i], decode_info_buffer); + } else if (request_uri->u_name[i].len == th_contact_encode_param_legacy.len && + memcmp(th_contact_encode_param_legacy.s, request_uri->u_name[i].s, th_contact_encode_param_legacy.len) == 0) { + LM_DBG("We found legacy param in R-URI with value of %.*s\n", + request_uri->u_val[i].len, request_uri->u_val[i].s); + return th_no_dlg_seq_handling(msg, &request_uri->u_val[i], decode_info_buffer_legacy); + } + } + } else if (msg->route != NULL && auto_route_on_trusted_socket) { + LM_DBG("Route header found, checking params\n"); + + if (!msg->route->parsed && parse_rr(msg->route) != 0) { + LM_ERR("failed to parse Route header\n"); + return -1; + } + + auto_route = (rr_t *) msg->route->parsed; + + if (parse_uri(auto_route->nameaddr.uri.s, auto_route->nameaddr.uri.len, &route_uri) < 0) { + LM_ERR("Bad Route URI\n"); + return TOPOH_MATCH_FAILURE; + } + + LM_DBG("Auto Route header has '%d' params\n", route_uri.u_params_no); + + self_route = check_self(&route_uri.host, route_uri.port_no ? route_uri.port_no : SIP_PORT, 0); + tag_match = th_no_dlg_one_way_hiding(msg->rcv.bind_address); + + if (self_route || tag_match) { + if (!tag_match) { + LM_ERR("Inbound socket is not a trusted internal socket or tag matching disable\n"); + return TOPOH_MATCH_FAILURE; + } + + for (i = 0; i < route_uri.u_params_no; i++) { + if (route_uri.u_name[i].len == th_contact_encode_param.len && + memcmp(th_contact_encode_param.s, route_uri.u_name[i].s, th_contact_encode_param.len) == 0) { + LM_DBG("We found param in Route header with value of %.*s\n", + route_uri.u_val[i].len, route_uri.u_val[i].s); + + thinfo = &route_uri.u_val[i]; + break; + } + } + + if (thinfo == NULL) { + LM_ERR("No param with %.*s found in auto Route\n", th_contact_encode_param.len, th_contact_encode_param.s); + return TOPOH_MATCH_FAILURE; + } + + return th_no_dlg_auto_route_seq_handling(msg, auto_route, thinfo, self_route); + } + } + + LM_DBG("Topology hiding did not match\n"); + return TOPOH_MATCH_FAILURE; +} + +static int free_msg_rrs(struct sip_msg *msg) { + struct hdr_field *hdr; + + for (hdr = msg->record_route; hdr; hdr = hdr->sibling) { + if (hdr->parsed) { + free_rr((rr_t **)&hdr->parsed); + hdr->parsed = NULL; + } + } + + return 0; +} + +static struct lump *anchor_after_last_record_route(struct sip_msg *msg) { + struct hdr_field *last_rr = msg->record_route; + unsigned int offset; + + if (last_rr) { + while (last_rr->sibling) + last_rr = last_rr->sibling; + offset = last_rr->name.s + last_rr->len - msg->buf; + } else { + offset = msg->headers->name.s - msg->buf; + } + + return anchor_lump(msg, offset, HDR_RECORDROUTE_T); +} + +// TODO log callId perhaps? +static void th_no_dlg_onreply(struct cell *t, int type, struct tmcb_params *param) { + struct th_no_dlg_param *p = *(param->param); + str route_s = STR_NULL; + str *username = &p->username; + str *rpl_original_rrs = NULL; + str *additional_rrs = NULL; + struct sip_msg *req = param->req; + struct sip_msg *rpl = param->rpl; + struct lump *lmp = NULL, *rr_lmp = NULL; + char *suffix = NULL, *req_rr_buf = NULL, *rpl_rr_buf = NULL, *rr_free_str = NULL; + int req_rr_count = 0, rpl_rr_count = 0, req_rr_buf_len = 0, rpl_rr_buf_len = 0; + unsigned int flags = p->flags; + int is_sequential = 0; + int rebuild_req_rrs = 0; + int one_way_hiding = th_no_dlg_one_way_hiding(t->uas.response.dst.send_sock); + int req_one_way_hiding = th_no_dlg_one_way_hiding(t->uac[t->first_branch]->request.dst.send_sock); + route_count_t route_count = { 0 }; + + LM_DBG("Response callback with flags %u \n", flags); + + /* parse all headers to be sure that all RR and Contact hdrs are found */ + if (parse_headers(rpl, HDR_EOH_F, 0)< 0) { + LM_ERR("Failed to parse reply\n"); + return; + } + + if (parse_to_header(req) < 0 || req->to == NULL || get_to(req) == NULL) { + LM_ERR("cannot parse TO header\n"); + return; + } + + /* do_rr determined by if the request has a tag, don't add them on sequential */ + is_sequential = get_to(req)->tag_value.len > 0 && get_to(req)->tag_value.s != NULL; + + LM_DBG("Original request trusted send sock '%d' reply is trusted send sock '%d'\n", req_one_way_hiding, one_way_hiding); + + if (!req_one_way_hiding && (lmp = restore_vias_from_req(req, rpl)) == NULL) { + LM_ERR("Failed to restore VIA headers from request \n"); + return; + } + + if (!is_sequential && req_one_way_hiding) { + route_count = th_no_dlg_match_record_route_or_route_uris(req, rpl, HDR_RECORDROUTE_T, auto_route_on_trusted_socket && req_one_way_hiding); + + if (topo_delete_record_route_uris(rpl, route_count.delete_count) < 0) { + LM_ERR("Failed to remove '%d' Record-Route URIs\n", route_count.delete_count); + goto cleanup; + } + } else if (!is_sequential && one_way_hiding) { + // Rebuild the Record-Routes for consistency into single uri per single header + if ((rpl_rr_count = list_rr_body(rpl->record_route, &rpl_original_rrs)) < 0 ){ + LM_ERR("failed to print route records \n"); + goto cleanup; + } + + if (rpl_rr_count > 0) { + if (topo_delete_record_route_uris(rpl, 0) < 0) { + LM_ERR("Failed to remove all Record-Route URIs\n"); + goto cleanup; + } + + if (rr_lmp == NULL) { + rr_lmp = anchor_lump(rpl, rpl->headers->name.s - rpl->buf, HDR_RECORDROUTE_T); + } + + for (int i = 0; i < rpl_rr_count; i++) { + BUILD_RR_HEADER_BUFFER(rpl_rr_buf, rpl_rr_buf_len, rpl_original_rrs[i]); + + if (!rpl_rr_buf) { + LM_ERR("no more pkg memory\n"); + goto cleanup; + } + + if (!(rr_lmp = insert_new_lump_after(rr_lmp, rpl_rr_buf, rpl_rr_buf_len, 0))) { + LM_ERR("failed to insert prefix\n"); + pkg_free(rpl_rr_buf); + goto cleanup; + } + } + } + + if (auto_route_on_trusted_socket) { + rr_lmp = th_no_dlg_add_auto_record_route(rpl, flags, rr_lmp); + if (rr_lmp == NULL) { + LM_ERR("Failed to add Record-Route header\n"); + if (suffix) + pkg_free(suffix); + goto cleanup; + } + } + + rebuild_req_rrs = req->record_route != NULL; + } else { + rebuild_req_rrs = req->record_route != NULL; + + if (topo_delete_record_route_uris(rpl, 0) < 0) { + LM_ERR("Failed to remove all Record-Route URIs\n"); + goto cleanup; + } + } + + if (rebuild_req_rrs) { + if (one_way_hiding && (lmp = restore_vias_from_req(req, rpl)) == NULL) { + LM_ERR("Failed to restore VIA headers from request \n"); + return; + } + + if (rr_lmp == NULL) { + rr_lmp = anchor_after_last_record_route(rpl); + } + + if ((req_rr_count = list_rr_body(req->record_route, &additional_rrs)) < 0 ) { + LM_ERR("failed to print route records \n"); + goto cleanup; + } + + for (int i = 0; i < req_rr_count; i++) { + BUILD_RR_HEADER_BUFFER(req_rr_buf, req_rr_buf_len, additional_rrs[i]); + + if (!req_rr_buf) { + LM_ERR("no more pkg memory\n"); + goto cleanup; + } + + if (!(rr_lmp = insert_new_lump_after(rr_lmp, req_rr_buf, req_rr_buf_len, 0))) { + LM_ERR("failed to insert prefix\n"); + pkg_free(req_rr_buf); + goto cleanup; + } + } + } + if (!one_way_hiding && !(rpl->REPLY_STATUS >= 300 && rpl->REPLY_STATUS < 400)) { + if (p->routes.s != NULL) { + route_s = p->routes; + } else if (rpl->record_route) { + if (print_rr_body(rpl->record_route, &route_s, 1, 0, &route_count.skip_encode_count) != 0){ + LM_ERR("failed to print route records \n"); + goto cleanup; + } + + rr_free_str = route_s.s; + } + + if (th_no_dlg_encode_contact(rpl, flags, route_s, username) < 0) { + LM_ERR("Failed to encode contact header \n"); + } + } +cleanup: + /* We parse the record-routes in the request from the transaction + * they need to be cleaned up as it's in pkg memory + * this request can used from a transaction timeout to generate a response + * if they're parsed and not nulled it will crash + */ + free_msg_rrs(req); + if (rr_free_str != NULL) + pkg_free(rr_free_str); +} + +static inline int th_no_dlg_onrequest(struct sip_msg *req, uint16_t flags, str *username) { + int one_way_hiding = 0; + int do_rr = 0; + str route_s = STR_NULL; + + LM_DBG("Request callback with flags %u\n", flags); + + /* parse all headers to be sure that all RR and Contact hdrs are found */ + if (parse_headers(req, HDR_EOH_F, 0) >= 0) { + one_way_hiding = th_no_dlg_one_way_hiding(req->force_send_socket != NULL ? req->force_send_socket : req->rcv.bind_address); + do_rr = get_to(req)->tag_value.len == 0 || get_to(req)->tag_value.s == NULL; + if (!one_way_hiding) { + if (topo_delete_vias(req) < 0) { + LM_ERR("Failed to remove via headers\n"); + return -1; + } + + if (req->record_route) { + if (print_rr_body(req->record_route, &route_s, 0, 0, NULL) != 0){ + LM_ERR("failed to print route records \n"); + goto error; + } + } + + if (th_no_dlg_encode_contact(req, flags, route_s, username) < 0) { + LM_ERR("Failed to encode contact header\n"); + goto error; + } -/* We encode the RR headers, the actual Contact and the socket str for this leg */ -/* Via headers will be restored using the TM module, no need to save anything for them */ -static char* build_encoded_contact_suffix(struct sip_msg* msg, str *routes, int *suffix_len, int flags) -{ + if (topo_delete_record_route_uris(req, 0) < 0) { + LM_ERR("Failed to remove Record Route header \n"); + goto error; + } + } else if (do_rr && auto_route_on_trusted_socket) { + if (th_no_dlg_add_auto_record_route(req, flags, NULL) == NULL) { + LM_ERR("Failed to add Record-Route header\n"); + return -1; + } + } + } else { + LM_ERR("Failed to parse request\n"); + return -1; + } + + return 1; +error: + if (route_s.s != NULL) { + pkg_free(route_s.s); + } + + return -1; +} + +#define HAS_NO_CONTACT_BODY(_m) (((contact_body_t *) ((_m)->contact->parsed))->star == 1 || \ + ((contact_body_t *) ((_m)->contact->parsed))->contacts == NULL || \ + ((contact_body_t *) ((_m)->contact->parsed))->contacts->next != NULL) + +static char* build_encoded_contact_suffix_legacy(struct sip_msg* msg, str rr_set, int *suffix_len, int flags) { short rr_len,ct_len,addr_len,flags_len,enc_len; - char *suffix_plain,*suffix_enc,*p,*s; - str rr_set = {NULL, 0}; + char *suffix_plain = NULL,*suffix_enc = NULL,*p = NULL,*s = NULL; + char *rr_set_free_str = NULL; str contact; str flags_str; int i,total_len; - struct sip_uri ctu; + struct sip_uri ctu, rr_uri; struct th_ct_params* el; param_t *it; - int is_req = (msg->first_line.type==SIP_REQUEST)?1:0; + rr_t *head = NULL; + const struct socket_info *rr_sock = NULL; + int params_len = 0; int local_len = sizeof(short) /* RR length */ + - sizeof(short) /* Contact length */ + - sizeof(short) /* Flags length */ + - sizeof(short) /* bind addr */; + sizeof(short) /* Contact length */ + + sizeof(short) /* RR length */ + + sizeof(short) /* bind addr */; /* parse all headers as we can have multiple RR headers in the same message */ - if( parse_headers(msg,HDR_EOH_F,0)<0 ){ + if (parse_headers(msg,HDR_EOH_F,0)<0 ){ LM_ERR("failed to parse all headers\n"); return NULL; } - if (routes && routes->len) { - rr_set = *routes; - rr_len = (short)routes->len; - } else if(msg->record_route){ - if(print_rr_body(msg->record_route, &rr_set, !is_req, 0, NULL) != 0){ - LM_ERR("failed to print route records \n"); - return NULL; - } - rr_len = (short)rr_set.len; - } else { - rr_len = 0; - } - - if ( parse_contact(msg->contact)<0 || - ((contact_body_t *)msg->contact->parsed)->contacts==NULL || - ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { + if (parse_contact(msg->contact) < 0 || HAS_NO_CONTACT_BODY(msg)) { LM_ERR("bad Contact HDR\n"); goto error; } else { @@ -84,6 +709,8 @@ static char* build_encoded_contact_suffix(struct sip_msg* msg, str *routes, int ct_len = (short)contact.len; } + rr_len = rr_set.len; + flags_str.s = int2str(flags, &flags_str.len); flags_len = (short)flags_str.len; @@ -93,14 +720,13 @@ static char* build_encoded_contact_suffix(struct sip_msg* msg, str *routes, int calc_word64_encode_len(local_len) : calc_word32_encode_len(local_len); total_len = enc_len + 1 /* ; */ + - th_contact_encode_param.len + + th_contact_encode_param_legacy.len + 1 /* = */ + + params_len + /* URI and header params */ 1 /* > */; if (th_param_list) { - if ( parse_contact(msg->contact)<0 || - ((contact_body_t *)msg->contact->parsed)->contacts==NULL || - ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { + if (parse_contact(msg->contact) < 0 || HAS_NO_CONTACT_BODY(msg)) { LM_ERR("bad Contact HDR\n"); } else { contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri; @@ -111,7 +737,7 @@ static char* build_encoded_contact_suffix(struct sip_msg* msg, str *routes, int /* we just iterate over the unknown params */ for (i=0;iparam_name, &ctu.u_name[i])) - total_len += topo_ct_param_len(&ctu.u_name[i], &ctu.u_val[i], 0); + params_len += topo_ct_param_len(&ctu.u_name[i], &ctu.u_val[i], 0); } } } @@ -119,20 +745,42 @@ static char* build_encoded_contact_suffix(struct sip_msg* msg, str *routes, int } if (th_hdr_param_list) { - if ( parse_contact(msg->contact)<0 || - ((contact_body_t *)msg->contact->parsed)->contacts==NULL || - ((contact_body_t *)msg->contact->parsed)->contacts->next!=NULL ) { + if (parse_contact(msg->contact) < 0 || HAS_NO_CONTACT_BODY(msg)) { LM_ERR("bad Contact HDR\n"); } else { for (el=th_hdr_param_list;el;el=el->next) { for (it=((contact_body_t *)msg->contact->parsed)->contacts->params;it;it=it->next) { if (str_match(&el->param_name, &it->name)) - total_len += topo_ct_param_len(&it->name, &it->body, 1); + params_len += topo_ct_param_len(&it->name, &it->body, 1); } } } } + if (rr_set.len > 0) { + if (parse_rr_body(rr_set.s, rr_set.len, &head) != 0) { + LM_ERR("failed parsing route set\n"); + goto error; + } + + if (parse_uri(head->nameaddr.uri.s, head->nameaddr.uri.len, &rr_uri) < 0) { + LM_ERR("Failed to parse SIP uri\n"); + goto error; + } + + rr_sock = grep_sock_info(&rr_uri.host, rr_uri.port_no ? rr_uri.port_no : SIP_PORT, rr_uri.proto); + + if (th_no_dlg_one_way_hiding(rr_sock)) { + rr_set.s = rr_set.s + head->nameaddr.uri.len + 1; + rr_set.len = rr_set.len - (head->nameaddr.uri.len + 1); + } + } + + if (head != NULL) + pkg_free(head); + + total_len += params_len; + suffix_enc = pkg_malloc(total_len+1); if (!suffix_enc) { LM_ERR("no more pkg\n"); @@ -166,12 +814,12 @@ static char* build_encoded_contact_suffix(struct sip_msg* msg, str *routes, int memcpy(p,msg->rcv.bind_address->sock_str.s,msg->rcv.bind_address->sock_str.len); p+= msg->rcv.bind_address->sock_str.len; for (i=0;i<(int)(p-suffix_plain);i++) - suffix_plain[i] ^= topo_hiding_ct_encode_pw.s[i%topo_hiding_ct_encode_pw.len]; + suffix_plain[i] ^= topo_hiding_ct_encode_pw_legacy.s[i%topo_hiding_ct_encode_pw_legacy.len]; s = suffix_enc; *s++ = ';'; - memcpy(s,th_contact_encode_param.s,th_contact_encode_param.len); - s+= th_contact_encode_param.len; + memcpy(s,th_contact_encode_param_legacy.s,th_contact_encode_param_legacy.len); + s+= th_contact_encode_param_legacy.len; *s++ = '='; if (th_ct_enc_scheme == ENC_BASE64) word64encode((unsigned char*)s,(unsigned char *)suffix_plain,p-suffix_plain); @@ -204,296 +852,663 @@ static char* build_encoded_contact_suffix(struct sip_msg* msg, str *routes, int } } - if (rr_set.s && !routes) - pkg_free(rr_set.s); - pkg_free(suffix_plain); - *suffix_len = total_len; - return suffix_enc; + if (rr_set_free_str) + pkg_free(rr_set_free_str); + pkg_free(suffix_plain); + *suffix_len = total_len; + return suffix_enc; +error: + if (suffix_enc) + pkg_free(suffix_enc); + if (suffix_plain) + pkg_free(suffix_plain); + if (rr_set_free_str) + pkg_free(rr_set_free_str); + return NULL; +} + +static char* build_encoded_thinfo_suffix(struct sip_msg* msg, str rr_set, int *suffix_len, uint16_t flags, int socket_only) { + uint16_t enc_len = 0; + char *suffix_enc, *s; + rr_t *next = NULL, *head = NULL; + int i, x, params_len = 0; + struct sip_uri ctu = { 0 }, rr_uri = { 0 }, rr_uri_r2 = { 0 }; + struct th_ct_params* el; + param_t *it; + str contact = STR_NULL; + char *rr_set_free_str = NULL; + const struct socket_info *rr_sock = NULL; + str ct_uri_params_skip[URI_MAX_U_PARAMS]; + int param_count = 0; + + /* parse all headers as we can have multiple + RR headers in the same message */ + if (parse_headers(msg, HDR_EOH_F, 0) < 0) { + LM_ERR("failed to parse all headers\n"); + return NULL; + } + + thinfo_buffer_reset(&encoded_uri_buf); + + if (socket_only == 1) { + goto socket_only; + } + + if (parse_contact(msg->contact) < 0 || HAS_NO_CONTACT_BODY(msg)) { + LM_ERR("bad Contact HDR\n"); + goto error; + } else { + contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri; + if (parse_uri(contact.s, contact.len, &ctu) < 0) { + LM_ERR("Bad Contact URI\n"); + goto error; + } + } + + if (th_param_list) { + for (el = th_param_list; el; el = el->next) { + /* we just iterate over the unknown params */ + for (i = 0; i < ctu.u_params_no; i++) { + if (str_match(&el->param_name, &ctu.u_name[i])) { + ct_uri_params_skip[param_count++] = ctu.u_name[i]; + params_len += topo_ct_param_len(&ctu.u_name[i], &ctu.u_val[i], 0); + } + } + } + } + + if (th_hdr_param_list) { + for (el = th_hdr_param_list; el; el = el->next) { + for (it = ((contact_body_t *)msg->contact->parsed)->contacts->params; it; it = it->next) { + if (str_match(&el->param_name, &it->name)) + params_len += topo_ct_param_len(&it->name, &it->body, 1); + } + } + } + + if (thinfo_encode_uri(&encoded_uri_buf, &ctu, param_count, ct_uri_params_skip, !(flags & TOPOH_KEEP_USER)) == -1) { + LM_ERR("Error encoding Contact URI\n"); + goto error; + } + + if (rr_set.len > 0) { + if (parse_rr_body(rr_set.s, rr_set.len, &head) != 0) { + LM_ERR("failed parsing route set\n"); + goto error; + } + + next = head; + } + + while (next != NULL) { + if (parse_uri(next->nameaddr.uri.s, next->nameaddr.uri.len, &rr_uri) < 0) { + LM_ERR("Failed to parse SIP uri\n"); + goto error; + } + + rr_sock = grep_sock_info(&rr_uri.host, rr_uri.port_no ? rr_uri.port_no : SIP_PORT, rr_uri.proto); + + if (!th_no_dlg_one_way_hiding(rr_sock)) { + if (!is_2rr(&rr_uri.params)) { + if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri, 0, NULL, 1) == -1) { + LM_ERR("Error encoding Route URI\n"); + goto error; + } + } else { + next = next->next; + if (next != NULL) { + if (parse_uri(next->nameaddr.uri.s, next->nameaddr.uri.len, &rr_uri_r2) < 0) { + LM_ERR("Failed to parse SIP uri\n"); + goto error; + } + } else { + if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri, 0, NULL, 1) == -1) { + LM_ERR("Error encoding Route URI\n"); + goto error; + } + LM_WARN("Previous Route has r2=on but no next Route\n"); + continue; + } + + if (is_2rr(&rr_uri_r2.params) && str_match(&rr_uri.host, &rr_uri_r2.host)) { + if (thinfo_encode_dual_uri(&encoded_uri_buf, &rr_uri, &rr_uri_r2) == -1) { + LM_ERR("Error encoding Route URI\n"); + goto error; + } + } else { + if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri, 0, NULL, 1) == -1) { + LM_ERR("Error encoding Route URI\n"); + goto error; + } + + if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri_r2, 0, NULL, 1) == -1) { + LM_ERR("Error encoding Route URI\n"); + goto error; + } + } + + memset(&rr_uri_r2, 0, sizeof(rr_uri_r2)); + } + } + + memset(&rr_uri, 0, sizeof(rr_uri)); + next = next->next; + } + + if (head != NULL) { + pkg_free(head); + head = NULL; + } + +socket_only: + if (thinfo_encode_socket(&encoded_uri_buf, msg->rcv.bind_address) < 0) { + LM_ERR("Error encoding socket\n"); + goto error; + } + + enc_len = th_ct_enc_scheme == ENC_BASE64 ? + calc_word64_encode_len(encoded_uri_buf.len) : calc_word32_encode_len(encoded_uri_buf.len); + + thinfo_buffer_finalize(&encoded_uri_buf, flags); + + for (i = 0; i < encoded_uri_buf.len; i++) + encoded_uri_buf.buf[i] ^= topo_hiding_ct_encode_pw.s[i % topo_hiding_ct_encode_pw.len]; + + suffix_enc = pkg_malloc(1 + th_contact_encode_param.len + 1 + enc_len + params_len + 1); + if (!suffix_enc) { + LM_ERR("no more pkg\n"); + goto error; + } + + s = suffix_enc; + *s++ = ';'; + memcpy(s, th_contact_encode_param.s, th_contact_encode_param.len); + s += th_contact_encode_param.len; + *s++ = '='; + + if (th_ct_enc_scheme == ENC_BASE64) + word64encode((unsigned char*)s, encoded_uri_buf.buf, encoded_uri_buf.len); + else + word32encode((unsigned char*)s, encoded_uri_buf.buf, encoded_uri_buf.len); + + s += enc_len; + + if (param_count > 0) { + for (x = 0; x < param_count; x++) { + /* we just iterate over the unknown params */ + for (i = 0; i < ctu.u_params_no; i++) { + if (str_match(&ct_uri_params_skip[x], &ctu.u_name[i])) + s = topo_ct_param_copy(s, &ctu.u_name[i], &ctu.u_val[i], 0); + } + } + } + + if (!socket_only) + *s++ = '>'; + + if (socket_only != 1 && th_hdr_param_list) { + for (el = th_hdr_param_list; el; el = el->next) { + for (it = ((contact_body_t *)msg->contact->parsed)->contacts->params; it; it = it->next) { + if (str_match(&el->param_name, &it->name)) + s = topo_ct_param_copy(s, &it->name, &it->body, 1); + } + } + } + + if (rr_set_free_str) + pkg_free(rr_set_free_str); + + *suffix_len = s - suffix_enc; + + return suffix_enc; +error: + if (rr_set_free_str) { + pkg_free(rr_set_free_str); + } + if (head) { + pkg_free(head); + } + if (suffix_enc) { + pkg_free(suffix_enc); + } + return NULL; +} + +static int th_no_dlg_encode_contact(struct sip_msg *msg, uint16_t flags, str routes, str *ct_user) { + struct lump* lump; + char *prefix = NULL,*suffix = NULL,*ct_username = NULL; + int prefix_len, suffix_len = 0, ct_username_len = 0; + struct sip_uri ctu; + str contact; + + if (!msg->contact) { + if(parse_headers(msg, HDR_CONTACT_F, 0)< 0) { + LM_ERR("Failed to parse headers\n"); + return -1; + } + if (!msg->contact) + return 0; + } + + if (!(lump = delete_existing_contact(msg, 0))) { + LM_ERR("Failed to delete existing contact \n"); + goto error; + } + + LM_DBG("Flags '%d' passed for encoding Contact\n", flags); + + prefix_len = 5; /* len) { + ct_username = ct_user->s; + ct_username_len = ct_user->len; + prefix_len += 1 + /* @ */ + ct_username_len; + } else if (flags & TOPOH_KEEP_USER) { + if (parse_contact(msg->contact) < 0 || HAS_NO_CONTACT_BODY(msg)) { + LM_ERR("bad Contact HDR\n"); + } else { + contact = ((contact_body_t *)msg->contact->parsed)->contacts->uri; + if (parse_uri(contact.s, contact.len, &ctu) < 0) { + LM_ERR("Bad Contact URI\n"); + } else { + ct_username = ctu.user.s; + ct_username_len = ctu.user.len; + LM_DBG("Trying to propagate username [%.*s]\n", ct_username_len, + ct_username); + if (ct_username_len > 0) + prefix_len += 1 + /* @ */ + ct_username_len; + } + } + } + + prefix = pkg_malloc(prefix_len); + if (!prefix) { + LM_ERR("no more pkg\n"); + goto error; + } + + memcpy(prefix, " 0) { + memcpy(prefix + 5, ct_username, ct_username_len); + prefix[prefix_len - 1] = '@'; + } + + if (!(lump = insert_new_lump_after(lump, prefix, prefix_len,0))) { + LM_ERR("failed inserting 'param); - struct sip_msg *req = param->req; - struct sip_msg *rpl = param->rpl; - char *route; - int size; +static inline int topo_no_dlg_route(struct sip_msg *msg, str rr_buf[static 1]) { + rr_t *head = NULL, *rrp = NULL; + struct sip_uri rr_uri; + char *route = NULL, *hdrs = NULL; + int size = 0, start_index = 0; + int route_flags = 0; + struct lump *lmp = NULL; + + if (parse_rr_body(rr_buf->s, rr_buf->len, &head) != 0) { + LM_ERR("failed parsing route set\n"); + route_flags = ROUTE_FAILURE; + goto cleanup; + } - /* parse all headers to be sure that all RR and Contact hdrs are found */ - if (parse_headers(rpl, HDR_EOH_F, 0)< 0) { - LM_ERR("Failed to parse reply\n"); - return; + rrp = head; + + if (parse_uri(head->nameaddr.uri.s, head->nameaddr.uri.len, &rr_uri) < 0) { + LM_ERR("Failed to parse SIP uri\n"); + route_flags = ROUTE_FAILURE; + goto cleanup; } - if (topo_delete_record_routes(rpl) < 0) { - LM_ERR("Failed to remove Record Route header \n"); - return; + if (!is_strict(&rr_uri.params)) { + route_flags |= ROUTE_LOOSE; + } else { + route_flags |= ROUTE_STRICT; } - if(topo_delete_vias(rpl) < 0) { - LM_ERR("Failed to remove via headers\n"); - return; + if (is_2rr(&rr_uri.params)) { + route_flags |= ROUTE_DOUBLE_RR; } - if ( !(rpl->REPLY_STATUS>=300 && rpl->REPLY_STATUS<400) ) { - if (topo_no_dlg_encode_contact(rpl,flags, - (p?&p->routes:NULL),(p?&p->username:NULL)) < 0) { - LM_ERR("Failed to encode contact header \n"); - return; + if (route_flags & (ROUTE_STRICT | ROUTE_SELF)) { + LM_DBG("First Route header is a strict router\n"); + + if (route_flags & ROUTE_STRICT && set_ruri(msg, &rrp->nameaddr.uri) != 0) { + LM_ERR("failed setting new dst uri\n"); + route_flags = ROUTE_FAILURE; + goto cleanup; } - } - if (!(lmp = restore_vias_from_req(req,rpl))) { - LM_ERR("Failed to restore VIA headers from request \n"); - return ; + start_index = rrp->nameaddr.uri.len + 3; /* 3 = <>,*/ + rrp = head->next; } - /* pass record route headers */ - if(do_rr && req->record_route){ - if(print_rr_body(req->record_route, &rr_set, 0, 1, NULL) != 0 ){ - LM_ERR("failed to print route records \n"); - return; - } + hdrs = rr_buf->s + start_index; - size = rr_set.len + RECORD_ROUTE_LEN + CRLF_LEN; + if (rrp != NULL && start_index < rr_buf->len) { + size = rr_buf->len - start_index + ROUTE_LEN + CRLF_LEN; route = pkg_malloc(size); - if (route == NULL) { + if (route == 0) { LM_ERR("no more pkg memory\n"); - pkg_free(rr_set.s); - return; + route_flags = ROUTE_FAILURE; + goto cleanup; } - memcpy(route, RECORD_ROUTE, RECORD_ROUTE_LEN); - memcpy(route+RECORD_ROUTE_LEN, rr_set.s, rr_set.len); - memcpy(route+RECORD_ROUTE_LEN+rr_set.len, CRLF, CRLF_LEN); - /* put after Via */ - if ((lmp = insert_new_lump_after(lmp, route, size, HDR_RECORDROUTE_T)) == 0) { + memcpy(route, ROUTE_STR, ROUTE_LEN); + memcpy(route + ROUTE_LEN, hdrs, rr_buf->len - start_index); + memcpy(route + ROUTE_LEN + rr_buf->len - start_index, CRLF, CRLF_LEN); + + LM_DBG("Adding Route header: [%.*s] \n", size, route); + + lmp = anchor_lump(msg, msg->headers->name.s - msg->buf, HDR_RECORDROUTE_T); + + if (lmp == NULL || insert_new_lump_after(lmp, route, size, HDR_ROUTE_T) == NULL) { LM_ERR("failed inserting new route set\n"); pkg_free(route); - pkg_free(rr_set.s); - return; + route_flags = ROUTE_FAILURE; + goto cleanup; } - LM_DBG("Added record route [%.*s]\n", size, route); - pkg_free(rr_set.s); - } - return; -} + msg->msg_flags |= FL_HAS_ROUTE_LUMP; + rr_buf->len = rr_buf->len - start_index; + rr_buf->s = memcpy(rr_buf->s, hdrs, rr_buf->len); -static void th_no_dlg_onreply(struct cell* t, int type, struct tmcb_params *param) -{ - _th_no_dlg_onreply(t,type,param,0,1); -} + LM_DBG("setting dst_uri to <%.*s> \n", rrp->nameaddr.uri.len, rrp->nameaddr.uri.s); -static void th_no_dlg_user_onreply(struct cell* t, int type, struct tmcb_params *param) -{ - _th_no_dlg_onreply(t,type,param,TOPOH_KEEP_USER,1); -} + if (route_flags & ROUTE_LOOSE && set_dst_uri(msg, &rrp->nameaddr.uri) !=0 ) { + route_flags = ROUTE_FAILURE; + LM_ERR("Error set_dst_uri\n"); + } + } -static void th_no_dlg_onreply_within(struct cell* t, int type, struct tmcb_params *param) -{ - _th_no_dlg_onreply(t,type,param,0,0); -} +cleanup: + if (head != NULL) + free_rr(&head); -static void th_no_dlg_user_onreply_within(struct cell* t, int type, struct tmcb_params *param) -{ - _th_no_dlg_onreply(t,type,param,TOPOH_KEEP_USER,0); + return route_flags; } -int topology_hiding_match(struct sip_msg *msg) -{ - struct sip_uri *r_uri; - int i; +static inline int topo_no_dlg_rewrite_contact_as_next_route(struct sip_msg *msg, const str contact_buf[static 1]) { + char *remote_contact = NULL; + struct lump *lmp = NULL; + int size = 0; - if (parse_sip_msg_uri(msg)<0) { - LM_ERR("Failed to parse request URI\n"); + size = contact_buf->len + ROUTE_PREF_LEN + ROUTE_SUFF_LEN; + remote_contact = pkg_malloc(size); + if (remote_contact == NULL) { + LM_ERR("no more pkg \n"); return -1; } - if (parse_headers(msg, HDR_ROUTE_F, 0) == -1) { - LM_ERR("failed to parse route headers\n"); - } + memcpy(remote_contact, ROUTE_PREF,ROUTE_PREF_LEN); + memcpy(remote_contact + ROUTE_PREF_LEN, contact_buf->s, contact_buf->len); + memcpy(remote_contact + ROUTE_PREF_LEN + contact_buf->len, + ROUTE_SUFF, ROUTE_SUFF_LEN); - r_uri = &msg->parsed_uri; + LM_DBG("Adding remote contact route header : [%.*s]\n", + size, remote_contact); - if (check_self(&r_uri->host,r_uri->port_no ? r_uri->port_no : SIP_PORT, 0) == 1 && msg->route == NULL) { - /* Seems we are in the topo hiding case : - * we are in the R-URI and there are no other route headers */ - for (i=0;iu_params_no;i++) - if (r_uri->u_name[i].len == th_contact_encode_param.len && - memcmp(th_contact_encode_param.s,r_uri->u_name[i].s,th_contact_encode_param.len)==0) { - LM_DBG("We found param in R-URI with value of %.*s\n", - r_uri->u_val[i].len,r_uri->u_val[i].s); - /* pass the param value to the matching funcs */ - return topo_no_dlg_seq_handling(msg,&r_uri->u_val[i]); - } + lmp = anchor_lump(msg, msg->headers->name.s - msg->buf, HDR_ROUTE_T); + + if (insert_new_lump_after(lmp, remote_contact, size, HDR_ROUTE_T) == 0) { + LM_ERR("failed inserting remote contact route\n"); + pkg_free(remote_contact); + return -1; } - return -1; + msg->msg_flags |= FL_HAS_ROUTE_LUMP; + return 1; } -int topo_hiding_no_dlg(struct sip_msg *req, - struct cell* t,int extra_flags,struct th_params *params) { - transaction_cb* used_cb; - struct th_no_dlg_param *p = NULL; +static decoded_info_buffer_t decode_info_buffer(str *info) { + int max_size, dec_len, decoded_uri_buf_len, i; + uint8_t uri_count; + int proto = 0; + str host = STR_NULL; + unsigned short port = 0; + decoded_info_buffer_t decoded_buffer = { 0 }; - /* parse all headers to be sure that all RR and Contact hdrs are found */ - if (parse_headers(req, HDR_EOH_F, 0)< 0) { - LM_ERR("Failed to parse reply\n"); - return -1; + max_size = th_ct_enc_scheme == ENC_BASE64 ? + calc_max_word64_decode_len(info->len) : + calc_max_word32_decode_len(info->len); + + LM_DBG("Size of decoded length %d\n", max_size); + if (max_size > MAX_THINFO_BUFFER_SIZE) { + LM_ERR("Size of decoded buffer %d larger than max size %d\n", max_size, MAX_THINFO_BUFFER_SIZE); + goto error; } - if (topo_delete_record_routes(req) < 0) { - LM_ERR("Failed to remove Record Route header \n"); - return -1; - } + if (th_ct_enc_scheme == ENC_BASE64) + dec_len = word64decode(decoded_uri_buf.buf, (unsigned char *)info->s, info->len); + else + dec_len = word32decode(decoded_uri_buf.buf, (unsigned char *)info->s, info->len); - if(topo_delete_vias(req) < 0) { - LM_ERR("Failed to remove via headers\n"); - return -1; + if (dec_len <= 0) { + LM_ERR("Decoded length less than zero, decoded len %d\n", dec_len); + goto error; } - if (topo_no_dlg_encode_contact(req,extra_flags,NULL, ¶ms->ct_caller_user) < 0) { - LM_ERR("Failed to encode contact header \n"); - return -1; + for (i = 0; i < dec_len; i++) + decoded_uri_buf.buf[i] ^= topo_hiding_ct_encode_pw.s[i % topo_hiding_ct_encode_pw.len]; + + decoded_uri_buf.len = dec_len; + decoded_uri_buf.pos = 0; + + uri_count = thinfo_get_uri_count(&decoded_uri_buf); + if (uri_count == 0 || uri_count > MAX_ENCODED_SIP_URIS) { + LM_ERR("Decoded URI count %d less than zero or larger than max size %d\n", uri_count, MAX_ENCODED_SIP_URIS); + goto error; + } + + LM_DBG("Decoded URI count %u\n", uri_count); + + decoded_buffer.flags = thinfo_get_flags(&decoded_uri_buf); + decoded_uri_buf_len = thinfo_decode_uris(&decoded_uri_buf, decoded_uri_str, uri_count, decoded_uris); + + if (decoded_uri_buf_len < 0) { + LM_ERR("Decoded len less than 0\n"); + goto error; + } + + if (thinfo_decode_socket(&decoded_uri_buf, &proto, &host, &port) <= 0) { + LM_ERR("Failed to decode socket\n"); + goto error; } - if (extra_flags & TOPOH_KEEP_USER) { - used_cb = th_no_dlg_user_onreply; - } else { - used_cb = th_no_dlg_onreply; - if (params && params->ct_callee_user.len) { - p = shm_malloc(sizeof *p + params->ct_callee_user.len); - if (p) { - memset(p, 0, sizeof *p); - p->username.s = (char *)(p + 1); - p->username.len = params->ct_callee_user.len; - memcpy(p->username.s, params->ct_callee_user.s, - params->ct_callee_user.len); - } + if (host.len > 0 && host.s != NULL) { + decoded_buffer.sock = grep_sock_info(&host, port, proto); + + if (!decoded_buffer.sock && th_internal_trusted_tag.len > 0) { + decoded_buffer.sock = grep_internal_sock_info(&th_internal_trusted_tag, 0, proto); + } else if (decoded_buffer.sock && th_internal_trusted_tag.len == 0) { + LM_WARN("non-local socket <%.*s:%d>...ignoring\n", host.len, host.s, port); } - } - if (extra_flags & TOPOH_HIDE_CALLID) - LM_WARN("Cannot hide callid when dialog support is not engaged!\n"); - if (extra_flags & TOPOH_DID_IN_USER) - LM_WARN("Cannot store DID in user when dialog support is not engaged!\n"); + if (decoded_buffer.sock) { + decoded_buffer.state |= HAS_SOCK; + } + } - if (tm_api.register_tmcb( req, 0, TMCB_RESPONSE_FWDED, - used_cb,p, (p?shm_free_wrap:NULL))<0 ) { - LM_ERR("failed to register TMCB\n"); - return -1; + if (decoded_uris[0].s != NULL && decoded_uris[0].len > 0) { + decoded_buffer.contact = (str) { .s = decoded_uris[0].s, .len = decoded_uris[0].len }; + decoded_buffer.state |= HAS_CONTACT; } + + if (uri_count > 1) { + decoded_buffer.routes = (str) { .s = decoded_uris[1].s, .len = decoded_uri_buf_len - decoded_buffer.contact.len - 1 }; + decoded_buffer.state |= HAS_ROUTES; + } - return 1; + decoded_buffer.contact.s++; // Removing < + decoded_buffer.contact.len -= 2; // Removing <> + + decoded_uris_count = uri_count; + ctx_decoded_routes_set_valid(); + + LM_DBG("Extracted routes [%.*s], contact [%.*s], flags [%u] and bind socket address [%.*s:%d] and proto %d\n", + decoded_buffer.routes.len, decoded_buffer.routes.s,decoded_buffer.contact.len, decoded_buffer.contact.s, + decoded_buffer.flags, host.len, host.s, port, proto); + + FINALIZE_DECODED_BUF_STATE(decoded_buffer); + return decoded_buffer; +error: + return (decoded_info_buffer_t) { .state = INVALID_BUF }; } -#define ROUTE_STR "Route: " -#define ROUTE_LEN (sizeof(ROUTE_STR) - 1) -#define ROUTE_PREF "Route: <" -#define ROUTE_PREF_LEN (sizeof(ROUTE_PREF) -1) -#define ROUTE_SUFF ">\r\n" -#define ROUTE_SUFF_LEN (sizeof(ROUTE_SUFF) -1) +static decoded_info_buffer_t decode_info_buffer_legacy(str *info) { + str flags_buf = STR_NULL, bind_buf = STR_NULL, host = STR_NULL; + int max_size, port = 0, proto = 0; + char *p; + int i, dec_len, size; + unsigned int parsed_flags; + decoded_info_buffer_t decoded_buffer = { 0 }; + + max_size = th_ct_enc_scheme == ENC_BASE64 ? + calc_max_word64_decode_len(info->len) : + calc_max_word32_decode_len(info->len); + + if (max_size > sizeof(dec_buf_legacy)) { + LM_ERR("Decoded size %d exceeds buffer size %zu\n", max_size, sizeof(dec_buf_legacy)); + goto error; + } + + if (th_ct_enc_scheme == ENC_BASE64) + dec_len = word64decode((unsigned char *)dec_buf_legacy, + (unsigned char *)info->s, info->len); + else + dec_len = word32decode((unsigned char *)dec_buf_legacy, + (unsigned char *)info->s, info->len); + + for (i = 0; i < dec_len; i++) + dec_buf_legacy[i] ^= topo_hiding_ct_encode_pw_legacy.s[i % topo_hiding_ct_encode_pw_legacy.len]; + + #define __extract_len_and_buf(_p, _len, _s) \ + do { \ + (_s).len = *(short *)p;\ + if ((_s).len < 0 || (_s).len > _len) {\ + LM_ERR("bad length %d in encoded contact\n", (_s).len); \ + goto error;\ + }\ + (_s).s = _p + sizeof(short);\ + _p += sizeof(short) + (_s).len;\ + _len -= sizeof(short) + (_s).len;\ + } while(0) + + p = dec_buf_legacy; + size = dec_len; + __extract_len_and_buf(p, size, decoded_buffer.routes); + __extract_len_and_buf(p, size, decoded_buffer.contact); + __extract_len_and_buf(p, size, flags_buf); + __extract_len_and_buf(p, size, bind_buf); + + decoded_buffer.flags |= (HAS_ROUTES | HAS_CONTACT); + + if (str2int(&flags_buf, &parsed_flags) < 0) { + LM_WARN("Failed to convert string to integer, default to no flags\n"); + parsed_flags = 0; + } + + decoded_buffer.flags = (uint16_t)(parsed_flags); + + if (bind_buf.len && bind_buf.s) { + LM_DBG("forcing send socket for req to [%.*s]\n", bind_buf.len, bind_buf.s); + + if (parse_phostport(bind_buf.s, bind_buf.len, &host.s, &host.len, &port, &proto) != 0) { + LM_ERR("bad socket <%.*s>\n", bind_buf.len, bind_buf.s); + } else { + decoded_buffer.sock = grep_sock_info(&host, (unsigned short) port, proto); + if (!decoded_buffer.sock && th_internal_trusted_tag.len > 0) { + decoded_buffer.sock = grep_internal_sock_info(&th_internal_trusted_tag, 0, proto); + } else { + LM_WARN("non-local socket <%.*s>...ignoring\n", bind_buf.len, bind_buf.s); + } + } + } -int topo_no_dlg_seq_handling(struct sip_msg *msg,str *info) -{ - int max_size,dec_len,i,size,flags; - char *dec_buf,*p,*route=NULL,*hdrs,*remote_contact; - struct hdr_field *it; - str rr_buf,ct_buf,flags_buf,bind_buf; - rr_t *head = NULL, *rrp; - int next_strict=0; - struct sip_uri fru; - char* buf = msg->buf; - struct lump* lmp = NULL; - str host; - int port,proto; - const struct socket_info *sock; - str route_buf = {0, 0}; + LM_DBG("Extracted routes [%.*s], contact [%.*s], flags [%u] and bind socket address [%.*s:%d] and proto %d\n", + decoded_buffer.routes.len, decoded_buffer.routes.s,decoded_buffer.contact.len, decoded_buffer.contact.s, + decoded_buffer.flags, host.len, host.s, port, proto); + +FINALIZE_DECODED_BUF_STATE(decoded_buffer); + return decoded_buffer; +error: + return (decoded_info_buffer_t) { .state = INVALID_BUF }; +} + +static char user_buf[UINT16_MAX]; +static str ct_user_buf = { .s = user_buf, .len = 0 }; + +static int th_no_dlg_seq_handling(struct sip_msg *msg, str *info, decode_info_fn decode_fn) { + char *msg_buf = NULL, *route_free_str = NULL; + str route_s = STR_NULL; struct th_no_dlg_param *param = NULL; - transaction_cb* used_cb; + struct hdr_field *it; + struct sip_uri contact_uri = { 0 }; + int route_flags = ROUTE_SUCCESS; + int one_way_hiding = 0; + decoded_info_buffer_t decoded_buffer = { 0 }; + + ct_user_buf.len = 0; /* parse all headers to be sure that all RR and Contact hdrs are found */ - if (parse_headers(msg, HDR_EOH_F, 0)< 0) { + if (parse_headers(msg, HDR_EOH_F, 0) < 0) { LM_ERR("Failed to parse reply\n"); - return -1; + return TOPOH_MATCH_FAILURE; } - /* delete vias */ - if(topo_delete_vias(msg) < 0) { - LM_ERR("Failed to remove via headers\n"); - return -1; - } + msg_buf = msg->buf; - /* delete record route */ - for (it=msg->record_route;it;it=it->sibling) { - if (del_lump(msg, it->name.s - buf, it->len, 0) == 0) { + /* delete record route, shouldn't have a record-route here anyway */ + for (it = msg->record_route; it; it = it->sibling) { + if (del_lump(msg, it->name.s - msg_buf, it->len, 0) == 0) { LM_ERR("del_lump failed\n"); - return -1; + return TOPOH_MATCH_FAILURE; } } - max_size = th_ct_enc_scheme == ENC_BASE64 ? - calc_max_word64_decode_len(info->len) : - calc_max_word32_decode_len(info->len); - dec_buf = pkg_malloc(max_size); - if (dec_buf==NULL) { - LM_ERR("No more pkg\n"); - return -1; - } - - if (th_ct_enc_scheme == ENC_BASE64) - dec_len = word64decode((unsigned char *)dec_buf, - (unsigned char *)info->s,info->len); - else - dec_len = word32decode((unsigned char *)dec_buf, - (unsigned char *)info->s,info->len); - for (i=0;i_len) {\ - LM_ERR("bad length %d in encoded contact\n", (_s).len);\ - goto err_free_buf;\ - }\ - (_s).s = _p + sizeof(short);\ - _p += sizeof(short) + (_s).len;\ - _len -= sizeof(short) + (_s).len;\ - } while(0) - - p = dec_buf; - size = dec_len; - __extract_len_and_buf(p, size, rr_buf); - __extract_len_and_buf(p, size, ct_buf); - __extract_len_and_buf(p, size, flags_buf); - __extract_len_and_buf(p, size, bind_buf); - - LM_DBG("extracted routes [%.*s] , ct [%.*s] , flags [%.*s] and bind [%.*s]\n", - rr_buf.len,rr_buf.s,ct_buf.len,ct_buf.s,flags_buf.len,flags_buf.s,bind_buf.len,bind_buf.s); - - if (rr_buf.len) { - if (parse_rr_body(rr_buf.s,rr_buf.len,&head) != 0) { - LM_ERR("failed parsing route set\n"); - goto err_free_buf; - } - - if(parse_uri(head->nameaddr.uri.s, head->nameaddr.uri.len, &fru) < 0) { - LM_ERR("Failed to parse SIP uri\n"); - goto err_free_head; - } - if(is_strict(&fru.params)) - next_strict = 1; - } - if (msg->dst_uri.s && msg->dst_uri.len) { /* reset dst_uri if previously set * either by loose route or manually */ @@ -502,222 +1517,460 @@ int topo_no_dlg_seq_handling(struct sip_msg *msg,str *info) msg->dst_uri.len = 0; } - if (!next_strict) { - LM_DBG("Fixing message. Next hop is Loose router\n"); - if (ct_buf.len && ct_buf.s) { - LM_DBG("Setting new URI to <%.*s> \n",ct_buf.len, - ct_buf.s); - - if (set_ruri(msg,&ct_buf) != 0) { - LM_ERR("failed setting ruri\n"); - goto err_free_head; + if (msg->route) { + for (it = msg->route; it; it = it->sibling) { + if (it->parsed && ((rr_t*)it->parsed)->deleted) + continue; + if (del_lump(msg, it->name.s - msg_buf, it->len, HDR_ROUTE_T) == NULL) { + LM_ERR("del_lump failed \n"); + return -1; } } - if( parse_headers( msg, HDR_EOH_F, 0)<0 ) { - LM_ERR("failed to parse headers when looking after ROUTEs\n"); - goto err_free_head; + } + + + decoded_buffer = decode_fn(info); + if (!(decoded_buffer.state & HAS_CONTACT) || (decoded_buffer.state & INVALID_BUF)) { + LM_ERR("Failed to decode buffer\n"); + return -1; + } + + if (decoded_buffer.flags & TOPOH_KEEP_USER) { + if (parse_sip_msg_uri(msg) < 0) { + LM_ERR("Failed to parse request URI\n"); + return -1; } - if (msg->route) { - for (it=msg->route;it;it=it->sibling) { - if (it->parsed && ((rr_t*)it->parsed)->deleted) - continue; - if ((lmp = del_lump(msg,it->name.s - buf,it->len,HDR_ROUTE_T)) == 0) { - LM_ERR("del_lump failed \n"); - goto err_free_head; - } - } + if (msg->parsed_uri.user.len > 0 && msg->parsed_uri.user.len < UINT16_MAX) { + memcpy(ct_user_buf.s, msg->parsed_uri.user.s, msg->parsed_uri.user.len); + ct_user_buf.len += msg->parsed_uri.user.len; + } else if (msg->parsed_uri.user.len >= UINT16_MAX) { + LM_ERR("User larger than %d\n", UINT16_MAX); + return -1; } - if ( rr_buf.len !=0 && rr_buf.s) { + if (msg->parsed_uri.passwd.len > 0 && msg->parsed_uri.passwd.len + ct_user_buf.len + 1 < UINT16_MAX) { + memcpy(ct_user_buf.s + ct_user_buf.len, ":", 1); + ct_user_buf.len++; + memcpy(ct_user_buf.s + ct_user_buf.len, msg->parsed_uri.passwd.s, msg->parsed_uri.passwd.len); + ct_user_buf.len += msg->parsed_uri.passwd.len; + } else if (msg->parsed_uri.passwd.len + ct_user_buf.len + 1 >= UINT16_MAX) { + LM_ERR("Password larger than %d\n", UINT16_MAX); + return -1; + } + } - lmp = anchor_lump(msg,msg->headers->name.s - buf,0); - if (lmp == 0) { - LM_ERR("failed anchoring new lump\n"); - goto err_free_head; - } + if (decoded_buffer.state & HAS_ROUTES) { + route_flags = topo_no_dlg_route(msg, &decoded_buffer.routes); + if (route_flags & ROUTE_FAILURE) { + LM_ERR("Failure to Route\n"); + return -1; + } - size = rr_buf.len + ROUTE_LEN + CRLF_LEN; - route = pkg_malloc(size+1); - if (route == 0) { - LM_ERR("no more pkg memory\n"); - goto err_free_head; - } + param = shm_malloc(sizeof *param + decoded_buffer.routes.len); + if (param) { + memset(param, 0, sizeof *param); + param->routes.s = (char *)(param + 1); + param->routes.len = decoded_buffer.routes.len; + memcpy(param->routes.s, decoded_buffer.routes.s, decoded_buffer.routes.len); + } else { + LM_ERR("Failed to allocate params\n"); + return -1; + } + } else { + param = shm_malloc(sizeof *param); + if (param == NULL) { + LM_ERR("Failed to allocate params\n"); + return -1; + } - memcpy(route,ROUTE_STR,ROUTE_LEN); - memcpy(route+ROUTE_LEN,rr_buf.s,rr_buf.len); - memcpy(route+ROUTE_LEN+rr_buf.len,CRLF,CRLF_LEN); + memset(param, 0, sizeof *param); + } - route[size] = 0; + if (!(route_flags & ROUTE_FAILURE) && !(route_flags & ROUTE_STRICT)) { + LM_DBG("Setting new URI to <%.*s> \n", decoded_buffer.contact.len, decoded_buffer.contact.s); - if ((lmp = insert_new_lump_after(lmp,route,size,HDR_ROUTE_T)) == 0) { - LM_ERR("failed inserting new route set\n"); - goto err_free_route; - } - msg->msg_flags |= FL_HAS_ROUTE_LUMP; - route_buf = rr_buf; + if (parse_uri(decoded_buffer.contact.s, decoded_buffer.contact.len, &contact_uri) < 0) { + LM_ERR("Bad Route URI\n"); + goto err_free_params; + } - LM_DBG("Setting route header to <%s> \n",route); - LM_DBG("setting dst_uri to <%.*s> \n",head->nameaddr.uri.len, - head->nameaddr.uri.s); + if (set_ruri(msg, &decoded_buffer.contact) != 0) { + LM_ERR("failed setting ruri\n"); + goto err_free_params; + } - if (set_dst_uri(msg,&head->nameaddr.uri) !=0 ) { - goto err_free_head; + if (contact_uri.user.len == 0 && ct_user_buf.len > 0) { + if (rewrite_ruri(msg, &ct_user_buf, 0, RW_RURI_USERPASS) < 0) { + LM_ERR("Failed to set R-URI user\n"); + goto err_free_params; } } + } else if (!(route_flags & ROUTE_FAILURE) && (route_flags & ROUTE_STRICT)) { + if (topo_no_dlg_rewrite_contact_as_next_route(msg, &decoded_buffer.contact) != 1) { + LM_ERR("Failure to rewrite Contact header as next Route\n"); + goto err_free_params; + } + } + + param->flags = decoded_buffer.flags; + + /* register tm callback for response in */ + if (tm_api.register_tmcb(msg, 0, TMCB_RESPONSE_FWDED, th_no_dlg_onreply, param, shm_free_wrap) < 0) { + LM_ERR("failed to register TMCB\n"); + goto err_free_params; + } + + route_s = param->routes; + param = NULL; + + if (decoded_buffer.sock != NULL) { + msg->force_send_socket = decoded_buffer.sock; } else { - LM_DBG("Fixing message. Next hop is Strict router\n"); - if (msg->route) { - for (it=msg->route;it;it=it->sibling) { - if (it->parsed && ((rr_t*)it->parsed)->deleted) - continue; - if ((lmp = del_lump(msg,it->name.s - buf,it->len,HDR_ROUTE_T)) == 0) { - LM_ERR("del_lump failed \n"); - goto err_free_head; + LM_WARN("Socket is NULL, using default ingress socket\n"); + } + + one_way_hiding = th_no_dlg_one_way_hiding(decoded_buffer.sock); + + if (!one_way_hiding) { + if (topo_delete_vias(msg) < 0) { + LM_ERR("Failed to remove via headers\n"); + return TOPOH_MATCH_FAILURE; + } + + if (route_s.s == NULL && msg->record_route) { + if (print_rr_body(msg->record_route, &route_s, 0, 0, NULL) != 0){ + LM_ERR("failed to print route records \n"); + if (route_s.s != NULL) { + pkg_free(route_s.s); } + return TOPOH_MATCH_FAILURE; } + + route_free_str = route_s.s; } - if ( rr_buf.len !=0 && rr_buf.s) { - if (set_ruri(msg,&head->nameaddr.uri) !=0 ) { - LM_ERR("failed setting new dst uri\n"); - goto err_free_head; + if (th_no_dlg_encode_contact(msg, decoded_buffer.flags, route_s, NULL) < 0) { + LM_ERR("Failed to encode contact header \n"); + if (route_free_str != NULL) { + pkg_free(route_free_str); } - i=0; - rrp = head; - while (rrp) { - i++; - rrp=rrp->next; - } + return TOPOH_MATCH_FAILURE; + } - /* If there are more routes other than the first, add them */ - if (i > 1) { - lmp = anchor_lump(msg,msg->headers->name.s - buf,0); - if (lmp == 0) { - LM_ERR("failed anchoring new lump\n"); - goto err_free_head; - } + if (route_free_str != NULL) { + pkg_free(route_free_str); + } + } - hdrs = rr_buf.s + head->len + 1; + return TOPOH_MATCH_SUCCESS; - size = rr_buf.len - head->len - 1 + ROUTE_LEN + CRLF_LEN; - route = pkg_malloc(size); - if (route == 0) { - LM_ERR("no more pkg memory\n"); - goto err_free_head; - } +err_free_params: + if (param) + shm_free(param); + return TOPOH_MATCH_FAILURE; +} - memcpy(route,ROUTE_STR,ROUTE_LEN); - memcpy(route+ROUTE_LEN,hdrs,rr_buf.len - head->len-1); - memcpy(route+ROUTE_LEN+rr_buf.len - head->len-1,CRLF,CRLF_LEN); +static inline int th_no_dlg_match_socket_tag(const struct socket_info *socket, str socket_tag_to_match[static 1]) { + if (socket != NULL && socket->tag.len > 0) { + LM_DBG("Socket tag %.*s tag to match %.*s\n", socket->tag.len, socket->tag.s, socket_tag_to_match->len, socket_tag_to_match->s); - LM_DBG("Adding Route header : [%.*s] \n",size,route); + return socket->tag.len == socket_tag_to_match->len && + strncmp(socket->tag.s, socket_tag_to_match->s, socket_tag_to_match->len) == 0; + } - if ((lmp = insert_new_lump_after(lmp,route,size,HDR_ROUTE_T)) == 0) { - LM_ERR("failed inserting new route set\n"); - goto err_free_route; - } - msg->msg_flags |= FL_HAS_ROUTE_LUMP; - route_buf.s = route; - route_buf.len = rr_buf.len - head->len - 1; - } + LM_DBG("Socket null == %s?\n", socket == NULL ? "true" : "false"); - if (lmp == NULL) { - lmp = anchor_lump(msg,msg->headers->name.s - buf,0); - if (lmp == 0) - { - LM_ERR("failed anchoring new lump\n"); - return -1; - } - } + return 0; +} - if (ct_buf.len && ct_buf.s) { - size = ct_buf.len + ROUTE_PREF_LEN + ROUTE_SUFF_LEN; - remote_contact = pkg_malloc(size); - if (remote_contact == NULL) { - LM_ERR("no more pkg \n"); - goto err_free_head; - } +static inline int th_no_dlg_one_way_hiding(const struct socket_info *socket) { + return th_no_dlg_match_socket_tag(socket, &th_internal_trusted_tag); +} - memcpy(remote_contact,ROUTE_PREF,ROUTE_PREF_LEN); - memcpy(remote_contact+ROUTE_PREF_LEN,ct_buf.s,ct_buf.len); - memcpy(remote_contact+ROUTE_PREF_LEN+ct_buf.len, - ROUTE_SUFF,ROUTE_SUFF_LEN); +static struct lump* th_no_dlg_add_auto_record_route(struct sip_msg* msg, uint16_t flags, struct lump *anchor) { + struct lump *l, *existing_routes; + char *prefix, *suffix, *rpl_route_hdr, *thinfo = NULL; + int prefix_len, suffix_len, rpl_route_hdr_len, thinfo_len; + int prefix_counter = 0, suffix_counter = 0; + str *rpl_rrs = NULL; + unsigned int rpl_rr_count = 0; + int is_reply = msg->first_line.type == SIP_REPLY; - LM_DBG("Adding remote contact route header : [%.*s]\n", - size,remote_contact); + if (parse_headers(msg, HDR_EOH_F, 0)< 0) { + LM_ERR("Failed to parse reply\n"); + return NULL; + } - if (insert_new_lump_after(lmp,remote_contact,size,HDR_ROUTE_T) == 0) { - LM_ERR("failed inserting remote contact route\n"); - pkg_free(remote_contact); - goto err_free_head; - } - msg->msg_flags |= FL_HAS_ROUTE_LUMP; - } - } + if ((rpl_rr_count = list_rr_body(msg->record_route, &rpl_rrs)) < 0){ + LM_ERR("failed to print Record-Route header body\n"); + return NULL; } - if (route_buf.s && route_buf.len) { - param = shm_malloc(sizeof *param + route_buf.len); - if (param) { - memset(param, 0, sizeof *param); - param->routes.s = (char *)(param + 1); - param->routes.len = route_buf.len; - memcpy(param->routes.s, route_buf.s, route_buf.len); - } + + if (rpl_rr_count > 0 && topo_delete_record_route_uris(msg, rpl_rr_count) < 0) { + LM_ERR("Failed to remove '%d' Record-Route URIs\n", rpl_rr_count); + return NULL; } - if (flags_buf.len && flags_buf.s) { - if (str2int(&flags_buf, (unsigned int*) &flags) < 0) { - LM_WARN("Failed to convert string to integer, default to no flags\n"); - flags = 0; - } + if (anchor == NULL) { + l = anchor_after_last_record_route(msg); } else { - flags = 0; + l = anchor; } + existing_routes = l; + if (!l) { + LM_ERR("failed to create anchor\n"); + return NULL; + } + + prefix_len = RR_PREFIX_LEN + RR_URI_PREFIX_LEN; + prefix = pkg_malloc(prefix_len); + if (!prefix) { + LM_ERR("no pkg memory for prefix\n"); + return NULL; + } + + memcpy(prefix, RR_PREFIX, RR_PREFIX_LEN); + prefix_counter += RR_PREFIX_LEN; + + memcpy(prefix + prefix_counter, RR_URI_PREFIX, RR_URI_PREFIX_LEN); + prefix_counter += RR_URI_PREFIX_LEN; + + if (!(l = insert_new_lump_after(l, prefix, prefix_len, 0))) { + LM_ERR("failed to insert prefix\n"); + pkg_free(prefix); + return NULL; + } + + l = insert_subst_lump_after(l, SUBST_SND_ALL, 0); + if (!l) { + LM_ERR("failed to insert subst lump\n"); + return NULL; + } + + if (!(thinfo = build_encoded_thinfo_suffix(msg, STR_NULL, &thinfo_len, flags, 1))) { + LM_ERR("Failed to add build Record-Route suffix\n"); + return NULL; + } + + if (!(l = insert_new_lump_after(l, thinfo, thinfo_len, 0))) { + LM_ERR("failed to insert thinfo param\n"); + pkg_free(thinfo); + return NULL; + } + + suffix_len = RR_LR_LEN + RR_TERM_LEN + CRLF_LEN; + + suffix = pkg_malloc(suffix_len); + if (!suffix) { + LM_ERR("no pkg memory for suffix\n"); + return NULL; + } + + memcpy(suffix, RR_LR, RR_LR_LEN); + suffix_counter += RR_LR_LEN; + memcpy(suffix + suffix_counter, RR_TERM, RR_TERM_LEN); + suffix_counter += RR_TERM_LEN; + + memcpy(suffix + suffix_counter, CRLF, CRLF_LEN); + + if (!(l = insert_new_lump_after(l, suffix, suffix_len, 0))) { + LM_ERR("failed to insert suffix\n"); + pkg_free(suffix); + return NULL; + } + + if (rpl_rr_count > 0) { + if (is_reply) { + for (int i = rpl_rr_count - 1; i >= 0; i--) { + BUILD_RR_HEADER_BUFFER(rpl_route_hdr, rpl_route_hdr_len, rpl_rrs[i]); + + if (!rpl_route_hdr) { + LM_ERR("no more pkg memory\n"); + return NULL; + } + + if (!(insert_new_lump_before(existing_routes, rpl_route_hdr, rpl_route_hdr_len, 0))) { + LM_ERR("failed to insert route before\n"); + pkg_free(rpl_route_hdr); + return NULL; + } + } + } else { + for (int i = 0; i < rpl_rr_count; i++) { + BUILD_RR_HEADER_BUFFER(rpl_route_hdr, rpl_route_hdr_len, rpl_rrs[i]); + + if (!rpl_route_hdr) { + LM_ERR("no more pkg memory\n"); + return NULL; + } + + if (!(l = insert_new_lump_after(l, rpl_route_hdr, rpl_route_hdr_len, 0))) { + LM_ERR("failed to insert route after\n"); + pkg_free(rpl_route_hdr); + return NULL; + } + } + } + } + + return l; +} - if (flags & TOPOH_KEEP_USER) - used_cb = th_no_dlg_user_onreply_within; - else - used_cb = th_no_dlg_onreply_within; +static int rr_equal(rr_t *p1, rr_t *p2) { + if (p1 == NULL || p2 == NULL) { + return 0; + } - /* register tm callback for response in */ - if (tm_api.register_tmcb( msg, 0, TMCB_RESPONSE_FWDED, - used_cb,param,(param?shm_free_wrap:NULL))<0 ) { - LM_ERR("failed to register TMCB\n"); + if (p1 == p2) { + return 1; } - if (bind_buf.len && bind_buf.s) { - LM_DBG("forcing send socket for req to [%.*s]\n",bind_buf.len,bind_buf.s); - if (parse_phostport( bind_buf.s, bind_buf.len, &host.s, &host.len, - &port, &proto)!=0) { - LM_ERR("bad socket <%.*s>\n", bind_buf.len, bind_buf.s); - } else { - sock = grep_sock_info( &host, (unsigned short)port, proto); - if (!sock) { - LM_WARN("non-local socket <%.*s>...ignoring\n", bind_buf.len, bind_buf.s); + return compare_uris(&p1->nameaddr.uri, NULL, &p2->nameaddr.uri, NULL) == 0; +} + +static route_count_t th_no_dlg_match_record_route_or_route_uris(struct sip_msg *req, struct sip_msg *rpl, hdr_types_t hdr_type, int req_auto_routed) { + struct hdr_field *req_hf = NULL, *rpl_hf = NULL; + rr_t *req_rr = NULL, *rpl_rr = NULL; + int rpl_route_count = 0; + int matched_count = 0; + unsigned int delete_count = 0; + unsigned int skip_encode_count = 0; + int matched = 0; + + if (hdr_type != HDR_RECORDROUTE_T && hdr_type != HDR_ROUTE_T) { + LM_ERR("Header type has to be one of Record-Route or Route\n"); + return (route_count_t) { + .delete_count = 64, + .skip_encode_count = 64 + }; + } + + if (parse_headers(req, HDR_EOH_F, 0) == -1) { + LM_ERR("Failed to parse req headers\n"); + return (route_count_t) { + .delete_count = 64, + .skip_encode_count = 64 + }; + } + + if (parse_headers(rpl, HDR_EOH_F, 0) == -1) { + LM_ERR("Failed to parse rpl headers\n"); + return (route_count_t) { + .delete_count = 64, + .skip_encode_count = 64 + }; + } + + LM_DBG("Matching '%s' headers\n", hdr_type == HDR_RECORDROUTE_T ? "Record-Route" : "Route"); + + req_hf = hdr_type == HDR_RECORDROUTE_T ? req->record_route : req->route; + if (req_hf == NULL) { + + rpl_hf = hdr_type == HDR_RECORDROUTE_T ? rpl->record_route : rpl->route; + while (rpl_hf != NULL) { + if (parse_rr(rpl_hf) < 0) { + LM_ERR("Failed to '%.*s' headers in reply\n", rpl_hf->name.len, rpl_hf->name.s); + return (route_count_t) { + .delete_count = 64, + .skip_encode_count = 64 + }; + } + + rpl_rr = (rr_t*)rpl_hf->parsed; + + while (rpl_rr) { + rpl_route_count++; + rpl_rr = rpl_rr->next; } - msg->force_send_socket = sock; + + rpl_hf = rpl_hf->sibling; } + + return (route_count_t) { + .delete_count = rpl_route_count, + .skip_encode_count = req_auto_routed ? 1 : 0 + }; + } + + if (parse_rr(req_hf) < 0) { + LM_ERR("Failed to '%.*s' headers in request\n", req_hf->name.len, req_hf->name.s); + return (route_count_t) { + .delete_count = 64, + .skip_encode_count = 64 + }; } + req_rr = (rr_t*)req_hf->parsed; + + rpl_hf = hdr_type == HDR_RECORDROUTE_T ? rpl->record_route : rpl->route; + while (rpl_hf != NULL) { + if (parse_rr(rpl_hf) < 0) { + LM_ERR("Failed to '%.*s' headers in reply\n", rpl_hf->name.len, rpl_hf->name.s); + return (route_count_t) { + .delete_count = 64, + .skip_encode_count = 64 + }; + } + rpl_rr = (rr_t*) rpl_hf->parsed; + + if (req_rr == NULL) { + LM_ERR("Reply headers left to check when all Request headers checked\n"); + return (route_count_t) { + .delete_count = 64, + .skip_encode_count = 64 + }; + } + + while (rpl_rr) { + rpl_route_count++; + matched = rr_equal(req_rr, rpl_rr); + if (matched) { + matched_count++; + + req_rr = req_rr->next; + if (req_rr == NULL) { + req_hf = req_hf->sibling; + if (req_hf != NULL) { + if (parse_rr(req_hf) < 0) { + LM_ERR("Failed to '%.*s' headers in request\n", req_hf->name.len, req_hf->name.s); + return (route_count_t) { + .delete_count = 64, + .skip_encode_count = 64 + }; + } + req_rr = (rr_t*)req_hf->parsed; + } + } + } - if (rr_buf.len) - free_rr(&head); - pkg_free(dec_buf); + if (matched_count > 0 && !matched) { + return (route_count_t) { + .delete_count = 64, + .skip_encode_count = 64 + }; + } - if (topo_no_dlg_encode_contact(msg,flags,NULL,NULL) < 0) { - LM_ERR("Failed to encode contact header \n"); - return -1; + rpl_rr = rpl_rr->next; + } + + rpl_hf = rpl_hf->sibling; } - return 1; + if (req_rr != NULL) { + LM_ERR("Not all request headers were matched in reply (matched count %d)\n", matched_count); + return (route_count_t) { + .delete_count = 64, + .skip_encode_count = 64 + }; + } -err_free_route: - if (route) - pkg_free(route); -err_free_head: - if (rr_buf.len) - free_rr(&head); -err_free_buf: - pkg_free(dec_buf); - return -1; -} + delete_count = rpl_route_count - matched_count; + skip_encode_count = rpl_route_count - delete_count; + + LM_DBG("Delete header count '%d', skip encode count '%d'\n", delete_count, skip_encode_count); + + return (route_count_t) { + .delete_count = delete_count, + .skip_encode_count = req_auto_routed ? skip_encode_count + 1 : skip_encode_count + }; +} \ No newline at end of file diff --git a/modules/topology_hiding/th_no_dlg_logic.h b/modules/topology_hiding/th_no_dlg_logic.h index f7125c7e5e9..45077c458f7 100644 --- a/modules/topology_hiding/th_no_dlg_logic.h +++ b/modules/topology_hiding/th_no_dlg_logic.h @@ -21,15 +21,25 @@ #ifndef _TH_NO_DLG_LOGIC_H #define _TH_NO_DLG_LOGIC_H +#include "th_common_logic.h" + #include "../../str.h" #include "../tm/t_hooks.h" -#include "th_common_logic.h" #include "../../context.h" enum encode_scheme {ENC_BASE64, ENC_BASE32}; +extern str decoded_uris[12]; +extern int decoded_uris_count; +extern int ctx_decoded_routes_valid_idx; + +#define ctx_decoded_routes_set_valid() \ + context_put_int(CONTEXT_GLOBAL, current_processing_ctx, ctx_decoded_routes_valid_idx, 1) + +#define ctx_decoded_routes_is_valid() \ + context_get_int(CONTEXT_GLOBAL, current_processing_ctx, ctx_decoded_routes_valid_idx) -int topo_hiding_no_dlg(struct sip_msg *req, struct cell* t, int extra_flags, struct th_params *params); +int topo_hiding_no_dlg(struct sip_msg *req, struct cell* t, unsigned int extra_flags, struct th_params *params); int topo_hiding_match_no_dlg(struct sip_msg *msg); #endif \ No newline at end of file diff --git a/modules/topology_hiding/thinfo_codec.c b/modules/topology_hiding/thinfo_codec.c index 0537aa6a66f..cd85d07275e 100644 --- a/modules/topology_hiding/thinfo_codec.c +++ b/modules/topology_hiding/thinfo_codec.c @@ -12,8 +12,6 @@ #define SCHEME_TELS 0x0003 #define SCHEME_URN_S 0x0004 #define SCHEME_URN_N 0x0005 -#define SCHEME_M1 0x0006 // Magic bit 1 - must be 0 (invalid/garbage detection) -#define SCHEME_M2 0x0007 // Magic bit 2 - must be 0 (invalid/garbage detection) #define TRANSPORT_MASK 0x0038 #define TRANSPORT_UDP 0x0000 @@ -22,14 +20,11 @@ #define TRANSPORT_SCTP 0x0018 #define TRANSPORT_WS 0x0020 #define TRANSPORT_WSS 0x0028 -#define TRANSPORT_M1 0x0030 // Magic bit 1 - must be 0 (invalid/garbage detection) -#define TRANSPORT_M2 0x0038 // Magic bit 2 - must be 0 (invalid/garbage detection) #define DOMAIN_MASK 0x00C0 #define DOMAIN_IPV4 0x0000 #define DOMAIN_IPV6 0x0040 #define DOMAIN_FQDN 0x0080 -#define DOMAIN_M1 0x00C0 // Magic bit - must be 0 (invalid/garbage detection) #define HAS_USERNAME 0x0100 #define HAS_PASSWORD 0x0200 @@ -38,7 +33,6 @@ #define HAS_HEADERS 0x1000 #define HAS_LR 0x2000 // lr or lr=on present #define IS_DUAL_URI 0x4000 // Dual URI encoding flag -#define RESERVED_BIT 0x8000 // Reserved for future use #define SOCKET_PROTO_MASK 0x07 // 3 bits for protocol (bits 0-2) #define SOCKET_IP_MASK 0x18 // 2 bits for IP type (bits 3-4) @@ -46,7 +40,6 @@ #define SOCKET_IPV6 0x08 #define SOCKET_HAS_PORT 0x20 // Bit 5: port is present - // URI2 properties byte (1 byte following URI1 data) #define URI2_SCHEME_MASK 0x07 // Bits 0-2: scheme for URI2 #define URI2_TRANSPORT_MASK 0x38 // Bits 3-5: transport for URI2 @@ -54,7 +47,6 @@ #define URI2_HAS_PORT 0x40 // Bit 6: URI2 has port #define URI2_HAS_R2 0x80 // Bit 7: r2 flag for both URIs in dual encoding -static str r2_on_uri_param = str_init("r2=on"); static str lr_uri_param = str_init("lr"); static str lr_on_uri_param = str_init("lr=on"); static str transport_uri_param = str_init("transport"); @@ -71,15 +63,6 @@ static const uint8_t SCHEMES[] = { [URN_NENA_SERVICE_URI_T] = SCHEME_URN_S }; -static const enum _uri_type SCHEME_TO_ENUM[] = { - [SCHEME_SIP] = SIP_URI_T, - [SCHEME_SIPS] = SIPS_URI_T, - [SCHEME_TEL] = TEL_URI_T, - [SCHEME_TELS] = TELS_URI_T, - [SCHEME_URN_N] = URN_SERVICE_URI_T, - [SCHEME_URN_S] = URN_NENA_SERVICE_URI_T -}; - static const str SCHEME_STRINGS[] = { [SCHEME_SIP] = str_init("sip"), [SCHEME_SIPS] = str_init("sips"), @@ -99,15 +82,6 @@ static const uint8_t TRANSPORTS[] = { [PROTO_WSS] = TRANSPORT_WSS }; -static const enum sip_protos TRANSPORT_TO_ENUM[] = { - [TRANSPORT_UDP] = PROTO_UDP, - [TRANSPORT_TCP] = PROTO_TCP, - [TRANSPORT_TLS] = PROTO_TLS, - [TRANSPORT_SCTP] = PROTO_SCTP, - [TRANSPORT_WS] = PROTO_WS, - [TRANSPORT_WSS] = PROTO_WSS -}; - static const char *TRANSPORT_STRINGS[] = { [TRANSPORT_UDP] = "transport=udp", [TRANSPORT_TCP] = "transport=tcp", @@ -284,6 +258,7 @@ static int encode_uris(thinfo_encoded_t *thinfo, struct sip_uri *uri1, struct si } uri2_props |= URI2_HAS_R2; *uri2_props_ptr = uri2_props; + thinfo->uri_count++; } if (uri1->params.len > 0 && uri1->params.len <= UINT8_MAX) { @@ -314,6 +289,7 @@ static int encode_uris(thinfo_encoded_t *thinfo, struct sip_uri *uri1, struct si props_ptr[0] = (props >> 8) & 0xFF; props_ptr[1] = props & 0xFF; + thinfo->uri_count++; thinfo->len = p - thinfo->buf; return p - (thinfo->buf + start_pos); } @@ -638,14 +614,15 @@ int thinfo_decode_uris(thinfo_encoded_t *thinfo, char decoded_uri_str[static MAX } void thinfo_buffer_reset(thinfo_encoded_t *thinfo) { - thinfo->len = 0; - thinfo->pos = 0; + thinfo->uri_count = 0; + thinfo->len = 0; + thinfo->pos = 0; } -void thinfo_buffer_finalize(thinfo_encoded_t *thinfo, uint16_t flags, uint8_t count) { +void thinfo_buffer_finalize(thinfo_encoded_t *thinfo, uint16_t flags) { thinfo->buf[0] = (flags >> 8) & 0xFF; thinfo->buf[1] = flags & 0xFF; - thinfo->buf[2] = count; + thinfo->buf[2] = thinfo->uri_count; } uint8_t thinfo_get_uri_count(thinfo_encoded_t *thinfo) { diff --git a/modules/topology_hiding/thinfo_codec.h b/modules/topology_hiding/thinfo_codec.h index 22420d62308..56edf6fd09f 100644 --- a/modules/topology_hiding/thinfo_codec.h +++ b/modules/topology_hiding/thinfo_codec.h @@ -145,6 +145,7 @@ */ typedef struct { unsigned char buf[MAX_THINFO_BUFFER_SIZE]; /**< Buffer holding encoded binary data */ + uint8_t uri_count; /**< Current amount of encoded URIs */ uint16_t len; /**< Current length of encoded data */ int pos; /**< Current read/write position */ } thinfo_encoded_t; @@ -238,9 +239,8 @@ uint16_t thinfo_get_flags(thinfo_encoded_t *thinfo); * * @param thinfo Pointer to the encoded buffer structure (updates buf with header) * @param flags Flags value to write to the header - * @param uri_count Number of URIs encoded in the buffer */ -void thinfo_buffer_finalize(thinfo_encoded_t *thinfo, uint16_t flags, uint8_t uri_count); +void thinfo_buffer_finalize(thinfo_encoded_t *thinfo, uint16_t flags); /** * @brief Reset the encoded buffer to initial state diff --git a/modules/topology_hiding/topo_hiding_logic.c b/modules/topology_hiding/topo_hiding_logic.c index 65b81fe64e2..a642156030a 100644 --- a/modules/topology_hiding/topo_hiding_logic.c +++ b/modules/topology_hiding/topo_hiding_logic.c @@ -26,6 +26,7 @@ #include "../../ut.h" #include "topo_hiding_logic.h" +#include "th_no_dlg_logic.h" extern int force_dialog; extern struct rr_binds rr_api; @@ -33,6 +34,7 @@ extern struct tm_binds tm_api; extern struct dlg_binds dlg_api; extern str topo_hiding_prefix; extern str topo_hiding_seed; +extern int th_loop_protection; static struct th_ct_params *th_param_list=NULL; static struct th_ct_params *th_hdr_param_list=NULL; diff --git a/modules/topology_hiding/topology_hiding.c b/modules/topology_hiding/topology_hiding.c index 3b0f66fbdbf..301b952a668 100644 --- a/modules/topology_hiding/topology_hiding.c +++ b/modules/topology_hiding/topology_hiding.c @@ -393,7 +393,7 @@ int w_topology_hiding_match(struct sip_msg *req, void *seq_match_mode_val) mm = (int)(long)seq_match_mode_val; if (!dlg_api.match_dialog || dlg_api.match_dialog(req, mm) < 0) - return topology_hiding_match(req); + return topo_hiding_match_no_dlg(req); else /* we went to the dlg module, which triggered us back, all good */ return 1; @@ -482,11 +482,13 @@ static int pv_topo_decoded_uri(struct sip_msg *msg, pv_param_t *param, pv_value_ field_id = param->pvn.u.isname.name.n; } + LM_DBG("Decoded uri %.*s\n", decoded_uris[index].len - 2, decoded_uris[index].s + 1); + if (field_id == TH_ROUTE_FULL) { return pv_get_strval(msg, param, res, &decoded_uris[index]); } - if (parse_uri(decoded_uris[index].s + 1, decoded_uris[index].len - 1, &uri) < 0) { + if (parse_uri(decoded_uris[index].s + 1, decoded_uris[index].len - 2, &uri) < 0) { LM_ERR("Bad Contact URI\n"); return -1; } diff --git a/parser/parse_rr.c b/parser/parse_rr.c index 67619287600..cdbea2eff04 100644 --- a/parser/parse_rr.c +++ b/parser/parse_rr.c @@ -472,6 +472,53 @@ int print_rr_body(struct hdr_field *iroute, str *oroute, int order, } +int list_rr_body(struct hdr_field *iroute, str **oroute) +{ + rr_t *p; + int n = 0; +#define MAX_RR_HDRS 64 + static str route[MAX_RR_HDRS]; + struct hdr_field *hdr; + + if(iroute==NULL) + return 0; + + memset(route, 0, MAX_RR_HDRS*sizeof(str)); + + while (iroute!=NULL) + { + hdr=iroute; + if (parse_rr(hdr) < 0) + { + LM_ERR("failed to parse RR\n"); + goto error; + } + + p =(rr_t*)hdr->parsed; + while (p) + { + route[n].s = p->nameaddr.name.s; + route[n].len = p->len; + LM_DBG("current rr is %.*s\n", route[n].len, route[n].s); + + n++; + if(n==MAX_RR_HDRS) + { + LM_ERR("too many RR\n"); + goto error; + } + p = p->next; + } + + iroute = iroute->sibling; + } + + *oroute = &route[0]; + + return n; +error: + return -1; +} /* * Path must be available. Function returns the first uri diff --git a/parser/parse_rr.h b/parser/parse_rr.h index 2286c67209e..ea5daa712ff 100644 --- a/parser/parse_rr.h +++ b/parser/parse_rr.h @@ -94,6 +94,12 @@ int shm_duplicate_rr(rr_t** _new, rr_t* _r, int _first); int print_rr_body(struct hdr_field *iroute, str *oroute, int order, int no_change, unsigned int * nb_recs); + +/* + * print body for all RR headers in an array of strings, return array size + */ +int list_rr_body(struct hdr_field *iroute, str **oroute); + /* * Function returns the first uri * from Path without any duplication. From bbba1f626f1478a040e947ef246da9bd66656ba3 Mon Sep 17 00:00:00 2001 From: Kordian Pawelec Date: Tue, 19 May 2026 15:07:38 +0100 Subject: [PATCH 5/8] Adding modparam to configure encoding in transaction only mode --- modules/topology_hiding/th_common_logic.h | 2 +- modules/topology_hiding/th_no_dlg_logic.c | 230 +++++++++++++++++----- modules/topology_hiding/th_no_dlg_logic.h | 18 +- modules/topology_hiding/topology_hiding.c | 66 +++---- 4 files changed, 219 insertions(+), 97 deletions(-) diff --git a/modules/topology_hiding/th_common_logic.h b/modules/topology_hiding/th_common_logic.h index b4dcb3bbe08..118da3769b2 100644 --- a/modules/topology_hiding/th_common_logic.h +++ b/modules/topology_hiding/th_common_logic.h @@ -80,7 +80,7 @@ static inline char *topo_ct_param_copy(char *buf, str *name, str *val, int shoul return buf; } -static void shm_free_wrap(void *param) { +static inline void shm_free_wrap(void *param) { if (param) shm_free(param); } diff --git a/modules/topology_hiding/th_no_dlg_logic.c b/modules/topology_hiding/th_no_dlg_logic.c index 1c55418b65b..c58310e48b4 100644 --- a/modules/topology_hiding/th_no_dlg_logic.c +++ b/modules/topology_hiding/th_no_dlg_logic.c @@ -105,20 +105,26 @@ static char decoded_uri_str[MAX_ENCODED_URI_SIZE * 3]; static char dec_buf_legacy[4096]; extern int th_ct_enc_scheme; -extern str topo_hiding_ct_encode_pw; -extern str th_contact_encode_param; -extern int th_ct_enc_scheme_legacy; -extern str topo_hiding_ct_encode_pw_legacy; -extern str th_contact_encode_param_legacy; extern str th_internal_trusted_tag; extern str th_external_socket_tag; extern str th_is_self_socket_tag; extern int auto_route_on_trusted_socket; -extern int th_compact_encoding; extern struct th_ct_params *th_param_list; extern struct th_ct_params *th_hdr_param_list; +static int param_password_count = 0; +static char *buffers[TH_INFO_PASSWORD_ROTATION_SIZE] = { 0 }; +static thinfo_options_t param_passwords[TH_INFO_PASSWORD_ROTATION_SIZE] = { + { + .param_name = DEFAULT_PARAM, + .param_password = DEFAULT_PW, + .compact_encoding = 1 + } +}; + +static thinfo_options_t *encoding_options = NULL; + typedef struct { unsigned int delete_count; unsigned int skip_encode_count; @@ -149,20 +155,23 @@ typedef struct { (db).state |= HAS_SOCK; \ } while(0) -typedef decoded_info_buffer_t (*decode_info_fn)(str *); -static decoded_info_buffer_t decode_info_buffer(str *); -static decoded_info_buffer_t decode_info_buffer_legacy(str *); +typedef decoded_info_buffer_t (*decode_info_fn)(str *, const thinfo_options_t *); +static decoded_info_buffer_t decode_info_buffer(str *, const thinfo_options_t *); +static decoded_info_buffer_t decode_info_buffer_legacy(str *, const thinfo_options_t *); static int th_no_dlg_encode_contact(struct sip_msg *, uint16_t, str, str *); static inline int th_no_dlg_onrequest(struct sip_msg *, uint16_t, str *); static void th_no_dlg_onreply(struct cell *, int, struct tmcb_params *); -static int th_no_dlg_seq_handling(struct sip_msg *, str *, decode_info_fn); +static int th_no_dlg_seq_handling(struct sip_msg *, str *, decode_info_fn, const thinfo_options_t *); static inline int th_no_dlg_one_way_hiding(const struct socket_info *); static struct lump* th_no_dlg_add_auto_record_route(struct sip_msg *, uint16_t, struct lump *); static route_count_t th_no_dlg_match_record_route_or_route_uris(struct sip_msg *, struct sip_msg *, hdr_types_t, int); static char* build_encoded_thinfo_suffix(struct sip_msg *, str, int *, uint16_t, int); +static char* build_encoded_contact_suffix_legacy(struct sip_msg *, str, int *, int); + +static thinfo_options_t *th_get_options(const str *); int topo_hiding_no_dlg(struct sip_msg *req, struct cell* t, unsigned int extra_flags, struct th_params *params) { struct th_no_dlg_param *p = NULL; @@ -189,12 +198,17 @@ int topo_hiding_no_dlg(struct sip_msg *req, struct cell* t, unsigned int extra_f memset(p, 0, sizeof *p); if (!(extra_flags & TOPOH_KEEP_USER)) { - p->username.s = (char *)(p + 1); - p->username.len = params->ct_callee_user.len; - memcpy(p->username.s, params->ct_callee_user.s, - params->ct_callee_user.len); - - username = ¶ms->ct_caller_user; + if (params && params->ct_callee_user.len) { + p = shm_malloc(sizeof *p + params->ct_callee_user.len); + if (p) { + memset(p, 0, sizeof *p); + p->username.s = (char *)(p + 1); + p->username.len = params->ct_callee_user.len; + memcpy(p->username.s, params->ct_callee_user.s, + params->ct_callee_user.len); + username = ¶ms->ct_callee_user; + } + } } p->flags = extra_flags; @@ -215,7 +229,7 @@ int topo_hiding_no_dlg(struct sip_msg *req, struct cell* t, unsigned int extra_f return -1; } -static int th_no_dlg_auto_route_seq_handling(struct sip_msg *msg, rr_t auto_route[static 1], str thinfo[static 1], int self_route) { +static int th_no_dlg_auto_route_seq_handling(struct sip_msg *msg, rr_t auto_route[static 1], str thinfo[static 1], int self_route, const thinfo_options_t *options) { struct th_no_dlg_param *p = NULL; rr_t *after_auto = NULL; const struct socket_info *sock = NULL; @@ -247,7 +261,7 @@ static int th_no_dlg_auto_route_seq_handling(struct sip_msg *msg, rr_t auto_rout LM_DBG("Size of base64 decoded length %d and size of param len %d\n", dec_len, thinfo->len); for (i = 0; i < dec_len; i++) - decoded_uri_buf.buf[i] ^= topo_hiding_ct_encode_pw.s[i % topo_hiding_ct_encode_pw.len]; + decoded_uri_buf.buf[i] ^= options->param_password.s[i % options->param_password.len]; if (thinfo_get_uri_count(&decoded_uri_buf) != 0) { LM_ERR("Encoded URI count is invalid, can only be 0 in auto Route\n"); @@ -354,6 +368,7 @@ int topo_hiding_match_no_dlg(struct sip_msg *msg) { str *thinfo = NULL; rr_t *auto_route = NULL; int i, self_route, tag_match; + thinfo_options_t *thinfo_decode = NULL; if (parse_sip_msg_uri(msg) < 0) { LM_ERR("Failed to parse request URI\n"); @@ -370,16 +385,17 @@ int topo_hiding_match_no_dlg(struct sip_msg *msg) { /* topology_hiding_match with thinfo and request domain is us * needs to have a thinfo to continue otherwise we cannot match */ for (i = 0; i < request_uri->u_params_no; i++) { - if (request_uri->u_name[i].len == th_contact_encode_param.len && - memcmp(th_contact_encode_param.s, request_uri->u_name[i].s, th_contact_encode_param.len) == 0) { - LM_DBG("We found param in R-URI with value of %.*s\n", - request_uri->u_val[i].len, request_uri->u_val[i].s); - return th_no_dlg_seq_handling(msg, &request_uri->u_val[i], decode_info_buffer); - } else if (request_uri->u_name[i].len == th_contact_encode_param_legacy.len && - memcmp(th_contact_encode_param_legacy.s, request_uri->u_name[i].s, th_contact_encode_param_legacy.len) == 0) { - LM_DBG("We found legacy param in R-URI with value of %.*s\n", - request_uri->u_val[i].len, request_uri->u_val[i].s); - return th_no_dlg_seq_handling(msg, &request_uri->u_val[i], decode_info_buffer_legacy); + thinfo_decode = th_get_options(&request_uri->u_name[i]); + if (thinfo_decode != NULL) { + if (thinfo_decode->compact_encoding) { + LM_DBG("We found param in R-URI with value of %.*s\n", + request_uri->u_val[i].len, request_uri->u_val[i].s); + return th_no_dlg_seq_handling(msg, &request_uri->u_val[i], decode_info_buffer, thinfo_decode); + } else { + LM_DBG("We found legacy param in R-URI with value of %.*s\n", + request_uri->u_val[i].len, request_uri->u_val[i].s); + return th_no_dlg_seq_handling(msg, &request_uri->u_val[i], decode_info_buffer_legacy, thinfo_decode); + } } } } else if (msg->route != NULL && auto_route_on_trusted_socket) { @@ -409,22 +425,23 @@ int topo_hiding_match_no_dlg(struct sip_msg *msg) { } for (i = 0; i < route_uri.u_params_no; i++) { - if (route_uri.u_name[i].len == th_contact_encode_param.len && - memcmp(th_contact_encode_param.s, route_uri.u_name[i].s, th_contact_encode_param.len) == 0) { + // encoding the socket uses the compact encoding regardless of the option + // reuse the same param name and password but with compact encoding + thinfo_decode = th_get_options(&route_uri.u_name[i]); + if (thinfo_decode != NULL) { LM_DBG("We found param in Route header with value of %.*s\n", route_uri.u_val[i].len, route_uri.u_val[i].s); - thinfo = &route_uri.u_val[i]; break; } } if (thinfo == NULL) { - LM_ERR("No param with %.*s found in auto Route\n", th_contact_encode_param.len, th_contact_encode_param.s); + LM_ERR("No known th_contact_encode_param_password param in auto Route\n"); return TOPOH_MATCH_FAILURE; } - - return th_no_dlg_auto_route_seq_handling(msg, auto_route, thinfo, self_route); + + return th_no_dlg_auto_route_seq_handling(msg, auto_route, thinfo, self_route, thinfo_decode); } } @@ -718,11 +735,11 @@ static char* build_encoded_contact_suffix_legacy(struct sip_msg* msg, str rr_set local_len += rr_len + ct_len + flags_len + addr_len; enc_len = th_ct_enc_scheme == ENC_BASE64 ? calc_word64_encode_len(local_len) : calc_word32_encode_len(local_len); - total_len = enc_len + - 1 /* ; */ + - th_contact_encode_param_legacy.len + - 1 /* = */ + - params_len + /* URI and header params */ + total_len = enc_len + + 1 /* ; */ + + encoding_options->param_name.len + + 1 /* = */ + + params_len + /* URI and header params */ 1 /* > */; if (th_param_list) { @@ -814,12 +831,12 @@ static char* build_encoded_contact_suffix_legacy(struct sip_msg* msg, str rr_set memcpy(p,msg->rcv.bind_address->sock_str.s,msg->rcv.bind_address->sock_str.len); p+= msg->rcv.bind_address->sock_str.len; for (i=0;i<(int)(p-suffix_plain);i++) - suffix_plain[i] ^= topo_hiding_ct_encode_pw_legacy.s[i%topo_hiding_ct_encode_pw_legacy.len]; + suffix_plain[i] ^= encoding_options->param_password.s[i % encoding_options->param_password.len]; s = suffix_enc; *s++ = ';'; - memcpy(s,th_contact_encode_param_legacy.s,th_contact_encode_param_legacy.len); - s+= th_contact_encode_param_legacy.len; + memcpy(s, encoding_options->param_name.s, encoding_options->param_name.len); + s += encoding_options->param_name.len; *s++ = '='; if (th_ct_enc_scheme == ENC_BASE64) word64encode((unsigned char*)s,(unsigned char *)suffix_plain,p-suffix_plain); @@ -1012,9 +1029,9 @@ static char* build_encoded_thinfo_suffix(struct sip_msg* msg, str rr_set, int *s thinfo_buffer_finalize(&encoded_uri_buf, flags); for (i = 0; i < encoded_uri_buf.len; i++) - encoded_uri_buf.buf[i] ^= topo_hiding_ct_encode_pw.s[i % topo_hiding_ct_encode_pw.len]; + encoded_uri_buf.buf[i] ^= encoding_options->param_password.s[i % encoding_options->param_password.len]; - suffix_enc = pkg_malloc(1 + th_contact_encode_param.len + 1 + enc_len + params_len + 1); + suffix_enc = pkg_malloc(1 + encoding_options->param_name.len + 1 + enc_len + params_len + 1); if (!suffix_enc) { LM_ERR("no more pkg\n"); goto error; @@ -1022,8 +1039,8 @@ static char* build_encoded_thinfo_suffix(struct sip_msg* msg, str rr_set, int *s s = suffix_enc; *s++ = ';'; - memcpy(s, th_contact_encode_param.s, th_contact_encode_param.len); - s += th_contact_encode_param.len; + memcpy(s, encoding_options->param_name.s, encoding_options->param_name.len); + s += encoding_options->param_name.len; *s++ = '='; if (th_ct_enc_scheme == ENC_BASE64) @@ -1082,7 +1099,7 @@ static int th_no_dlg_encode_contact(struct sip_msg *msg, uint16_t flags, str rou str contact; if (!msg->contact) { - if(parse_headers(msg, HDR_CONTACT_F, 0)< 0) { + if(parse_headers(msg, HDR_CONTACT_F, 0) < 0) { LM_ERR("Failed to parse headers\n"); return -1; } @@ -1141,7 +1158,7 @@ static int th_no_dlg_encode_contact(struct sip_msg *msg, uint16_t flags, str rou /* make sure we do not free this string in case of a further error */ prefix = NULL; - if (th_compact_encoding) { + if (encoding_options->compact_encoding) { if (!(suffix = build_encoded_thinfo_suffix(msg, routes, &suffix_len, flags, 0))) { LM_ERR("Failed to build suffix \n"); goto error; @@ -1303,7 +1320,7 @@ static inline int topo_no_dlg_rewrite_contact_as_next_route(struct sip_msg *msg, return 1; } -static decoded_info_buffer_t decode_info_buffer(str *info) { +static decoded_info_buffer_t decode_info_buffer(str *info, const thinfo_options_t *options) { int max_size, dec_len, decoded_uri_buf_len, i; uint8_t uri_count; int proto = 0; @@ -1332,7 +1349,7 @@ static decoded_info_buffer_t decode_info_buffer(str *info) { } for (i = 0; i < dec_len; i++) - decoded_uri_buf.buf[i] ^= topo_hiding_ct_encode_pw.s[i % topo_hiding_ct_encode_pw.len]; + decoded_uri_buf.buf[i] ^= options->param_password.s[i % options->param_password.len]; decoded_uri_buf.len = dec_len; decoded_uri_buf.pos = 0; @@ -1398,7 +1415,7 @@ static decoded_info_buffer_t decode_info_buffer(str *info) { return (decoded_info_buffer_t) { .state = INVALID_BUF }; } -static decoded_info_buffer_t decode_info_buffer_legacy(str *info) { +static decoded_info_buffer_t decode_info_buffer_legacy(str *info, const thinfo_options_t *options) { str flags_buf = STR_NULL, bind_buf = STR_NULL, host = STR_NULL; int max_size, port = 0, proto = 0; char *p; @@ -1423,7 +1440,7 @@ static decoded_info_buffer_t decode_info_buffer_legacy(str *info) { (unsigned char *)info->s, info->len); for (i = 0; i < dec_len; i++) - dec_buf_legacy[i] ^= topo_hiding_ct_encode_pw_legacy.s[i % topo_hiding_ct_encode_pw_legacy.len]; + dec_buf_legacy[i] ^= options->param_password.s[i % options->param_password.len]; #define __extract_len_and_buf(_p, _len, _s) \ do { \ @@ -1481,7 +1498,7 @@ FINALIZE_DECODED_BUF_STATE(decoded_buffer); static char user_buf[UINT16_MAX]; static str ct_user_buf = { .s = user_buf, .len = 0 }; -static int th_no_dlg_seq_handling(struct sip_msg *msg, str *info, decode_info_fn decode_fn) { +static int th_no_dlg_seq_handling(struct sip_msg *msg, str *info, decode_info_fn decode_fn, const thinfo_options_t *options) { char *msg_buf = NULL, *route_free_str = NULL; str route_s = STR_NULL; struct th_no_dlg_param *param = NULL; @@ -1529,7 +1546,7 @@ static int th_no_dlg_seq_handling(struct sip_msg *msg, str *info, decode_info_fn } - decoded_buffer = decode_fn(info); + decoded_buffer = decode_fn(info, options); if (!(decoded_buffer.state & HAS_CONTACT) || (decoded_buffer.state & INVALID_BUF)) { LM_ERR("Failed to decode buffer\n"); return -1; @@ -1973,4 +1990,109 @@ static route_count_t th_no_dlg_match_record_route_or_route_uris(struct sip_msg * .delete_count = delete_count, .skip_encode_count = req_auto_routed ? skip_encode_count + 1 : skip_encode_count }; +} + +void th_free_param_passwords(void) { + int i; + + for (i = 0; i < param_password_count; i++) { + if (buffers[i] != NULL) + pkg_free(buffers[i]); + } + param_password_count = 0; +} + +int th_add_encode_param_password(modparam_t type, void *val) { + char *colon = NULL, *param_val = NULL; + char encoding_type = 0; + thinfo_options_t slot = { .compact_encoding = 1 }; + + if ((PARAM_TYPE_MASK(type) & STR_PARAM) == 0) { + LM_ERR("string value required\n"); + return -1; + } + + if (!val) { + LM_ERR("empty value\n"); + return -1; + } + + param_val = (char*) val; + + if (*param_val == '\0') { + LM_ERR("parameter is empty string\n"); + return -1; + } + + buffers[param_password_count] = pkg_malloc(strlen(param_val)); + + if (buffers[param_password_count] == NULL) { + LM_ERR("Failed to allocate string buffer\n"); + return -1; + } + + memcpy(buffers[param_password_count], param_val, strlen(param_val)); + param_val = buffers[param_password_count]; + + if (param_password_count >= 2) { + LM_ERR("at most 2 entries allowed\n"); + return -1; + } + + colon = strchr(param_val, ':'); + if (!colon) { + slot.param_name.len = strlen(param_val); + slot.param_name.s = param_val; + + slot.param_password = DEFAULT_PW; + + goto add_password; + } + + slot.param_name.s = param_val; + slot.param_name.len = colon - param_val; + slot.param_password.s = colon + 1; + + colon = strchr(slot.param_password.s, ':'); + + if (!colon) { + slot.param_password.len = strlen(slot.param_password.s); + goto add_password; + } else { + slot.param_password.len = colon - slot.param_password.s; + + encoding_type = *(colon + 1); + + if (encoding_type == 'C' || encoding_type == 'c') { + slot.compact_encoding = 1; + } else if (encoding_type == 'L' || encoding_type == 'l') { + slot.compact_encoding = 0; + } else { + LM_ERR("Encoding type not set correctly, must be one of C|c|L|l\n"); + return -1; + } + } + +add_password: + memcpy(¶m_passwords[param_password_count], &slot, sizeof(slot)); + param_password_count++; + return 1; +} + +static thinfo_options_t *th_get_options(const str *pn) { + if (!pn || !pn->s) + return NULL; + + for (int i = 0; i < TH_INFO_PASSWORD_ROTATION_SIZE; i++) { + if (pn->len == param_passwords[i].param_name.len && + memcmp(pn->s, param_passwords[i].param_name.s, pn->len) == 0) + return ¶m_passwords[i]; + } + + return NULL; +} + +int th_set_use_param(str *use_param) { + encoding_options = th_get_options(use_param); + return encoding_options != NULL; } \ No newline at end of file diff --git a/modules/topology_hiding/th_no_dlg_logic.h b/modules/topology_hiding/th_no_dlg_logic.h index 45077c458f7..bb89826f8c5 100644 --- a/modules/topology_hiding/th_no_dlg_logic.h +++ b/modules/topology_hiding/th_no_dlg_logic.h @@ -23,12 +23,24 @@ #include "th_common_logic.h" -#include "../../str.h" #include "../tm/t_hooks.h" +#include "../../str.h" #include "../../context.h" +#include "../../sr_module.h" enum encode_scheme {ENC_BASE64, ENC_BASE32}; +#define TH_INFO_PASSWORD_ROTATION_SIZE 2 + +#define DEFAULT_PARAM str_init("thinfo") +#define DEFAULT_PW str_init("ToPoCtPaSS") + +typedef struct { + str param_name; + str param_password; + int compact_encoding; +} thinfo_options_t; + extern str decoded_uris[12]; extern int decoded_uris_count; extern int ctx_decoded_routes_valid_idx; @@ -42,4 +54,8 @@ extern int ctx_decoded_routes_valid_idx; int topo_hiding_no_dlg(struct sip_msg *req, struct cell* t, unsigned int extra_flags, struct th_params *params); int topo_hiding_match_no_dlg(struct sip_msg *msg); +void th_free_param_passwords(void); +int th_add_encode_param_password(modparam_t type, void *val); +int th_set_use_param(str *); + #endif \ No newline at end of file diff --git a/modules/topology_hiding/topology_hiding.c b/modules/topology_hiding/topology_hiding.c index 301b952a668..07cc9be6004 100644 --- a/modules/topology_hiding/topology_hiding.c +++ b/modules/topology_hiding/topology_hiding.c @@ -30,6 +30,9 @@ #include "topo_hiding_logic.h" #include "th_no_dlg_logic.h" +#include "../../trim.h" +#include "../../ut.h" + struct tm_binds tm_api; struct dlg_binds dlg_api; @@ -39,21 +42,17 @@ int th_loop_protection = 0; str topo_hiding_ct_hdr_params = {0,0}; str topo_hiding_prefix = str_init("DLGCH_"); str topo_hiding_seed = str_init("OpenSIPS"); -str topo_hiding_ct_encode_pw = str_init("ToPoCtPaSS"); -str th_contact_encode_param = str_init("thinfo"); + str th_contact_encode_scheme = str_init("base64"); str th_contact_caller_var = str_init("_th_contact_caller_username_var_"); str th_contact_callee_var = str_init("_th_contact_callee_username_var_"); -str topo_hiding_ct_encode_pw_legacy = str_init("ToPoCtPaSS"); -str th_contact_encode_param_legacy = str_init("thinfol"); -str th_contact_encode_scheme_legacy = str_init("base64"); + str th_internal_trusted_tag = STR_EMPTY; str th_external_socket_tag = STR_EMPTY; +str th_use_param = DEFAULT_PARAM; int auto_route_on_trusted_socket = 1; -int th_compact_encoding = 0; int th_ct_enc_scheme; -int th_ct_enc_scheme_legacy; /* Global buffer for decoded routes */ str decoded_uris[12]; @@ -95,24 +94,20 @@ static const cmd_export_t cmds[]={ /* Exported parameters */ static const param_export_t params[] = { - { "force_dialog", INT_PARAM, &force_dialog }, - { "th_passed_contact_uri_params", STR_PARAM, &topo_hiding_ct_params.s }, - { "th_passed_contact_params", STR_PARAM, &topo_hiding_ct_hdr_params.s }, - { "th_callid_passwd", STR_PARAM, &topo_hiding_seed.s }, - { "th_callid_prefix", STR_PARAM, &topo_hiding_prefix.s }, - { "th_contact_encode_passwd", STR_PARAM, &topo_hiding_ct_encode_pw.s }, - { "th_contact_encode_param", STR_PARAM, &th_contact_encode_param.s }, - { "th_contact_encode_scheme", STR_PARAM, &th_contact_encode_scheme.s }, - { "th_contact_caller_username_var", STR_PARAM, &th_contact_caller_var.s }, - { "th_contact_callee_username_var", STR_PARAM, &th_contact_callee_var.s }, - { "th_contact_encode_passwd_legacy", STR_PARAM, &topo_hiding_ct_encode_pw_legacy.s }, - { "th_contact_encode_param_legacy", STR_PARAM, &th_contact_encode_param_legacy.s }, - { "th_contact_encode_scheme_legacy", STR_PARAM, &th_contact_encode_scheme_legacy.s }, - { "th_internal_trusted_tag", STR_PARAM, &th_internal_trusted_tag.s }, - { "th_external_socket_tag", STR_PARAM, &th_external_socket_tag.s }, - { "th_auto_route_on_trusted_socket", INT_PARAM, &auto_route_on_trusted_socket }, - { "th_compact_encoding", INT_PARAM, &th_compact_encoding }, - { "th_callid_loop_protection", INT_PARAM, &th_loop_protection }, + { "force_dialog", INT_PARAM, &force_dialog }, + { "th_passed_contact_uri_params", STR_PARAM, &topo_hiding_ct_params.s }, + { "th_passed_contact_params", STR_PARAM, &topo_hiding_ct_hdr_params.s }, + { "th_callid_passwd", STR_PARAM, &topo_hiding_seed.s }, + { "th_callid_prefix", STR_PARAM, &topo_hiding_prefix.s }, + { "th_contact_encode_scheme", STR_PARAM, &th_contact_encode_scheme.s }, + { "th_contact_caller_username_var", STR_PARAM, &th_contact_caller_var.s }, + { "th_contact_callee_username_var", STR_PARAM, &th_contact_callee_var.s }, + { "th_callid_loop_protection", INT_PARAM, &th_loop_protection }, + { "th_internal_trusted_tag", STR_PARAM, &th_internal_trusted_tag.s }, + { "th_external_socket_tag", STR_PARAM, &th_external_socket_tag.s }, + { "th_auto_route_on_trusted_socket", INT_PARAM, &auto_route_on_trusted_socket }, + { "th_use_param", STR_PARAM, &th_use_param.s }, + { "th_contact_encode_param_password", STR_PARAM|USE_FUNC_PARAM, th_add_encode_param_password }, {0, 0, 0} }; @@ -183,10 +178,6 @@ static int mod_init(void) /* param handling */ topo_hiding_prefix.len = strlen(topo_hiding_prefix.s); topo_hiding_seed.len = strlen(topo_hiding_seed.s); - th_contact_encode_param.len = strlen(th_contact_encode_param.s); - topo_hiding_ct_encode_pw.len = strlen(topo_hiding_ct_encode_pw.s); - th_contact_encode_param_legacy.len = strlen(th_contact_encode_param_legacy.s); - topo_hiding_ct_encode_pw_legacy.len = strlen(topo_hiding_ct_encode_pw_legacy.s); if (topo_hiding_ct_params.s) { topo_hiding_ct_params.len = strlen(topo_hiding_ct_params.s); topo_parse_passed_ct_params(&topo_hiding_ct_params); @@ -207,17 +198,6 @@ static int mod_init(void) "Use 'base64' or 'base32'\n"); goto error; } - - th_contact_encode_scheme_legacy.len = strlen(th_contact_encode_scheme_legacy.s); - if (!str_strcmp(&th_contact_encode_scheme_legacy, const_str("base64"))) - th_ct_enc_scheme_legacy = ENC_BASE64; - else if (!str_strcmp(&th_contact_encode_scheme_legacy, const_str("base32"))) - th_ct_enc_scheme_legacy = ENC_BASE32; - else { - LM_ERR("Unsupported value for 'th_contact_encode_scheme_legacy' modparam!" - "Use 'base64' or 'base32'\n"); - goto error; - } if (th_internal_trusted_tag.s) { th_internal_trusted_tag.len = strlen(th_internal_trusted_tag.s); @@ -258,6 +238,10 @@ static int mod_init(void) "hiding signalling for ongoing calls will be lost after " "restart\n"); + if (th_set_use_param(&th_use_param) < 0) { + LM_ERR("Param '%.*s' not in options\n", th_use_param.len, th_use_param.s); + return -1; + } return 0; error: @@ -266,7 +250,7 @@ static int mod_init(void) static void mod_destroy(void) { - return; + th_free_param_passwords(); } static int fixup_mmode(void **param) From 9fb595b553231aea9757457a0f257fbec9010351 Mon Sep 17 00:00:00 2001 From: David Trihy Date: Wed, 27 May 2026 10:39:30 +0100 Subject: [PATCH 6/8] Adding logic to encode only one auto route header --- modules/topology_hiding/th_no_dlg_logic.c | 130 ++++++++++++---------- 1 file changed, 74 insertions(+), 56 deletions(-) diff --git a/modules/topology_hiding/th_no_dlg_logic.c b/modules/topology_hiding/th_no_dlg_logic.c index c58310e48b4..f521ee3d006 100644 --- a/modules/topology_hiding/th_no_dlg_logic.c +++ b/modules/topology_hiding/th_no_dlg_logic.c @@ -884,19 +884,82 @@ static char* build_encoded_contact_suffix_legacy(struct sip_msg* msg, str rr_set return NULL; } +static int th_binary_encode_record_route(rr_t *record_route, rr_t **out_rr, int encode_self) { + struct sip_uri rr_uri = { 0 }, rr_uri_r2 = { 0 }; + const struct socket_info *rr_sock = NULL; + + if (record_route == NULL) { + LM_DBG("Record-Route to encode is NULL, skipping\n"); + return -1; + } + + if (parse_uri(record_route->nameaddr.uri.s, record_route->nameaddr.uri.len, &rr_uri) < 0) { + LM_ERR("Failed to parse SIP uri\n"); + return -1; + } + + rr_sock = grep_sock_info(&rr_uri.host, rr_uri.port_no ? rr_uri.port_no : SIP_PORT, rr_uri.proto); + + if (th_no_dlg_one_way_hiding(rr_sock) && !encode_self) { + LM_DBG("Route header is self, skipping encode\n"); + return 1; + } + + if (!is_2rr(&rr_uri.params)) { + if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri, 0, NULL, 1) == -1) { + LM_ERR("Error encoding Route URI\n"); + return -1; + } + } else { + record_route = record_route->next; + if (record_route != NULL) { + if (parse_uri(record_route->nameaddr.uri.s, record_route->nameaddr.uri.len, &rr_uri_r2) < 0) { + LM_ERR("Failed to parse SIP uri\n"); + return -1; + } + + if (is_2rr(&rr_uri_r2.params) && str_match(&rr_uri.host, &rr_uri_r2.host)) { + if (thinfo_encode_dual_uri(&encoded_uri_buf, &rr_uri, &rr_uri_r2) == -1) { + LM_ERR("Error encoding Route URI\n"); + return -1; + } + } else { + if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri, 0, NULL, 1) == -1) { + LM_ERR("Error encoding Route URI\n"); + return -1; + } + + if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri_r2, 0, NULL, 1) == -1) { + LM_ERR("Error encoding Route URI\n"); + return -1; + } + } + } else { + if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri, 0, NULL, 1) == -1) { + LM_ERR("Error encoding Route URI\n"); + return -1; + } + LM_WARN("Previous Route has r2=on but no next Route\n"); + } + } + + *out_rr = record_route != NULL ? record_route->next : NULL; + return 0; +} + static char* build_encoded_thinfo_suffix(struct sip_msg* msg, str rr_set, int *suffix_len, uint16_t flags, int socket_only) { uint16_t enc_len = 0; char *suffix_enc, *s; rr_t *next = NULL, *head = NULL; int i, x, params_len = 0; - struct sip_uri ctu = { 0 }, rr_uri = { 0 }, rr_uri_r2 = { 0 }; + struct sip_uri ctu = { 0 }; struct th_ct_params* el; param_t *it; str contact = STR_NULL; char *rr_set_free_str = NULL; - const struct socket_info *rr_sock = NULL; str ct_uri_params_skip[URI_MAX_U_PARAMS]; int param_count = 0; + int encode_self_rr = 0, encode_ret_code = 0; /* parse all headers as we can have multiple RR headers in the same message */ @@ -957,60 +1020,15 @@ static char* build_encoded_thinfo_suffix(struct sip_msg* msg, str rr_set, int *s next = head; } - while (next != NULL) { - if (parse_uri(next->nameaddr.uri.s, next->nameaddr.uri.len, &rr_uri) < 0) { - LM_ERR("Failed to parse SIP uri\n"); - goto error; - } - - rr_sock = grep_sock_info(&rr_uri.host, rr_uri.port_no ? rr_uri.port_no : SIP_PORT, rr_uri.proto); - - if (!th_no_dlg_one_way_hiding(rr_sock)) { - if (!is_2rr(&rr_uri.params)) { - if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri, 0, NULL, 1) == -1) { - LM_ERR("Error encoding Route URI\n"); - goto error; - } - } else { - next = next->next; - if (next != NULL) { - if (parse_uri(next->nameaddr.uri.s, next->nameaddr.uri.len, &rr_uri_r2) < 0) { - LM_ERR("Failed to parse SIP uri\n"); - goto error; - } - } else { - if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri, 0, NULL, 1) == -1) { - LM_ERR("Error encoding Route URI\n"); - goto error; - } - LM_WARN("Previous Route has r2=on but no next Route\n"); - continue; - } - - if (is_2rr(&rr_uri_r2.params) && str_match(&rr_uri.host, &rr_uri_r2.host)) { - if (thinfo_encode_dual_uri(&encoded_uri_buf, &rr_uri, &rr_uri_r2) == -1) { - LM_ERR("Error encoding Route URI\n"); - goto error; - } - } else { - if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri, 0, NULL, 1) == -1) { - LM_ERR("Error encoding Route URI\n"); - goto error; - } - - if (thinfo_encode_uri(&encoded_uri_buf, &rr_uri_r2, 0, NULL, 1) == -1) { - LM_ERR("Error encoding Route URI\n"); - goto error; - } - } - - memset(&rr_uri_r2, 0, sizeof(rr_uri_r2)); - } - } - - memset(&rr_uri, 0, sizeof(rr_uri)); - next = next->next; - } + while (next != NULL) { + encode_ret_code = th_binary_encode_record_route(next, &next, encode_self_rr); + if (encode_ret_code < 0) { + goto error; + } else if (encode_ret_code == 1) { + // Found first occurence of self Record-Route, need to encode the rest + encode_self_rr = 1; + } + } if (head != NULL) { pkg_free(head); From 5b974f0f2812ec4d3e6b0061e9d6b753d634e02b Mon Sep 17 00:00:00 2001 From: David Trihy Date: Fri, 5 Jun 2026 12:24:32 +0100 Subject: [PATCH 7/8] Fixing some memory issues --- modules/topology_hiding/th_no_dlg_logic.c | 64 +++++++++++------------ modules/topology_hiding/th_no_dlg_logic.h | 3 +- modules/topology_hiding/topology_hiding.c | 4 +- 3 files changed, 34 insertions(+), 37 deletions(-) diff --git a/modules/topology_hiding/th_no_dlg_logic.c b/modules/topology_hiding/th_no_dlg_logic.c index f521ee3d006..f483820c745 100644 --- a/modules/topology_hiding/th_no_dlg_logic.c +++ b/modules/topology_hiding/th_no_dlg_logic.c @@ -34,7 +34,6 @@ #define START_THINFO_BUF_SZ 1000 #define THINFO_MAX_BUFFER_SIZE 10000 -#define MAX_ENCODED_SIP_URIS 12 #define TOPOH_MATCH_TAG_MATCH 2 #define TOPOH_MATCH_SUCCESS 1 @@ -184,7 +183,7 @@ int topo_hiding_no_dlg(struct sip_msg *req, struct cell* t, unsigned int extra_f LM_WARN("Cannot store DID in user when dialog support is not engaged!\n"); if (!(extra_flags & TOPOH_KEEP_USER) && params && params->ct_callee_user.len) { - param_size = sizeof *p + params->ct_callee_user.len + sizeof(uint16_t); + param_size = sizeof *p + params->ct_callee_user.len; } else { param_size = sizeof *p; } @@ -199,15 +198,11 @@ int topo_hiding_no_dlg(struct sip_msg *req, struct cell* t, unsigned int extra_f if (!(extra_flags & TOPOH_KEEP_USER)) { if (params && params->ct_callee_user.len) { - p = shm_malloc(sizeof *p + params->ct_callee_user.len); - if (p) { - memset(p, 0, sizeof *p); - p->username.s = (char *)(p + 1); - p->username.len = params->ct_callee_user.len; - memcpy(p->username.s, params->ct_callee_user.s, - params->ct_callee_user.len); - username = ¶ms->ct_callee_user; - } + p->username.s = (char *)(p + 1); + p->username.len = params->ct_callee_user.len; + memcpy(p->username.s, params->ct_callee_user.s, + params->ct_callee_user.len); + username = ¶ms->ct_callee_user; } } @@ -477,7 +472,6 @@ static struct lump *anchor_after_last_record_route(struct sip_msg *msg) { return anchor_lump(msg, offset, HDR_RECORDROUTE_T); } -// TODO log callId perhaps? static void th_no_dlg_onreply(struct cell *t, int type, struct tmcb_params *param) { struct th_no_dlg_param *p = *(param->param); str route_s = STR_NULL; @@ -680,6 +674,9 @@ static inline int th_no_dlg_onrequest(struct sip_msg *req, uint16_t flags, str * return -1; } + if (route_s.s != NULL) + pkg_free(route_s.s); + return 1; error: if (route_s.s != NULL) { @@ -793,8 +790,10 @@ static char* build_encoded_contact_suffix_legacy(struct sip_msg* msg, str rr_set } } - if (head != NULL) - pkg_free(head); + if (head != NULL) { + free_rr(&head); + head = NULL; + } total_len += params_len; @@ -881,6 +880,8 @@ static char* build_encoded_contact_suffix_legacy(struct sip_msg* msg, str rr_set pkg_free(suffix_plain); if (rr_set_free_str) pkg_free(rr_set_free_str); + if (head) + free_rr(&head); return NULL; } @@ -1031,7 +1032,7 @@ static char* build_encoded_thinfo_suffix(struct sip_msg* msg, str rr_set, int *s } if (head != NULL) { - pkg_free(head); + free_rr(&head); head = NULL; } @@ -1097,15 +1098,12 @@ static char* build_encoded_thinfo_suffix(struct sip_msg* msg, str rr_set, int *s return suffix_enc; error: - if (rr_set_free_str) { + if (rr_set_free_str) pkg_free(rr_set_free_str); - } - if (head) { - pkg_free(head); - } - if (suffix_enc) { + if (head) + free_rr(&head); + if (suffix_enc) pkg_free(suffix_enc); - } return NULL; } @@ -1460,17 +1458,17 @@ static decoded_info_buffer_t decode_info_buffer_legacy(str *info, const thinfo_o for (i = 0; i < dec_len; i++) dec_buf_legacy[i] ^= options->param_password.s[i % options->param_password.len]; - #define __extract_len_and_buf(_p, _len, _s) \ - do { \ - (_s).len = *(short *)p;\ - if ((_s).len < 0 || (_s).len > _len) {\ - LM_ERR("bad length %d in encoded contact\n", (_s).len); \ - goto error;\ - }\ - (_s).s = _p + sizeof(short);\ - _p += sizeof(short) + (_s).len;\ - _len -= sizeof(short) + (_s).len;\ - } while(0) + #define __extract_len_and_buf(_p, _len, _s) \ + do { \ + memcpy(&(_s).len, _p, sizeof(short)); \ + if ((_s).len < 0 || (_s).len > _len) { \ + LM_ERR("bad length %d in encoded contact\n", (_s).len); \ + goto error; \ + } \ + (_s).s = _p + sizeof(short); \ + _p += sizeof(short) + (_s).len; \ + _len -= sizeof(short) + (_s).len; \ + } while(0) p = dec_buf_legacy; size = dec_len; diff --git a/modules/topology_hiding/th_no_dlg_logic.h b/modules/topology_hiding/th_no_dlg_logic.h index bb89826f8c5..6b0560ade08 100644 --- a/modules/topology_hiding/th_no_dlg_logic.h +++ b/modules/topology_hiding/th_no_dlg_logic.h @@ -31,6 +31,7 @@ enum encode_scheme {ENC_BASE64, ENC_BASE32}; #define TH_INFO_PASSWORD_ROTATION_SIZE 2 +#define MAX_ENCODED_SIP_URIS 12 #define DEFAULT_PARAM str_init("thinfo") #define DEFAULT_PW str_init("ToPoCtPaSS") @@ -41,7 +42,7 @@ typedef struct { int compact_encoding; } thinfo_options_t; -extern str decoded_uris[12]; +extern str decoded_uris[MAX_ENCODED_SIP_URIS]; extern int decoded_uris_count; extern int ctx_decoded_routes_valid_idx; diff --git a/modules/topology_hiding/topology_hiding.c b/modules/topology_hiding/topology_hiding.c index 07cc9be6004..b7eb286db58 100644 --- a/modules/topology_hiding/topology_hiding.c +++ b/modules/topology_hiding/topology_hiding.c @@ -55,7 +55,7 @@ int auto_route_on_trusted_socket = 1; int th_ct_enc_scheme; /* Global buffer for decoded routes */ -str decoded_uris[12]; +str decoded_uris[MAX_ENCODED_SIP_URIS]; int decoded_uris_count = 0; /* Context flag to track if decoded routes are valid for current message */ @@ -384,8 +384,6 @@ int w_topology_hiding_match(struct sip_msg *req, void *seq_match_mode_val) } static char *callid_buf=NULL; -static int callid_buf_len=0; - static int pv_topo_callee_callid(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { struct dlg_cell *dlg; From 0d8947c8fbade9faf18adf69b3aaf43f1db785a4 Mon Sep 17 00:00:00 2001 From: David Trihy Date: Fri, 5 Jun 2026 13:41:41 +0100 Subject: [PATCH 8/8] Initialize *suffix_enc to NULL --- modules/topology_hiding/th_no_dlg_logic.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/modules/topology_hiding/th_no_dlg_logic.c b/modules/topology_hiding/th_no_dlg_logic.c index f483820c745..b8342c3de74 100644 --- a/modules/topology_hiding/th_no_dlg_logic.c +++ b/modules/topology_hiding/th_no_dlg_logic.c @@ -692,7 +692,7 @@ static inline int th_no_dlg_onrequest(struct sip_msg *req, uint16_t flags, str * static char* build_encoded_contact_suffix_legacy(struct sip_msg* msg, str rr_set, int *suffix_len, int flags) { short rr_len,ct_len,addr_len,flags_len,enc_len; - char *suffix_plain = NULL,*suffix_enc = NULL,*p = NULL,*s = NULL; + char *suffix_plain = NULL, *suffix_enc = NULL, *p = NULL, *s = NULL; char *rr_set_free_str = NULL; str contact; str flags_str; @@ -950,7 +950,7 @@ static int th_binary_encode_record_route(rr_t *record_route, rr_t **out_rr, int static char* build_encoded_thinfo_suffix(struct sip_msg* msg, str rr_set, int *suffix_len, uint16_t flags, int socket_only) { uint16_t enc_len = 0; - char *suffix_enc, *s; + char *suffix_enc = NULL, *s = NULL; rr_t *next = NULL, *head = NULL; int i, x, params_len = 0; struct sip_uri ctu = { 0 }; @@ -1209,11 +1209,6 @@ static int th_no_dlg_encode_contact(struct sip_msg *msg, uint16_t flags, str rou return -1; } -static inline void topo_no_dlg_seq_free(void *p) { - if (p) - shm_free(p); -} - static inline int topo_no_dlg_route(struct sip_msg *msg, str rr_buf[static 1]) { rr_t *head = NULL, *rrp = NULL; struct sip_uri rr_uri;