src/modules/topoh/th_msg.c
b16b1294
 /**
  *
  * Copyright (C) 2009 SIP-Router.org
  *
5ae20460
  * This file is part of Kamailio, a free SIP server.
b16b1294
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
  *
  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
2d473a9d
 /*!
  * \file
  * \brief SIP-router topoh ::
  * \ingroup topoh
  * Module: \ref topoh
  */
 
b16b1294
 #include <string.h>
 
cf83221d
 #include "../../core/dprint.h"
 #include "../../core/mem/mem.h"
 #include "../../core/data_lump.h"
 #include "../../core/forward.h"
 #include "../../core/trim.h"
 #include "../../core/msg_translator.h"
 #include "../../core/parser/parse_rr.h"
 #include "../../core/parser/parse_uri.h"
 #include "../../core/parser/parse_param.h"
 #include "../../core/parser/parse_from.h"
 #include "../../core/parser/parse_to.h"
 #include "../../core/parser/parse_via.h"
 #include "../../core/parser/contact/parse_contact.h"
 #include "../../core/parser/parse_refer_to.h"
b16b1294
 #include "th_mask.h"
 #include "th_msg.h"
 
 extern str th_cookie_name;
 extern str th_cookie_value;
 extern str th_via_prefix;
 extern str th_uri_prefix;
9d5a1ff7
 extern str th_callid_prefix;
b16b1294
 
 extern str th_ip;
 extern str th_uparam_name;
 extern str th_uparam_prefix;
 extern str th_vparam_name;
 extern str th_vparam_prefix;
 
 extern int th_param_mask_callid;
a0cd3fb7
 extern int th_mask_addr_myself;
de3386e4
 extern int th_uri_prefix_checks;
