Browse code

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 authored on 23/07/2020 13:48:58
Showing 4 changed files
... ...
@@ -304,6 +304,109 @@ modparam("topos", "event_mode", 2)
304 304
 ...
305 305
 modparam("topos", "contact_host", "proxy.domain.com")
306 306
 ...
307
+</programlisting>
308
+		</example>
309
+	</section>
310
+	<section id="topos.p.contact_mode">
311
+		<title><varname>contact_mode</varname> (int)</title>
312
+		<para>
313
+		Control the mode where the key to lookup the message data from
314
+		the database or redis server is stored. The default is to use
315
+		the Contact user (0), alternatively a Contact URI parameter
316
+		can be used (1) with values from the SIP message, or from AVP
317
+		variables (2). This can be useful for interoperating which
318
+		gateways that need a certain user part in the Contact URI.
319
+		</para>
320
+		<para>In mode (1) the a-side contact user is taken from the
321
+		request URI and the b-side contact user from the Contact header
322
+		of the processed initial SIP request.
323
+		</para>
324
+		<para>If you use the mode (2), you need to configure the
325
+		<emphasis>a_contact_avp</emphasis> and <emphasis>b_contact_avp</emphasis>
326
+		parameter. Furthermore you need to assign values to them during
327
+		the processing of the initial SIP request.
328
+		</para>
329
+		<para>
330
+		The name of the Contact URI parameter can be customized with
331
+		the <emphasis>cparam_name</emphasis> parameter.
332
+		</para>
333
+		<para>
334
+		<emphasis>
335
+			Default value is 0 - use the Contact user
336
+		</emphasis>
337
+		</para>
338
+		<example>
339
+		<title>Set <varname>contact_mode</varname> parameter</title>
340
+		<programlisting format="linespecific">
341
+...
342
+modparam("topos", "contact_mode", 1)
343
+...
344
+</programlisting>
345
+		</example>
346
+	</section>
347
+	<section id="topos.p.cparam_name">
348
+		<title><varname>cparam_name</varname> (int)</title>
349
+		<para>
350
+		Name of the Contact URI parameter to store the database or
351
+		redis server key for message lookup.
352
+		</para>
353
+		<para>
354
+		This parameter is only used when the <emphasis>contact_mode</emphasis>
355
+		parameter is set to <emphasis>1</emphasis> or <emphasis>2</emphasis>.
356
+		</para>
357
+		<para>
358
+		<emphasis>
359
+			Default value is <quote>tps</quote>.
360
+		</emphasis>
361
+		</para>
362
+		<example>
363
+		<title>Set <varname>cparam_name</varname> parameter</title>
364
+		<programlisting format="linespecific">
365
+...
366
+modparam("topos", "cparam_name", "xyz")
367
+...
368
+</programlisting>
369
+		</example>
370
+	</section>
371
+	<section id="topos.p.a_contact_avp">
372
+		<title><varname>a_contact_avp</varname> (str)</title>
373
+		<para>
374
+			Name of the AVP parameter to evaluate for the A-side
375
+			Contact Header user part. This parameter is only
376
+			necessary in contact_mode (2).
377
+		</para>
378
+		<para>
379
+		<emphasis>
380
+			Default value is <quote>NULL</quote> (disabled).
381
+		</emphasis>
382
+		</para>
383
+		<example>
384
+		<title>Set <varname>a_contact_avp</varname> parameter</title>
385
+		<programlisting format="linespecific">
386
+...
387
+modparam("topos", "a_contact_avp", "$avp(tps-act)")
388
+...
389
+</programlisting>
390
+		</example>
391
+	</section>
392
+	<section id="topos.p.b_contact_avp">
393
+		<title><varname>b_contact_avp</varname> (str)</title>
394
+		<para>
395
+			Name of the AVP parameter to evaluate for the B-side
396
+			Contact Header user part. This parameter is only
397
+			necessary in contact_mode (2).
398
+		</para>
399
+		<para>
400
+		<emphasis>
401
+			Default value is <quote>NULL</quote> (disabled).
402
+		</emphasis>
403
+		</para>
404
+		<example>
405
+		<title>Set <varname>b_contact_avp</varname> parameter</title>
406
+		<programlisting format="linespecific">
407
+...
408
+modparam("topos", "b_contact_avp", "$avp(tps-bct)")
409
+...
307 410
 </programlisting>
