Coverage Report

Created: 2025-08-26 06:38

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