b16b1294
 
 int th_skip_rw(char *s, int len)
 {
 	while(len>0)
 	{
 		if(s[len-1]==' ' || s[len-1]=='\t' || s[len-1]=='\n' || s[len-1]=='\r'
 				|| s[len-1]==',')
 			len--;
 		else return len;
 	}
 	return 0;
 }
 
 struct via_param *th_get_via_param(struct via_body *via, str *name)
 {
 	struct via_param *p;
 	for(p=via->param_lst; p; p=p->next)
 	{
 		if(p->name.len==name->len
 				&& strncasecmp(p->name.s, name->s, name->len)==0)
 			return p;
 	}
 	return NULL;
 }
 
 int th_get_param_value(str *in, str *name, str *value)
 {
 	param_t* params = NULL;
 	param_t* p = NULL;
 	param_hooks_t phooks;
 	if (parse_params(in, CLASS_ANY, &phooks, &params)<0)
 		return -1;
 	for (p = params; p; p=p->next)
 	{
 		if (p->name.len==name->len
 				&& strncasecmp(p->name.s, name->s, name->len)==0)
 		{
 			*value = p->body;
 			free_params(params);
 			return 0;
 		}
 	}
66ab19a0
 
b16b1294
 	if(params) free_params(params);
 	return 1;
 
 }
 
 int th_get_uri_param_value(str *uri, str *name, str *value)
 {
951df23f
 	sip_uri_t puri;
b16b1294
 
 	memset(value, 0, sizeof(str));
 	if(parse_uri(uri->s, uri->len, &puri)<0)
 		return -1;
951df23f
 
 	LM_DBG("uri params: [%.*s] - sip uri params: [%.*s]\n",
 			puri.params.len, (puri.params.s)?puri.params.s:"",
 			puri.sip_params.len, (puri.sip_params.s)?puri.sip_params.s:"");
 
 	if(puri.sip_params.len>0)
 		return th_get_param_value(&puri.sip_params, name, value);
 
b16b1294
 	return th_get_param_value(&puri.params, name, value);
 }
 
 int th_get_uri_type(str *uri, int *mode, str *value)
 {
951df23f
 	sip_uri_t puri;
b16b1294
 	int ret;
 	str r2 = {"r2", 2};
 
 	memset(value, 0, sizeof(str));
 	*mode = 0;
 	if(parse_uri(uri->s, uri->len, &puri)<0)
 		return -1;
 
a0cd3fb7
 	LM_DBG("PARAMS [%.*s]\n", puri.params.len, puri.params.s);
b16b1294
 	if(puri.host.len==th_ip.len
 			&& strncasecmp(puri.host.s, th_ip.s, th_ip.len)==0)
 	{
 		/* host matches TH ip */
 		ret = th_get_param_value(&puri.params, &th_uparam_name, value);
a0cd3fb7
 		if(ret<0)
 			return -1; /* eroor parsing parameters */
 		if(ret==0)
 			return 2; /* param found - decode */
 		if(th_mask_addr_myself==0)
 			return 0; /* param not found - skip */
 	}
 
 	if(check_self(&puri.host, puri.port_no, 0)==1)
 	{
 		/* myself -- matched on all protos */
 		ret = th_get_param_value(&puri.params, &r2, value);
b16b1294
 		if(ret<0)
 			return -1;
a0cd3fb7
 		if(ret==1) /* not found */
b16b1294
 			return 0; /* skip */
a0cd3fb7
 		LM_DBG("VALUE [%.*s]\n",
 				value->len, value->s);
 		if(value->len==2 && strncasecmp(value->s, "on", 2)==0)
 			*mode = 1;
 		memset(value, 0, sizeof(str));
 		return 0; /* skip */
 	}
 	/* not myself & not mask ip */
 	return 1; /* encode */
b16b1294
 }
 
 int th_mask_via(sip_msg_t *msg)
 {
 	hdr_field_t *hdr;
 	struct via_body *via;
 	struct lump* l;
 	int i;
 	str out;
 	int vlen;
 
 	i=0;
 	for(hdr=msg->h_via1; hdr; hdr=next_sibling_hdr(hdr))
 	{
 		for(via=(struct via_body*)hdr->parsed; via; via=via->next)
 		{
 			i++;
 			LM_DBG("=======via[%d]\n", i);
 			LM_DBG("hdr: [%.*s]\n", via->hdr.len, via->hdr.s);
 			vlen = th_skip_rw(via->name.s, via->bsize);
 			LM_DBG("body: %d: [%.*s]\n", vlen, vlen, via->name.s);
 			if(i!=1)
 			{
 				out.s = th_mask_encode(via->name.s, vlen, &th_via_prefix,
 						&out.len);
 				if(out.s==NULL)
 				{
 					LM_ERR("cannot encode via %d\n", i);
 					return -1;
 				}
66ab19a0
 
b16b1294
 				LM_DBG("+body: %d: [%.*s]\n", out.len, out.len, out.s);
 				l=del_lump(msg, via->name.s-msg->buf, vlen, 0);
 				if (l==0)
 				{
 					LM_ERR("failed deleting via [%d]\n", i);
 					pkg_free(out.s);
 					return -1;
 				}
 				if (insert_new_lump_after(l, out.s, out.len, 0)==0){
 					LM_ERR("could not insert new lump\n");
 					pkg_free(out.s);
 					return -1;
 				}
 			}
 		}
 	}
 	return 0;
 }
 
 int th_mask_callid(sip_msg_t *msg)
 {
 	struct lump* l;
 	str out;
 
 	if(th_param_mask_callid==0)
 		return 0;
 
 	if(msg->callid==NULL)
 	{
 		LM_ERR("cannot get Call-Id header\n");
 		return -1;
 	}
66ab19a0
 
9d5a1ff7
 	out.s = th_mask_encode(msg->callid->body.s, msg->callid->body.len,
 				&th_callid_prefix, &out.len);
b16b1294
 	if(out.s==NULL)
 	{
 		LM_ERR("cannot encode callid\n");
 		return -1;
 	}
66ab19a0
 
b16b1294
 	l=del_lump(msg, msg->callid->body.s-msg->buf, msg->callid->body.len, 0);
 	if (l==0)
 	{
 		LM_ERR("failed deleting callid\n");
 		pkg_free(out.s);
 		return -1;
 	}
 	if (insert_new_lump_after(l, out.s, out.len, 0)==0) {
 		LM_ERR("could not insert new lump\n");
 		pkg_free(out.s);
 		return -1;
 	}
 
 	return 0;
 }
 
 int th_mask_contact(sip_msg_t *msg)
 {
 	struct lump* l;
 	str out;
 	str in;
66f80a68
 	char *p;
b16b1294
 	contact_t *c;
 
66ab19a0
 	if(msg->contact==NULL)
b16b1294
 	{
 		LM_DBG("no contact header\n");
 		return 0;
 	}
 
 	if(parse_contact(msg->contact) < 0)
 	{
 		LM_ERR("failed parsing contact header\n");
 		return -1;
 	}
66ab19a0
 
b16b1294
 	c = ((contact_body_t*)msg->contact->parsed)->contacts;
101670ac
 	if(c == NULL)
 	{
 		LM_ERR("invalid contact header\n");
 		return -1;
 	}
b16b1294
 	in = c->uri;
 
 	out.s = th_mask_encode(in.s, in.len, &th_uri_prefix, &out.len);
 	if(out.s==NULL)
 	{
 		LM_ERR("cannot encode contact uri\n");
 		return -1;
 	}
66f80a68
 	if(*(in.s-1)!='<')
 	{
 		/* add < > around contact uri if not there */
 		p = (char*)pkg_malloc(out.len+3);
 		if(p==NULL)
 		{
32c917f6
 			PKG_MEM_ERROR;
66f80a68
 			pkg_free(out.s);
 			return -1;
 		}
 		*p = '<';
 		strncpy(p+1, out.s, out.len);
 		p[out.len+1] = '>';
 		p[out.len+2] = '\0';
 		pkg_free(out.s);
 		out.s = p;
 		out.len += 2;
 	}
66ab19a0
 
b16b1294
 	l=del_lump(msg, in.s-msg->buf, in.len, 0);
 	if (l==0)
 	{
 		LM_ERR("failed deleting contact uri\n");
 		pkg_free(out.s);
 		return -1;
 	}
 	if (insert_new_lump_after(l, out.s, out.len, 0)==0) {
 		LM_ERR("could not insert new lump\n");
 		pkg_free(out.s);
 		return -1;
 	}
 
 	return 0;
 }
 
 int th_mask_record_route(sip_msg_t *msg)
 {
 	hdr_field_t *hdr;
 	struct lump* l;
 	int i;
 	rr_t *rr;
 	str out;
 
 	if(msg->record_route==NULL)
 	{
 		LM_DBG("no record route header\n");
 		return 0;
 	}
 	hdr = msg->record_route;
 	i = 0;
66ab19a0
 	while(hdr!=NULL)
b16b1294
 	{
66ab19a0
 		if (parse_rr(hdr) < 0)
b16b1294
 		{
 			LM_ERR("failed to parse RR\n");
 			return -1;
 		}
 
 		rr =(rr_t*)hdr->parsed;
 		while(rr)
 		{
 			i++;
 			if(i!=1)
 			{
 				out.s = th_mask_encode(rr->nameaddr.uri.s, rr->nameaddr.uri.len,
 						&th_uri_prefix, &out.len);
 				if(out.s==NULL)
 				{
 					LM_ERR("cannot encode r-r %d\n", i);
 					return -1;
 				}
 				l=del_lump(msg, rr->nameaddr.uri.s-msg->buf,
 						rr->nameaddr.uri.len, 0);
 				if (l==0)
 				{
 					LM_ERR("failed deleting r-r [%d]\n", i);
 					pkg_free(out.s);
 					return -1;
 				}
 				if (insert_new_lump_after(l, out.s, out.len, 0)==0){
 					LM_ERR("could not insert new lump\n");
 					pkg_free(out.s);
 					return -1;
 				}
 			}
 			rr = rr->next;
 		}
 		hdr = next_sibling_hdr(hdr);
 	}
 
 	return 0;
 }
 
 int th_unmask_via(sip_msg_t *msg, str *cookie)
 {
 	hdr_field_t *hdr;
 	struct via_body *via;
 	struct via_body *via2;
 	struct via_param *vp;
 	struct lump* l;
 	int i;
 	str out;
 	int vlen;
 
 	i=0;
 	for(hdr=msg->h_via1; hdr; hdr=next_sibling_hdr(hdr))
 	{
 		for(via=(struct via_body*)hdr->parsed; via; via=via->next)
 		{
 			i++;
 			LM_DBG("=======via[%d]\n", i);
 			LM_DBG("hdr: [%.*s]\n", via->hdr.len, via->hdr.s);
 			vlen = th_skip_rw(via->name.s, via->bsize);
 			LM_DBG("body: %d: [%.*s]\n", vlen, vlen, via->name.s);
 			if(i!=1)
 			{
055fca8d
 				/* Skip if via is not encoded */
de3386e4
 				if (th_uri_prefix_checks && (via->host.len!=th_ip.len
 						|| strncasecmp(via->host.s, th_ip.s, th_ip.len)!=0))
055fca8d
 				{
c8c884c4
 					LM_DBG("via %d is not encoded - skip\n",i);
055fca8d
 					continue;
 				}
 
b16b1294
 				vp = th_get_via_param(via, &th_vparam_name);
 				if(vp==NULL)
 				{
 					LM_ERR("cannot find param in via %d\n", i);
 					return -1;
 				}
c8c884c4
 				if(th_vparam_prefix.len > 0) {
 					if(vp->value.len <= th_vparam_prefix.len) {
 						LM_DBG("shorter param len in via %d - skip\n", i);
 						continue;
 					}
 					if(strncmp(vp->value.s, th_vparam_prefix.s,
 									th_vparam_prefix.len) != 0) {
 						LM_DBG("no prefix in via %d - skip\n", i);
 						continue;
 					}
e6950ffb
 				}
 				if(i==2) {
b16b1294
 					out.s = th_mask_decode(vp->value.s, vp->value.len,
 							&th_vparam_prefix, CRLF_LEN+1, &out.len);
e6950ffb
 				} else {
b16b1294
 					out.s = th_mask_decode(vp->value.s, vp->value.len,
 							&th_vparam_prefix, 0, &out.len);
e6950ffb
 				}
78ccdb7f
 				if(out.s==NULL || out.len<=0)
b16b1294
 				{
055fca8d
 					LM_ERR("cannot decode via %d\n", i);
b16b1294
 					return -1;
 				}
66ab19a0
 
b16b1294
 				LM_DBG("+body: %d: [%.*s]\n", out.len, out.len, out.s);
 				if(i==2)
 				{
 					via2=pkg_malloc(sizeof(struct via_body));
 					if (via2==0)
 					{
32c917f6
 						PKG_MEM_ERROR;
b16b1294
 						pkg_free(out.s);
 						return -1;
 
 					}
66ab19a0
 
b16b1294
 					memset(via2, 0, sizeof(struct via_body));
 					memcpy(out.s+out.len, CRLF, CRLF_LEN);
 					out.s[out.len+CRLF_LEN]='X';
 					if(parse_via(out.s, out.s+out.len+CRLF_LEN+1, via2)==NULL)
 					{
 						LM_ERR("error parsing decoded via2\n");
 						free_via_list(via2);
 						pkg_free(out.s);
 						return -1;
 					}
 					out.s[out.len] = '\0';
 					vp = th_get_via_param(via2, &th_cookie_name);
 					if(vp==NULL)
 					{
 						LM_ERR("cannot find cookie in via2\n");
 						free_via_list(via2);
 						pkg_free(out.s);
 						return -1;
 					}
 					*cookie = vp->value;
 					free_via_list(via2);
 				}
 				l=del_lump(msg, via->name.s-msg->buf, vlen, 0);
 				if (l==0)
 				{
 					LM_ERR("failed deleting via [%d]\n", i);
 					pkg_free(out.s);
 					return -1;
 				}
 				if (insert_new_lump_after(l, out.s, out.len, 0)==0)
 				{
 					LM_ERR("could not insert new lump\n");
 					pkg_free(out.s);
 					return -1;
 				}
 			}
 		}
 	}
 
 	return 0;
 }
 
 int th_unmask_callid(sip_msg_t *msg)
 {
 	struct lump* l;
 	str out;
66ab19a0
 
b16b1294
 	if(th_param_mask_callid==0)
 		return 0;
66ab19a0
 
b16b1294
 	if(msg->callid==NULL)
 	{
 		LM_ERR("cannot get Call-Id header\n");
 		return -1;
 	}
055fca8d
 
 	/* Do nothing if call-id is not encoded */
 	if ((msg->callid->body.len<th_callid_prefix.len) ||
 			(strncasecmp(msg->callid->body.s,th_callid_prefix.s,th_callid_prefix.len)!=0))
 	{
 		LM_DBG("call-id [%.*s] not encoded",msg->callid->body.len,msg->callid->body.s);
 		return 0;
 	}
66ab19a0
 
9d5a1ff7
 	out.s = th_mask_decode(msg->callid->body.s, msg->callid->body.len,
 					&th_callid_prefix, 0, &out.len);
b16b1294
 	if(out.s==NULL)
 	{
 		LM_ERR("cannot decode callid\n");
 		return -1;
 	}
66ab19a0
 
b16b1294
 	l=del_lump(msg, msg->callid->body.s-msg->buf, msg->callid->body.len, 0);
 	if (l==0)
 	{
 		LM_ERR("failed deleting callid\n");
 		pkg_free(out.s);
 		return -1;
 	}
 	if (insert_new_lump_after(l, out.s, out.len, 0)==0) {
 		LM_ERR("could not insert new lump\n");
 		pkg_free(out.s);
 		return -1;
 	}
 
 	return 0;
 }
 
