1 /*
2  * Route & Record-Route header field parser
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 /*! \file
24  * \brief Parser :: Route & Record-Route header field parser
25  *
26  * \ingroup parser
27  */
28 
29 #include <string.h>
30 #include "parse_rr.h"
31 #include "../mem/mem.h"
32 #include "../mem/shm_mem.h"
33 #include "../dprint.h"
34 #include "../trim.h"
35 #include "../ut.h"
36 
37 /*! \brief
38  * Parse Route or Record-Route body
39  */
do_parse_rr_body(char * buf,int len,rr_t ** head)40 static inline int do_parse_rr_body(char *buf, int len, rr_t **head)
41 {
42 	rr_t* r, *last;
43 	str s;
44 	param_hooks_t hooks;
45 
46 	/* Make a temporary copy of the string pointer */
47 	if(buf==0 || len<=0)
48 	{
49 		LM_DBG("No body for record-route\n");
50 		*head = 0;
51 		return -2;
52 	}
53 	s.s = buf;
54 	s.len = len;
55 	trim_leading(&s);
56 
57 	last = 0;
58 	if (*head) {
59 		/* go to last rr in list */
60 		last = *head;
61 		while (last->next) {
62 			last = last->next;
63 		}
64 	}
65 
66 	while(1) {
67 		/* Allocate and clear rr structure */
68 		r = (rr_t*)pkg_malloc(sizeof(rr_t));
69 		if (!r) {
70 			PKG_MEM_ERROR;
71 			goto error;
72 		}
73 		memset(r, 0, sizeof(rr_t));
74 
75 		/* Parse name-addr part of the header */
76 		if (parse_nameaddr(&s, &r->nameaddr) < 0) {
77 			LM_ERR("Failed parsing name-addr (%.*s)\n",
78 					s.len, ZSW(s.s));
79 			goto error;
80 		}
81 		r->len = r->nameaddr.len;
82 
83 		/* Shift just behind the closing > */
84 		s.s = r->nameaddr.name.s + r->nameaddr.len;  /* Point just behind > */
85 		s.len -= r->nameaddr.len;
86 
87 		trim_leading(&s); /* Skip any white-chars */
88 
89 		if (s.len == 0) goto ok; /* Nothing left, finish */
90 
91 		if (s.s[0] == ';') {         /* Route parameter found */
92 			s.s++;
93 			s.len--;
94 			trim_leading(&s);
95 
96 			if (s.len == 0) {
97 				LM_ERR("Error while parsing params\n");
98 				goto error;
99 			}
100 
101 			/* Parse all parameters */
102 			if (parse_params(&s, CLASS_ANY, &hooks, &r->params) < 0) {
103 				LM_ERR("Error while parsing params\n");
104 				goto error;
105 			}
106 			r->len = r->params->name.s + r->params->len - r->nameaddr.name.s;
107 
108 			/* Copy hooks */
109 			/*r->r2 = hooks.rr.r2; */
110 
111 			trim_leading(&s);
112 			if (s.len == 0) goto ok;
113 		}
114 
115 		if (s.s[0] != ',') {
116 			LM_ERR("Invalid character '%c', comma expected\n", s.s[0]);
117 			goto error;
118 		}
119 
120 		/* Next character is comma or end of header*/
121 		s.s++;
122 		s.len--;
123 		trim_leading(&s);
124 
125 		if (s.len == 0) {
126 			LM_ERR("Text after comma missing\n");
127 			goto error;
128 		}
129 
130 		/* Append the structure as last parameter of the linked list */
131 		if (!*head) *head = r;
132 		if (last) last->next = r;
133 		last = r;
134 	}
135 
136 error:
137 	if (r) free_rr(&r);
138 	free_rr(head); /* Free any rr created so far */
139 	*head = NULL;
140 	LM_ERR("Failed parsing rr header body [%.*s]\n", len, ZSW(buf));
141 	return -1;
142 
143 ok:
144 	if (!*head) *head = r;
145 	if (last) last->next = r;
146 	return 0;
147 }
148 
149 /*! \brief
150  * Wrapper to do_parse_rr_body() for external calls
151  */
parse_rr_body(char * buf,int len,rr_t ** head)152 int parse_rr_body(char *buf, int len, rr_t **head)
153 {
154 	return do_parse_rr_body(buf, len, head);
155 }
156 
157 /*! \brief
158  * Parse Route and Record-Route header fields
159  */
parse_rr(struct hdr_field * _h)160 int parse_rr(struct hdr_field* _h)
161 {
162 	rr_t* r = NULL;
163 
164 	if (!_h) {
165 		LM_ERR("Invalid parameter value\n");
166 		return -1;
167 	}
168 
169 	if (_h->parsed) {
170 		/* Already parsed, return */
171 		return 0;
172 	}
173 
174 	if(do_parse_rr_body(_h->body.s, _h->body.len, &r) < 0)
175 		return -1;
176 	_h->parsed = (void*)r;
177 	return 0;
178 }
179 
180 /*! \brief
181  * Free list of rrs
182  * _r is head of the list
183  */
do_free_rr(rr_t ** _r,int _shm)184 static inline void do_free_rr(rr_t** _r, int _shm)
185 {
186 	rr_t* ptr;
187 
188 	while(*_r) {
189 		ptr = *_r;
190 		*_r = (*_r)->next;
191 		if (ptr->params) {
192 			if (_shm) shm_free_params(ptr->params);
193 			else free_params(ptr->params);
194 		}
195 		if (_shm) shm_free(ptr);
196 		else pkg_free(ptr);
197 	}
198 }
199 
200 
201 /*! \brief
202  * Free list of rrs
203  * _r is head of the list
204  */
205 
free_rr(rr_t ** _r)206 void free_rr(rr_t** _r)
207 {
208 	do_free_rr(_r, 0);
209 }
210 
211 
212 /*! \brief
213  * Free list of rrs
214  * _r is head of the list
215  */
216 
shm_free_rr(rr_t ** _r)217 void shm_free_rr(rr_t** _r)
218 {
219 	do_free_rr(_r, 1);
220 }
221 
222 
223 /*! \brief
224  * Print list of RRs, just for debugging
225  */
print_rr(FILE * _o,rr_t * _r)226 void print_rr(FILE* _o, rr_t* _r)
227 {
228 	rr_t* ptr;
229 
230 	ptr = _r;
231 
232 	while(ptr) {
233 		fprintf(_o, "---RR---\n");
234 		print_nameaddr(_o, &ptr->nameaddr);
235 		fprintf(_o, "r2 : %p\n", ptr->r2);
236 		if (ptr->params) {
237 			print_params(_o, ptr->params);
238 		}
239 		fprintf(_o, "len: %d\n", ptr->len);
240 		fprintf(_o, "---/RR---\n");
241 		ptr = ptr->next;
242 	}
243 }
244 
245 
246 /*! \brief
247  * Translate all pointers in the structure and also
248  * in all parameters in the list
249  */
xlate_pointers(rr_t * _orig,rr_t * _r)250 static inline void xlate_pointers(rr_t* _orig, rr_t* _r)
251 {
252 	param_t* ptr;
253 	_r->nameaddr.uri.s = translate_pointer(_r->nameaddr.name.s,
254 			_orig->nameaddr.name.s, _r->nameaddr.uri.s);
255 
256 	ptr = _r->params;
257 	while(ptr) {
258 		/*		if (ptr->type == P_R2) _r->r2 = ptr; */
259 		ptr->name.s = translate_pointer(_r->nameaddr.name.s,
260 				_orig->nameaddr.name.s, ptr->name.s);
261 		ptr->body.s = translate_pointer(_r->nameaddr.name.s,
262 				_orig->nameaddr.name.s, ptr->body.s);
263 		ptr = ptr->next;
264 	}
265 }
266 
267 
268 /*! \brief
269  * Duplicate a single rr_t structure using pkg_malloc or shm_malloc
270  */
do_duplicate_rr(rr_t ** _new,rr_t * _r,int _shm)271 static inline int do_duplicate_rr(rr_t** _new, rr_t* _r, int _shm)
272 {
273 	int len, ret;
274 	rr_t* res, *prev, *it;
275 
276 	if (!_new || !_r) {
277 		LM_ERR("Invalid parameter value\n");
278 		return -1;
279 	}
280 	prev  = NULL;
281 	*_new = NULL;
282 	it    = _r;
283 	while(it)
284 	{
285 		if (it->params) {
286 			len = it->params->name.s + it->params->len - it->nameaddr.name.s;
287 		} else {
288 			len = it->nameaddr.len;
289 		}
290 
291 		if (_shm) res = shm_malloc(sizeof(rr_t) + len);
292 		else res = pkg_malloc(sizeof(rr_t) + len);
293 		if (!res) {
294 			if (_shm) {
295 				SHM_MEM_ERROR;
296 			} else {
297 				PKG_MEM_ERROR;
298 			}
299 			ret = -2;
300 			goto error;
301 		}
302 		memcpy(res, it, sizeof(rr_t));
303 
304 		res->nameaddr.name.s = (char*)res + sizeof(rr_t);
305 		memcpy(res->nameaddr.name.s, it->nameaddr.name.s, len);
306 
307 		if (_shm) {
308 			ret = shm_duplicate_params(&res->params, it->params);
309 		} else {
310 			ret = duplicate_params(&res->params, it->params);
311 		}
312 
313 		if (ret < 0) {
314 			LM_ERR("Error while duplicating parameters\n");
315 			if (_shm) shm_free(res);
316 			else pkg_free(res);
317 			ret = -3;
318 			goto error;
319 		}
320 
321 		xlate_pointers(it, res);
322 
323 		res->next=NULL;
324 		if(*_new==NULL)
325 			*_new = res;
326 		if(prev)
327 			prev->next = res;
328 		prev = res;
329 		it = it->next;
330 	}
331 	return 0;
332 
333 error:
334 	if(*_new != NULL) {
335 		if (_shm) {
336 			shm_free_rr(_new);
337 		} else {
338 			free_rr(_new);
339 		}
340 		*_new = NULL;
341 	}
342 
343 	return ret;
344 }
345 
346 
347 /*! \brief
348  * Duplicate a single rr_t structure using pkg_malloc
349  */
duplicate_rr(rr_t ** _new,rr_t * _r)350 int duplicate_rr(rr_t** _new, rr_t* _r)
351 {
352 	return do_duplicate_rr(_new, _r, 0);
353 }
354 
355 
356 /*! \brief
357  * Duplicate a single rr_t structure using pkg_malloc
358  */
shm_duplicate_rr(rr_t ** _new,rr_t * _r)359 int shm_duplicate_rr(rr_t** _new, rr_t* _r)
360 {
361 	return do_duplicate_rr(_new, _r, 1);
362 }
363 
364 /*!
365  * get first RR header and print comma separated bodies in oroute
366  * - order = 0 normal; order = 1 reverse
367  * - nb_recs - input=skip number of rr; output=number of printed rrs
368  */
print_rr_body(struct hdr_field * iroute,str * oroute,int order,unsigned int * nb_recs)369 int print_rr_body(struct hdr_field *iroute, str *oroute, int order,
370 												unsigned int * nb_recs)
371 {
372 	rr_t *p;
373 	int n = 0, nr=0;
374 	int i = 0;
375 	int route_len;
376 #define MAX_RR_HDRS	64
377 	static str route[MAX_RR_HDRS];
378 	char *cp, *start;
379 
380 	if(iroute==NULL)
381 		return 0;
382 
383 	route_len= 0;
384 	memset(route, 0, MAX_RR_HDRS*sizeof(str));
385 
386 	while (iroute!=NULL)
387 	{
388 		if (parse_rr(iroute) < 0)
389 		{
390 			LM_ERR("failed to parse RR\n");
391 			goto error;
392 		}
393 
394 		p =(rr_t*)iroute->parsed;
395 		while (p)
396 		{
397 			route[n].s = p->nameaddr.name.s;
398 			route[n].len = p->len;
399 			LM_DBG("current rr is %.*s\n", route[n].len, route[n].s);
400 
401 			n++;
402 			if(n==MAX_RR_HDRS)
403 			{
404 				LM_ERR("too many RR\n");
405 				goto error;
406 			}
407 			p = p->next;
408 		}
409 
410 		iroute = next_sibling_hdr(iroute);
411 	}
412 
413 	for(i=0;i<n;i++){
414 		if(!nb_recs || (nb_recs
415 			&& ( (!order&& (i>=*nb_recs)) || (order && (i<=(n-*nb_recs)) )) ) )
416 		{
417 			route_len+= route[i].len;
418 			nr++;
419 		}
420 
421 	}
422 
423 	if(nb_recs)
424 		LM_DBG("skipping %i route records\n", *nb_recs);
425 
426 	route_len += --nr; /* for commas */
427 
428 	oroute->s=(char*)pkg_malloc(route_len);
429 
430 	if(oroute->s==0)
431 	{
432 		PKG_MEM_ERROR;
433 		goto error;
434 	}
435 	cp = start = oroute->s;
436 	if(order==0)
437 	{
438 		i= (nb_recs == NULL) ? 0:*nb_recs;
439 
440 		while (i<n)
441 		{
442 			memcpy(cp, route[i].s, route[i].len);
443 			cp += route[i].len;
444 			if (++i<n)
445 				*(cp++) = ',';
446 		}
447 	} else {
448 
449 		i = (nb_recs == NULL) ? n-1 : (n-*nb_recs-1);
450 
451 		while (i>=0)
452 		{
453 			memcpy(cp, route[i].s, route[i].len);
454 			cp += route[i].len;
455 			if (i-->0)
456 				*(cp++) = ',';
457 		}
458 	}
459 	oroute->len=cp - start;
460 
461 	LM_DBG("out rr [%.*s]\n", oroute->len, oroute->s);
462 	LM_DBG("we have %i records\n", (nb_recs == NULL) ? n : n-*nb_recs);
463 	if(nb_recs != NULL)
464 		*nb_recs = (unsigned int)n-*nb_recs;
465 
466 	return 0;
467 
468 error:
469 	return -1;
470 }
471 
472 
473 /*!
474  * Path must be available. Function returns the first uri
475  * from Path without any duplication.
476  */
get_path_dst_uri(str * _p,str * _dst)477 int get_path_dst_uri(str *_p, str *_dst)
478 {
479 	rr_t *route = 0;
480 
481 	LM_DBG("path for branch: '%.*s'\n", _p->len, _p->s);
482 	if(parse_rr_body(_p->s, _p->len, &route) < 0) {
483 		LM_ERR("failed to parse Path body\n");
484 		return -1;
485 	}
486 
487 	if(!route) {
488 		LM_ERR("failed to parse Path body no head found\n");
489 		return -1;
490 	}
491 	*_dst = route->nameaddr.uri;
492 
493 	free_rr(&route);
494 
495 	return 0;
496 }
497