mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
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
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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 */
|
||||
|
@@ -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
|
||||
|
45
channels/sip/utils.c
Normal file
45
channels/sip/utils.c
Normal file
@@ -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));
|
||||
}
|
Reference in New Issue
Block a user