309e5fc8
 #define TH_CALLID_SIZE	256
 int th_unmask_callid_str(str *icallid, str *ocallid)
 {
 	static char th_callid_buf[TH_CALLID_SIZE];
 	str out;
 
 	if(th_param_mask_callid==0)
 		return 0;
 
 	if(icallid->s==NULL) {
 		LM_ERR("invalid Call-Id value\n");
 		return -1;
 	}
 
 	if(th_callid_prefix.len>0) {
 		if(th_callid_prefix.len >= icallid->len) {
 			return 1;
 		}
 		if(strncmp(icallid->s, th_callid_prefix.s, th_callid_prefix.len)!=0) {
 			return 1;
 		}
 	}
 	out.s = th_mask_decode(icallid->s, icallid->len,
 					&th_callid_prefix, 0, &out.len);
b5ce9d8f
 	if(out.s == NULL) {
 		LM_ERR("failed to decode call-id\n");
 		return -2;
 	}
309e5fc8
 	if(out.len>=TH_CALLID_SIZE) {
 		pkg_free(out.s);
 		LM_ERR("not enough callid buf size (needed %d)\n", out.len);
 		return -2;
 	}
 
 	memcpy(th_callid_buf, out.s, out.len);
 	th_callid_buf[out.len] = '\0';
 
 	pkg_free(out.s);
 
 	ocallid->s = th_callid_buf;
 	ocallid->len = out.len;
 
 	return 0;
 }
 