308 411
 		</example>
309 412
 	</section>
... ...
@@ -94,6 +94,12 @@ static str _tps_eventrt_outgoing_name = str_init("topos:msg-outgoing");
94 94
 static int _tps_eventrt_sending = -1;
95 95
 static str _tps_eventrt_sending_name = str_init("topos:msg-sending");
96 96
 str _tps_contact_host = str_init("");
97
+int _tps_contact_mode = 0;
98
+str _tps_cparam_name = str_init("tps");
99
+str _tps_acontact_avp;
100
+str _tps_bcontact_avp;
101
+pv_spec_t _tps_acontact_spec;
102
+pv_spec_t _tps_bcontact_spec;
97 103
 
98 104
 sanity_api_t scb;
99 105
 
... ...
@@ -131,6 +137,10 @@ static param_export_t params[]={
131 137
 	{"event_callback",	PARAM_STR, &_tps_eventrt_callback},
132 138
 	{"event_mode",		PARAM_INT, &_tps_eventrt_mode},
133 139
 	{"contact_host",	PARAM_STR, &_tps_contact_host},
140
+	{"contact_mode",	PARAM_INT, &_tps_contact_mode},
141
+	{"cparam_name",		PARAM_STR, &_tps_cparam_name},
142
+	{"a_contact_avp",	PARAM_STR, &_tps_acontact_avp},
143
+	{"b_contact_avp",	PARAM_STR, &_tps_bcontact_avp},
134 144
 	{0,0,0}
135 145
 };
136 146
 
... ...
@@ -203,6 +213,26 @@ static int mod_init(void)
203 213
 	if(sruid_init(&_tps_sruid, '-', "tpsh", SRUID_INC)<0)
204 214
 		return -1;
205 215
 
216
+	if (_tps_contact_mode == 2 && (_tps_acontact_avp.s == NULL || _tps_acontact_avp.len == 0 ||
217
+			 _tps_bcontact_avp.s == NULL || _tps_bcontact_avp.len == 0)) {
218
+		LM_ERR("contact_mode parameter is 2, but a_contact and/or b_contact AVPs not defined\n");
219
+		return -1;
220
+	}
221
+	if(_tps_acontact_avp.len > 0 && _tps_acontact_avp.s != NULL) {
222
+		if(pv_parse_spec(&_tps_acontact_avp, &_tps_acontact_spec) == 0 || _tps_acontact_spec.type != PVT_AVP) {
223
+			LM_ERR("malformed or non AVP %.*s AVP definition\n",
224
+				_tps_acontact_avp.len, _tps_acontact_avp.s);
225
+			return -1;
226
+		}
227
+	}
228
+	if(_tps_bcontact_avp.len > 0 && _tps_bcontact_avp.s != NULL) {
229
+		if(pv_parse_spec(&_tps_bcontact_avp, &_tps_bcontact_spec) == 0 || _tps_bcontact_spec.type != PVT_AVP) {
230
+			LM_ERR("malformed or non AVP %.*s AVP definition\n",
231
+				_tps_bcontact_avp.len, _tps_bcontact_avp.s);
232
+			return -1;
233
+		}
234
+	}
235
+
206 236
 	sr_event_register_cb(SREV_NET_DATA_IN,  tps_msg_received);
207 237
 	sr_event_register_cb(SREV_NET_DATA_OUT, tps_msg_sent);
208 238
 
... ...
@@ -47,6 +47,8 @@
47 47
 #include "tps_storage.h"
48 48
 
