Asterisk - The Open Source Telephony Project  18.5.0
reqresp_parser.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16 
17 /*!
18  * \file
19  * \brief sip request parsing functions and unit tests
20  */
21 
22 /*** MODULEINFO
23  <support_level>deprecated</support_level>
24  ***/
25 
26 #include "asterisk.h"
27 
28 #include "include/sip.h"
29 #include "include/sip_utils.h"
30 #include "include/reqresp_parser.h"
31 
32 #ifdef HAVE_XLOCALE_H
34 #endif
35 
36 /*! \brief * parses a URI in its components.*/
37 int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
38  char **hostport, struct uriparams *params, char **headers,
39  char **residue)
40 {
41  char *userinfo = NULL;
42  char *parameters = NULL;
43  char *endparams = NULL;
44  char *c = NULL;
45  int error = 0;
46  int teluri_scheme = 0;
47 
48  /*
49  * Initialize requested strings - some functions don't care if parse_uri fails
50  * and will attempt to use string pointers passed into parse_uri even after a
51  * parse_uri failure
52  */
53  if (user) {
54  *user = "";
55  }
56  if (pass) {
57  *pass = "";
58  }
59  if (hostport) {
60  *hostport = "";
61  }
62  if (headers) {
63  *headers = "";
64  }
65  if (residue) {
66  *residue = "";
67  }
68 
69  /* check for valid input */
70  if (ast_strlen_zero(uri)) {
71  return -1;
72  }
73 
74  if (scheme) {
75  int l;
76  char *scheme2 = ast_strdupa(scheme);
77  char *cur = strsep(&scheme2, ",");
78  for (; !ast_strlen_zero(cur); cur = strsep(&scheme2, ",")) {
79  l = strlen(cur);
80  if (!strncasecmp(uri, cur, l)) {
81  teluri_scheme = !strncasecmp(uri, "tel:", 4); /* TEL URI */
82  uri += l;
83  break;
84  }
85  }
86  if (ast_strlen_zero(cur)) {
87  ast_debug(1, "No supported scheme found in '%s' using the scheme[s] %s\n", uri, scheme);
88  error = -1;
89  }
90  }
91 
92  if (!hostport) {
93  /* if we don't want to split around hostport, keep everything as a
94  * userinfo - cos thats how old parse_uri operated*/
95  userinfo = uri;
96  } else if (teluri_scheme) {
97  /*
98  * tel: TEL URI INVITE RFC 3966 patch
99  * See http://www.ietf.org/rfc/rfc3966.txt
100  *
101  * Once the full RFC 3966 parsing is implemented,
102  * the ext= or isub= parameters would be extracted from userinfo.
103  * When this kind of subaddressing would be implemented, the userinfo must be further parsed.
104  * Those parameters would be used for ISDN or PSTN local extensions.
105  *
106  * Current restrictions:
107  * We currently consider the ";isub=" or the ";ext=" as part of the userinfo (unparsed).
108  */
109 
110  if ((c = strstr(uri, ";phone-context="))) {
111  /*
112  * Local number with context or domain.
113  * ext= or isub= TEL URI parameters should be upfront.
114  * All other parameters should come after the ";phone-context=" parameter.
115  * If other parameters would occur before ";phone-context=" they will be ignored.
116  */
117 
118  *c = '\0';
119  userinfo = uri;
120  uri = c + 15;
121  *hostport = uri;
122  } else if ('+' == uri[0]) {
123  /* Global number without context or domain; possibly followed by RFC 3966 and optional other parameters. */
124 
125  userinfo = uri;
126  *hostport = uri;
127  } else {
128  ast_debug(1, "No RFC 3966 global number or context found in '%s'; returning local number anyway\n", uri);
129  userinfo = uri; /* Return local number anyway */
130  error = -1;
131  }
132  } else {
133  char *dom = "";
134  if ((c = strchr(uri, '@'))) {
135  *c++ = '\0';
136  dom = c;
137  userinfo = uri;
138  uri = c; /* userinfo can contain ? and ; chars so step forward before looking for params and headers */
139  } else {
140  /* domain-only URI, according to the SIP RFC. */
141  dom = uri;
142  userinfo = "";
143  }
144 
145  *hostport = dom;
146  }
147 
148  if (pass && (c = strchr(userinfo, ':'))) { /* user:password */
149  *c++ = '\0';
150  *pass = c;
151  } else if (pass) {
152  *pass = "";
153  }
154 
155  if (user) {
156  *user = userinfo;
157  }
158 
159  parameters = uri;
160  /* strip [?headers] from end of uri - even if no header pointer exists*/
161  if ((c = strrchr(uri, '?'))) {
162  *c++ = '\0';
163  uri = c;
164  if (headers) {
165  *headers = c;
166  }
167  if ((c = strrchr(uri, ';'))) {
168  *c++ = '\0';
169  } else {
170  c = strrchr(uri, '\0');
171  }
172  uri = c; /* residue */
173 
174 
175  } else if (headers) {
176  *headers = "";
177  }
178 
179  /* parse parameters */
180  endparams = strchr(parameters,'\0');
181  if ((c = strchr(parameters, ';'))) {
182  *c++ = '\0';
183  parameters = c;
184  } else {
185  parameters = endparams;
186  }
187 
188  if (params) {
189  char *rem = parameters; /* unparsed or unrecognised remainder */
190  char *label;
191  char *value;
192  int lr = 0;
193 
194  params->transport = "";
195  params->user = "";
196  params->method = "";
197  params->ttl = "";
198  params->maddr = "";
199  params->lr = 0;
200 
201  rem = parameters;
202 
203  while ((value = strchr(parameters, '=')) || (lr = !strncmp(parameters, "lr", 2))) {
204  /* The while condition will not continue evaluation to set lr if it matches "lr=" */
205  if (lr) {
206  value = parameters;
207  } else {
208  *value++ = '\0';
209  }
210  label = parameters;
211  if ((c = strchr(value, ';'))) {
212  *c++ = '\0';
213  parameters = c;
214  } else {
215  parameters = endparams;
216  }
217 
218  if (!strcmp(label, "transport")) {
219  params->transport = value;
220  rem = parameters;
221  } else if (!strcmp(label, "user")) {
222  params->user = value;
223  rem = parameters;
224  } else if (!strcmp(label, "method")) {
225  params->method = value;
226  rem = parameters;
227  } else if (!strcmp(label, "ttl")) {
228  params->ttl = value;
229  rem = parameters;
230  } else if (!strcmp(label, "maddr")) {
231  params->maddr = value;
232  rem = parameters;
233  /* Treat "lr", "lr=yes", "lr=on", "lr=1", "lr=almostanything" as lr enabled and "", "lr=no", "lr=off", "lr=0", "lr=" and "lranything" as lr disabled */
234  } else if ((!strcmp(label, "lr") && strcmp(value, "no") && strcmp(value, "off") && strcmp(value, "0") && strcmp(value, "")) || ((lr) && strcmp(value, "lr"))) {
235  params->lr = 1;
236  rem = parameters;
237  } else {
238  value--;
239  *value = '=';
240  if (c) {
241  c--;
242  *c = ';';
243  }
244  }
245  }
246  if (rem > uri) { /* no headers */
247  uri = rem;
248  }
249 
250  }
251 
252  if (residue) {
253  *residue = uri;
254  }
255 
256  return error;
257 }
258 
259 #ifdef TEST_FRAMEWORK
260 AST_TEST_DEFINE(sip_parse_uri_full_test)
261 {
262  int res = AST_TEST_PASS;
263  char uri[1024];
264  char *user, *pass, *hostport, *headers, *residue;
265  struct uriparams params;
266 
267  struct testdata {
268  char *desc;
269  char *uri;
270  char *user;
271  char *pass;
272  char *hostport;
273  char *headers;
274  char *residue;
275  struct uriparams params;
276  AST_LIST_ENTRY(testdata) list;
277  };
278 
279 
280  struct testdata *testdataptr;
281 
282  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
283 
284  struct testdata td1 = {
285  .desc = "no headers",
286  .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=residue",
287  .user = "user",
288  .pass = "secret",
289  .hostport = "host:5060",
290  .headers = "",
291  .residue = "param2=residue",
292  .params.transport = "tcp",
293  .params.lr = 0,
294  .params.user = ""
295  };
296 
297  struct testdata td2 = {
298  .desc = "with headers",
299  .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;param2=discard2?header=blah&header2=blah2;param3=residue",
300  .user = "user",
301  .pass = "secret",
302  .hostport = "host:5060",
303  .headers = "header=blah&header2=blah2",
304  .residue = "param3=residue",
305  .params.transport = "tcp",
306  .params.lr = 0,
307  .params.user = ""
308  };
309 
310  struct testdata td3 = {
311  .desc = "difficult user",
312  .uri = "sip:-_.!~*'()&=+$,;?/:secret@host:5060;transport=tcp",
313  .user = "-_.!~*'()&=+$,;?/",
314  .pass = "secret",
315  .hostport = "host:5060",
316  .headers = "",
317  .residue = "",
318  .params.transport = "tcp",
319  .params.lr = 0,
320  .params.user = ""
321  };
322 
323  struct testdata td4 = {
324  .desc = "difficult pass",
325  .uri = "sip:user:-_.!~*'()&=+$,@host:5060;transport=tcp",
326  .user = "user",
327  .pass = "-_.!~*'()&=+$,",
328  .hostport = "host:5060",
329  .headers = "",
330  .residue = "",
331  .params.transport = "tcp",
332  .params.lr = 0,
333  .params.user = ""
334  };
335 
336  struct testdata td5 = {
337  .desc = "difficult host",
338  .uri = "sip:user:[email protected].:5060;transport=tcp",
339  .user = "user",
340  .pass = "secret",
341  .hostport = "1-1.a-1.:5060",
342  .headers = "",
343  .residue = "",
344  .params.transport = "tcp",
345  .params.lr = 0,
346  .params.user = ""
347  };
348 
349  struct testdata td6 = {
350  .desc = "difficult params near transport",
351  .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$;transport=tcp",
352  .user = "user",
353  .pass = "secret",
354  .hostport = "host:5060",
355  .headers = "",
356  .residue = "",
357  .params.transport = "tcp",
358  .params.lr = 0,
359  .params.user = ""
360  };
361 
362  struct testdata td7 = {
363  .desc = "difficult params near headers",
364  .uri = "sip:user:secret@host:5060;-_.!~*'()[]/:&+$=-_.!~*'()[]/:&+$?header=blah&header2=blah2;-_.!~*'()[]/:&+$=residue",
365  .user = "user",
366  .pass = "secret",
367  .hostport = "host:5060",
368  .headers = "header=blah&header2=blah2",
369  .residue = "-_.!~*'()[]/:&+$=residue",
370  .params.transport = "",
371  .params.lr = 0,
372  .params.user = ""
373  };
374 
375  struct testdata td8 = {
376  .desc = "lr parameter",
377  .uri = "sip:user:secret@host:5060;param=discard;lr?header=blah",
378  .user = "user",
379  .pass = "secret",
380  .hostport = "host:5060",
381  .headers = "header=blah",
382  .residue = "",
383  .params.transport = "",
384  .params.lr = 1,
385  .params.user = ""
386  };
387 
388  struct testdata td9 = {
389  .desc = "alternative lr parameter",
390  .uri = "sip:user:secret@host:5060;param=discard;lr=yes?header=blah",
391  .user = "user",
392  .pass = "secret",
393  .hostport = "host:5060",
394  .headers = "header=blah",
395  .residue = "",
396  .params.transport = "",
397  .params.lr = 1,
398  .params.user = ""
399  };
400 
401  struct testdata td10 = {
402  .desc = "no lr parameter",
403  .uri = "sip:user:secret@host:5060;paramlr=lr;lr=no;lr=off;lr=0;lr=;=lr;lrextra;lrparam2=lr?header=blah",
404  .user = "user",
405  .pass = "secret",
406  .hostport = "host:5060",
407  .headers = "header=blah",
408  .residue = "",
409  .params.transport = "",
410  .params.lr = 0,
411  .params.user = ""
412  };
413 
414  /* RFC 3966 TEL URI INVITE */
415  struct testdata td11 = {
416  .desc = "tel local number",
417  .uri = "tel:0987654321;phone-context=+32987654321",
418  .user = "0987654321",
419  .pass = "",
420  .hostport = "+32987654321",
421  .headers = "",
422  .residue = "",
423  .params.transport = "",
424  .params.lr = 0,
425  .params.user = ""
426  };
427 
428  struct testdata td12 = {
429  .desc = "tel global number",
430  .uri = "tel:+32987654321",
431  .user = "+32987654321",
432  .pass = "",
433  .hostport = "+32987654321",
434  .headers = "",
435  .residue = "",
436  .params.transport = "",
437  .params.lr = 0,
438  .params.user = ""
439  };
440 
441  /*
442  * Once the full RFC 3966 parsing is implemented,
443  * only the ext= or isub= parameters would be extracted from .user
444  * Then the ;param=discard would be ignored,
445  * and the .user would only contain "0987654321"
446  */
447  struct testdata td13 = {
448  .desc = "tel local number",
449  .uri = "tel:0987654321;ext=1234;param=discard;phone-context=+32987654321;transport=udp;param2=discard2?header=blah&header2=blah2;param3=residue",
450  .user = "0987654321;ext=1234;param=discard",
451  .pass = "",
452  .hostport = "+32987654321",
453  .headers = "header=blah&header2=blah2",
454  .residue = "param3=residue",
455  .params.transport = "udp",
456  .params.lr = 0,
457  .params.user = ""
458  };
459 
460  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
461  AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
462  AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
463  AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
464  AST_LIST_INSERT_TAIL(&testdatalist, &td5, list);
465  AST_LIST_INSERT_TAIL(&testdatalist, &td6, list);
466  AST_LIST_INSERT_TAIL(&testdatalist, &td7, list);
467  AST_LIST_INSERT_TAIL(&testdatalist, &td8, list);
468  AST_LIST_INSERT_TAIL(&testdatalist, &td9, list);
469  AST_LIST_INSERT_TAIL(&testdatalist, &td10, list);
470  AST_LIST_INSERT_TAIL(&testdatalist, &td11, list);
471  AST_LIST_INSERT_TAIL(&testdatalist, &td12, list);
472  AST_LIST_INSERT_TAIL(&testdatalist, &td13, list);
473 
474  switch (cmd) {
475  case TEST_INIT:
476  info->name = "sip_uri_full_parse_test";
477  info->category = "/channels/chan_sip/";
478  info->summary = "tests sip full uri parsing";
479  info->description =
480  "Tests full parsing of various URIs "
481  "Verifies output matches expected behavior.";
482  return AST_TEST_NOT_RUN;
483  case TEST_EXECUTE:
484  break;
485  }
486 
487  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
488  user = pass = hostport = headers = residue = NULL;
489  params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
490  params.lr = 0;
491 
492  ast_copy_string(uri,testdataptr->uri,sizeof(uri));
493  if (parse_uri_full(uri, "sip:,sips:,tel:", &user,
494  &pass, &hostport,
495  &params,
496  &headers,
497  &residue) ||
498  (user && strcmp(testdataptr->user, user)) ||
499  (pass && strcmp(testdataptr->pass, pass)) ||
500  (hostport && strcmp(testdataptr->hostport, hostport)) ||
501  (headers && strcmp(testdataptr->headers, headers)) ||
502  (residue && strcmp(testdataptr->residue, residue)) ||
503  (strcmp(testdataptr->params.transport,params.transport)) ||
504  (testdataptr->params.lr != params.lr) ||
505  (strcmp(testdataptr->params.user,params.user))
506  ) {
507  ast_test_status_update(test, "Sub-Test: %s, failed.\n", testdataptr->desc);
508  res = AST_TEST_FAIL;
509  }
510  }
511 
512 
513  return res;
514 }
515 #endif
516 
517 int parse_uri(char *uri, const char *scheme, char **user, char **pass,
518  char **hostport, char **transport) {
519  int ret;
520  char *headers;
521  struct uriparams params;
522 
523  headers = NULL;
524  ret = parse_uri_full(uri, scheme, user, pass, hostport, &params, &headers, NULL);
525  if (transport) {
526  *transport=params.transport;
527  }
528  return ret;
529 }
530 
531 #ifdef TEST_FRAMEWORK
532 AST_TEST_DEFINE(sip_parse_uri_test)
533 {
534  int res = AST_TEST_PASS;
535  char *name, *pass, *hostport, *transport;
536  char uri1[] = "sip:name@host";
537  char uri2[] = "sip:name@host;transport=tcp";
538  char uri3[] = "sip:name:secret@host;transport=tcp";
539  char uri4[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
540  /* test 5 is for NULL input */
541  char uri6[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
542  char uri7[] = "sip:name:secret@host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
543  char uri8[] = "sip:host";
544  char uri9[] = "sip:host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
545  char uri10[] = "host:port;transport=tcp?headers=%40%40testblah&headers2=blah%20blah";
546  char uri11[] = "host";
547  char uri12[] = "tel:911"; /* TEL URI Local number without context or global number */
548 
549  switch (cmd) {
550  case TEST_INIT:
551  info->name = "sip_uri_parse_test";
552  info->category = "/channels/chan_sip/";
553  info->summary = "tests sip uri parsing";
554  info->description =
555  "Tests parsing of various URIs "
556  "Verifies output matches expected behavior.";
557  return AST_TEST_NOT_RUN;
558  case TEST_EXECUTE:
559  break;
560  }
561 
562  /* Test 1, simple URI */
563  name = pass = hostport = transport = NULL;
564  if (parse_uri(uri1, "sip:,sips:", &name, &pass, &hostport, &transport) ||
565  strcmp(name, "name") ||
566  !ast_strlen_zero(pass) ||
567  strcmp(hostport, "host") ||
568  !ast_strlen_zero(transport)) {
569  ast_test_status_update(test, "Test 1: simple uri failed. \n");
570  res = AST_TEST_FAIL;
571  }
572 
573  /* Test 2, add tcp transport */
574  name = pass = hostport = transport = NULL;
575  if (parse_uri(uri2, "sip:,sips:", &name, &pass, &hostport, &transport) ||
576  strcmp(name, "name") ||
577  !ast_strlen_zero(pass) ||
578  strcmp(hostport, "host") ||
579  strcmp(transport, "tcp")) {
580  ast_test_status_update(test, "Test 2: uri with addtion of tcp transport failed. \n");
581  res = AST_TEST_FAIL;
582  }
583 
584  /* Test 3, add secret */
585  name = pass = hostport = transport = NULL;
586  if (parse_uri(uri3, "sip:,sips:", &name, &pass, &hostport, &transport) ||
587  strcmp(name, "name") ||
588  strcmp(pass, "secret") ||
589  strcmp(hostport, "host") ||
590  strcmp(transport, "tcp")) {
591  ast_test_status_update(test, "Test 3: uri with addition of secret failed.\n");
592  res = AST_TEST_FAIL;
593  }
594 
595  /* Test 4, add port and unparsed header field*/
596  name = pass = hostport = transport = NULL;
597  if (parse_uri(uri4, "sip:,sips:", &name, &pass, &hostport, &transport) ||
598  strcmp(name, "name") ||
599  strcmp(pass, "secret") ||
600  strcmp(hostport, "host:port") ||
601  strcmp(transport, "tcp")) {
602  ast_test_status_update(test, "Test 4: add port and unparsed header field failed.\n");
603  res = AST_TEST_FAIL;
604  }
605 
606  /* Test 5, verify parse_uri does not crash when given a NULL uri */
607  name = pass = hostport = transport = NULL;
608  if (!parse_uri(NULL, "sip:,sips:", &name, &pass, &hostport, &transport)) {
609  ast_test_status_update(test, "Test 5: passing a NULL uri failed.\n");
610  res = AST_TEST_FAIL;
611  }
612 
613  /* Test 6, verify parse_uri does not crash when given a NULL output parameters */
614  name = pass = hostport = transport = NULL;
615  if (parse_uri(uri6, "sip:,sips:", NULL, NULL, NULL, NULL)) {
616  ast_test_status_update(test, "Test 6: passing NULL output parameters failed.\n");
617  res = AST_TEST_FAIL;
618  }
619 
620  /* Test 7, verify parse_uri returns user:secret and hostport when no port or secret output parameters are supplied. */
621  name = pass = hostport = transport = NULL;
622  if (parse_uri(uri7, "sip:,sips:", &name, NULL, &hostport, NULL) ||
623  strcmp(name, "name:secret") ||
624  strcmp(hostport, "host:port")) {
625 
626  ast_test_status_update(test, "Test 7: providing no port and secret output parameters failed.\n");
627  res = AST_TEST_FAIL;
628  }
629 
630  /* Test 8, verify parse_uri can handle a hostport only uri */
631  name = pass = hostport = transport = NULL;
632  if (parse_uri(uri8, "sip:,sips:", &name, &pass, &hostport, &transport) ||
633  strcmp(hostport, "host") ||
634  !ast_strlen_zero(name)) {
635  ast_test_status_update(test, "Test 8: add port and unparsed header field failed.\n");
636  res = AST_TEST_FAIL;
637  }
638 
639  /* Test 9, add port and unparsed header field with hostport only uri*/
640  name = pass = hostport = transport = NULL;
641  if (parse_uri(uri9, "sip:,sips:", &name, &pass, &hostport, &transport) ||
642  !ast_strlen_zero(name) ||
643  !ast_strlen_zero(pass) ||
644  strcmp(hostport, "host:port") ||
645  strcmp(transport, "tcp")) {
646  ast_test_status_update(test, "Test 9: hostport only uri failed \n");
647  res = AST_TEST_FAIL;
648  }
649 
650  /* Test 10, handle invalid/missing "sip:,sips:" scheme
651  * we expect parse_uri to return an error, but still parse
652  * the results correctly here */
653  name = pass = hostport = transport = NULL;
654  if (!parse_uri(uri10, "sip:,sips:", &name, &pass, &hostport, &transport) ||
655  !ast_strlen_zero(name) ||
656  !ast_strlen_zero(pass) ||
657  strcmp(hostport, "host:port") ||
658  strcmp(transport, "tcp")) {
659  ast_test_status_update(test, "Test 10: missing \"sip:sips:\" scheme failed\n");
660  res = AST_TEST_FAIL;
661  }
662 
663  /* Test 11, simple hostport only URI with missing scheme
664  * we expect parse_uri to return an error, but still parse
665  * the results correctly here */
666  name = pass = hostport = transport = NULL;
667  if (!parse_uri(uri11, "sip:,sips:", &name, &pass, &hostport, &transport) ||
668  !ast_strlen_zero(name) ||
669  !ast_strlen_zero(pass) ||
670  strcmp(hostport, "host") ||
671  !ast_strlen_zero(transport)) {
672  ast_test_status_update(test, "Test 11: simple uri with missing scheme failed. \n");
673  res = AST_TEST_FAIL;
674  }
675 
676  /* Test 12, simple URI */
677  name = pass = hostport = transport = NULL;
678  if (!parse_uri(uri12, "sip:,sips:,tel:", &name, &pass, &hostport, &transport) ||
679  strcmp(name, "911") || /* We return local number anyway */
680  !ast_strlen_zero(pass) ||
681  !ast_strlen_zero(hostport) || /* No global number nor context */
682  !ast_strlen_zero(transport)) {
683  ast_test_status_update(test, "Test 12: TEL URI INVITE failed.\n");
684  res = AST_TEST_FAIL;
685  }
686 
687  return res;
688 }
689 #endif
690 
691 /*! \brief Get caller id name from SIP headers, copy into output buffer
692  *
693  * \retval input string pointer placed after display-name field if possible
694  */
695 const char *get_calleridname(const char *input, char *output, size_t outputsize)
696 {
697  /* From RFC3261:
698  *
699  * From = ( "From" / "f" ) HCOLON from-spec
700  * from-spec = ( name-addr / addr-spec ) *( SEMI from-param )
701  * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
702  * display-name = *(token LWS)/ quoted-string
703  * token = 1*(alphanum / "-" / "." / "!" / "%" / "*"
704  * / "_" / "+" / "`" / "'" / "~" )
705  * quoted-string = SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
706  * qdtext = LWS / %x21 / %x23-5B / %x5D-7E
707  * / UTF8-NONASCII
708  * quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F)
709  *
710  * HCOLON = *WSP ":" SWS
711  * SWS = [LWS]
712  * LWS = *[*WSP CRLF] 1*WSP
713  * WSP = (SP / HTAB)
714  *
715  * Deviations from it:
716  * - following CRLF's in LWS is not done (here at least)
717  * - ascii NUL is never legal as it terminates the C-string
718  * - utf8-nonascii is not checked for validity
719  */
720  char *orig_output = output;
721  const char *orig_input = input;
722 
723  if (!output || !outputsize) {
724  /* Bad output parameters. Should never happen. */
725  return input;
726  }
727 
728  /* clear any empty characters in the beginning */
729  input = ast_skip_blanks(input);
730 
731  /* make sure the output buffer is initilized */
732  *orig_output = '\0';
733 
734  /* make room for '\0' at the end of the output buffer */
735  --outputsize;
736 
737  /* no data at all or no display name? */
738  if (!input || *input == '<') {
739  return input;
740  }
741 
742  /* quoted-string rules */
743  if (input[0] == '"') {
744  input++; /* skip the first " */
745 
746  for (; *input; ++input) {
747  if (*input == '"') { /* end of quoted-string */
748  break;
749  } else if (*input == 0x5c) { /* quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) */
750  ++input;
751  if (!*input) {
752  break;
753  }
754  if ((unsigned char) *input > 0x7f || *input == 0xa || *input == 0xd) {
755  continue; /* not a valid quoted-pair, so skip it */
756  }
757  } else if ((*input != 0x9 && (unsigned char) *input < 0x20)
758  || *input == 0x7f) {
759  continue; /* skip this invalid character. */
760  }
761 
762  if (0 < outputsize) {
763  /* We still have room for the output display-name. */
764  *output++ = *input;
765  --outputsize;
766  }
767  }
768 
769  /* if this is successful, input should be at the ending quote */
770  if (*input != '"') {
771  ast_log(LOG_WARNING, "No ending quote for display-name was found\n");
772  *orig_output = '\0';
773  return orig_input;
774  }
775 
776  /* make sure input is past the last quote */
777  ++input;
778 
779  /* terminate output */
780  *output = '\0';
781  } else { /* either an addr-spec or tokenLWS-combo */
782  for (; *input; ++input) {
783  /* token or WSP (without LWS) */
784  if ((*input >= '0' && *input <= '9') || (*input >= 'A' && *input <= 'Z')
785  || (*input >= 'a' && *input <= 'z') || *input == '-' || *input == '.'
786  || *input == '!' || *input == '%' || *input == '*' || *input == '_'
787  || *input == '+' || *input == '`' || *input == '\'' || *input == '~'
788  || *input == 0x9 || *input == ' ') {
789  if (0 < outputsize) {
790  /* We still have room for the output display-name. */
791  *output++ = *input;
792  --outputsize;
793  }
794  } else if (*input == '<') { /* end of tokenLWS-combo */
795  /* we could assert that the previous char is LWS, but we don't care */
796  break;
797  } else if (*input == ':') {
798  /* This invalid character which indicates this is addr-spec rather than display-name. */
799  *orig_output = '\0';
800  return orig_input;
801  } else { /* else, invalid character we can skip. */
802  continue; /* skip this character */
803  }
804  }
805 
806  if (*input != '<') { /* if we never found the start of addr-spec then this is invalid */
807  *orig_output = '\0';
808  return orig_input;
809  }
810 
811  /* terminate output while trimming any trailing whitespace */
812  do {
813  *output-- = '\0';
814  } while (orig_output <= output && (*output == 0x9 || *output == ' '));
815  }
816 
817  return input;
818 }
819 
820 #ifdef TEST_FRAMEWORK
821 AST_TEST_DEFINE(get_calleridname_test)
822 {
823  int res = AST_TEST_PASS;
824  const char *in1 = " \" quoted-text internal \\\" quote \"<stuff>";
825  const char *in2 = " token text with no quotes <stuff>";
826  const char *overflow1 = " \"quoted-text overflow 1234567890123456789012345678901234567890\" <stuff>";
827  const char *overflow2 = " non-quoted text overflow 1234567890123456789012345678901234567890 <stuff>";
828  const char *noendquote = " \"quoted-text no end <stuff>";
829  const char *addrspec = " sip:blah@blah";
830  const char *no_quotes_no_brackets = "blah@blah";
831  const char *after_dname;
832  char dname[40];
833 
834  switch (cmd) {
835  case TEST_INIT:
836  info->name = "sip_get_calleridname_test";
837  info->category = "/channels/chan_sip/";
838  info->summary = "decodes callerid name from sip header";
839  info->description = "Decodes display-name field of sip header. Checks for valid output and expected failure cases.";
840  return AST_TEST_NOT_RUN;
841  case TEST_EXECUTE:
842  break;
843  }
844 
845  /* quoted-text with backslash escaped quote */
846  after_dname = get_calleridname(in1, dname, sizeof(dname));
847  ast_test_status_update(test, "display-name1: %s\nafter: %s\n", dname, after_dname);
848  if (strcmp(dname, " quoted-text internal \" quote ")) {
849  ast_test_status_update(test, "display-name1 test failed\n");
850  res = AST_TEST_FAIL;
851  }
852 
853  /* token text */
854  after_dname = get_calleridname(in2, dname, sizeof(dname));
855  ast_test_status_update(test, "display-name2: %s\nafter: %s\n", dname, after_dname);
856  if (strcmp(dname, "token text with no quotes")) {
857  ast_test_status_update(test, "display-name2 test failed\n");
858  res = AST_TEST_FAIL;
859  }
860 
861  /* quoted-text buffer overflow */
862  after_dname = get_calleridname(overflow1, dname, sizeof(dname));
863  ast_test_status_update(test, "overflow display-name1: %s\nafter: %s\n", dname, after_dname);
864  if (strcmp(dname, "quoted-text overflow 123456789012345678")) {
865  ast_test_status_update(test, "overflow display-name1 test failed\n");
866  res = AST_TEST_FAIL;
867  }
868 
869  /* non-quoted-text buffer overflow */
870  after_dname = get_calleridname(overflow2, dname, sizeof(dname));
871  ast_test_status_update(test, "overflow display-name2: %s\nafter: %s\n", dname, after_dname);
872  if (strcmp(dname, "non-quoted text overflow 12345678901234")) {
873  ast_test_status_update(test, "overflow display-name2 test failed\n");
874  res = AST_TEST_FAIL;
875  }
876 
877  /* quoted-text buffer with no terminating end quote */
878  after_dname = get_calleridname(noendquote, dname, sizeof(dname));
879  ast_test_status_update(test, "noendquote display-name1: %s\nafter: %s\n", dname, after_dname);
880  if (*dname != '\0' && after_dname != noendquote) {
881  ast_test_status_update(test, "no end quote for quoted-text display-name failed\n");
882  res = AST_TEST_FAIL;
883  }
884 
885  /* addr-spec rather than display-name. */
886  after_dname = get_calleridname(addrspec, dname, sizeof(dname));
887  ast_test_status_update(test, "addr-spec display-name1: %s\nafter: %s\n", dname, after_dname);
888  if (*dname != '\0' && after_dname != addrspec) {
889  ast_test_status_update(test, "detection of addr-spec failed\n");
890  res = AST_TEST_FAIL;
891  }
892 
893  /* no quotes, no brackets */
894  after_dname = get_calleridname(no_quotes_no_brackets, dname, sizeof(dname));
895  ast_test_status_update(test, "no_quotes_no_brackets display-name1: %s\nafter: %s\n", dname, after_dname);
896  if (*dname != '\0' && after_dname != no_quotes_no_brackets) {
897  ast_test_status_update(test, "detection of addr-spec failed\n");
898  res = AST_TEST_FAIL;
899  }
900 
901  return res;
902 }
903 #endif
904 
905 int get_name_and_number(const char *hdr, char **name, char **number)
906 {
907  char header[256];
908  char tmp_name[256];
909  char *tmp_number = NULL;
910  char *hostport = NULL;
911  char *dummy = NULL;
912 
913  if (!name || !number || ast_strlen_zero(hdr)) {
914  return -1;
915  }
916 
917  *number = NULL;
918  *name = NULL;
919  ast_copy_string(header, hdr, sizeof(header));
920 
921  /* strip the display-name portion off the beginning of the header. */
922  get_calleridname(header, tmp_name, sizeof(tmp_name));
923 
924  /* get uri within < > brackets */
925  tmp_number = get_in_brackets(header);
926 
927  /* parse out the number here */
928  if (parse_uri(tmp_number, "sip:,sips:", &tmp_number, &dummy, &hostport, NULL) || ast_strlen_zero(tmp_number)) {
929  ast_log(LOG_ERROR, "can not parse name and number from sip header.\n");
930  return -1;
931  }
932 
933  /* number is not option, and must be present at this point */
934  *number = ast_strdup(tmp_number);
936 
937  /* name is optional and may not be present at this point */
938  if (!ast_strlen_zero(tmp_name)) {
939  *name = ast_strdup(tmp_name);
940  }
941 
942  return 0;
943 }
944 
945 #ifdef TEST_FRAMEWORK
946 AST_TEST_DEFINE(get_name_and_number_test)
947 {
948  int res = AST_TEST_PASS;
949  char *name = NULL;
950  char *number = NULL;
951  const char *in1 = "NAME <sip:NUMBER@place>";
952  const char *in2 = "\"NA><ME\" <sip:NUMBER@place>";
953  const char *in3 = "NAME";
954  const char *in4 = "<sip:NUMBER@place>";
955  const char *in5 = "This is a screwed up string <sip:LOLCLOWNS<sip:>@place>";
956 
957  switch (cmd) {
958  case TEST_INIT:
959  info->name = "sip_get_name_and_number_test";
960  info->category = "/channels/chan_sip/";
961  info->summary = "Tests getting name and number from sip header";
962  info->description =
963  "Runs through various test situations in which a name and "
964  "and number can be retrieved from a sip header.";
965  return AST_TEST_NOT_RUN;
966  case TEST_EXECUTE:
967  break;
968  }
969 
970  /* Test 1. get name and number */
971  number = name = NULL;
972  if ((get_name_and_number(in1, &name, &number)) ||
973  strcmp(name, "NAME") ||
974  strcmp(number, "NUMBER")) {
975 
976  ast_test_status_update(test, "Test 1, simple get name and number failed.\n");
977  res = AST_TEST_FAIL;
978  }
979  ast_free(name);
980  ast_free(number);
981 
982  /* Test 2. get quoted name and number */
983  number = name = NULL;
984  if ((get_name_and_number(in2, &name, &number)) ||
985  strcmp(name, "NA><ME") ||
986  strcmp(number, "NUMBER")) {
987 
988  ast_test_status_update(test, "Test 2, get quoted name and number failed.\n");
989  res = AST_TEST_FAIL;
990  }
991  ast_free(name);
992  ast_free(number);
993 
994  /* Test 3. name only */
995  number = name = NULL;
996  if (!(get_name_and_number(in3, &name, &number))) {
997 
998  ast_test_status_update(test, "Test 3, get name only was expected to fail but did not.\n");
999  res = AST_TEST_FAIL;
1000  }
1001  ast_free(name);
1002  ast_free(number);
1003 
1004  /* Test 4. number only */
1005  number = name = NULL;
1006  if ((get_name_and_number(in4, &name, &number)) ||
1007  !ast_strlen_zero(name) ||
1008  strcmp(number, "NUMBER")) {
1009 
1010  ast_test_status_update(test, "Test 4, get number with no name present failed.\n");
1011  res = AST_TEST_FAIL;
1012  }
1013  ast_free(name);
1014  ast_free(number);
1015 
1016  /* Test 5. malformed string, since number can not be parsed, this should return an error. */
1017  number = name = NULL;
1018  if (!(get_name_and_number(in5, &name, &number)) ||
1019  !ast_strlen_zero(name) ||
1020  !ast_strlen_zero(number)) {
1021 
1022  ast_test_status_update(test, "Test 5, processing malformed string failed.\n");
1023  res = AST_TEST_FAIL;
1024  }
1025  ast_free(name);
1026  ast_free(number);
1027 
1028  /* Test 6. NULL output parameters */
1029  number = name = NULL;
1030  if (!(get_name_and_number(in5, NULL, NULL))) {
1031 
1032  ast_test_status_update(test, "Test 6, NULL output parameters failed.\n");
1033  res = AST_TEST_FAIL;
1034  }
1035 
1036  /* Test 7. NULL input parameter */
1037  number = name = NULL;
1038  if (!(get_name_and_number(NULL, &name, &number)) ||
1039  !ast_strlen_zero(name) ||
1040  !ast_strlen_zero(number)) {
1041 
1042  ast_test_status_update(test, "Test 7, NULL input parameter failed.\n");
1043  res = AST_TEST_FAIL;
1044  }
1045  ast_free(name);
1046  ast_free(number);
1047 
1048  return res;
1049 }
1050 #endif
1051 
1052 int get_in_brackets_const(const char *src,const char **start,int *length)
1053 {
1054  const char *parse = src;
1055  const char *first_bracket;
1056  const char *second_bracket;
1057 
1058  if (start == NULL) {
1059  return -1;
1060  }
1061  if (length == NULL) {
1062  return -1;
1063  }
1064  *start = NULL;
1065  *length = -1;
1066  if (ast_strlen_zero(src)) {
1067  return 1;
1068  }
1069 
1070  /*
1071  * Skip any quoted text until we find the part in brackets.
1072  * On any error give up and return -1
1073  */
1074  while ( (first_bracket = strchr(parse, '<')) ) {
1075  const char *first_quote = strchr(parse, '"');
1076  first_bracket++;
1077  if (!first_quote || first_quote >= first_bracket) {
1078  break; /* no need to look at quoted part */
1079  }
1080  /* the bracket is within quotes, so ignore it */
1081  parse = find_closing_quote(first_quote + 1, NULL);
1082  if (!*parse) {
1083  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", src);
1084  return -1;
1085  }
1086  parse++;
1087  }
1088 
1089  /* Require a first bracket. Unlike get_in_brackets_full, this procedure is passed a const,
1090  * so it can expect a pointer to an original value */
1091  if (!first_bracket) {
1092  ast_log(LOG_WARNING, "No opening bracket found in '%s'\n", src);
1093  return 1;
1094  }
1095 
1096  if ((second_bracket = strchr(first_bracket, '>'))) {
1097  *start = first_bracket;
1098  *length = second_bracket - first_bracket;
1099  return 0;
1100  }
1101  ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", src);
1102  return -1;
1103 }
1104 
1105 int get_in_brackets_full(char *tmp,char **out,char **residue)
1106 {
1107  const char *parse = tmp;
1108  char *first_bracket;
1109  char *second_bracket;
1110 
1111  if (out) {
1112  *out = "";
1113  }
1114  if (residue) {
1115  *residue = "";
1116  }
1117 
1118  if (ast_strlen_zero(tmp)) {
1119  return 1;
1120  }
1121 
1122  /*
1123  * Skip any quoted text until we find the part in brackets.
1124  * On any error give up and return -1
1125  */
1126  while ( (first_bracket = strchr(parse, '<')) ) {
1127  char *first_quote = strchr(parse, '"');
1128  first_bracket++;
1129  if (!first_quote || first_quote >= first_bracket) {
1130  break; /* no need to look at quoted part */
1131  }
1132  /* the bracket is within quotes, so ignore it */
1133  parse = find_closing_quote(first_quote + 1, NULL);
1134  if (!*parse) {
1135  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp);
1136  return -1;
1137  }
1138  parse++;
1139  }
1140 
1141  /* If no first bracket then still look for a second bracket as some other parsing functions
1142  may overwrite first bracket with NULL when terminating a token based display-name. As this
1143  only affects token based display-names there is no danger of brackets being in quotes */
1144  if (first_bracket) {
1145  parse = first_bracket;
1146  } else {
1147  parse = tmp;
1148  }
1149 
1150  if ((second_bracket = strchr(parse, '>'))) {
1151  *second_bracket++ = '\0';
1152  if (out) {
1153  *out = (char *) parse;
1154  }
1155  if (residue) {
1156  *residue = second_bracket;
1157  }
1158  return 0;
1159  }
1160 
1161  if ((first_bracket)) {
1162  ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
1163  return -1;
1164  }
1165 
1166  if (out) {
1167  *out = tmp;
1168  }
1169 
1170  return 1;
1171 }
1172 
1173 char *get_in_brackets(char *tmp)
1174 {
1175  char *out;
1176 
1177  if ((get_in_brackets_full(tmp, &out, NULL))) {
1178  return tmp;
1179  }
1180  return out;
1181 }
1182 
1183 #ifdef TEST_FRAMEWORK
1184 AST_TEST_DEFINE(get_in_brackets_test)
1185 {
1186  int res = AST_TEST_PASS;
1187  char in_brackets[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
1188  char no_name[] = "<sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1189  char quoted_string[] = "\"I'm a quote stri><ng\" <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1190  char missing_end_quote[] = "\"I'm a quote string <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1191  char name_no_quotes[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1192  char no_end_bracket[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah";
1193  char no_name_no_brackets[] = "sip:name@host";
1194  char missing_start_bracket[] = "sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>";
1195  char *uri = NULL;
1196 
1197  switch (cmd) {
1198  case TEST_INIT:
1199  info->name = "sip_get_in_brackets_test";
1200  info->category = "/channels/chan_sip/";
1201  info->summary = "Tests getting a sip uri in <> brackets within a sip header.";
1202  info->description =
1203  "Runs through various test situations in which a sip uri "
1204  "in angle brackets needs to be retrieved";
1205  return AST_TEST_NOT_RUN;
1206  case TEST_EXECUTE:
1207  break;
1208  }
1209 
1210  /* Test 1, simple get in brackets */
1211  if (!(uri = get_in_brackets(no_name)) || strcmp(uri, in_brackets)) {
1212  ast_test_status_update(test, "Test 1, simple get in brackets failed. %s\n", uri);
1213  res = AST_TEST_FAIL;
1214  }
1215 
1216  /* Test 2, starts with quoted string */
1217  if (!(uri = get_in_brackets(quoted_string)) || strcmp(uri, in_brackets)) {
1218  ast_test_status_update(test, "Test 2, get in brackets with quoted string in front failed. %s\n", uri);
1219  res = AST_TEST_FAIL;
1220  }
1221 
1222  /* Test 3, missing end quote */
1223  if (!(uri = get_in_brackets(missing_end_quote)) || !strcmp(uri, in_brackets)) {
1224  ast_test_status_update(test, "Test 3, missing end quote failed. %s\n", uri);
1225  res = AST_TEST_FAIL;
1226  }
1227 
1228  /* Test 4, starts with a name not in quotes */
1229  if (!(uri = get_in_brackets(name_no_quotes)) || strcmp(uri, in_brackets)) {
1230  ast_test_status_update(test, "Test 4, passing name not in quotes failed. %s\n", uri);
1231  res = AST_TEST_FAIL;
1232  }
1233 
1234  /* Test 5, no end bracket, should just return everything after the first '<' */
1235  if (!(uri = get_in_brackets(no_end_bracket)) || !strcmp(uri, in_brackets)) {
1236  ast_test_status_update(test, "Test 5, no end bracket failed. %s\n", uri);
1237  res = AST_TEST_FAIL;
1238  }
1239 
1240  /* Test 6, NULL input */
1241  if (get_in_brackets(NULL)) {
1242  ast_test_status_update(test, "Test 6, NULL input failed.\n");
1243  res = AST_TEST_FAIL;
1244  }
1245 
1246  /* Test 7, no name, and no brackets. */
1247  if (!(uri = get_in_brackets(no_name_no_brackets)) || strcmp(uri, "sip:name@host")) {
1248  ast_test_status_update(test, "Test 7 failed. %s\n", uri);
1249  res = AST_TEST_FAIL;
1250  }
1251 
1252  /* Test 8, no start bracket, but with ending bracket. */
1253  if (!(uri = get_in_brackets(missing_start_bracket)) || strcmp(uri, in_brackets)) {
1254  ast_test_status_update(test, "Test 8 failed. %s\n", uri);
1255  res = AST_TEST_FAIL;
1256  }
1257 
1258  return res;
1259 }
1260 #endif
1261 
1262 int parse_name_andor_addr(char *uri, const char *scheme, char **name,
1263  char **user, char **pass, char **hostport,
1264  struct uriparams *params, char **headers,
1265  char **residue)
1266 {
1267  char buf[1024];
1268  char **residue2 = residue;
1269  char *orig_uri = uri;
1270  int ret;
1271 
1272  buf[0] = '\0';
1273  if (name) {
1274  uri = (char *) get_calleridname(uri, buf, sizeof(buf));
1275  }
1276  ret = get_in_brackets_full(uri, &uri, residue);
1277  if (ret == 0) {
1278  /*
1279  * The uri is in brackets so do not treat unknown trailing uri
1280  * parameters as potential message header parameters.
1281  */
1282  if (residue && **residue) {
1283  /* step over the first semicolon as per parse_uri_full residue */
1284  *residue = *residue + 1;
1285  }
1286  residue2 = NULL;
1287  }
1288 
1289  if (name) {
1290  if (buf[0]) {
1291  /*
1292  * There is always room at orig_uri for the display-name because
1293  * at least one character has always been removed. A '"' or '<'
1294  * has been removed.
1295  */
1296  strcpy(orig_uri, buf);
1297  *name = orig_uri;
1298  } else {
1299  *name = "";
1300  }
1301  }
1302 
1303  return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2);
1304 }
1305 
1306 #ifdef TEST_FRAMEWORK
1307 AST_TEST_DEFINE(parse_name_andor_addr_test)
1308 {
1309  int res = AST_TEST_PASS;
1310  char uri[1024];
1311  char *name, *user, *pass, *hostport, *headers, *residue;
1312  struct uriparams params;
1313 
1314  struct testdata {
1315  char *desc;
1316  char *uri;
1317  char *name;
1318  char *user;
1319  char *pass;
1320  char *hostport;
1321  char *headers;
1322  char *residue;
1323  struct uriparams params;
1324  AST_LIST_ENTRY(testdata) list;
1325  };
1326 
1327  struct testdata *testdataptr;
1328 
1329  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1330 
1331  struct testdata td1 = {
1332  .desc = "quotes and brackets",
1333  .uri = "\"name :@ \" <sip:user:secret@host:5060;param=discard;transport=tcp>;tag=tag",
1334  .name = "name :@ ",
1335  .user = "user",
1336  .pass = "secret",
1337  .hostport = "host:5060",
1338  .headers = "",
1339  .residue = "tag=tag",
1340  .params.transport = "tcp",
1341  .params.lr = 0,
1342  .params.user = ""
1343  };
1344 
1345  struct testdata td2 = {
1346  .desc = "no quotes",
1347  .uri = "givenname familyname <sip:user:secret@host:5060;param=discard;transport=tcp>;expires=3600",
1348  .name = "givenname familyname",
1349  .user = "user",
1350  .pass = "secret",
1351  .hostport = "host:5060",
1352  .headers = "",
1353  .residue = "expires=3600",
1354  .params.transport = "tcp",
1355  .params.lr = 0,
1356  .params.user = ""
1357  };
1358 
1359  struct testdata td3 = {
1360  .desc = "no brackets",
1361  .uri = "sip:user:secret@host:5060;param=discard;transport=tcp;q=1",
1362  .name = "",
1363  .user = "user",
1364  .pass = "secret",
1365  .hostport = "host:5060",
1366  .headers = "",
1367  .residue = "q=1",
1368  .params.transport = "tcp",
1369  .params.lr = 0,
1370  .params.user = ""
1371  };
1372 
1373  struct testdata td4 = {
1374  .desc = "just host",
1375  .uri = "sips:host",
1376  .name = "",
1377  .user = "",
1378  .pass = "",
1379  .hostport = "host",
1380  .headers = "",
1381  .residue = "",
1382  .params.transport = "",
1383  .params.lr = 0,
1384  .params.user = ""
1385  };
1386 
1387 
1388  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
1389  AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
1390  AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
1391  AST_LIST_INSERT_TAIL(&testdatalist, &td4, list);
1392 
1393 
1394  switch (cmd) {
1395  case TEST_INIT:
1396  info->name = "parse_name_andor_addr_test";
1397  info->category = "/channels/chan_sip/";
1398  info->summary = "tests parsing of name_andor_addr abnf structure";
1399  info->description =
1400  "Tests parsing of abnf name-andor-addr = name-addr / addr-spec "
1401  "Verifies output matches expected behavior.";
1402  return AST_TEST_NOT_RUN;
1403  case TEST_EXECUTE:
1404  break;
1405  }
1406 
1407  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1408  name = user = pass = hostport = headers = residue = NULL;
1409  params.transport = params.user = params.method = params.ttl = params.maddr = NULL;
1410  params.lr = 0;
1411  ast_copy_string(uri,testdataptr->uri,sizeof(uri));
1412  if (parse_name_andor_addr(uri, "sip:,sips:",
1413  &name,
1414  &user,
1415  &pass,
1416  &hostport,
1417  &params,
1418  &headers,
1419  &residue) ||
1420  (name && strcmp(testdataptr->name, name)) ||
1421  (user && strcmp(testdataptr->user, user)) ||
1422  (pass && strcmp(testdataptr->pass, pass)) ||
1423  (hostport && strcmp(testdataptr->hostport, hostport)) ||
1424  (headers && strcmp(testdataptr->headers, headers)) ||
1425  (residue && strcmp(testdataptr->residue, residue)) ||
1426  (strcmp(testdataptr->params.transport,params.transport)) ||
1427  (strcmp(testdataptr->params.user,params.user))
1428  ) {
1429  ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1430  res = AST_TEST_FAIL;
1431  }
1432  }
1433 
1434  return res;
1435 }
1436 #endif
1437 
1438 int get_comma(char *in, char **out)
1439 {
1440  char *c;
1441  char *parse = in;
1442  if (out) {
1443  *out = in;
1444  }
1445 
1446  /* Skip any quoted text */
1447  while (*parse) {
1448  if ((c = strchr(parse, '"'))) {
1449  in = (char *)find_closing_quote((const char *)c + 1, NULL);
1450  if (!*in) {
1451  ast_log(LOG_WARNING, "No closing quote found in '%s'\n", c);
1452  return -1;
1453  } else {
1454  break;
1455  }
1456  } else {
1457  break;
1458  }
1459  parse++;
1460  }
1461  parse = in;
1462 
1463  /* Skip any userinfo components of a uri as they may contain commas */
1464  if ((c = strchr(parse,'@'))) {
1465  parse = c+1;
1466  }
1467  if ((out) && (c = strchr(parse,','))) {
1468  *c++ = '\0';
1469  *out = c;
1470  return 0;
1471  }
1472  return 1;
1473 }
1474 
1475 int parse_contact_header(char *contactheader, struct contactliststruct *contactlist)
1476 {
1477  int res;
1478  int last;
1479  char *comma;
1480  char *residue;
1481  char *param;
1482  char *value;
1483  struct contact *split_contact = NULL;
1484 
1485  if (*contactheader == '*') {
1486  return 1;
1487  }
1488 
1489  split_contact = ast_calloc(1, sizeof(*split_contact));
1490 
1491  AST_LIST_HEAD_SET_NOLOCK(contactlist, split_contact);
1492  while ((last = get_comma(contactheader, &comma)) != -1) {
1493  res = parse_name_andor_addr(contactheader, "sip:,sips:",
1494  &split_contact->name, &split_contact->user,
1495  &split_contact->pass, &split_contact->hostport,
1496  &split_contact->params, &split_contact->headers,
1497  &residue);
1498  if (res == -1) {
1499  return res;
1500  }
1501 
1502  /* parse contact params */
1503  split_contact->expires = split_contact->q = "";
1504 
1505  while ((value = strchr(residue,'='))) {
1506  *value++ = '\0';
1507 
1508  param = residue;
1509  if ((residue = strchr(value,';'))) {
1510  *residue++ = '\0';
1511  } else {
1512  residue = "";
1513  }
1514 
1515  if (!strcmp(param,"expires")) {
1516  split_contact->expires = value;
1517  } else if (!strcmp(param,"q")) {
1518  split_contact->q = value;
1519  }
1520  }
1521 
1522  if (last) {
1523  return 0;
1524  }
1525  contactheader = comma;
1526 
1527  split_contact = ast_calloc(1, sizeof(*split_contact));
1528  AST_LIST_INSERT_TAIL(contactlist, split_contact, list);
1529  }
1530  return last;
1531 }
1532 
1533 #ifdef TEST_FRAMEWORK
1534 AST_TEST_DEFINE(parse_contact_header_test)
1535 {
1536  int res = AST_TEST_PASS;
1537  char contactheader[1024];
1538  int star;
1539  struct contactliststruct contactlist;
1540  struct contactliststruct *contactlistptr=&contactlist;
1541 
1542  struct testdata {
1543  char *desc;
1544  char *contactheader;
1545  int star;
1546  struct contactliststruct *contactlist;
1547 
1548  AST_LIST_ENTRY(testdata) list;
1549  };
1550 
1551  struct testdata *testdataptr;
1552  struct contact *tdcontactptr;
1553  struct contact *contactptr;
1554 
1555  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1556  struct contactliststruct contactlist1, contactlist2;
1557 
1558  struct testdata td1 = {
1559  .desc = "single contact",
1560  .contactheader = "\"name :@;?&,\" <sip:user:secret@host:5082;param=discard;transport=tcp>;expires=3600",
1561  .contactlist = &contactlist1,
1562  .star = 0
1563  };
1564  struct contact contact11 = {
1565  .name = "name :@;?&,",
1566  .user = "user",
1567  .pass = "secret",
1568  .hostport = "host:5082",
1569  .params.transport = "tcp",
1570  .params.ttl = "",
1571  .params.lr = 0,
1572  .headers = "",
1573  .expires = "3600",
1574  .q = ""
1575  };
1576 
1577  struct testdata td2 = {
1578  .desc = "multiple contacts",
1579  .contactheader = "sip:,user1,:,secret1,@host1;ttl=7;q=1;expires=3600,sips:host2",
1580  .contactlist = &contactlist2,
1581  .star = 0,
1582  };
1583  struct contact contact21 = {
1584  .name = "",
1585  .user = ",user1,",
1586  .pass = ",secret1,",
1587  .hostport = "host1",
1588  .params.transport = "",
1589  .params.ttl = "7",
1590  .params.lr = 0,
1591  .headers = "",
1592  .expires = "3600",
1593  .q = "1"
1594  };
1595  struct contact contact22 = {
1596  .name = "",
1597  .user = "",
1598  .pass = "",
1599  .hostport = "host2",
1600  .params.transport = "",
1601  .params.ttl = "",
1602  .params.lr = 0,
1603  .headers = "",
1604  .expires = "",
1605  .q = ""
1606  };
1607 
1608  struct testdata td3 = {
1609  .desc = "star - all contacts",
1610  .contactheader = "*",
1611  .star = 1,
1612  .contactlist = NULL
1613  };
1614 
1615  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &td1);
1616  AST_LIST_INSERT_TAIL(&testdatalist, &td2, list);
1617  AST_LIST_INSERT_TAIL(&testdatalist, &td3, list);
1618 
1619  AST_LIST_HEAD_SET_NOLOCK(&contactlist1, &contact11);
1620 
1621  AST_LIST_HEAD_SET_NOLOCK(&contactlist2, &contact21);
1622  AST_LIST_INSERT_TAIL(&contactlist2, &contact22, list);
1623 
1624 
1625  switch (cmd) {
1626  case TEST_INIT:
1627  info->name = "parse_contact_header_test";
1628  info->category = "/channels/chan_sip/";
1629  info->summary = "tests parsing of sip contact header";
1630  info->description =
1631  "Tests parsing of a contact header including those with multiple contacts "
1632  "Verifies output matches expected behavior.";
1633  return AST_TEST_NOT_RUN;
1634  case TEST_EXECUTE:
1635  break;
1636  }
1637 
1638  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1639  ast_copy_string(contactheader,testdataptr->contactheader,sizeof(contactheader));
1640  star = parse_contact_header(contactheader,contactlistptr);
1641  if (testdataptr->star) {
1642  /* expecting star rather than list of contacts */
1643  if (!star) {
1644  ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1645  res = AST_TEST_FAIL;
1646  break;
1647  }
1648  } else {
1649  contactptr = AST_LIST_FIRST(contactlistptr);
1650  AST_LIST_TRAVERSE(testdataptr->contactlist, tdcontactptr, list) {
1651  if (!contactptr ||
1652  strcmp(tdcontactptr->name, contactptr->name) ||
1653  strcmp(tdcontactptr->user, contactptr->user) ||
1654  strcmp(tdcontactptr->pass, contactptr->pass) ||
1655  strcmp(tdcontactptr->hostport, contactptr->hostport) ||
1656  strcmp(tdcontactptr->headers, contactptr->headers) ||
1657  strcmp(tdcontactptr->expires, contactptr->expires) ||
1658  strcmp(tdcontactptr->q, contactptr->q) ||
1659  strcmp(tdcontactptr->params.transport, contactptr->params.transport) ||
1660  strcmp(tdcontactptr->params.ttl, contactptr->params.ttl) ||
1661  (tdcontactptr->params.lr != contactptr->params.lr)
1662  ) {
1663  ast_test_status_update(test, "Sub-Test: %s,failed.\n", testdataptr->desc);
1664  res = AST_TEST_FAIL;
1665  break;
1666  }
1667 
1668  contactptr = AST_LIST_NEXT(contactptr,list);
1669  }
1670 
1671  while ((contactptr = AST_LIST_REMOVE_HEAD(contactlistptr,list))) {
1672  ast_free(contactptr);
1673  }
1674  }
1675  }
1676 
1677  return res;
1678 }
1679 #endif
1680 
1681 /*!
1682  * \brief Parse supported header in incoming packet
1683  *
1684  * \details This function parses through the options parameters and
1685  * builds a bit field representing all the SIP options in that field. When an
1686  * item is found that is not supported, it is copied to the unsupported
1687  * out buffer.
1688  *
1689  * \param options list
1690  * \param unsupported out buffer (optional)
1691  * \param unsupported_len out buffer length (optional)
1692  */
1693 unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len)
1694 {
1695  char *next, *sep;
1696  char *temp;
1697  int i, found, supported;
1698  unsigned int profile = 0;
1699 
1700  char *out = unsupported;
1701  size_t outlen = unsupported_len;
1702  char *cur_out = out;
1703 
1704  if (ast_strlen_zero(options) )
1705  return 0;
1706 
1707  temp = ast_strdupa(options);
1708 
1709  ast_debug(3, "Begin: parsing SIP \"Supported: %s\"\n", options);
1710  for (next = temp; next; next = sep) {
1711  found = FALSE;
1712  supported = FALSE;
1713  if ((sep = strchr(next, ',')) != NULL) {
1714  *sep++ = '\0';
1715  }
1716 
1717  /* trim leading and trailing whitespace */
1718  next = ast_strip(next);
1719 
1720  if (ast_strlen_zero(next)) {
1721  continue; /* if there is a blank argument in there just skip it */
1722  }
1723 
1724  ast_debug(3, "Found SIP option: -%s-\n", next);
1725  for (i = 0; i < ARRAY_LEN(sip_options); i++) {
1726  if (!strcasecmp(next, sip_options[i].text)) {
1727  profile |= sip_options[i].id;
1728  if (sip_options[i].supported == SUPPORTED) {
1729  supported = TRUE;
1730  }
1731  found = TRUE;
1732  ast_debug(3, "Matched SIP option: %s\n", next);
1733  break;
1734  }
1735  }
1736 
1737  /* If option is not supported, add to unsupported out buffer */
1738  if (!supported && out && outlen) {
1739  size_t copylen = strlen(next);
1740  size_t cur_outlen = strlen(out);
1741  /* Check to see if there is enough room to store this option.
1742  * Copy length is string length plus 2 for the ',' and '\0' */
1743  if ((cur_outlen + copylen + 2) < outlen) {
1744  /* if this isn't the first item, add the ',' */
1745  if (cur_outlen) {
1746  *cur_out = ',';
1747  cur_out++;
1748  cur_outlen++;
1749  }
1750  ast_copy_string(cur_out, next, (outlen - cur_outlen));
1751  cur_out += copylen;
1752  }
1753  }
1754 
1755  if (!found) {
1756  profile |= SIP_OPT_UNKNOWN;
1757  if (!strncasecmp(next, "x-", 2))
1758  ast_debug(3, "Found private SIP option, not supported: %s\n", next);
1759  else
1760  ast_debug(3, "Found no match for SIP option: %s (Please file bug report!)\n", next);
1761  }
1762  }
1763 
1764  return profile;
1765 }
1766 
1767 #ifdef TEST_FRAMEWORK
1768 AST_TEST_DEFINE(sip_parse_options_test)
1769 {
1770  int res = AST_TEST_PASS;
1771  char unsupported[64];
1772  unsigned int option_profile = 0;
1773  struct testdata {
1774  char *name;
1775  char *input_options;
1776  char *expected_unsupported;
1777  unsigned int expected_profile;
1778  AST_LIST_ENTRY(testdata) list;
1779  };
1780 
1781  struct testdata *testdataptr;
1782  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
1783 
1784  struct testdata test1 = {
1785  .name = "test_all_unsupported",
1786  .input_options = "unsupported1,,, ,unsupported2,unsupported3,unsupported4",
1787  .expected_unsupported = "unsupported1,unsupported2,unsupported3,unsupported4",
1788  .expected_profile = SIP_OPT_UNKNOWN,
1789  };
1790  struct testdata test2 = {
1791  .name = "test_all_unsupported_one_supported",
1792  .input_options = " unsupported1, replaces, unsupported3 , , , ,unsupported4",
1793  .expected_unsupported = "unsupported1,unsupported3,unsupported4",
1794  .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES
1795  };
1796  struct testdata test3 = {
1797  .name = "test_two_supported_two_unsupported",
1798  .input_options = ",, timer ,replaces ,unsupported3,unsupported4",
1799  .expected_unsupported = "unsupported3,unsupported4",
1800  .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
1801  };
1802 
1803  struct testdata test4 = {
1804  .name = "test_all_supported",
1805  .input_options = "timer,replaces",
1806  .expected_unsupported = "",
1807  .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
1808  };
1809 
1810  struct testdata test5 = {
1811  .name = "test_all_supported_redundant",
1812  .input_options = "timer,replaces,timer,replace,timer,replaces",
1813  .expected_unsupported = "",
1814  .expected_profile = SIP_OPT_REPLACES | SIP_OPT_TIMER,
1815  };
1816  struct testdata test6 = {
1817  .name = "test_buffer_overflow",
1818  .input_options = "unsupported1,replaces,timer,unsupported4,unsupported_huge____"
1819  "____________________________________,__________________________________________"
1820  "________________________________________________",
1821  .expected_unsupported = "unsupported1,unsupported4",
1822  .expected_profile = SIP_OPT_UNKNOWN | SIP_OPT_REPLACES | SIP_OPT_TIMER,
1823  };
1824  struct testdata test7 = {
1825  .name = "test_null_input",
1826  .input_options = NULL,
1827  .expected_unsupported = "",
1828  .expected_profile = 0,
1829  };
1830  struct testdata test8 = {
1831  .name = "test_whitespace_input",
1832  .input_options = " ",
1833  .expected_unsupported = "",
1834  .expected_profile = 0,
1835  };
1836  struct testdata test9 = {
1837  .name = "test_whitespace_plus_option_input",
1838  .input_options = " , , ,timer , , , , , ",
1839  .expected_unsupported = "",
1840  .expected_profile = SIP_OPT_TIMER,
1841  };
1842 
1843  switch (cmd) {
1844  case TEST_INIT:
1845  info->name = "sip_parse_options_test";
1846  info->category = "/channels/chan_sip/";
1847  info->summary = "Tests parsing of sip options";
1848  info->description =
1849  "Tests parsing of SIP options from supported and required "
1850  "header fields. Verifies when unsupported options are encountered "
1851  "that they are appended to the unsupported out buffer and that the "
1852  "correct bit field representnig the option profile is returned.";
1853  return AST_TEST_NOT_RUN;
1854  case TEST_EXECUTE:
1855  break;
1856  }
1857 
1858  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &test1);
1859  AST_LIST_INSERT_TAIL(&testdatalist, &test2, list);
1860  AST_LIST_INSERT_TAIL(&testdatalist, &test3, list);
1861  AST_LIST_INSERT_TAIL(&testdatalist, &test4, list);
1862  AST_LIST_INSERT_TAIL(&testdatalist, &test5, list);
1863  AST_LIST_INSERT_TAIL(&testdatalist, &test6, list);
1864  AST_LIST_INSERT_TAIL(&testdatalist, &test7, list);
1865  AST_LIST_INSERT_TAIL(&testdatalist, &test8, list);
1866  AST_LIST_INSERT_TAIL(&testdatalist, &test9, list);
1867 
1868  /* Test with unsupported char buffer */
1869  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
1870  memset(unsupported, 0, sizeof(unsupported));
1871  option_profile = parse_sip_options(testdataptr->input_options, unsupported, ARRAY_LEN(unsupported));
1872  if (option_profile != testdataptr->expected_profile ||
1873  strcmp(unsupported, testdataptr->expected_unsupported)) {
1874  ast_test_status_update(test, "Test with output buffer \"%s\", expected unsupported: %s actual unsupported:"
1875  "%s expected bit profile: %x actual bit profile: %x\n",
1876  testdataptr->name,
1877  testdataptr->expected_unsupported,
1878  unsupported,
1879  testdataptr->expected_profile,
1880  option_profile);
1881  res = AST_TEST_FAIL;
1882  } else {
1883  ast_test_status_update(test, "\"%s\" passed got expected unsupported: %s and bit profile: %x\n",
1884  testdataptr->name,
1885  unsupported,
1886  option_profile);
1887  }
1888 
1889  option_profile = parse_sip_options(testdataptr->input_options, NULL, 0);
1890  if (option_profile != testdataptr->expected_profile) {
1891  ast_test_status_update(test, "NULL output test \"%s\", expected bit profile: %x actual bit profile: %x\n",
1892  testdataptr->name,
1893  testdataptr->expected_profile,
1894  option_profile);
1895  res = AST_TEST_FAIL;
1896  } else {
1897  ast_test_status_update(test, "\"%s\" with NULL output buf passed, bit profile: %x\n",
1898  testdataptr->name,
1899  option_profile);
1900  }
1901  }
1902 
1903  return res;
1904 }
1905 #endif
1906 
1907 /*! \brief helper routine for sip_uri_cmp to compare URI parameters
1908  *
1909  * This takes the parameters from two SIP URIs and determines
1910  * if the URIs match. The rules for parameters *suck*. Here's a breakdown
1911  * 1. If a parameter appears in both URIs, then they must have the same value
1912  * in order for the URIs to match
1913  * 2. If one URI has a user, maddr, ttl, or method parameter, then the other
1914  * URI must also have that parameter and must have the same value
1915  * in order for the URIs to match
1916  * 3. All other headers appearing in only one URI are not considered when
1917  * determining if URIs match
1918  *
1919  * \param input1 Parameters from URI 1
1920  * \param input2 Parameters from URI 2
1921  * \retval 0 URIs' parameters match
1922  * \retval nonzero URIs' parameters do not match
1923  */
1924 static int sip_uri_params_cmp(const char *input1, const char *input2)
1925 {
1926  char *params1 = NULL;
1927  char *params2 = NULL;
1928  char *pos1;
1929  char *pos2;
1930  int zerolength1 = 0;
1931  int zerolength2 = 0;
1932  int maddrmatch = 0;
1933  int ttlmatch = 0;
1934  int usermatch = 0;
1935  int methodmatch = 0;
1936 
1937  if (ast_strlen_zero(input1)) {
1938  zerolength1 = 1;
1939  } else {
1940  params1 = ast_strdupa(input1);
1941  }
1942  if (ast_strlen_zero(input2)) {
1943  zerolength2 = 1;
1944  } else {
1945  params2 = ast_strdupa(input2);
1946  }
1947 
1948  /* Quick optimization. If both params are zero-length, then
1949  * they match
1950  */
1951  if (zerolength1 && zerolength2) {
1952  return 0;
1953  }
1954 
1955  for (pos1 = strsep(&params1, ";"); pos1; pos1 = strsep(&params1, ";")) {
1956  char *value1 = pos1;
1957  char *name1 = strsep(&value1, "=");
1958  char *params2dup = NULL;
1959  int matched = 0;
1960  if (!value1) {
1961  value1 = "";
1962  }
1963  /* Checkpoint reached. We have the name and value parsed for param1
1964  * We have to duplicate params2 each time through this loop
1965  * or else the inner loop below will not work properly.
1966  */
1967  if (!zerolength2) {
1968  params2dup = ast_strdupa(params2);
1969  }
1970  for (pos2 = strsep(&params2dup, ";"); pos2; pos2 = strsep(&params2dup, ";")) {
1971  char *name2 = pos2;
1972  char *value2 = strchr(pos2, '=');
1973  if (!value2) {
1974  value2 = "";
1975  } else {
1976  *value2++ = '\0';
1977  }
1978  if (!strcasecmp(name1, name2)) {
1979  if (strcasecmp(value1, value2)) {
1980  goto fail;
1981  } else {
1982  matched = 1;
1983  break;
1984  }
1985  }
1986  }
1987  /* Check to see if the parameter is one of the 'must-match' parameters */
1988  if (!strcasecmp(name1, "maddr")) {
1989  if (matched) {
1990  maddrmatch = 1;
1991  } else {
1992  goto fail;
1993  }
1994  } else if (!strcasecmp(name1, "ttl")) {
1995  if (matched) {
1996  ttlmatch = 1;
1997  } else {
1998  goto fail;
1999  }
2000  } else if (!strcasecmp(name1, "user")) {
2001  if (matched) {
2002  usermatch = 1;
2003  } else {
2004  goto fail;
2005  }
2006  } else if (!strcasecmp(name1, "method")) {
2007  if (matched) {
2008  methodmatch = 1;
2009  } else {
2010  goto fail;
2011  }
2012  }
2013  }
2014 
2015  /* We've made it out of that horrible O(m*n) construct and there are no
2016  * failures yet. We're not done yet, though, because params2 could have
2017  * an maddr, ttl, user, or method header and params1 did not.
2018  */
2019  for (pos2 = strsep(&params2, ";"); pos2; pos2 = strsep(&params2, ";")) {
2020  char *value2 = pos2;
2021  char *name2 = strsep(&value2, "=");
2022  if (!value2) {
2023  value2 = "";
2024  }
2025  if ((!strcasecmp(name2, "maddr") && !maddrmatch) ||
2026  (!strcasecmp(name2, "ttl") && !ttlmatch) ||
2027  (!strcasecmp(name2, "user") && !usermatch) ||
2028  (!strcasecmp(name2, "method") && !methodmatch)) {
2029  goto fail;
2030  }
2031  }
2032  return 0;
2033 
2034 fail:
2035  return 1;
2036 }
2037 
2038 /*! \brief helper routine for sip_uri_cmp to compare URI headers
2039  *
2040  * This takes the headers from two SIP URIs and determines
2041  * if the URIs match. The rules for headers is simple. If a header
2042  * appears in one URI, then it must also appear in the other URI. The
2043  * order in which the headers appear does not matter.
2044  *
2045  * \param input1 Headers from URI 1
2046  * \param input2 Headers from URI 2
2047  * \retval 0 URI headers match
2048  * \retval nonzero URI headers do not match
2049  */
2050 static int sip_uri_headers_cmp(const char *input1, const char *input2)
2051 {
2052  char *headers1 = NULL;
2053  char *headers2 = NULL;
2054  int zerolength1 = 0;
2055  int zerolength2 = 0;
2056  int different = 0;
2057  char *header1;
2058 
2059  if (ast_strlen_zero(input1)) {
2060  zerolength1 = 1;
2061  } else {
2062  headers1 = ast_strdupa(input1);
2063  }
2064 
2065  if (ast_strlen_zero(input2)) {
2066  zerolength2 = 1;
2067  } else {
2068  headers2 = ast_strdupa(input2);
2069  }
2070 
2071  /* If one URI contains no headers and the other
2072  * does, then they cannot possibly match
2073  */
2074  if (zerolength1 != zerolength2) {
2075  return 1;
2076  }
2077 
2078  if (zerolength1 && zerolength2)
2079  return 0;
2080 
2081  /* At this point, we can definitively state that both inputs are
2082  * not zero-length. First, one more optimization. If the length
2083  * of the headers is not equal, then we definitely have no match
2084  */
2085  if (strlen(headers1) != strlen(headers2)) {
2086  return 1;
2087  }
2088 
2089  for (header1 = strsep(&headers1, "&"); header1; header1 = strsep(&headers1, "&")) {
2090  if (!strcasestr(headers2, header1)) {
2091  different = 1;
2092  break;
2093  }
2094  }
2095 
2096  return different;
2097 }
2098 
2099 /*!
2100  * \brief Compare domain sections of SIP URIs
2101  *
2102  * For hostnames, a case insensitive string comparison is
2103  * used. For IP addresses, a binary comparison is used. This
2104  * is mainly because IPv6 addresses have many ways of writing
2105  * the same address.
2106  *
2107  * For specifics about IP address comparison, see the following
2108  * document: http://tools.ietf.org/html/draft-ietf-sip-ipv6-abnf-fix-05
2109  *
2110  * \param host1 The domain from the first URI
2111  * \param host2 THe domain from the second URI
2112  * \retval 0 The domains match
2113  * \retval nonzero The domains do not match
2114  */
2115 static int sip_uri_domain_cmp(const char *host1, const char *host2)
2116 {
2117  struct ast_sockaddr addr1;
2118  struct ast_sockaddr addr2;
2119  int addr1_parsed;
2120  int addr2_parsed;
2121 
2122  addr1_parsed = ast_sockaddr_parse(&addr1, host1, 0);
2123  addr2_parsed = ast_sockaddr_parse(&addr2, host2, 0);
2124 
2125  if (addr1_parsed != addr2_parsed) {
2126  /* One domain was an IP address and the other had
2127  * a host name. FAIL!
2128  */
2129  return 1;
2130  }
2131 
2132  /* Both are host names. A string comparison will work
2133  * perfectly here. Specifying the "C" locale ensures that
2134  * The LC_CTYPE conventions use those defined in ANSI C,
2135  * i.e. ASCII.
2136  */
2137  if (!addr1_parsed) {
2138 #ifdef HAVE_XLOCALE_H
2139  if(!c_locale) {
2140  return strcasecmp(host1, host2);
2141  } else {
2142  return strcasecmp_l(host1, host2, c_locale);
2143  }
2144 #else
2145  return strcasecmp(host1, host2);
2146 #endif
2147  }
2148 
2149  /* Both contain IP addresses */
2150  return ast_sockaddr_cmp(&addr1, &addr2);
2151 }
2152 
2153 int sip_uri_cmp(const char *input1, const char *input2)
2154 {
2155  char *uri1;
2156  char *uri2;
2157  char *uri_scheme1;
2158  char *uri_scheme2;
2159  char *host1;
2160  char *host2;
2161  char *params1;
2162  char *params2;
2163  char *headers1;
2164  char *headers2;
2165 
2166  /* XXX It would be really nice if we could just use parse_uri_full() here
2167  * to separate the components of the URI, but unfortunately it is written
2168  * in a way that can cause URI parameters to be discarded.
2169  */
2170 
2171  if (!input1 || !input2) {
2172  return 1;
2173  }
2174 
2175  uri1 = ast_strdupa(input1);
2176  uri2 = ast_strdupa(input2);
2177 
2180 
2181  uri_scheme1 = strsep(&uri1, ":");
2182  uri_scheme2 = strsep(&uri2, ":");
2183 
2184  if (strcmp(uri_scheme1, uri_scheme2)) {
2185  return 1;
2186  }
2187 
2188  /* This function is tailored for SIP and SIPS URIs. There's no
2189  * need to check uri_scheme2 since we have determined uri_scheme1
2190  * and uri_scheme2 are equivalent already.
2191  */
2192  if (strcmp(uri_scheme1, "sip") && strcmp(uri_scheme1, "sips")) {
2193  return 1;
2194  }
2195 
2196  if (ast_strlen_zero(uri1) || ast_strlen_zero(uri2)) {
2197  return 1;
2198  }
2199 
2200  if ((host1 = strchr(uri1, '@'))) {
2201  *host1++ = '\0';
2202  }
2203  if ((host2 = strchr(uri2, '@'))) {
2204  *host2++ = '\0';
2205  }
2206 
2207  /* Check for mismatched username and passwords. This is the
2208  * only case-sensitive comparison of a SIP URI
2209  */
2210  if ((host1 && !host2) ||
2211  (host2 && !host1) ||
2212  (host1 && host2 && strcmp(uri1, uri2))) {
2213  return 1;
2214  }
2215 
2216  if (!host1) {
2217  host1 = uri1;
2218  }
2219  if (!host2) {
2220  host2 = uri2;
2221  }
2222 
2223  /* Strip off the parameters and headers so we can compare
2224  * host and port
2225  */
2226 
2227  if ((params1 = strchr(host1, ';'))) {
2228  *params1++ = '\0';
2229  }
2230  if ((params2 = strchr(host2, ';'))) {
2231  *params2++ = '\0';
2232  }
2233 
2234  /* Headers come after parameters, but there may be headers without
2235  * parameters, thus the S_OR
2236  */
2237  if ((headers1 = strchr(S_OR(params1, host1), '?'))) {
2238  *headers1++ = '\0';
2239  }
2240  if ((headers2 = strchr(S_OR(params2, host2), '?'))) {
2241  *headers2++ = '\0';
2242  }
2243 
2244  if (sip_uri_domain_cmp(host1, host2)) {
2245  return 1;
2246  }
2247 
2248  /* Headers have easier rules to follow, so do those first */
2249  if (sip_uri_headers_cmp(headers1, headers2)) {
2250  return 1;
2251  }
2252 
2253  /* And now the parameters. Ugh */
2254  return sip_uri_params_cmp(params1, params2);
2255 }
2256 
2257 #define URI_CMP_MATCH 0
2258 #define URI_CMP_NOMATCH 1
2259 
2260 #ifdef TEST_FRAMEWORK
2261 AST_TEST_DEFINE(sip_uri_cmp_test)
2262 {
2263  static const struct {
2264  const char *uri1;
2265  const char *uri2;
2266  int expected_result;
2267  } uri_cmp_tests [] = {
2268  /* These are identical, so they match */
2270  /* Different usernames. No match */
2272  /* Different hosts. No match */
2274  /* Now start using IP addresses. Identical, so they match */
2276  /* Two identical IPv4 addresses represented differently. Match */
2278  /* Logically equivalent IPv4 Address and hostname. No Match */
2279  { "sip:[email protected]", "sip:bob@localhost", URI_CMP_NOMATCH },
2280  /* Logically equivalent IPv6 address and hostname. No Match */
2281  { "sip:bob@[::1]", "sip:bob@localhost", URI_CMP_NOMATCH },
2282  /* Try an IPv6 one as well */
2283  { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:db8::1234]", URI_CMP_MATCH },
2284  /* Two identical IPv6 addresses represented differently. Match */
2285  { "sip:bob@[2001:db8::1234]", "sip:bob@[2001:0db8::1234]", URI_CMP_MATCH },
2286  /* Different ports. No match */
2287  { "sip:[email protected]:5060", "sip:[email protected]:5061", URI_CMP_NOMATCH },
2288  /* Same port logically, but only one address specifies it. No match */
2289  { "sip:[email protected]:5060", "sip:[email protected]", URI_CMP_NOMATCH },
2290  /* And for safety, try with IPv6 */
2291  { "sip:bob@[2001:db8:1234]:5060", "sip:bob@[2001:db8:1234]", URI_CMP_NOMATCH },
2292  /* User comparison is case sensitive. No match */
2294  /* Host comparison is case insensitive. Match */
2296  /* Add headers to the URI. Identical, so they match */
2297  { "sip:[email protected]?header1=value1&header2=value2", "sip:[email protected]?header1=value1&header2=value2", URI_CMP_MATCH },
2298  /* Headers in URI 1 are not in URI 2. No Match */
2299  { "sip:[email protected]?header1=value1&header2=value2", "sip:[email protected]", URI_CMP_NOMATCH },
2300  /* Header present in both URIs does not have matching values. No match */
2301  { "sip:[email protected]?header1=value1&header2=value2", "sip:[email protected]?header1=value1&header2=value3", URI_CMP_NOMATCH },
2302  /* Add parameters to the URI. Identical so they match */
2303  { "sip:[email protected];param1=value1;param2=value2", "sip:[email protected];param1=value1;param2=value2", URI_CMP_MATCH },
2304  /* Same parameters in both URIs but appear in different order. Match */
2305  { "sip:[email protected];param2=value2;param1=value1", "sip:[email protected];param1=value1;param2=value2", URI_CMP_MATCH },
2306  /* params in URI 1 are not in URI 2. Match */
2307  { "sip:[email protected];param1=value1;param2=value2", "sip:[email protected]", URI_CMP_MATCH },
2308  /* param present in both URIs does not have matching values. No match */
2309  { "sip:[email protected];param1=value1;param2=value2", "sip:[email protected];param1=value1;param2=value3", URI_CMP_NOMATCH },
2310  /* URI 1 has a maddr param but URI 2 does not. No match */
2311  { "sip:[email protected];param1=value1;maddr=192.168.0.1", "sip:[email protected];param1=value1", URI_CMP_NOMATCH },
2312  /* URI 1 and URI 2 both have identical maddr params. Match */
2313  { "sip:[email protected];param1=value1;maddr=192.168.0.1", "sip:[email protected];param1=value1;maddr=192.168.0.1", URI_CMP_MATCH },
2314  /* URI 1 is a SIPS URI and URI 2 is a SIP URI. No Match */
2316  /* No URI schemes. No match */
2318  /* Crashiness tests. Just an address scheme. No match */
2319  { "sip", "sips", URI_CMP_NOMATCH },
2320  /* Still just an address scheme. Even though they're the same, No match */
2321  { "sip", "sip", URI_CMP_NOMATCH },
2322  /* Empty strings. No match */
2323  { "", "", URI_CMP_NOMATCH },
2324  /* An empty string and a NULL. No match */
2325  { "", NULL, URI_CMP_NOMATCH },
2326  };
2327  int i;
2328  int test_res = AST_TEST_PASS;
2329  switch (cmd) {
2330  case TEST_INIT:
2331  info->name = "sip_uri_cmp_test";
2332  info->category = "/channels/chan_sip/";
2333  info->summary = "Tests comparison of SIP URIs";
2334  info->description = "Several would-be tricky URI comparisons are performed";
2335  return AST_TEST_NOT_RUN;
2336  case TEST_EXECUTE:
2337  break;
2338  }
2339 
2340  for (i = 0; i < ARRAY_LEN(uri_cmp_tests); ++i) {
2341  int cmp_res1;
2342  int cmp_res2;
2343  if ((cmp_res1 = sip_uri_cmp(uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2))) {
2344  /* URI comparison may return -1 or +1 depending on the failure. Standardize
2345  * the return value to be URI_CMP_NOMATCH on any failure
2346  */
2347  cmp_res1 = URI_CMP_NOMATCH;
2348  }
2349  if (cmp_res1 != uri_cmp_tests[i].expected_result) {
2350  ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
2351  "Expected %s but got %s\n", uri_cmp_tests[i].uri1, uri_cmp_tests[i].uri2,
2352  uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
2353  cmp_res1 == URI_CMP_MATCH ? "Match" : "No Match");
2354  test_res = AST_TEST_FAIL;
2355  }
2356 
2357  /* All URI comparisons are commutative, so for the sake of being thorough, we'll
2358  * rerun the comparison with the parameters reversed
2359  */
2360  if ((cmp_res2 = sip_uri_cmp(uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1))) {
2361  /* URI comparison may return -1 or +1 depending on the failure. Standardize
2362  * the return value to be URI_CMP_NOMATCH on any failure
2363  */
2364  cmp_res2 = URI_CMP_NOMATCH;
2365  }
2366  if (cmp_res2 != uri_cmp_tests[i].expected_result) {
2367  ast_test_status_update(test, "Unexpected comparison result for URIs %s and %s. "
2368  "Expected %s but got %s\n", uri_cmp_tests[i].uri2, uri_cmp_tests[i].uri1,
2369  uri_cmp_tests[i].expected_result == URI_CMP_MATCH ? "Match" : "No Match",
2370  cmp_res2 == URI_CMP_MATCH ? "Match" : "No Match");
2371  test_res = AST_TEST_FAIL;
2372  }
2373  }
2374 
2375  return test_res;
2376 }
2377 #endif
2378 
2379 void free_via(struct sip_via *v)
2380 {
2381  if (!v) {
2382  return;
2383  }
2384 
2385  ast_free(v->via);
2386  ast_free(v);
2387 }
2388 
2389 struct sip_via *parse_via(const char *header)
2390 {
2391  struct sip_via *v = ast_calloc(1, sizeof(*v));
2392  char *via, *parm;
2393 
2394  if (!v) {
2395  return NULL;
2396  }
2397 
2398  v->via = ast_strdup(header);
2399  v->ttl = 1;
2400 
2401  via = v->via;
2402 
2403  if (ast_strlen_zero(via)) {
2404  ast_log(LOG_ERROR, "received request without a Via header\n");
2405  free_via(v);
2406  return NULL;
2407  }
2408 
2409  /* seperate the first via-parm */
2410  via = strsep(&via, ",");
2411 
2412  /* chop off sent-protocol */
2413  v->protocol = strsep(&via, " \t\r\n");
2414  if (ast_strlen_zero(v->protocol)) {
2415  ast_log(LOG_ERROR, "missing sent-protocol in Via header\n");
2416  free_via(v);
2417  return NULL;
2418  }
2420 
2421  if (via) {
2422  via = ast_skip_blanks(via);
2423  }
2424 
2425  /* chop off sent-by */
2426  v->sent_by = strsep(&via, "; \t\r\n");
2427  if (ast_strlen_zero(v->sent_by)) {
2428  ast_log(LOG_ERROR, "missing sent-by in Via header\n");
2429  free_via(v);
2430  return NULL;
2431  }
2432  v->sent_by = ast_skip_blanks(v->sent_by);
2433 
2434  /* store the port, we have to handle ipv6 addresses containing ':'
2435  * characters gracefully */
2436  if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (!(parm = strchr(v->sent_by, ']')) && (parm = strchr(v->sent_by, ':')))) {
2437  char *endptr;
2438 
2439  v->port = strtol(++parm, &endptr, 10);
2440  }
2441 
2442  /* evaluate any via-parms */
2443  while ((parm = strsep(&via, "; \t\r\n"))) {
2444  char *c;
2445  if ((c = strstr(parm, "maddr="))) {
2446  v->maddr = ast_skip_blanks(c + sizeof("maddr=") - 1);
2447  } else if ((c = strstr(parm, "branch="))) {
2448  v->branch = ast_skip_blanks(c + sizeof("branch=") - 1);
2449  } else if ((c = strstr(parm, "ttl="))) {
2450  char *endptr;
2451  c = ast_skip_blanks(c + sizeof("ttl=") - 1);
2452  v->ttl = strtol(c, &endptr, 10);
2453 
2454  /* make sure we got a valid ttl value */
2455  if (c == endptr) {
2456  v->ttl = 1;
2457  }
2458  }
2459  }
2460 
2461  return v;
2462 }
2463 
2464 #ifdef TEST_FRAMEWORK
2465 AST_TEST_DEFINE(parse_via_test)
2466 {
2467  int res = AST_TEST_PASS;
2468  int i = 1;
2469  struct sip_via *via;
2470  struct testdata {
2471  char *in;
2472  char *expected_protocol;
2473  char *expected_branch;
2474  char *expected_sent_by;
2475  char *expected_maddr;
2476  unsigned int expected_port;
2477  unsigned char expected_ttl;
2478  int expected_null;
2479  AST_LIST_ENTRY(testdata) list;
2480  };
2481  struct testdata *testdataptr;
2482  static AST_LIST_HEAD_NOLOCK(testdataliststruct, testdata) testdatalist;
2483  struct testdata t1 = {
2484  .in = "SIP/2.0/UDP host:port;branch=thebranch",
2485  .expected_protocol = "SIP/2.0/UDP",
2486  .expected_sent_by = "host:port",
2487  .expected_branch = "thebranch",
2488  };
2489  struct testdata t2 = {
2490  .in = "SIP/2.0/UDP host:port",
2491  .expected_protocol = "SIP/2.0/UDP",
2492  .expected_sent_by = "host:port",
2493  .expected_branch = "",
2494  };
2495  struct testdata t3 = {
2496  .in = "SIP/2.0/UDP",
2497  .expected_null = 1,
2498  };
2499  struct testdata t4 = {
2500  .in = "BLAH/BLAH/BLAH host:port;branch=",
2501  .expected_protocol = "BLAH/BLAH/BLAH",
2502  .expected_sent_by = "host:port",
2503  .expected_branch = "",
2504  };
2505  struct testdata t5 = {
2506  .in = "SIP/2.0/UDP host:5060;branch=thebranch;maddr=224.0.0.1;ttl=1",
2507  .expected_protocol = "SIP/2.0/UDP",
2508  .expected_sent_by = "host:5060",
2509  .expected_port = 5060,
2510  .expected_branch = "thebranch",
2511  .expected_maddr = "224.0.0.1",
2512  .expected_ttl = 1,
2513  };
2514  struct testdata t6 = {
2515  .in = "SIP/2.0/UDP host:5060;\n branch=thebranch;\r\n maddr=224.0.0.1; ttl=1",
2516  .expected_protocol = "SIP/2.0/UDP",
2517  .expected_sent_by = "host:5060",
2518  .expected_port = 5060,
2519  .expected_branch = "thebranch",
2520  .expected_maddr = "224.0.0.1",
2521  .expected_ttl = 1,
2522  };
2523  struct testdata t7 = {
2524  .in = "SIP/2.0/UDP [::1]:5060",
2525  .expected_protocol = "SIP/2.0/UDP",
2526  .expected_sent_by = "[::1]:5060",
2527  .expected_port = 5060,
2528  .expected_branch = "",
2529  };
2530  switch (cmd) {
2531  case TEST_INIT:
2532  info->name = "parse_via_test";
2533  info->category = "/channels/chan_sip/";
2534  info->summary = "Tests parsing the Via header";
2535  info->description =
2536  "Runs through various test situations in which various "
2537  " parameters parameter must be extracted from a VIA header";
2538  return AST_TEST_NOT_RUN;
2539  case TEST_EXECUTE:
2540  break;
2541  }
2542 
2543  AST_LIST_HEAD_SET_NOLOCK(&testdatalist, &t1);
2544  AST_LIST_INSERT_TAIL(&testdatalist, &t2, list);
2545  AST_LIST_INSERT_TAIL(&testdatalist, &t3, list);
2546  AST_LIST_INSERT_TAIL(&testdatalist, &t4, list);
2547  AST_LIST_INSERT_TAIL(&testdatalist, &t5, list);
2548  AST_LIST_INSERT_TAIL(&testdatalist, &t6, list);
2549  AST_LIST_INSERT_TAIL(&testdatalist, &t7, list);
2550 
2551 
2552  AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
2553  via = parse_via(testdataptr->in);
2554  if (!via) {
2555  if (!testdataptr->expected_null) {
2556  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2557  "failed to parse header\n",
2558  i, testdataptr->in);
2559  res = AST_TEST_FAIL;
2560  }
2561  i++;
2562  continue;
2563  }
2564 
2565  if (testdataptr->expected_null) {
2566  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2567  "successfully parased invalid via header\n",
2568  i, testdataptr->in);
2569  res = AST_TEST_FAIL;
2570  free_via(via);
2571  i++;
2572  continue;
2573  }
2574 
2575  if ((ast_strlen_zero(via->protocol) && !ast_strlen_zero(testdataptr->expected_protocol))
2576  || (!ast_strlen_zero(via->protocol) && strcmp(via->protocol, testdataptr->expected_protocol))) {
2577 
2578  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2579  "parsed protocol = \"%s\"\n"
2580  "expected = \"%s\"\n"
2581  "failed to parse protocol\n",
2582  i, testdataptr->in, via->protocol, testdataptr->expected_protocol);
2583  res = AST_TEST_FAIL;
2584  }
2585 
2586  if ((ast_strlen_zero(via->sent_by) && !ast_strlen_zero(testdataptr->expected_sent_by))
2587  || (!ast_strlen_zero(via->sent_by) && strcmp(via->sent_by, testdataptr->expected_sent_by))) {
2588 
2589  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2590  "parsed sent_by = \"%s\"\n"
2591  "expected = \"%s\"\n"
2592  "failed to parse sent-by\n",
2593  i, testdataptr->in, via->sent_by, testdataptr->expected_sent_by);
2594  res = AST_TEST_FAIL;
2595  }
2596 
2597  if (testdataptr->expected_port && testdataptr->expected_port != via->port) {
2598  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2599  "parsed port = \"%u\"\n"
2600  "expected = \"%u\"\n"
2601  "failed to parse port\n",
2602  i, testdataptr->in, via->port, testdataptr->expected_port);
2603  res = AST_TEST_FAIL;
2604  }
2605 
2606  if ((ast_strlen_zero(via->branch) && !ast_strlen_zero(testdataptr->expected_branch))
2607  || (!ast_strlen_zero(via->branch) && strcmp(via->branch, testdataptr->expected_branch))) {
2608 
2609  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2610  "parsed branch = \"%s\"\n"
2611  "expected = \"%s\"\n"
2612  "failed to parse branch\n",
2613  i, testdataptr->in, via->branch, testdataptr->expected_branch);
2614  res = AST_TEST_FAIL;
2615  }
2616 
2617  if ((ast_strlen_zero(via->maddr) && !ast_strlen_zero(testdataptr->expected_maddr))
2618  || (!ast_strlen_zero(via->maddr) && strcmp(via->maddr, testdataptr->expected_maddr))) {
2619 
2620  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2621  "parsed maddr = \"%s\"\n"
2622  "expected = \"%s\"\n"
2623  "failed to parse maddr\n",
2624  i, testdataptr->in, via->maddr, testdataptr->expected_maddr);
2625  res = AST_TEST_FAIL;
2626  }
2627 
2628  if (testdataptr->expected_ttl && testdataptr->expected_ttl != via->ttl) {
2629  ast_test_status_update(test, "TEST#%d FAILED: VIA = \"%s\"\n"
2630  "parsed ttl = \"%d\"\n"
2631  "expected = \"%d\"\n"
2632  "failed to parse ttl\n",
2633  i, testdataptr->in, via->ttl, testdataptr->expected_ttl);
2634  res = AST_TEST_FAIL;
2635  }
2636 
2637  free_via(via);
2638  i++;
2639  }
2640  return res;
2641 }
2642 #endif
2643 
2645 {
2646  AST_TEST_REGISTER(get_calleridname_test);
2647  AST_TEST_REGISTER(sip_parse_uri_test);
2648  AST_TEST_REGISTER(get_in_brackets_test);
2649  AST_TEST_REGISTER(get_name_and_number_test);
2650  AST_TEST_REGISTER(sip_parse_uri_full_test);
2651  AST_TEST_REGISTER(parse_name_andor_addr_test);
2652  AST_TEST_REGISTER(parse_contact_header_test);
2653  AST_TEST_REGISTER(sip_parse_options_test);
2654  AST_TEST_REGISTER(sip_uri_cmp_test);
2655  AST_TEST_REGISTER(parse_via_test);
2656 }
2658 {
2659  AST_TEST_UNREGISTER(sip_parse_uri_test);
2660  AST_TEST_UNREGISTER(get_calleridname_test);
2661  AST_TEST_UNREGISTER(get_in_brackets_test);
2662  AST_TEST_UNREGISTER(get_name_and_number_test);
2663  AST_TEST_UNREGISTER(sip_parse_uri_full_test);
2664  AST_TEST_UNREGISTER(parse_name_andor_addr_test);
2665  AST_TEST_UNREGISTER(parse_contact_header_test);
2666  AST_TEST_UNREGISTER(sip_parse_options_test);
2667  AST_TEST_UNREGISTER(sip_uri_cmp_test);
2668  AST_TEST_UNREGISTER(parse_via_test);
2669 }
2670 
2672 {
2673 #ifdef HAVE_XLOCALE_H
2674  c_locale = newlocale(LC_CTYPE_MASK, "C", NULL);
2675  if (!c_locale) {
2676  return -1;
2677  }
2678 #endif
2679  return 0;
2680 }
2681 
2683 {
2684 #ifdef HAVE_XLOCALE_H
2685  if (c_locale) {
2686  freelocale(c_locale);
2687  c_locale = NULL;
2688  }
2689 #endif
2690 }
static char user[512]
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
Definition: main/utils.c:616
chan_sip header file
static char pass[512]
char * user
struct uriparams params
char * headers
char * method
AST_TEST_DEFINE(sip_parse_uri_full_test)
char * expires
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
#define FALSE
Definition: app_minivm.c:521
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
unsigned int parse_sip_options(const char *options, char *unsupported, size_t unsupported_len)
Parse supported header in incoming packet.
const char * maddr
Definition: sip.h:879
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define URI_CMP_NOMATCH
int get_in_brackets_const(const char *src, const char **start, int *length)
Get text in brackets on a const without copy.
#define LOG_WARNING
Definition: logger.h:274
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
unsigned char ttl
Definition: sip.h:881
static int tmp()
Definition: bt_open.c:389
int get_in_brackets_full(char *tmp, char **out, char **residue)
Get text in brackets and any trailing residue.
static int sip_uri_domain_cmp(const char *host1, const char *host2)
Compare domain sections of SIP URIs.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
void * locale_t
Definition: localtime.h:32
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
static const char desc[]
Definition: cdr_mysql.c:73
#define SIP_OPT_UNKNOWN
Definition: sip.h:167
int sip_uri_cmp(const char *input1, const char *input2)
Compare two URIs as described in RFC 3261 Section 19.1.4.
#define SIP_OPT_TIMER
Definition: sip.h:148
static struct test_val c
char * text
Definition: app_queue.c:1508
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * find_closing_quote(const char *start, const char *lim)
Locate closing quote in a string, skipping escaped quotes. optionally with a limit on the search...
Definition: chan_sip.c:5074
#define NULL
Definition: resample.c:96
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Definition: netsock2.c:388
int value
Definition: syslog.c:37
int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
parses a URI in its components.
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1584
Socket address structure.
Definition: netsock2.h:97
#define ast_strlen_zero(foo)
Definition: strings.h:52
char * transport
Structure to store Via information.
Definition: sip.h:874
Number structure.
Definition: app_followme.c:154
int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport)
parses a URI in its components.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
int get_name_and_number(const char *hdr, char **name, char **number)
Get name and number from sip header.
char * hostport
void sip_request_parser_register_tests(void)
register request parsing tests
FILE * in
Definition: utils/frame.c:33
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
struct sla_ringing_trunk * last
Definition: app_meetme.c:1092
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
const char * branch
Definition: sip.h:878
char * get_in_brackets(char *tmp)
Pick out text in brackets from character string.
const char * get_calleridname(const char *input, char *output, size_t outputsize)
Get caller id name from SIP headers, copy into output buffer.
void free_via(struct sip_via *v)
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int id
Definition: sip.h:1828
void sip_reqresp_parser_exit(void)
Free resources used by request and response parser.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
char * via
Definition: sip.h:875
#define URI_CMP_MATCH
char * pass
char * user
sip request response parser header file
char * name
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
char * maddr
int parse_contact_header(char *contactheader, struct contactliststruct *contactlist)
static int sip_uri_headers_cmp(const char *input1, const char *input2)
helper routine for sip_uri_cmp to compare URI headers
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
locale_t c_locale
static enum ast_test_result_state test_res
def info(msg)
int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **user, char **pass, char **hostport, struct uriparams *params, char **headers, char **residue)
Parse the ABNF structure name-andor-addr = name-addr / addr-spec into its components and return any t...
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:157
int get_comma(char *in, char **out)
Parse all contact header contacts.
char * strcasestr(const char *, const char *)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
uri parameters
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define AST_LIST_HEAD_SET_NOLOCK(head, entry)
Initializes a list head structure with a specified first entry.
Definition: linkedlists.h:387
char * ttl
static const char name[]
Definition: cdr_mysql.c:74
static const struct cfsip_options sip_options[]
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
structure to hold users read from users.conf
const char * sent_by
Definition: sip.h:877
#define SIP_OPT_REPLACES
Definition: sip.h:146
unsigned int port
Definition: sip.h:880
char * strsep(char **str, const char *delims)
#define SUPPORTED
Definition: sip.h:142
void sip_request_parser_unregister_tests(void)
unregister request parsing tests
FILE * out
Definition: utils/frame.c:33
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
#define TRUE
Definition: app_minivm.c:518
int sip_reqresp_parser_init(void)
initialize request and response parser data
const struct ast_flags ast_uri_sip_user
Definition: main/utils.c:575
int error(const char *format,...)
Definition: utils/frame.c:999
char * q
struct sip_via * parse_via(const char *header)
Parse a Via header.
static struct test_options options
static int sip_uri_params_cmp(const char *input1, const char *input2)
helper routine for sip_uri_cmp to compare URI parameters
sip utils header file
const char * protocol
Definition: sip.h:876