b16b1294
 int th_flip_record_route(sip_msg_t *msg, int mode)
 {
 	hdr_field_t *hdr;
 	struct lump* l;
 	int i;
 	rr_t *rr;
 	str out;
 	int utype;
 	str pval;
 	int r2;
 	int act;
 
 	if(msg->record_route==NULL)
 	{
 		LM_DBG("no record route header\n");
 		return 0;
 	}
 	hdr = msg->record_route;
 	i = 0;
 	act = 0;
 	if(mode==1)
 		act = 2;
66ab19a0
 	while(hdr!=NULL)
b16b1294
 	{
66ab19a0
 		if (parse_rr(hdr) < 0)
b16b1294
 		{
 			LM_ERR("failed to parse RR\n");
 			return -1;
 		}
 
 		rr =(rr_t*)hdr->parsed;
 		while(rr)
 		{
 			i++;
 			r2 = 0;
 			utype = th_get_uri_type(&rr->nameaddr.uri, &r2, &pval);
 			if(utype==0 && mode==1)
 			{
 				if(r2==1)
 				{
 					act--;
 					if(act==0)
 						return 0;
 					utype = 1;
 				} else {
 					return 0;
 				}
 			}
 			out.s = NULL;
 			switch(utype) {
 				case 1: /* encode */
 					if(act!=0 && mode==1)
 					{
 						out.s = th_mask_encode(rr->nameaddr.uri.s,
 							rr->nameaddr.uri.len, &th_uri_prefix, &out.len);
 						if(out.s==NULL)
 						{
 							LM_ERR("cannot encode r-r %d\n", i);
 							return -1;
 						}
 					}
 				break;
 				case 2: /* decode */
 					if(mode==0)
 					{
 						out.s = th_mask_decode(pval.s,
 							pval.len, &th_uparam_prefix, 0, &out.len);
 						if(out.s==NULL)
 						{
 							LM_ERR("cannot decode r-r %d\n", i);
 							return -1;
 						}
 					}
 				break;
 			}
 			if(out.s!=NULL)
 			{
 				l=del_lump(msg, rr->nameaddr.uri.s-msg->buf,
 						rr->nameaddr.uri.len, 0);
 				if (l==0)
 				{
 					LM_ERR("failed deleting r-r [%d]\n", i);
 					pkg_free(out.s);
 					return -1;
 				}
 				if (insert_new_lump_after(l, out.s, out.len, 0)==0){
 					LM_ERR("could not insert new lump\n");
 					pkg_free(out.s);
 					return -1;
 				}
 			}
 			rr = rr->next;
 		}
 		hdr = next_sibling_hdr(hdr);
 	}
 
 	return 0;
 }
 
 int th_unmask_route(sip_msg_t *msg)
 {
 	hdr_field_t *hdr;
 	struct lump* l;
 	int i;
 	rr_t *rr;
 	str out;
 	str eval;
 
 	if(msg->route==NULL)
 	{
 		LM_DBG("no record route header\n");
 		return 0;
 	}
 	hdr = msg->route;
 	i = 0;
66ab19a0
 	while(hdr!=NULL)
b16b1294
 	{
66ab19a0
 		if (parse_rr(hdr) < 0)
b16b1294
 		{
 			LM_ERR("failed to parse RR\n");
 			return -1;
 		}
 
 		rr =(rr_t*)hdr->parsed;
 		while(rr)
 		{
 			i++;
 			if(i!=1)
 			{
055fca8d
 				/* Skip if route is not encoded */
de3386e4
 				if (th_uri_prefix_checks
 						&& ((rr->nameaddr.uri.len<th_uri_prefix.len) ||
 						(strncasecmp(rr->nameaddr.uri.s,th_uri_prefix.s,
66ab19a0
 									th_uri_prefix.len)!=0)))
055fca8d
 				{
cee4941d
 					LM_DBG("rr %d is not encoded: [%.*s] - missing prefix\n", i,
de3386e4
 							rr->nameaddr.uri.len, rr->nameaddr.uri.s);
055fca8d
 					rr = rr->next;
 					continue;
 				}
 
b16b1294
 				if(th_get_uri_param_value(&rr->nameaddr.uri, &th_uparam_name,
 							&eval)<0 || eval.len<=0)
d57f7012
 				{
cee4941d
 					LM_DBG("rr %d is not encoded: [%.*s] - missing param\n", i,
 							rr->nameaddr.uri.len, rr->nameaddr.uri.s);
d57f7012
 					rr = rr->next;
 					continue;
 				}
66ab19a0
 
b16b1294
 				out.s = th_mask_decode(eval.s, eval.len,
 							&th_uparam_prefix, 0, &out.len);
 
 				if(out.s==NULL)
 				{
 					LM_ERR("cannot decode R %d\n", i);
 					return -1;
 				}
 				l=del_lump(msg, rr->nameaddr.uri.s-msg->buf,
 						rr->nameaddr.uri.len, 0);
 				if (l==0)
 				{
 					LM_ERR("failed deleting R [%d]\n", i);
 					pkg_free(out.s);
 					return -1;
 				}
 				if (insert_new_lump_after(l, out.s, out.len, 0)==0){
 					LM_ERR("could not insert new lump\n");
 					pkg_free(out.s);
 					return -1;
 				}
 			}
 			rr = rr->next;
 		}
 		hdr = next_sibling_hdr(hdr);
 	}
 
 	return 0;
 }
 
 int th_unmask_ruri(sip_msg_t *msg)
 {
 	str eval;
 	struct lump* l;
 	str out;
 
055fca8d
 	/* Do nothing if ruri is not encoded */
de3386e4
 	if (th_uri_prefix_checks && ((REQ_LINE(msg).uri.len<th_uri_prefix.len) ||
 			(strncasecmp(REQ_LINE(msg).uri.s, th_uri_prefix.s,
66ab19a0
 						th_uri_prefix.len)!=0)))
055fca8d
 	{
 		LM_DBG("ruri [%.*s] is not encoded",REQ_LINE(msg).uri.len,REQ_LINE(msg).uri.s);
 		return 0;
 	}
 
b16b1294
 	if(th_get_uri_param_value(&REQ_LINE(msg).uri, &th_uparam_name, &eval)<0
5a0086fb
 			|| eval.len<=0) {
 		LM_DBG("no uri param [%.*s] in [%.*s]\n",
 				th_uparam_name.len, th_uparam_name.s,
 				REQ_LINE(msg).uri.len,REQ_LINE(msg).uri.s);
b16b1294
 		return -1;
5a0086fb
 	}
66ab19a0
 
b16b1294
 	out.s = th_mask_decode(eval.s, eval.len,
 				&th_uparam_prefix, 0, &out.len);
 	if(out.s==NULL)
 	{
5a0086fb
 		LM_ERR("cannot decode r-uri [%.*s]\n",
 				REQ_LINE(msg).uri.len,REQ_LINE(msg).uri.s);
b16b1294
 		return -1;
 	}
66ab19a0
 
b16b1294
 	LM_DBG("+decoded: %d: [%.*s]\n", out.len, out.len, out.s);
 	l=del_lump(msg, REQ_LINE(msg).uri.s-msg->buf, REQ_LINE(msg).uri.len, 0);
 	if (l==0)
 	{
 		LM_ERR("failed deleting r-uri\n");
 		pkg_free(out.s);
 		return -1;
 	}
 	if (insert_new_lump_after(l, out.s, out.len, 0)==0)
 	{
 		LM_ERR("could not insert new lump\n");
e9400dba
 		pkg_free(out.s);
 		return -1;
 	}
 
 	return 0;
 }
 
 int th_unmask_refer_to(sip_msg_t *msg)
 {
 	str eval;
 	str *uri;
 	int ulen;
 	struct lump* l;
 	str out;
 
 	if(!((get_cseq(msg)->method_id)&(METHOD_REFER)))
 		return 0;
 
 	if(parse_refer_to_header(msg)==-1)
 	{
 		LM_DBG("no Refer-To header\n");
 		return 0;
 	}
 	if(msg->refer_to==NULL || get_refer_to(msg)==NULL)
 	{
 		LM_DBG("Refer-To header not found\n");
 		return 0;
 	}
 
 	uri = &(get_refer_to(msg)->uri);
055fca8d
 
 	/* Do nothing if refer_to is not encoded */
de3386e4
 	if (th_uri_prefix_checks && ((uri->len<th_uri_prefix.len)
 			|| (strncasecmp(uri->s, th_uri_prefix.s, th_uri_prefix.len)!=0)))
055fca8d
 	{
 		LM_DBG("refer-to [%.*s] is not encoded",uri->len,uri->s);
 		return 0;
 	}
 
e9400dba
 	if(th_get_uri_param_value(uri, &th_uparam_name, &eval)<0
 			|| eval.len<=0)
 		return -1;
 
 	out.s = th_mask_decode(eval.s, eval.len,
 				&th_uparam_prefix, 0, &out.len);
 	if(out.s==NULL)
 	{
 		LM_ERR("cannot decode r-uri\n");
 		return -1;
 	}
 
 	LM_DBG("+decoded: %d: [%.*s]\n", out.len, out.len, out.s);
 	for(ulen=0; ulen<uri->len; ulen++)
 	{
 		if(uri->s[ulen]=='?')
 			break;
 	}
 
 	l=del_lump(msg, uri->s-msg->buf, ulen, 0);
 	if (l==0)
 	{
 		LM_ERR("failed deleting r-uri\n");
 		pkg_free(out.s);
 		return -1;
 	}
 	if (insert_new_lump_after(l, out.s, out.len, 0)==0)
 	{
 		LM_ERR("could not insert new lump\n");
f03706ce
 		pkg_free(out.s);
 		return -1;
 	}
 
 	return 0;
 }
 
 int th_update_hdr_replaces(sip_msg_t *msg)
 {
 	struct hdr_field *hf = NULL;
 	str replaces;
 	str rcallid;
 	struct lump* l;
 	str out;
 
 	LM_DBG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
 	if(th_param_mask_callid==0)
 		return 0;
 
 	if(!((get_cseq(msg)->method_id)&(METHOD_INVITE)))
 		return 0;
 
 	for (hf=msg->headers; hf; hf=hf->next)
 	{
 		if (hf->name.len==8 && strncasecmp(hf->name.s, "Replaces", 8)==0)
 			break;
 	}
 
 	if(hf==NULL)
 		return 0;
 
 	replaces = hf->body;
 	trim(&replaces);
 	rcallid.s = replaces.s;
 	for(rcallid.len=0; rcallid.len<replaces.len; rcallid.len++)
 	{
 		if(rcallid.s[rcallid.len]==';')
 			break;
 	}
 
 	if(rcallid.len>th_callid_prefix.len
 			&& strncmp(rcallid.s, th_callid_prefix.s, th_callid_prefix.len)==0)
 	{
 		/* value encoded - decode it */
 		out.s = th_mask_decode(rcallid.s, rcallid.len,
 					&th_callid_prefix, 0, &out.len);
 	} else {
 		/* value decoded - encode it */
 		out.s = th_mask_encode(rcallid.s, rcallid.len,
 				&th_callid_prefix, &out.len);
 	}
 	if(out.s==NULL)
 	{
 		LM_ERR("cannot update Replaces callid\n");
 		return -1;
 	}
 
 	l=del_lump(msg, rcallid.s-msg->buf, rcallid.len, 0);
 	if (l==0)
 	{
 		LM_ERR("failed deleting Replaces callid\n");
 		pkg_free(out.s);
 		return -1;
 	}
 	if (insert_new_lump_after(l, out.s, out.len, 0)==0) {
 		LM_ERR("could not insert new lump\n");
b16b1294
 		pkg_free(out.s);
 		return -1;
 	}
 
 	return 0;
 }
 
 char* th_msg_update(sip_msg_t *msg, unsigned int *olen)
 {
 	struct dest_info dst;
 
 	init_dest_info(&dst);
 	dst.proto = PROTO_UDP;
 	return build_req_buf_from_sip_req(msg,
 			olen, &dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE);
 }
 
 int th_add_via_cookie(sip_msg_t *msg, struct via_body *via)
 {
 	struct lump* l;
 	int viap;
 	str out;
 
 	if (via->params.s) {
 		viap = via->params.s - via->hdr.s - 1;
 	} else {
78ccdb7f
 		if (via->host.s) {
 			viap = via->host.s - via->hdr.s + via->host.len;
 		} else {
 			LM_ERR("no via parameter and no via host, can't insert cookie\n");
 			return -1;
 		}
b16b1294
 		if (via->port!=0)
 			viap += via->port_str.len + 1; /* +1 for ':'*/
 	}
 	l = anchor_lump(msg, via->hdr.s - msg->buf + viap, 0, 0);
 	if (l==0)
 	{
 		LM_ERR("failed adding cookie to via [%p]\n", via);
 		return -1;
 	}
66ab19a0
 
b16b1294
 	out.len = 1+th_cookie_name.len+1+th_cookie_value.len+1;
 	out.s = (char*)pkg_malloc(out.len+1);
 	if(out.s==0)
 	{
32c917f6
 		PKG_MEM_ERROR;
b16b1294
 		return -1;
 	}
 	out.s[0] = ';';
 	memcpy(out.s+1, th_cookie_name.s, th_cookie_name.len);
 	out.s[th_cookie_name.len+1]='=';
 	memcpy(out.s+th_cookie_name.len+2, th_cookie_value.s, th_cookie_value.len);
 	out.s[out.len-1] = 'v';
 	out.s[out.len] = '\0';
 	if (insert_new_lump_after(l, out.s, out.len, 0)==0){
 		LM_ERR("could not insert new lump!\n");
 		pkg_free(out.s);
 		return -1;
 	}
 	return 0;
 }
 
 int th_add_hdr_cookie(sip_msg_t *msg)
 {
 	struct lump* anchor;
 	str h;
 
 	h.len = th_cookie_name.len + 2 + th_cookie_value.len + 1 + CRLF_LEN;
 	h.s = (char*)pkg_malloc(h.len+1);
 	if(h.s == 0)
 	{
32c917f6
 		PKG_MEM_ERROR;
b16b1294
 		return -1;
 	}
 	anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
 	if(anchor == 0)
 	{
 		LM_ERR("can't get anchor\n");
 		pkg_free(h.s);
 		return -1;
 	}
 	memcpy(h.s, th_cookie_name.s, th_cookie_name.len);
 	memcpy(h.s+th_cookie_name.len, ": ", 2);
 	memcpy(h.s+th_cookie_name.len+2, th_cookie_value.s, th_cookie_value.len);
 	memcpy(h.s+th_cookie_name.len+2+th_cookie_value.len+1, CRLF, CRLF_LEN);
 	h.s[h.len-1-CRLF_LEN] = 'h';
 	h.s[h.len] = '\0';
 	if (insert_new_lump_before(anchor, h.s, h.len, 0) == 0)
 	{
 		LM_ERR("can't insert lump\n");
 		pkg_free(h.s);
 		return -1;
 	}
a0cd3fb7
 	LM_DBG("added cookie header [%s]\n", h.s);
b16b1294
 	return 0;
 }
 
 struct via_param *th_get_via_cookie(sip_msg_t *msg, struct via_body *via)
 {
 	struct via_param *p;
2367fb52
 
 	if (!via) {
 		return NULL;
 	}
b16b1294
 	for(p=via->param_lst; p; p=p->next)
 	{
 		if(p->name.len==th_cookie_name.len
 				&& strncasecmp(p->name.s, th_cookie_name.s,
 					th_cookie_name.len)==0)
 			return p;
 	}
 	return NULL;
 }
 
 hdr_field_t *th_get_hdr_cookie(sip_msg_t *msg)
 {
 	hdr_field_t *hf;
 	for (hf=msg->headers; hf; hf=hf->next)
 	{
 		if (hf->name.len==th_cookie_name.len
 				&& strncasecmp(hf->name.s, th_cookie_name.s,
 					th_cookie_name.len)==0)
 			return hf;
 	}
 	return NULL;
 }
 
 int th_add_cookie(sip_msg_t *msg)
 {
 	if(th_cookie_value.len<=0)
 		return 0;
 	th_add_hdr_cookie(msg);
 	th_add_via_cookie(msg, msg->via1);
 	return 0;
 }
 
 int th_del_hdr_cookie(sip_msg_t *msg)
 {
 	hdr_field_t *hf;
 	struct lump* l;
 	for (hf=msg->headers; hf; hf=hf->next)
 	{
 		if (hf->name.len==th_cookie_name.len
 				&& strncasecmp(hf->name.s, th_cookie_name.s,
 					th_cookie_name.len)==0)
 		{
 			l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
 			if (l==0) {
 				LM_ERR("unable to delete cookie header\n");
 				return -1;
 			}
 			return 0;
 		}
 	}
 	return 0;
 }
 
 int th_del_via_cookie(sip_msg_t *msg, struct via_body *via)
 {
 	struct via_param *p;
 	struct lump* l;
b480ac55
 
 	if(via==NULL) {
 		LM_DBG("no via header\n");
 		return 0;
 	}
b16b1294
 	for(p=via->param_lst; p; p=p->next)
 	{
 		if(p->name.len==th_cookie_name.len
 				&& strncasecmp(p->name.s, th_cookie_name.s,
 					th_cookie_name.len)==0)
 		{
 			l=del_lump(msg, p->start-msg->buf-1, p->size+1, 0);
 			if (l==0) {
 				LM_ERR("unable to delete cookie header\n");
 				return -1;
 			}
 			return 0;
 		}
 	}
 	return 0;
 }
 
 int th_del_cookie(sip_msg_t *msg)
 {
 	th_del_hdr_cookie(msg);
 	if(msg->first_line.type==SIP_REPLY)
 		th_del_via_cookie(msg, msg->via1);
 	return 0;
 }
 
 
