Browse Source

topos: add two new modes for topology hiding to preserve Contact user

- add two new modes for topology hiding to preserve Contact user
- add new variables contact_mode, cparam_name, a_contact_avp and b_contact_avp
- if contact_mode is 1, the internal key will be stored in a URI parameter
  instead of the Contact user, and the Contact users will be taken from the msg
- contact_mode 2 is the same as 1, but the Contact users will be taken from AVPs
- default is contact_mode 0 - the existing (old) behaviour
Henning Westerholt 5 years ago
parent
commit
2ffc26aa67

+ 103 - 0
src/modules/topos/doc/topos_admin.xml

@@ -304,6 +304,109 @@ modparam("topos", "event_mode", 2)
 ...
 modparam("topos", "contact_host", "proxy.domain.com")
 ...
+</programlisting>
+		</example>
+	</section>
+	<section id="topos.p.contact_mode">
+		<title><varname>contact_mode</varname> (int)</title>
+		<para>
+		Control the mode where the key to lookup the message data from
+		the database or redis server is stored. The default is to use
+		the Contact user (0), alternatively a Contact URI parameter
+		can be used (1) with values from the SIP message, or from AVP
+		variables (2). This can be useful for interoperating which
+		gateways that need a certain user part in the Contact URI.
+		</para>
+		<para>In mode (1) the a-side contact user is taken from the
+		request URI and the b-side contact user from the Contact header
+		of the processed initial SIP request.
+		</para>
+		<para>If you use the mode (2), you need to configure the
+		<emphasis>a_contact_avp</emphasis> and <emphasis>b_contact_avp</emphasis>
+		parameter. Furthermore you need to assign values to them during
+		the processing of the initial SIP request.
+		</para>
+		<para>
+		The name of the Contact URI parameter can be customized with
+		the <emphasis>cparam_name</emphasis> parameter.
+		</para>
+		<para>
+		<emphasis>
+			Default value is 0 - use the Contact user
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>contact_mode</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("topos", "contact_mode", 1)
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="topos.p.cparam_name">
+		<title><varname>cparam_name</varname> (int)</title>
+		<para>
+		Name of the Contact URI parameter to store the database or
+		redis server key for message lookup.
+		</para>
+		<para>
+		This parameter is only used when the <emphasis>contact_mode</emphasis>
+		parameter is set to <emphasis>1</emphasis> or <emphasis>2</emphasis>.
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>tps</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>cparam_name</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("topos", "cparam_name", "xyz")
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="topos.p.a_contact_avp">
+		<title><varname>a_contact_avp</varname> (str)</title>
+		<para>
+			Name of the AVP parameter to evaluate for the A-side
+			Contact Header user part. This parameter is only
+			necessary in contact_mode (2).
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>NULL</quote> (disabled).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>a_contact_avp</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("topos", "a_contact_avp", "$avp(tps-act)")
+...
+</programlisting>
+		</example>
+	</section>
+	<section id="topos.p.b_contact_avp">
+		<title><varname>b_contact_avp</varname> (str)</title>
+		<para>
+			Name of the AVP parameter to evaluate for the B-side
+			Contact Header user part. This parameter is only
+			necessary in contact_mode (2).
+		</para>
+		<para>
+		<emphasis>
+			Default value is <quote>NULL</quote> (disabled).
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>b_contact_avp</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("topos", "b_contact_avp", "$avp(tps-bct)")
+...
 </programlisting>
 		</example>
 	</section>

+ 30 - 0
src/modules/topos/topos_mod.c

@@ -94,6 +94,12 @@ static str _tps_eventrt_outgoing_name = str_init("topos:msg-outgoing");
 static int _tps_eventrt_sending = -1;
 static str _tps_eventrt_sending_name = str_init("topos:msg-sending");
 str _tps_contact_host = str_init("");
+int _tps_contact_mode = 0;
+str _tps_cparam_name = str_init("tps");
+str _tps_acontact_avp;
+str _tps_bcontact_avp;
+pv_spec_t _tps_acontact_spec;
+pv_spec_t _tps_bcontact_spec;
 
 sanity_api_t scb;
 