49 49
 extern int _tps_param_mask_callid;
50
+extern int _tps_contact_mode;
51
+extern str _tps_cparam_name;
50 52
 
51 53
 str _sr_hname_xbranch = str_init("P-SR-XBranch");
52 54
 str _sr_hname_xuuid = str_init("P-SR-XUID");
... ...
@@ -298,26 +300,52 @@ error:
298 300
 /**
299 301
  *
300 302
  */
301
-int tps_dlg_message_update(sip_msg_t *msg, tps_data_t *ptsd)
303
+int tps_dlg_message_update(sip_msg_t *msg, tps_data_t *ptsd, int ctmode)
302 304
 {
305
+	str tmp;
306
+
303 307
 	if(parse_sip_msg_uri(msg)<0) {
304 308
 		LM_ERR("failed to parse r-uri\n");
305 309
 		return -1;
306 310
 	}
307
-	if(msg->parsed_uri.user.len<10) {
308
-		LM_DBG("not an expected user format\n");
309
-		return 1;
310
-	}
311
-	if(memcmp(msg->parsed_uri.user.s, "atpsh-", 6)==0) {
312
-		ptsd->a_uuid = msg->parsed_uri.user;
313
-		return 0;
314
-	}
315
-	if(memcmp(msg->parsed_uri.user.s, "btpsh-", 6)==0) {
316
-		ptsd->a_uuid = msg->parsed_uri.user;
317
-		ptsd->b_uuid = msg->parsed_uri.user;
318
-		return 0;
311
+
312
+	if (ctmode == 1 || ctmode == 2) {
313
+		if(msg->parsed_uri.sip_params.len<10) {
314
+			LM_DBG("not an expected param format\n");
315
+			return 1;
316
+		}
317
+
318
+		tmp.s = msg->parsed_uri.sip_params.s;
319
+		// skip param and '=' sign
320
+		tmp.s += _tps_cparam_name.len + 1;
321
+		tmp.len = msg->parsed_uri.sip_params.len - _tps_cparam_name.len - 1;
322
+
323
+		if(memcmp(tmp.s, "atpsh-", 6)==0) {
324
+			ptsd->a_uuid = tmp;
325
+			return 0;
326
+		}
327
+		if(memcmp(tmp.s, "btpsh-", 6)==0) {
328
+			ptsd->a_uuid = tmp;
329
+			ptsd->b_uuid = tmp;
330
+			return 0;
331
+		}
332
+
333
+	} else {
334
+		if(msg->parsed_uri.user.len<10) {
335
+			LM_DBG("not an expected user format\n");
336
+			return 1;
337
+		}
338
+		if(memcmp(msg->parsed_uri.user.s, "atpsh-", 6)==0) {
339
+			ptsd->a_uuid = msg->parsed_uri.user;
340
+			return 0;
341
+		}
342
+		if(memcmp(msg->parsed_uri.user.s, "btpsh-", 6)==0) {
343
+			ptsd->a_uuid = msg->parsed_uri.user;
344
+			ptsd->b_uuid = msg->parsed_uri.user;
345
+			return 0;
346
+		}
319 347
 	}
320
-	LM_DBG("not an expected user prefix\n");
348
+	LM_DBG("not an expected prefix\n");
321 349
 
322 350
 	return 1;
323 351
 }
... ...
@@ -753,7 +781,7 @@ int tps_request_received(sip_msg_t *msg, int dialog)
753 781
 		return -1;
754 782
 	}
755 783
 
756
-	ret = tps_dlg_message_update(msg, &mtsd);
784
+	ret = tps_dlg_message_update(msg, &mtsd, _tps_contact_mode);
757 785
 	if(ret<0) {
758 786
 		LM_ERR("failed to update on dlg message\n");
759 787
 		return -1;
... ...
@@ -54,6 +54,12 @@ extern db1_con_t* _tps_db_handle;
54 54
 extern db_func_t _tpsdbf;
55 55
 
56 56
 extern str _tps_contact_host;
57
+extern int _tps_contact_mode;
58
+extern str _tps_cparam_name;
59
+extern str _tps_acontact_avp;
60
+extern str _tps_bcontact_avp;
61
+extern pv_spec_t _tps_acontact_spec;
62
+extern pv_spec_t _tps_bcontact_spec;
57 63
 
58 64
 #define TPS_STORAGE_LOCK_SIZE	1<<9
59 65
 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)