0219d5a9
 /**
  * return the special topoh cookie
  * - TH header of TH Via parame
  * - value is 3 chars
  *   [0] - direction:    d - downstream; u - upstream
  *   [1] - request type: i - initial; c - in-dialog; l - local in-dialog
  *   [2] - location:     h - header; v - via param
  * - if not found, returns 'xxx'
  */
b16b1294
 char* th_get_cookie(sip_msg_t *msg, int *clen)
 {
 	hdr_field_t *hf;
 	struct via_param *p;
 
 	hf = th_get_hdr_cookie(msg);
 	if(hf!=NULL)
 	{
 		*clen = hf->body.len;
 		return hf->body.s;
 	}
 	p = th_get_via_cookie(msg, msg->via1);
 	if(p!=NULL)
 	{
 		*clen = p->value.len;
 		return p->value.s;
 	}
 
 	*clen = 3;
 	return "xxx";
 }
 
 int th_route_direction(sip_msg_t *msg)
 {
 	rr_t *rr;
 	struct sip_uri puri;
 	str ftn = {"ftag", 4};
 	str ftv = {0, 0};
 
 	if(get_from(msg)->tag_value.len<=0)
 	{
 		LM_ERR("failed to get from header tag\n");
 		return -1;
 	}
 	if(msg->route==NULL)
 	{
 		LM_DBG("no route header - downstream\n");
 		return 0;
 	}
66ab19a0
 	if (parse_rr(msg->route) < 0)
b16b1294
 	{
 		LM_ERR("failed to parse route header\n");
 		return -1;
 	}
 
 	rr =(rr_t*)msg->route->parsed;
 
 	if (parse_uri(rr->nameaddr.uri.s, rr->nameaddr.uri.len, &puri) < 0) {
 		LM_ERR("failed to parse the first route URI\n");
 		return -1;
 	}
 	if(th_get_param_value(&puri.params, &ftn, &ftv)!=0)
 		return 0;
 
 	if(get_from(msg)->tag_value.len!=ftv.len
 			|| strncmp(get_from(msg)->tag_value.s, ftv.s, ftv.len)!=0)
 	{
 		LM_DBG("ftag mismatch\n");
 		return 1;
 	}
 	LM_DBG("ftag match\n");
 	return 0;
 }
 
 int th_skip_msg(sip_msg_t *msg)
 {
7f9b4290
 	if (msg->cseq==NULL || get_cseq(msg)==NULL) {
50453970
 		LM_WARN("Invalid/Unparsed CSeq in message. Skipping.");
 		return 1;
 	}
 
b16b1294
 	if((get_cseq(msg)->method_id)&(METHOD_REGISTER|METHOD_PUBLISH))
 		return 1;
 
 	return 0;
 }