@@ -131,6 +137,10 @@ static param_export_t params[]={
 	{"event_callback",	PARAM_STR, &_tps_eventrt_callback},
 	{"event_mode",		PARAM_INT, &_tps_eventrt_mode},
 	{"contact_host",	PARAM_STR, &_tps_contact_host},
+	{"contact_mode",	PARAM_INT, &_tps_contact_mode},
+	{"cparam_name",		PARAM_STR, &_tps_cparam_name},
+	{"a_contact_avp",	PARAM_STR, &_tps_acontact_avp},
+	{"b_contact_avp",	PARAM_STR, &_tps_bcontact_avp},
 	{0,0,0}
 };
 
@@ -203,6 +213,26 @@ static int mod_init(void)
 	if(sruid_init(&_tps_sruid, '-', "tpsh", SRUID_INC)<0)
 		return -1;
 
+	if (_tps_contact_mode == 2 && (_tps_acontact_avp.s == NULL || _tps_acontact_avp.len == 0 ||
+			 _tps_bcontact_avp.s == NULL || _tps_bcontact_avp.len == 0)) {
+		LM_ERR("contact_mode parameter is 2, but a_contact and/or b_contact AVPs not defined\n");
+		return -1;
+	}
+	if(_tps_acontact_avp.len > 0 && _tps_acontact_avp.s != NULL) {
+		if(pv_parse_spec(&_tps_acontact_avp, &_tps_acontact_spec) == 0 || _tps_acontact_spec.type != PVT_AVP) {
+			LM_ERR("malformed or non AVP %.*s AVP definition\n",
+				_tps_acontact_avp.len, _tps_acontact_avp.s);
+			return -1;
+		}
+	}
+	if(_tps_bcontact_avp.len > 0 && _tps_bcontact_avp.s != NULL) {
+		if(pv_parse_spec(&_tps_bcontact_avp, &_tps_bcontact_spec) == 0 || _tps_bcontact_spec.type != PVT_AVP) {
+			LM_ERR("malformed or non AVP %.*s AVP definition\n",
+				_tps_bcontact_avp.len, _tps_bcontact_avp.s);
+			return -1;
+		}
+	}
+
 	sr_event_register_cb(SREV_NET_DATA_IN,  tps_msg_received);
 	sr_event_register_cb(SREV_NET_DATA_OUT, tps_msg_sent);
 

+ 43 - 15
src/modules/topos/tps_msg.c

@@ -47,6 +47,8 @@
 #include "tps_storage.h"
 
 extern int _tps_param_mask_callid;
+extern int _tps_contact_mode;
+extern str _tps_cparam_name;
 
 str _sr_hname_xbranch = str_init("P-SR-XBranch");
 str _sr_hname_xuuid = str_init("P-SR-XUID");
@@ -298,26 +300,52 @@ error:
 /**
  *
  */