205 211
 /**
206 212
  *
207 213
  */
208
-int tps_storage_fill_contact(sip_msg_t *msg, tps_data_t *td, str *uuid, int dir)
214
+int tps_storage_fill_contact(sip_msg_t *msg, tps_data_t *td, str *uuid, int dir, int ctmode)
209 215
 {
210 216
 	str sv;
211
-	sip_uri_t puri;
217
+	sip_uri_t puri, curi;
218
+	pv_value_t pv_val;
212 219
 	int i;
213 220
 	int contact_len;
221
+	int cparam_len;
214 222
 
215 223
 	if(dir==TPS_DIR_DOWNSTREAM) {
216 224
 		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)
231 239
 	if (_tps_contact_host.len)
232 240
 		contact_len = sv.len - puri.host.len + _tps_contact_host.len;
233 241
 
234
-	if(td->cp + 8 + (2*uuid->len) + contact_len >= td->cbuf + TPS_DATA_SIZE) {
242
+	if (ctmode == 1 || ctmode == 2) {
243
+		cparam_len = _tps_cparam_name.len;
244
+	} else {
245
+		cparam_len = 0;
246
+	}
247
+
248
+	if(td->cp + 8 + (2*uuid->len) + cparam_len + contact_len >= td->cbuf + TPS_DATA_SIZE) {
235 249
 		LM_ERR("insufficient data buffer\n");
236 250
 		return -1;
237 251
 	}
238
-
252
+	// copy uuid
239 253
 	if(dir==TPS_DIR_DOWNSTREAM) {
240 254
 		td->b_uuid.s = td->cp;
241 255
 		*td->cp = 'b';
... ...
@@ -255,51 +269,153 @@ int tps_storage_fill_contact(sip_msg_t *msg, tps_data_t *td, str *uuid, int dir)
255 269
 
256 270
 		td->as_contact.s = td->cp;
257 271
 	}
272
+
258 273
 	*td->cp = '<';
259 274
 	td->cp++;
275
+	// look for sip:
260 276
 	for(i=0; i<sv.len; i++) {
261 277
 		*td->cp = sv.s[i];
262 278
 		td->cp++;
263 279
 		if(sv.s[i]==':') break;
264 280
 	}
265
-	if(dir==TPS_DIR_DOWNSTREAM) {
266
-		*td->cp = 'b';
267
-	} else {
268
-		*td->cp = 'a';
269
-	}
270
-	td->cp++;
271
-	memcpy(td->cp, uuid->s, uuid->len);
272
-	td->cp += uuid->len;
273
-	*td->cp = '@';
274
-	td->cp++;
281
+	// create new URI parameter for Contact header
282
+	if (ctmode == 1 || ctmode == 2) {
283
+		if (ctmode == 1) {
284
+			if (dir==TPS_DIR_DOWNSTREAM) {
285
+				/* extract the contact address */
286
+				if(parse_headers(msg, HDR_CONTACT_F, 0) < 0 || msg->contact==NULL) {
287
+					LM_WARN("bad sip message or missing Contact hdr\n");
288
+					return -1;
289
+				} else {
290
+					if(parse_contact(msg->contact)<0
291
+							|| ((contact_body_t*)msg->contact->parsed)->contacts==NULL
292
+							|| ((contact_body_t*)msg->contact->parsed)->contacts->next!=NULL) {
293
+						LM_ERR("bad Contact header\n");
294
+						return -1;
295
+					} else {
296
+						if (parse_uri(((contact_body_t*)msg->contact->parsed)->contacts->uri.s,
297
+						((contact_body_t*)msg->contact->parsed)->contacts->uri.len, &curi) < 0) {
298
+							LM_ERR("failed to parse the contact uri\n");
299
+							return -1;
300
+						}
301
+					}
302
+				}
303
+				memcpy(td->cp, curi.user.s, curi.user.len);
304
+				td->cp += curi.user.len;
305
+			} else {
306
+				/* extract the ruri */
307
+				if(parse_sip_msg_uri(msg)<0) {
308
+					LM_ERR("failed to parse r-uri\n");
309
+					return -1;
310
+				}
311
+				if(msg->parsed_uri.user.len==0) {
312
+					LM_ERR("no r-uri user\n");
313
+					return -1;
314
+				}
315
+				memcpy(td->cp, msg->parsed_uri.user.s, msg->parsed_uri.user.len);
316
+				td->cp += msg->parsed_uri.user.len;
317
+			}
318
+		} else if (ctmode == 2) {
319
+			if (dir==TPS_DIR_DOWNSTREAM) {
320
+				/* extract the a contact */
321
+				if ((pv_get_spec_value(msg, &_tps_acontact_spec, &pv_val) != 0)
322
+						&& (pv_val.flags & PV_VAL_STR) && (pv_val.rs.len <= 0)) {
323
+					LM_ERR("could not evaluate a_contact AVP\n");
324
+					return -1;
325
+				}
326
+				memcpy(td->cp, pv_val.rs.s, pv_val.rs.len);
327
+				td->cp += pv_val.rs.len;
328
+			} else {
329
+				/* extract the b contact */
330
+				if ((pv_get_spec_value(msg, &_tps_bcontact_spec, &pv_val) != 0)
331
+						&& (pv_val.flags & PV_VAL_STR) && (pv_val.rs.len <= 0)) {
332
+					LM_ERR("could not evaluate b_contact AVP\n");
333
+					return -1;
334
+				}
335
+				memcpy(td->cp, pv_val.rs.s, pv_val.rs.len);
336
+				td->cp += pv_val.rs.len;
337
+			}
338
+		}
339
+		*td->cp = '@';
340
+		td->cp++;
275 341
 
276
-	if (_tps_contact_host.len) { // using configured hostname in the contact header
277
-		memcpy(td->cp, _tps_contact_host.s, _tps_contact_host.len);
278
-		td->cp += _tps_contact_host.len;
279
-	} else {
280
-		memcpy(td->cp, puri.host.s, puri.host.len);
281
-		td->cp += puri.host.len;
282
-	}
342
+		if (_tps_contact_host.len) { // using configured hostname in the contact header
343
+			memcpy(td->cp, _tps_contact_host.s, _tps_contact_host.len);
344
+			td->cp += _tps_contact_host.len;
345
+		} else {
346
+			memcpy(td->cp, puri.host.s, puri.host.len);
347
+			td->cp += puri.host.len;
348
+		}
349
+		if(puri.port.len>0) {
350
+			*td->cp = ':';
351
+			td->cp++;
352
+			memcpy(td->cp, puri.port.s, puri.port.len);
353
+			td->cp += puri.port.len;
354
+		}
355
+		if(puri.transport_val.len>0) {
356
+			memcpy(td->cp, ";transport=", 11);
357
+			td->cp += 11;
358
+			memcpy(td->cp, puri.transport_val.s, puri.transport_val.len);
359
+			td->cp += puri.transport_val.len;
360
+		}
283 361
 
284
-	if(puri.port.len>0) {
285
-		*td->cp = ':';
362
+		*td->cp = ';';
286 363
 		td->cp++;
287
-		memcpy(td->cp, puri.port.s, puri.port.len);
288
-		td->cp += puri.port.len;
289
-	}
290
-	if(puri.transport_val.len>0) {
291
-		memcpy(td->cp, ";transport=", 11);
292
-		td->cp += 11;
293
-		memcpy(td->cp, puri.transport_val.s, puri.transport_val.len);
294
-		td->cp += puri.transport_val.len;
364
+		memcpy(td->cp, _tps_cparam_name.s, _tps_cparam_name.len);
365
+		td->cp += _tps_cparam_name.len;
366
+		*td->cp = '=';
367
+		td->cp++;
368
+		if(dir==TPS_DIR_DOWNSTREAM) {
369
+			*td->cp = 'b';
370
+		} else {
371
+			*td->cp = 'a';
372
+		}
373
+		td->cp++;
374
+		memcpy(td->cp, uuid->s, uuid->len);
375
+		td->cp += uuid->len;
376
+
377
+	// create new user part for Contact header URI
378
+	} else {
379
+		if(dir==TPS_DIR_DOWNSTREAM) {
380
+			*td->cp = 'b';
381
+		} else {
382
+			*td->cp = 'a';
383
+		}
384
+		td->cp++;
385
+		memcpy(td->cp, uuid->s, uuid->len);
386
+		td->cp += uuid->len;
387
+		*td->cp = '@';
388
+		td->cp++;
389
+
390
+		if (_tps_contact_host.len) { // using configured hostname in the contact header
391
+			memcpy(td->cp, _tps_contact_host.s, _tps_contact_host.len);
392
+			td->cp += _tps_contact_host.len;
393
+		} else {
394
+			memcpy(td->cp, puri.host.s, puri.host.len);
395
+			td->cp += puri.host.len;
396
+		}
397
+		if(puri.port.len>0) {
398
+			*td->cp = ':';
399
+			td->cp++;
400
+			memcpy(td->cp, puri.port.s, puri.port.len);
401
+			td->cp += puri.port.len;
402
+		}
403
+		if(puri.transport_val.len>0) {
404
+			memcpy(td->cp, ";transport=", 11);
405
+			td->cp += 11;
406
+			memcpy(td->cp, puri.transport_val.s, puri.transport_val.len);
407
+			td->cp += puri.transport_val.len;
408
+		}
295 409
 	}
296 410
 
297 411
 	*td->cp = '>';
298 412
 	td->cp++;
299 413
 	if(dir==TPS_DIR_DOWNSTREAM) {
300 414
 		td->bs_contact.len = td->cp - td->bs_contact.s;
415
+		LM_DBG("td->bs %.*s\n",  td->bs_contact.len,  td->bs_contact.s);
301 416
 	} else {
302 417
 		td->as_contact.len = td->cp - td->as_contact.s;
418
+		LM_DBG("td->as %.*s\n",  td->as_contact.len,  td->as_contact.s);
303 419
 	}
304 420
 	return 0;
305 421
 }
... ...
@@ -373,6 +489,7 @@ int tps_storage_link_msg(sip_msg_t *msg, tps_data_t *td, int dir)
373 489
 		LM_ERR("bad Contact header\n");
374 490
 		return -1;
375 491
 	}
492
+
376 493
 	if(msg->first_line.type==SIP_REQUEST) {
377 494
 		if(dir==TPS_DIR_DOWNSTREAM) {
378 495
 			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)
421 538
 		suid.len--;
422 539
 	}
423 540
 
424
-	ret = tps_storage_fill_contact(msg, td, &suid, TPS_DIR_DOWNSTREAM);
541
+	ret = tps_storage_fill_contact(msg, td, &suid, TPS_DIR_DOWNSTREAM, _tps_contact_mode);
425 542
 	if(ret<0) goto error;
426
-	ret = tps_storage_fill_contact(msg, td, &suid, TPS_DIR_UPSTREAM);
543
+	ret = tps_storage_fill_contact(msg, td, &suid, TPS_DIR_UPSTREAM, _tps_contact_mode);
427 544
 	if(ret<0) goto error;
428 545
 
429 546
 	ret = tps_storage_link_msg(msg, td, dir);