diff options
author | Terry Wilson <twilson@digium.com> | 2012-02-09 18:14:39 +0000 |
---|---|---|
committer | Terry Wilson <twilson@digium.com> | 2012-02-09 18:14:39 +0000 |
commit | e5c51ee44c79950ff90660f29ae4b78ce8cc06d2 (patch) | |
tree | 4a25b55ca8c3dcb00699c36ec270f0ff25750ca3 /channels/sip | |
parent | 8f5c33f95a44347308fa9987ddad0598ba060522 (diff) |
Add auto_force_rport and auto_comedia NAT options
This patch adds the auto_force_rport and auto_comedia NAT options. It
also converts the nat= setting to a list of comma-separated combinable
options: no, force_rport, comedia, auto_force_rport, and auto_comedia.
nat=yes remains as an undocumented option equal to
"force_rport,comedia". The first instance of 'yes' or 'no' in the list
stops parsing and overrides any previously set options. If an auto_*
option is specified with its non-auto_ counterpart, the auto setting
takes precedence.
This patch builds upon the patch posted to ASTERISK-17860 by JIRA user
pedro-garcia.
(closes issue ASTERISK-17860)
Review: https://reviewboard.asterisk.org/r/1698/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@354597 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels/sip')
-rw-r--r-- | channels/sip/config_parser.c | 118 | ||||
-rw-r--r-- | channels/sip/include/config_parser.h | 12 | ||||
-rw-r--r-- | channels/sip/include/sip.h | 5 | ||||
-rw-r--r-- | channels/sip/include/sip_utils.h | 6 | ||||
-rw-r--r-- | channels/sip/utils.c | 45 |
5 files changed, 185 insertions, 1 deletions
diff --git a/channels/sip/config_parser.c b/channels/sip/config_parser.c index 72a7b2c7d..55695e545 100644 --- a/channels/sip/config_parser.c +++ b/channels/sip/config_parser.c @@ -765,11 +765,128 @@ AST_TEST_DEFINE(sip_parse_host_line_test) } +/*! \brief Parse the comma-separated nat= option values */ +void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_flags *flags) +{ + char *parse, *this; + + if (!(parse = ast_strdupa(value))) { + return; + } + + /* Since we need to completely override the general settings if we are being called + * later for a peer, always set the flags for all options on the mask */ + ast_set_flag(&mask[0], SIP_NAT_FORCE_RPORT); + ast_set_flag(&mask[1], SIP_PAGE2_SYMMETRICRTP); + ast_set_flag(&mask[2], SIP_PAGE3_NAT_AUTO_RPORT); + ast_set_flag(&mask[2], SIP_PAGE3_NAT_AUTO_COMEDIA); + + while ((this = strsep(&parse, ","))) { + if (ast_false(this)) { + ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT); + ast_clear_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP); + ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT); + ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA); + break; /* It doesn't make sense to have no + something else */ + } else if (!strcasecmp(this, "yes")) { + ast_log(LOG_WARNING, "nat=yes is deprecated, use nat=force_rport,comedia instead\n"); + ast_set_flag(&flags[0], SIP_NAT_FORCE_RPORT); + ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP); + ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT); + ast_clear_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA); + break; /* It doesn't make sense to have yes + something else */ + } else if (!strcasecmp(this, "force_rport") && !ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) { + ast_set_flag(&flags[0], SIP_NAT_FORCE_RPORT); + } else if (!strcasecmp(this, "comedia") && !ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) { + ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP); + } else if (!strcasecmp(this, "auto_force_rport")) { + ast_set_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT); + /* In case someone did something dumb like nat=force_rport,auto_force_rport */ + ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT); + } else if (!strcasecmp(this, "auto_comedia")) { + ast_set_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA); + /* In case someone did something dumb like nat=comedia,auto_comedia*/ + ast_clear_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP); + } + } +} + +#define TEST_FORCE_RPORT 1 << 0 +#define TEST_COMEDIA 1 << 1 +#define TEST_AUTO_FORCE_RPORT 1 << 2 +#define TEST_AUTO_COMEDIA 1 << 3 +static int match_nat_options(int val, struct ast_flags *flags) +{ + if ((!ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT)) != !(val & TEST_FORCE_RPORT)) { + return 0; + } + if (!ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP) != !(val & TEST_COMEDIA)) { + return 0; + } + if (!ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT) != !(val & TEST_AUTO_FORCE_RPORT)) { + return 0; + } + if (!ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA) != !(val & TEST_AUTO_COMEDIA)) { + return 0; + } + return 1; +} + +AST_TEST_DEFINE(sip_parse_nat_test) +{ + int i, res = AST_TEST_PASS; + struct ast_flags mask[3] = {{0}}, flags[3] = {{0}}; + struct { + const char *str; + int i; + } options[] = { + { "yes", TEST_FORCE_RPORT | TEST_COMEDIA }, + { "no", 0 }, + { "force_rport", TEST_FORCE_RPORT }, + { "comedia", TEST_COMEDIA }, + { "auto_force_rport", TEST_AUTO_FORCE_RPORT }, + { "auto_comedia", TEST_AUTO_COMEDIA }, + { "force_rport,auto_force_rport", TEST_AUTO_FORCE_RPORT }, + { "auto_force_rport,force_rport", TEST_AUTO_FORCE_RPORT }, + { "comedia,auto_comedia", TEST_AUTO_COMEDIA }, + { "auto_comedia,comedia", TEST_AUTO_COMEDIA }, + { "force_rport,comedia", TEST_FORCE_RPORT | TEST_COMEDIA }, + { "force_rport,auto_comedia", TEST_FORCE_RPORT | TEST_AUTO_COMEDIA }, + { "force_rport,yes,no", TEST_FORCE_RPORT | TEST_COMEDIA }, + { "auto_comedia,no,yes", 0 }, + }; + + switch (cmd) { + case TEST_INIT: + info->name = "sip_parse_nat_test"; + info->category = "/channels/chan_sip/"; + info->summary = "tests sip.conf nat line parsing"; + info->description = + "Tests parsing of various nat line configurations. " + "Verifies output matches expected behavior."; + return AST_TEST_NOT_RUN; + case TEST_EXECUTE: + break; + } + + for (i = 0; i < ARRAY_LEN(options); i++) { + sip_parse_nat_option(options[i].str, mask, flags); + if (!match_nat_options(options[i].i, flags)) { + ast_test_status_update(test, "Failed nat=%s\n", options[i].str); + res = AST_TEST_FAIL; + } + memset(flags, 0, sizeof(flags)); + memset(mask, 0, sizeof(mask)); + } + + return res; +} /*! \brief SIP test registration */ void sip_config_parser_register_tests(void) { AST_TEST_REGISTER(sip_parse_register_line_test); AST_TEST_REGISTER(sip_parse_host_line_test); + AST_TEST_REGISTER(sip_parse_nat_test); } /*! \brief SIP test registration */ @@ -777,5 +894,6 @@ void sip_config_parser_unregister_tests(void) { AST_TEST_UNREGISTER(sip_parse_register_line_test); AST_TEST_UNREGISTER(sip_parse_host_line_test); + AST_TEST_UNREGISTER(sip_parse_nat_test); } diff --git a/channels/sip/include/config_parser.h b/channels/sip/include/config_parser.h index 76fefc2c6..2737016e6 100644 --- a/channels/sip/include/config_parser.h +++ b/channels/sip/include/config_parser.h @@ -43,6 +43,18 @@ int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const */ int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum sip_transport *transport); +/*! \brief Parse the comma-separated nat= option values + * \param value The comma-separated value + * \param mask An array of ast_flags that will be set by this function + * and used as a mask for copying the flags later + * \param flags An array of ast_flags that will be set by this function + * + * \note The nat-related values in both mask and flags are assumed to empty. This function + * will treat the first "yes" or "no" value in a list of values as overiding all other values + * and will stop parsing. Auto values will override their non-auto counterparts. + */ +void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_flags *flags); + /*! * \brief register config parsing tests */ diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index d5de40d9c..0ae8be8f8 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -363,9 +363,11 @@ #define SIP_PAGE3_SNOM_AOC (1 << 0) /*!< DPG: Allow snom aoc messages */ #define SIP_PAGE3_SRTP_TAG_32 (1 << 1) /*!< DP: Use a 32bit auth tag in INVITE not 80bit */ +#define SIP_PAGE3_NAT_AUTO_RPORT (1 << 2) /*!< DGP: Set SIP_NAT_FORCE_RPORT when NAT is detected */ +#define SIP_PAGE3_NAT_AUTO_COMEDIA (1 << 3) /*!< DGP: Set SIP_PAGE2_SYMMETRICRTP when NAT is detected */ #define SIP_PAGE3_FLAGS_TO_COPY \ - (SIP_PAGE3_SNOM_AOC | SIP_PAGE3_SRTP_TAG_32) + (SIP_PAGE3_SNOM_AOC | SIP_PAGE3_SRTP_TAG_32 | SIP_PAGE3_NAT_AUTO_RPORT | SIP_PAGE3_NAT_AUTO_COMEDIA) #define CHECK_AUTH_BUF_INITLEN 256 @@ -1062,6 +1064,7 @@ struct sip_pvt { * for incoming calls */ unsigned short req_secure_signaling:1;/*!< Whether we are required to have secure signaling or not */ + unsigned short natdetected:1; /*!< Whether we detected a NAT when processing the Via */ char tag[11]; /*!< Our tag for this session */ int timer_t1; /*!< SIP timer T1, ms rtt */ int timer_b; /*!< SIP timer B, ms */ diff --git a/channels/sip/include/sip_utils.h b/channels/sip/include/sip_utils.h index 47297ab68..01207e774 100644 --- a/channels/sip/include/sip_utils.h +++ b/channels/sip/include/sip_utils.h @@ -80,4 +80,10 @@ int hangup_sip2cause(int cause); */ const char *hangup_cause2sip(int cause); +/*! \brief Return a string describing the force_rport value for the given flags */ +const char *force_rport_string(struct ast_flags *flags); + +/*! \brief Return a string describing the comedia value for the given flags */ +const char *comedia_string(struct ast_flags *flags); + #endif diff --git a/channels/sip/utils.c b/channels/sip/utils.c new file mode 100644 index 000000000..14983ba82 --- /dev/null +++ b/channels/sip/utils.c @@ -0,0 +1,45 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2012, Digium, Inc. + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief Utility functions for chan_sip + * + * \author Terry Wilson <twilson@digium.com> + */ + +#include "asterisk.h" + +#include "asterisk/utils.h" +#include "asterisk/cli.h" +#include "include/sip.h" +#include "include/sip_utils.h" + +const char *force_rport_string(struct ast_flags *flags) +{ + if (ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) { + return ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT) ? "Auto (Yes)" : "Auto (No)"; + } + return AST_CLI_YESNO(ast_test_flag(&flags[0], SIP_NAT_FORCE_RPORT)); +} + +const char *comedia_string(struct ast_flags *flags) +{ + if (ast_test_flag(&flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) { + return ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP) ? "Auto (Yes)" : "Auto (No)"; + } + return AST_CLI_YESNO(ast_test_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP)); +} |