-int tps_dlg_message_update(sip_msg_t *msg, tps_data_t *ptsd)
+int tps_dlg_message_update(sip_msg_t *msg, tps_data_t *ptsd, int ctmode)
 {
+	str tmp;
+
 	if(parse_sip_msg_uri(msg)<0) {
 		LM_ERR("failed to parse r-uri\n");
 		return -1;
 	}
-	if(msg->parsed_uri.user.len<10) {
-		LM_DBG("not an expected user format\n");
-		return 1;
-	}
-	if(memcmp(msg->parsed_uri.user.s, "atpsh-", 6)==0) {
-		ptsd->a_uuid = msg->parsed_uri.user;
-		return 0;
-	}
-	if(memcmp(msg->parsed_uri.user.s, "btpsh-", 6)==0) {
-		ptsd->a_uuid = msg->parsed_uri.user;
-		ptsd->b_uuid = msg->parsed_uri.user;
-		return 0;
+
+	if (ctmode == 1 || ctmode == 2) {
+		if(msg->parsed_uri.sip_params.len<10) {
+			LM_DBG("not an expected param format\n");
+			return 1;
+		}
+
+		tmp.s = msg->parsed_uri.sip_params.s;
+		// skip param and '=' sign
+		tmp.s += _tps_cparam_name.len + 1;
+		tmp.len = msg->parsed_uri.sip_params.len - _tps_cparam_name.len - 1;
+
+		if(memcmp(tmp.s, "atpsh-", 6)==0) {
+			ptsd->a_uuid = tmp;
+			return 0;
+		}
+		if(memcmp(tmp.s, "btpsh-", 6)==0) {
+			ptsd->a_uuid = tmp;
+			ptsd->b_uuid = tmp;
+			return 0;
+		}
+
+	} else {
+		if(msg->parsed_uri.user.len<10) {
+			LM_DBG("not an expected user format\n");
+			return 1;
+		}
+		if(memcmp(msg->parsed_uri.user.s, "atpsh-", 6)==0) {
+			ptsd->a_uuid = msg->parsed_uri.user;
+			return 0;
+		}
+		if(memcmp(msg->parsed_uri.user.s, "btpsh-", 6)==0) {
+			ptsd->a_uuid = msg->parsed_uri.user;
+			ptsd->b_uuid = msg->parsed_uri.user;
+			return 0;
+		}
 	}
-	LM_DBG("not an expected user prefix\n");
+	LM_DBG("not an expected prefix\n");
 
 	return 1;
 }
@@ -753,7 +781,7 @@ int tps_request_received(sip_msg_t *msg, int dialog)
 		return -1;
 	}
 
