2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2010, Digium, Inc.
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.
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.
19 * \brief sip config parsing functions and unit tests
23 <support_level>core</support_level>
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include "include/sip.h"
31 #include "include/config_parser.h"
32 #include "include/sip_utils.h"
34 /*! \brief Parse register=> line in sip.conf
36 * \retval 0 on success
37 * \retval -1 on failure
39 int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const char *value, int lineno)
43 enum sip_transport transport = SIP_TRANSPORT_UDP;
45 char *userpart = NULL, *hostpart = NULL;
46 /* register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] */
47 AST_DECLARE_APP_ARGS(pre1,
49 AST_APP_ARG(userpart);
51 AST_DECLARE_APP_ARGS(pre2,
52 AST_APP_ARG(transport);
54 AST_APP_ARG(userpart);
56 AST_DECLARE_APP_ARGS(user1,
57 AST_APP_ARG(userpart);
59 AST_APP_ARG(authuser);
61 AST_DECLARE_APP_ARGS(user2,
65 AST_DECLARE_APP_ARGS(user3,
66 AST_APP_ARG(authuser);
67 AST_APP_ARG(domainport);
69 AST_DECLARE_APP_ARGS(host1,
70 AST_APP_ARG(hostpart);
73 AST_DECLARE_APP_ARGS(host2,
74 AST_APP_ARG(hostpart);
75 AST_APP_ARG(extension);
77 AST_DECLARE_APP_ARGS(host3,
89 ast_copy_string(buf, value, sizeof(buf));
91 /*! register => [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry]
93 * userpart => [peer?][transport://]user[@domain][:secret[:authuser]]
94 * hostpart => host[:port][/extension][~expiry]
96 if ((hostpart = strrchr(buf, '@'))) {
101 if (ast_strlen_zero(userpart) || ast_strlen_zero(hostpart)) {
102 ast_log(LOG_WARNING, "Format for registration is [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] at line %d\n", lineno);
108 * pre1.userpart => [transport://]user[@domain][:secret[:authuser]]
109 * hostpart => host[:port][/extension][~expiry]
111 AST_NONSTANDARD_RAW_ARGS(pre1, userpart, '?');
112 if (ast_strlen_zero(pre1.userpart)) {
113 pre1.userpart = pre1.peer;
119 * pre2.transport = transport
120 * pre2.userpart => user[@domain][:secret[:authuser]]
121 * hostpart => host[:port][/extension][~expiry]
123 AST_NONSTANDARD_RAW_ARGS(pre2, pre1.userpart, '/');
124 if (ast_strlen_zero(pre2.userpart)) {
125 pre2.userpart = pre2.transport;
126 pre2.transport = NULL;
128 pre2.transport[strlen(pre2.transport) - 1] = '\0'; /* Remove trailing : */
131 if (!ast_strlen_zero(pre2.blank)) {
132 ast_log(LOG_WARNING, "Format for registration is [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry] at line %d\n", lineno);
138 * pre2.transport = transport
139 * user1.userpart => user[@domain]
140 * user1.secret => secret
141 * user1.authuser => authuser
142 * hostpart => host[:port][/extension][~expiry]
144 AST_NONSTANDARD_RAW_ARGS(user1, pre2.userpart, ':');
148 * pre2.transport = transport
149 * user1.userpart => user[@domain]
150 * user1.secret => secret
151 * user1.authuser => authuser
152 * host1.hostpart => host[:port][/extension]
153 * host1.expiry => [expiry]
155 AST_NONSTANDARD_RAW_ARGS(host1, hostpart, '~');
159 * pre2.transport = transport
160 * user1.userpart => user[@domain]
161 * user1.secret => secret
162 * user1.authuser => authuser
163 * host2.hostpart => host[:port]
164 * host2.extension => [extension]
165 * host1.expiry => [expiry]
167 AST_NONSTANDARD_RAW_ARGS(host2, host1.hostpart, '/');
171 * pre2.transport = transport
172 * user1.userpart => user[@domain]
173 * user1.secret => secret
174 * user1.authuser => authuser
177 * host2.extension => extension
178 * host1.expiry => expiry
180 AST_NONSTANDARD_RAW_ARGS(host3, host2.hostpart, ':');
184 * pre2.transport = transport
186 * user2.domain => domain
187 * user1.secret => secret
188 * user1.authuser => authuser
191 * host2.extension => extension
192 * host1.expiry => expiry
194 AST_NONSTANDARD_RAW_ARGS(user2, user1.userpart, '@');
198 * pre2.transport = transport
200 * user2.domain => domain
201 * user1.secret => secret
202 * user3.authuser => authuser
203 * user3.domainport => domainport
206 * host2.extension => extension
207 * host1.expiry => expiry
209 AST_NONSTANDARD_RAW_ARGS(user3, user1.authuser, ':');
211 /* Reordering needed due to fields being [(:secret[:username])|(:regdomainport:secret:username)]
212 but parsing being [secret[:username[:regdomainport]]] */
213 if (user3.argc == 2) {
214 char *reorder = user3.domainport;
215 user3.domainport = user1.secret;
216 user1.secret = user3.authuser;
217 user3.authuser = reorder;
221 if (!(portnum = port_str2int(host3.port, 0))) {
222 ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", host3.port, lineno);
225 if (user3.domainport) {
226 if (!(domainport = port_str2int(user3.domainport, 0))) {
227 ast_log(LOG_NOTICE, "'%s' is not a valid domain port number on line %d of sip.conf. using default.\n", user3.domainport, lineno);
231 /* set transport type */
232 if (!pre2.transport) {
233 transport = SIP_TRANSPORT_UDP;
234 } else if (!strncasecmp(pre2.transport, "tcp", 3)) {
235 transport = SIP_TRANSPORT_TCP;
236 } else if (!strncasecmp(pre2.transport, "tls", 3)) {
237 transport = SIP_TRANSPORT_TLS;
238 } else if (!strncasecmp(pre2.transport, "udp", 3)) {
239 transport = SIP_TRANSPORT_UDP;
241 transport = SIP_TRANSPORT_UDP;
242 ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", pre2.transport, lineno);
245 /* if no portnum specified, set default for transport */
247 if (transport == SIP_TRANSPORT_TLS) {
248 portnum = STANDARD_TLS_PORT;
250 portnum = STANDARD_SIP_PORT;
254 /* copy into sip_registry object */
255 ast_string_field_set(reg, callback, ast_strip_quoted(S_OR(host2.extension, "s"), "\"", "\""));
256 ast_string_field_set(reg, username, ast_strip_quoted(S_OR(user2.user, ""), "\"", "\""));
257 ast_string_field_set(reg, hostname, ast_strip_quoted(S_OR(host3.host, ""), "\"", "\""));
258 ast_string_field_set(reg, authuser, ast_strip_quoted(S_OR(user3.authuser, ""), "\"", "\""));
259 ast_string_field_set(reg, secret, ast_strip_quoted(S_OR(user1.secret, ""), "\"", "\""));
260 ast_string_field_set(reg, peername, ast_strip_quoted(S_OR(pre1.peer, ""), "\"", "\""));
261 ast_string_field_set(reg, regdomain, ast_strip_quoted(S_OR(user2.domain, ""), "\"", "\""));
263 reg->transport = transport;
264 reg->timeout = reg->expire = -1;
265 reg->portno = portnum;
266 reg->regdomainport = domainport;
267 reg->callid_valid = FALSE;
268 reg->ocseq = INITIAL_CSEQ;
269 reg->refresh = reg->expiry = reg->configured_expiry = (host1.expiry ? atoi(ast_strip_quoted(host1.expiry, "\"", "\"")) : default_expiry);
274 AST_TEST_DEFINE(sip_parse_register_line_test)
276 int res = AST_TEST_PASS;
277 struct sip_registry *reg;
278 int default_expiry = 120;
279 const char *reg1 = "name@domain";
280 const char *reg2 = "name:pass@domain";
281 const char *reg3 = "name@namedomain:pass:authuser@domain";
282 const char *reg4 = "name@namedomain:pass:authuser@domain/extension";
283 const char *reg5 = "tcp://name@namedomain:pass:authuser@domain/extension";
284 const char *reg6 = "tls://name@namedomain:pass:authuser@domain/extension~111";
285 const char *reg7 = "peer?tcp://name@namedomain:pass:authuser@domain:1234/extension~111";
286 const char *reg8 = "peer?name@namedomain:pass:authuser@domain:1234/extension~111";
287 const char *reg9 = "peer?name:pass:authuser:1234/extension~111";
288 const char *reg10 = "@domin:1234";
289 const char *reg12 = "name@namedomain:4321:pass:authuser@domain";
290 const char *reg13 = "name@namedomain:4321::@domain";
294 info->name = "sip_parse_register_line_test";
295 info->category = "/channels/chan_sip/";
296 info->summary = "tests sip register line parsing";
298 "Tests parsing of various register line configurations. "
299 "Verifies output matches expected behavior.";
300 return AST_TEST_NOT_RUN;
305 /* ---Test reg 1, simple config --- */
306 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
309 sip_parse_register_line(reg, default_expiry, reg1, 1) ||
310 strcmp(reg->callback, "s") ||
311 strcmp(reg->username, "name") ||
312 strcmp(reg->regdomain, "") ||
313 strcmp(reg->hostname, "domain") ||
314 strcmp(reg->authuser, "") ||
315 strcmp(reg->secret, "") ||
316 strcmp(reg->peername, "") ||
317 reg->transport != SIP_TRANSPORT_UDP ||
318 reg->timeout != -1 ||
320 reg->refresh != default_expiry ||
321 reg->expiry != default_expiry ||
322 reg->configured_expiry != default_expiry ||
323 reg->portno != STANDARD_SIP_PORT ||
324 (reg->regdomainport) ||
325 reg->callid_valid != FALSE ||
326 reg->ocseq != INITIAL_CSEQ) {
328 ast_test_status_update(test, "Test 1: simple config failed\n");
331 ast_string_field_free_memory(reg);
334 /* ---Test reg 2, add secret --- */
335 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
338 sip_parse_register_line(reg, default_expiry, reg2, 1) ||
339 strcmp(reg->callback, "s") ||
340 strcmp(reg->username, "name") ||
341 strcmp(reg->regdomain, "") ||
342 strcmp(reg->hostname, "domain") ||
343 strcmp(reg->authuser, "") ||
344 strcmp(reg->secret, "pass") ||
345 strcmp(reg->peername, "") ||
346 reg->transport != SIP_TRANSPORT_UDP ||
347 reg->timeout != -1 ||
349 reg->refresh != default_expiry ||
350 reg->expiry != default_expiry ||
351 reg->configured_expiry != default_expiry ||
352 reg->portno != STANDARD_SIP_PORT ||
353 (reg->regdomainport) ||
354 reg->callid_valid != FALSE ||
355 reg->ocseq != INITIAL_CSEQ) {
357 ast_test_status_update(test, "Test 2: add secret failed\n");
360 ast_string_field_free_memory(reg);
363 /* ---Test reg 3, add userdomain and authuser --- */
364 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
367 sip_parse_register_line(reg, default_expiry, reg3, 1) ||
368 strcmp(reg->callback, "s") ||
369 strcmp(reg->username, "name") ||
370 strcmp(reg->regdomain, "namedomain") ||
371 strcmp(reg->hostname, "domain") ||
372 strcmp(reg->authuser, "authuser") ||
373 strcmp(reg->secret, "pass") ||
374 strcmp(reg->peername, "") ||
375 reg->transport != SIP_TRANSPORT_UDP ||
376 reg->timeout != -1 ||
378 reg->refresh != default_expiry ||
379 reg->expiry != default_expiry ||
380 reg->configured_expiry != default_expiry ||
381 reg->portno != STANDARD_SIP_PORT ||
382 (reg->regdomainport) ||
383 reg->callid_valid != FALSE ||
384 reg->ocseq != INITIAL_CSEQ) {
386 ast_test_status_update(test, "Test 3: add userdomain and authuser failed\n");
389 ast_string_field_free_memory(reg);
392 /* ---Test reg 4, add callback extension --- */
393 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
396 sip_parse_register_line(reg, default_expiry, reg4, 1) ||
397 strcmp(reg->callback, "extension") ||
398 strcmp(reg->username, "name") ||
399 strcmp(reg->regdomain, "namedomain") ||
400 strcmp(reg->hostname, "domain") ||
401 strcmp(reg->authuser, "authuser") ||
402 strcmp(reg->secret, "pass") ||
403 strcmp(reg->peername, "") ||
404 reg->transport != SIP_TRANSPORT_UDP ||
405 reg->timeout != -1 ||
407 reg->refresh != default_expiry ||
408 reg->expiry != default_expiry ||
409 reg->configured_expiry != default_expiry ||
410 reg->portno != STANDARD_SIP_PORT ||
411 (reg->regdomainport) ||
412 reg->callid_valid != FALSE ||
413 reg->ocseq != INITIAL_CSEQ) {
415 ast_test_status_update(test, "Test 4: add callback extension failed\n");
418 ast_string_field_free_memory(reg);
421 /* ---Test reg 5, add transport --- */
422 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
425 sip_parse_register_line(reg, default_expiry, reg5, 1) ||
426 strcmp(reg->callback, "extension") ||
427 strcmp(reg->username, "name") ||
428 strcmp(reg->regdomain, "namedomain") ||
429 strcmp(reg->hostname, "domain") ||
430 strcmp(reg->authuser, "authuser") ||
431 strcmp(reg->secret, "pass") ||
432 strcmp(reg->peername, "") ||
433 reg->transport != SIP_TRANSPORT_TCP ||
434 reg->timeout != -1 ||
436 reg->refresh != default_expiry ||
437 reg->expiry != default_expiry ||
438 reg->configured_expiry != default_expiry ||
439 reg->portno != STANDARD_SIP_PORT ||
440 (reg->regdomainport) ||
441 reg->callid_valid != FALSE ||
442 reg->ocseq != INITIAL_CSEQ) {
444 ast_test_status_update(test, "Test 5: add transport failed\n");
447 ast_string_field_free_memory(reg);
450 /* ---Test reg 6, change to tls transport, add expiry --- */
451 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
454 sip_parse_register_line(reg, default_expiry, reg6, 1) ||
455 strcmp(reg->callback, "extension") ||
456 strcmp(reg->username, "name") ||
457 strcmp(reg->regdomain, "namedomain") ||
458 strcmp(reg->hostname, "domain") ||
459 strcmp(reg->authuser, "authuser") ||
460 strcmp(reg->secret, "pass") ||
461 strcmp(reg->peername, "") ||
462 reg->transport != SIP_TRANSPORT_TLS ||
463 reg->timeout != -1 ||
465 reg->refresh != 111 ||
466 reg->expiry != 111 ||
467 reg->configured_expiry != 111 ||
468 reg->portno != STANDARD_TLS_PORT ||
469 (reg->regdomainport) ||
470 reg->callid_valid != FALSE ||
471 reg->ocseq != INITIAL_CSEQ) {
473 ast_test_status_update(test, "Test 6: change to tls transport and add expiry failed\n");
476 ast_string_field_free_memory(reg);
479 /* ---Test reg 7, change transport to tcp, add custom port, and add peer --- */
480 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
483 sip_parse_register_line(reg, default_expiry, reg7, 1) ||
484 strcmp(reg->callback, "extension") ||
485 strcmp(reg->username, "name") ||
486 strcmp(reg->regdomain, "namedomain") ||
487 strcmp(reg->hostname, "domain") ||
488 strcmp(reg->authuser, "authuser") ||
489 strcmp(reg->secret, "pass") ||
490 strcmp(reg->peername, "peer") ||
491 reg->transport != SIP_TRANSPORT_TCP ||
492 reg->timeout != -1 ||
494 reg->refresh != 111 ||
495 reg->expiry != 111 ||
496 reg->configured_expiry != 111 ||
497 reg->portno != 1234 ||
498 (reg->regdomainport) ||
499 reg->callid_valid != FALSE ||
500 reg->ocseq != INITIAL_CSEQ) {
502 ast_test_status_update(test, "Test 7, change transport to tcp, add custom port, and add peer failed.\n");
505 ast_string_field_free_memory(reg);
508 /* ---Test reg 8, remove transport --- */
509 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
512 sip_parse_register_line(reg, default_expiry, reg8, 1) ||
513 strcmp(reg->callback, "extension") ||
514 strcmp(reg->username, "name") ||
515 strcmp(reg->regdomain, "namedomain") ||
516 strcmp(reg->hostname, "domain") ||
517 strcmp(reg->authuser, "authuser") ||
518 strcmp(reg->secret, "pass") ||
519 strcmp(reg->peername, "peer") ||
520 reg->transport != SIP_TRANSPORT_UDP ||
521 reg->timeout != -1 ||
523 reg->refresh != 111 ||
524 reg->expiry != 111 ||
525 reg->configured_expiry != 111 ||
526 reg->portno != 1234 ||
527 (reg->regdomainport) ||
528 reg->callid_valid != FALSE ||
529 reg->ocseq != INITIAL_CSEQ) {
531 ast_test_status_update(test, "Test 8, remove transport failed.\n");
534 ast_string_field_free_memory(reg);
537 /* ---Test reg 9, missing domain, expected to fail --- */
538 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
540 } else if (!sip_parse_register_line(reg, default_expiry, reg9, 1)) {
541 ast_test_status_update(test,
542 "Test 9, missing domain, expected to fail but did not.\n");
545 ast_string_field_free_memory(reg);
548 /* ---Test reg 10, missing user, expected to fail --- */
549 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
551 } else if (!sip_parse_register_line(reg, default_expiry, reg10, 1)) {
552 ast_test_status_update(test,
553 "Test 10, missing user expected to fail but did not\n");
556 ast_string_field_free_memory(reg);
559 /* ---Test reg 11, no registry object, expected to fail--- */
560 if (!sip_parse_register_line(NULL, default_expiry, reg1, 1)) {
561 ast_test_status_update(test,
562 "Test 11, no registry object, expected to fail but did not.\n");
566 /* ---Test reg 12, no registry line, expected to fail --- */
567 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
569 } else if (!sip_parse_register_line(reg, default_expiry, NULL, 1)) {
571 ast_test_status_update(test,
572 "Test 12, NULL register line expected to fail but did not.\n");
575 ast_string_field_free_memory(reg);
578 /* ---Test reg13, add domain port --- */
579 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
582 sip_parse_register_line(reg, default_expiry, reg12, 1) ||
583 strcmp(reg->callback, "s") ||
584 strcmp(reg->username, "name") ||
585 strcmp(reg->regdomain, "namedomain") ||
586 strcmp(reg->hostname, "domain") ||
587 strcmp(reg->authuser, "authuser") ||
588 strcmp(reg->secret, "pass") ||
589 strcmp(reg->peername, "") ||
590 reg->transport != SIP_TRANSPORT_UDP ||
591 reg->timeout != -1 ||
593 reg->refresh != default_expiry ||
594 reg->expiry != default_expiry ||
595 reg->configured_expiry != default_expiry ||
596 reg->portno != STANDARD_SIP_PORT ||
597 reg->regdomainport != 4321 ||
598 reg->callid_valid != FALSE ||
599 reg->ocseq != INITIAL_CSEQ) {
601 ast_test_status_update(test, "Test 13, add domain port failed.\n");
604 ast_string_field_free_memory(reg);
607 /* ---Test reg14, domain port without secret --- */
608 if (!(reg = ast_calloc_with_stringfields(1, struct sip_registry, 256))) {
611 sip_parse_register_line(reg, default_expiry, reg13, 1) ||
612 strcmp(reg->callback, "s") ||
613 strcmp(reg->username, "name") ||
614 strcmp(reg->regdomain, "namedomain") ||
615 strcmp(reg->hostname, "domain") ||
616 strcmp(reg->authuser, "") ||
617 strcmp(reg->secret, "") ||
618 strcmp(reg->peername, "") ||
619 reg->transport != SIP_TRANSPORT_UDP ||
620 reg->timeout != -1 ||
622 reg->refresh != default_expiry ||
623 reg->expiry != default_expiry ||
624 reg->configured_expiry != default_expiry ||
625 reg->portno != STANDARD_SIP_PORT ||
626 reg->regdomainport != 4321 ||
627 reg->callid_valid != FALSE ||
628 reg->ocseq != INITIAL_CSEQ) {
630 ast_test_status_update(test, "Test 14, domain port without secret failed.\n");
633 ast_string_field_free_memory(reg);
640 ast_test_status_update(test, "Out of memory. \n");
644 int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum sip_transport *transport)
648 if (ast_strlen_zero(line)) {
652 if ((*hostname = strstr(line, "://"))) {
655 if (!strncasecmp(line, "tcp", 3)) {
656 *transport = SIP_TRANSPORT_TCP;
657 } else if (!strncasecmp(line, "tls", 3)) {
658 *transport = SIP_TRANSPORT_TLS;
659 } else if (!strncasecmp(line, "udp", 3)) {
660 *transport = SIP_TRANSPORT_UDP;
662 ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type on line %d of sip.conf. defaulting to udp.\n", line, lineno);
664 ast_log(LOG_NOTICE, "'%.3s' is not a valid transport type in sip config. defaulting to udp.\n", line);
668 *transport = SIP_TRANSPORT_UDP;
671 if ((line = strrchr(*hostname, '@')))
676 if (ast_sockaddr_split_hostport(line, hostname, &port, 0) == 0) {
678 ast_log(LOG_WARNING, "Cannot parse host '%s' on line %d of sip.conf.\n",
681 ast_log(LOG_WARNING, "Cannot parse host '%s' in sip config.\n", line);
687 if (!sscanf(port, "%5u", portnum)) {
689 ast_log(LOG_NOTICE, "'%s' is not a valid port number on line %d of sip.conf. using default.\n", port, lineno);
691 ast_log(LOG_NOTICE, "'%s' is not a valid port number in sip config. using default.\n", port);
698 if (*transport & SIP_TRANSPORT_TLS) {
699 *portnum = STANDARD_TLS_PORT;
701 *portnum = STANDARD_SIP_PORT;
708 AST_TEST_DEFINE(sip_parse_host_line_test)
710 int res = AST_TEST_PASS;
713 enum sip_transport transport;
714 char host1[] = "www.blah.com";
715 char host2[] = "tcp://www.blah.com";
716 char host3[] = "tls://10.10.10.10";
717 char host4[] = "tls://10.10.10.10:1234";
718 char host5[] = "10.10.10.10:1234";
722 info->name = "sip_parse_host_line_test";
723 info->category = "/channels/chan_sip/";
724 info->summary = "tests sip.conf host line parsing";
726 "Tests parsing of various host line configurations. "
727 "Verifies output matches expected behavior.";
728 return AST_TEST_NOT_RUN;
733 /* test 1, simple host */
734 sip_parse_host(host1, 1, &host, &port, &transport);
735 if (port != STANDARD_SIP_PORT ||
736 ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
737 transport != SIP_TRANSPORT_UDP) {
738 ast_test_status_update(test, "Test 1: simple host failed.\n");
742 /* test 2, add tcp transport */
743 sip_parse_host(host2, 1, &host, &port, &transport);
744 if (port != STANDARD_SIP_PORT ||
745 ast_strlen_zero(host) || strcmp(host, "www.blah.com") ||
746 transport != SIP_TRANSPORT_TCP) {
747 ast_test_status_update(test, "Test 2: tcp host failed.\n");
751 /* test 3, add tls transport */
752 sip_parse_host(host3, 1, &host, &port, &transport);
753 if (port != STANDARD_TLS_PORT ||
754 ast_strlen_zero(host) || strcmp(host, "10.10.10.10") ||
755 transport != SIP_TRANSPORT_TLS) {
756 ast_test_status_update(test, "Test 3: tls host failed. \n");
760 /* test 4, add custom port with tls */
761 sip_parse_host(host4, 1, &host, &port, &transport);
762 if (port != 1234 || ast_strlen_zero(host) ||
763 strcmp(host, "10.10.10.10") ||
764 transport != SIP_TRANSPORT_TLS) {
765 ast_test_status_update(test, "Test 4: tls host with custom port failed.\n");
769 /* test 5, simple host with custom port */
770 sip_parse_host(host5, 1, &host, &port, &transport);
771 if (port != 1234 || ast_strlen_zero(host) ||
772 strcmp(host, "10.10.10.10") ||
773 transport != SIP_TRANSPORT_UDP) {
774 ast_test_status_update(test, "Test 5: simple host with custom port failed.\n");
778 /* test 6, expected failure with NULL input */
779 if (!sip_parse_host(NULL, 1, &host, &port, &transport)) {
780 ast_test_status_update(test, "Test 6: expected error on NULL input did not occur.\n");
788 /*! \brief Parse the comma-separated nat= option values */
789 void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_flags *flags)
793 if (!(parse = ast_strdupa(value))) {
797 /* Since we need to completely override the general settings if we are being called
798 * later for a peer, always set the flags for all options on the mask */
799 ast_set_flag(&mask[0], SIP_NAT_FORCE_RPORT);
800 ast_set_flag(&mask[1], SIP_PAGE2_SYMMETRICRTP);
801 ast_set_flag(&mask[2], SIP_PAGE3_NAT_AUTO_RPORT);
802 ast_set_flag(&mask[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
804 while ((this = strsep(&parse, ","))) {
805 if (ast_false(this)) {
806 ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT);
807 ast_clear_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
808 ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
809 ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
810 break; /* It doesn't make sense to have no + something else */
811 } else if (!strcasecmp(this, "yes")) {
812 ast_log(LOG_WARNING, "nat=yes is deprecated, use nat=force_rport,comedia instead\n");
813 ast_set_flag(&flags[0], SIP_NAT_FORCE_RPORT);
814 ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
815 ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
816 ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
817 break; /* It doesn't make sense to have yes + something else */
818 } else if (!strcasecmp(this, "force_rport") && !ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
819 ast_set_flag(&flags[0], SIP_NAT_FORCE_RPORT);
820 } else if (!strcasecmp(this, "comedia") && !ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) {
821 ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
822 } else if (!strcasecmp(this, "auto_force_rport")) {
823 ast_set_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
824 /* In case someone did something dumb like nat=force_rport,auto_force_rport */
825 ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT);
826 } else if (!strcasecmp(this, "auto_comedia")) {
827 ast_set_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA);
828 /* In case someone did something dumb like nat=comedia,auto_comedia*/
829 ast_clear_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
834 #define TEST_FORCE_RPORT 1 << 0
835 #define TEST_COMEDIA 1 << 1
836 #define TEST_AUTO_FORCE_RPORT 1 << 2
837 #define TEST_AUTO_COMEDIA 1 << 3
838 static int match_nat_options(int val, struct ast_flags *flags)
840 if ((!ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT)) != !(val & TEST_FORCE_RPORT)) {
843 if (!ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP) != !(val & TEST_COMEDIA)) {
846 if (!ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT) != !(val & TEST_AUTO_FORCE_RPORT)) {
849 if (!ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA) != !(val & TEST_AUTO_COMEDIA)) {
855 AST_TEST_DEFINE(sip_parse_nat_test)
857 int i, res = AST_TEST_PASS;
858 struct ast_flags mask[3] = {{0}}, flags[3] = {{0}};
863 { "yes", TEST_FORCE_RPORT | TEST_COMEDIA },
865 { "force_rport", TEST_FORCE_RPORT },
866 { "comedia", TEST_COMEDIA },
867 { "auto_force_rport", TEST_AUTO_FORCE_RPORT },
868 { "auto_comedia", TEST_AUTO_COMEDIA },
869 { "force_rport,auto_force_rport", TEST_AUTO_FORCE_RPORT },
870 { "auto_force_rport,force_rport", TEST_AUTO_FORCE_RPORT },
871 { "comedia,auto_comedia", TEST_AUTO_COMEDIA },
872 { "auto_comedia,comedia", TEST_AUTO_COMEDIA },
873 { "force_rport,comedia", TEST_FORCE_RPORT | TEST_COMEDIA },
874 { "force_rport,auto_comedia", TEST_FORCE_RPORT | TEST_AUTO_COMEDIA },
875 { "force_rport,yes,no", TEST_FORCE_RPORT | TEST_COMEDIA },
876 { "auto_comedia,no,yes", 0 },
881 info->name = "sip_parse_nat_test";
882 info->category = "/channels/chan_sip/";
883 info->summary = "tests sip.conf nat line parsing";
885 "Tests parsing of various nat line configurations. "
886 "Verifies output matches expected behavior.";
887 return AST_TEST_NOT_RUN;
892 for (i = 0; i < ARRAY_LEN(options); i++) {
893 sip_parse_nat_option(options[i].str, mask, flags);
894 if (!match_nat_options(options[i].i, flags)) {
895 ast_test_status_update(test, "Failed nat=%s\n", options[i].str);
898 memset(flags, 0, sizeof(flags));
899 memset(mask, 0, sizeof(mask));
904 /*! \brief SIP test registration */
905 void sip_config_parser_register_tests(void)
907 AST_TEST_REGISTER(sip_parse_register_line_test);
908 AST_TEST_REGISTER(sip_parse_host_line_test);
909 AST_TEST_REGISTER(sip_parse_nat_test);
912 /*! \brief SIP test registration */
913 void sip_config_parser_unregister_tests(void)
915 AST_TEST_UNREGISTER(sip_parse_register_line_test);
916 AST_TEST_UNREGISTER(sip_parse_host_line_test);
917 AST_TEST_UNREGISTER(sip_parse_nat_test);