-	ret = tps_dlg_message_update(msg, &mtsd);
+	ret = tps_dlg_message_update(msg, &mtsd, _tps_contact_mode);
 	if(ret<0) {
 		LM_ERR("failed to update on dlg message\n");
 		return -1;

+ 150 - 33
src/modules/topos/tps_storage.c

@@ -54,6 +54,12 @@ extern db1_con_t* _tps_db_handle;
 extern db_func_t _tpsdbf;
 
 extern str _tps_contact_host;
+extern int _tps_contact_mode;
+extern str _tps_cparam_name;
+extern str _tps_acontact_avp;
+extern str _tps_bcontact_avp;
+extern pv_spec_t _tps_acontact_spec;
+extern pv_spec_t _tps_bcontact_spec;
 
 #define TPS_STORAGE_LOCK_SIZE	1<<9
 static gen_lock_set_t *_tps_storage_lock_set = NULL;
@@ -205,12 +211,14 @@ int tps_storage_branch_rm(sip_msg_t *msg, tps_data_t *td)
 /**
  *
  */
-int tps_storage_fill_contact(sip_msg_t *msg, tps_data_t *td, str *uuid, int dir)
+int tps_storage_fill_contact(sip_msg_t *msg, tps_data_t *td, str *uuid, int dir, int ctmode)
 {
 	str sv;
-	sip_uri_t puri;
+	sip_uri_t puri, curi;
+	pv_value_t pv_val;
 	int i;
 	int contact_len;
+	int cparam_len;
 
 	if(dir==TPS_DIR_DOWNSTREAM) {
 		sv = td->bs_contact;
@@ -231,11 +239,17 @@ int tps_storage_fill_contact(sip_msg_t *msg, tps_data_t *td, str *uuid, int dir)
 	if (_tps_contact_host.len)
 		contact_len = sv.len - puri.host.len + _tps_contact_host.len;
 
-	if(td->cp + 8 + (2*uuid->len) + contact_len >= td->cbuf + TPS_DATA_SIZE) {
+	if (ctmode == 1 || ctmode == 2) {
+		cparam_len = _tps_cparam_name.len;
+	} else {
+		cparam_len = 0;
+	}
+
+	if(td->cp + 8 + (2*uuid->len) + cparam_len + contact_len >= td->cbuf + TPS_DATA_SIZE) {
 		LM_ERR("insufficient data buffer\n");
 		return -1;
 	}
-
+	// copy uuid
 	if(dir==TPS_DIR_DOWNSTREAM) {
 		td->b_uuid.s = td->cp;
 		*td->cp = 'b';
@@ -255,51 +269,153 @@ int tps_storage_fill_contact(sip_msg_t *msg, tps_data_t *td, str *uuid, int dir)
 
 		td->as_contact.s = td->cp;
 	}
+
 	*td->cp = '<';
 	td->cp++;
+	// look for sip:
 	for(i=0; i<sv.len; i++) {
 		*td->cp = sv.s[i];
 		td->cp++;
 		if(sv.s[i]==':') break;
 	}
-	if(dir==TPS_DIR_DOWNSTREAM) {
-		*td->cp = 'b';
-	} else {
-		*td->cp = 'a';
-	}
-	td->cp++;
-	memcpy(td->cp, uuid->s, uuid->len);
-	td->cp += uuid->len;
-	*td->cp = '@';
-	td->cp++;
+	// create new URI parameter for Contact header
+	if (ctmode == 1 || ctmode == 2) {
+		if (ctmode == 1) {
+			if (dir==TPS_DIR_DOWNSTREAM) {
+				/* extract the contact address */
+				if(parse_headers(msg, HDR_CONTACT_F, 0) < 0 || msg->contact==NULL) {
+					LM_WARN("bad sip message or missing Contact hdr\n");
+					return -1;
+				} else {
+					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 header\n");
+						return -1;
+					} else {
+						if (parse_uri(((contact_body_t*)msg->contact->parsed)->contacts->uri.s,
+						((contact_body_t*)msg->contact->parsed)->contacts->uri.len, &curi) < 0) {
+							LM_ERR("failed to parse the contact uri\n");
+							return -1;
+						}
+					}
+				}
+				memcpy(td->cp, curi.user.s, curi.user.len);
+				td->cp += curi.user.len;
+			} else {
+				/* extract the ruri */
+				if(parse_sip_msg_uri(msg)<0) {
+					LM_ERR("failed to parse r-uri\n");
+					return -1;
+				}
+				if(msg->parsed_uri.user.len==0) {
+					LM_ERR("no r-uri user\n");
+					return -1;
+				}
+				memcpy(td->cp, msg->parsed_uri.user.s, msg->parsed_uri.user.len);
+				td->cp += msg->parsed_uri.user.len;
+			}
+		} else if (ctmode == 2) {
+			if (dir==TPS_DIR_DOWNSTREAM) {
+				/* extract the a contact */
+				if ((pv_get_spec_value(msg, &_tps_acontact_spec, &pv_val) != 0)
+						&& (pv_val.flags & PV_VAL_STR) && (pv_val.rs.len <= 0)) {
+					LM_ERR("could not evaluate a_contact AVP\n");
+					return -1;
+				}
+				memcpy(td->cp, pv_val.rs.s, pv_val.rs.len);
+				td->cp += pv_val.rs.len;
+			} else {
+				/* extract the b contact */
+				if ((pv_get_spec_value(msg, &_tps_bcontact_spec, &pv_val) != 0)
+						&& (pv_val.flags & PV_VAL_STR) && (pv_val.rs.len <= 0)) {
+					LM_ERR("could not evaluate b_contact AVP\n");
+					return -1;
+				}
+				memcpy(td->cp, pv_val.rs.s, pv_val.rs.len);
+				td->cp += pv_val.rs.len;
+			}
+		}
+		*td->cp = '@';
+		td->cp++;
 
-	if (_tps_contact_host.len) { // using configured hostname in the contact header
-		memcpy(td->cp, _tps_contact_host.s, _tps_contact_host.len);
-		td->cp += _tps_contact_host.len;
-	} else {
-		memcpy(td->cp, puri.host.s, puri.host.len);
-		td->cp += puri.host.len;
-	}
+		if (_tps_contact_host.len) { // using configured hostname in the contact header
+			memcpy(td->cp, _tps_contact_host.s, _tps_contact_host.len);
+			td->cp += _tps_contact_host.len;
+		} else {
+			memcpy(td->cp, puri.host.s, puri.host.len);
+			td->cp += puri.host.len;
+		}
+		if(puri.port.len>0) {
+			*td->cp = ':';
+			td->cp++;
+			memcpy(td->cp, puri.port.s, puri.port.len);
+			td->cp += puri.port.len;
+		}
+		if(puri.transport_val.len>0) {
+			memcpy(td->cp, ";transport=", 11);
+			td->cp += 11;
+			memcpy(td->cp, puri.transport_val.s, puri.transport_val.len);
+			td->cp += puri.transport_val.len;
+		}
 
-	if(puri.port.len>0) {
-		*td->cp = ':';
+		*td->cp = ';';
 		td->cp++;
-		memcpy(td->cp, puri.port.s, puri.port.len);
-		td->cp += puri.port.len;
-	}
-	if(puri.transport_val.len>0) {
-		memcpy(td->cp, ";transport=", 11);
-		td->cp += 11;
-		memcpy(td->cp, puri.transport_val.s, puri.transport_val.len);
-		td->cp += puri.transport_val.len;
+		memcpy(td->cp, _tps_cparam_name.s, _tps_cparam_name.len);
+		td->cp += _tps_cparam_name.len;
+		*td->cp = '=';
+		td->cp++;
+		if(dir==TPS_DIR_DOWNSTREAM) {
+			*td->cp = 'b';
+		} else {
+			*td->cp = 'a';
+		}
+		td->cp++;
+		memcpy(td->cp, uuid->s, uuid->len);
+		td->cp += uuid->len;
+
+	// create new user part for Contact header URI
+	} else {
+		if(dir==TPS_DIR_DOWNSTREAM) {
+			*td->cp = 'b';
+		} else {
+			*td->cp = 'a';
+		}
+		td->cp++;
+		memcpy(td->cp, uuid->s, uuid->len);
+		td->cp += uuid->len;
+		*td->cp = '@';
+		td->cp++;
+
+		if (_tps_contact_host.len) { // using configured hostname in the contact header
+			memcpy(td->cp, _tps_contact_host.s, _tps_contact_host.len);
+			td->cp += _tps_contact_host.len;
+		} else {
+			memcpy(td->cp, puri.host.s, puri.host.len);
+			td->cp += puri.host.len;
+		}
+		if(puri.port.len>0) {
+			*td->cp = ':';
+			td->cp++;
+			memcpy(td->cp, puri.port.s, puri.port.len);
+			td->cp += puri.port.len;
+		}
+		if(puri.transport_val.len>0) {
+			memcpy(td->cp, ";transport=", 11);
+			td->cp += 11;
+			memcpy(td->cp, puri.transport_val.s, puri.transport_val.len);
+			td->cp += puri.transport_val.len;
+		}
 	}
 
 	*td->cp = '>';
 	td->cp++;
 	if(dir==TPS_DIR_DOWNSTREAM) {
 		td->bs_contact.len = td->cp - td->bs_contact.s;
+		LM_DBG("td->bs %.*s\n",  td->bs_contact.len,  td->bs_contact.s);
 	} else {
 		td->as_contact.len = td->cp - td->as_contact.s;
+		LM_DBG("td->as %.*s\n",  td->as_contact.len,  td->as_contact.s);
 	}
 	return 0;
 }
@@ -373,6 +489,7 @@ int tps_storage_link_msg(sip_msg_t *msg, tps_data_t *td, int dir)
 		LM_ERR("bad Contact header\n");
 		return -1;
 	}
+
 	if(msg->first_line.type==SIP_REQUEST) {
 		if(dir==TPS_DIR_DOWNSTREAM) {
 			td->a_contact = ((contact_body_t*)msg->contact->parsed)->contacts->uri;
@@ -421,9 +538,9 @@ int tps_storage_record(sip_msg_t *msg, tps_data_t *td, int dialog, int dir)
 		suid.len--;
 	}
 
-	ret = tps_storage_fill_contact(msg, td, &suid, TPS_DIR_DOWNSTREAM);
+	ret = tps_storage_fill_contact(msg, td, &suid, TPS_DIR_DOWNSTREAM, _tps_contact_mode);
 	if(ret<0) goto error;
-	ret = tps_storage_fill_contact(msg, td, &suid, TPS_DIR_UPSTREAM);
+	ret = tps_storage_fill_contact(msg, td, &suid, TPS_DIR_UPSTREAM, _tps_contact_mode);
 	if(ret<0) goto error;
 
 	ret = tps_storage_link_msg(msg, td, dir);