mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 11:58:52 +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:
12
CHANGES
12
CHANGES
@@ -59,6 +59,12 @@ SIP Changes
|
||||
callbackextension options, incoming requests that are matched by address
|
||||
will be matched to the peer with the matching callbackextension if it is
|
||||
available.
|
||||
* NAT settings are now a combinable list of options. The equivalent of the
|
||||
deprecated nat=yes is nat=force_rport,comedia. nat=no behaves as before.
|
||||
* Two new NAT options, auto_force_rport and auto_comedia, have been added
|
||||
which set the force_rport and comedia options automatically if Asterisk
|
||||
detects that an incoming SIP request crossed a NAT after being sent by
|
||||
the remote endpoint.
|
||||
|
||||
Chan_local changes
|
||||
------------------
|
||||
@@ -125,6 +131,12 @@ AMI (Asterisk Manager Interface) changes
|
||||
if the i(variable) option is used. StopMixMonitor will accept MixMonitorID as
|
||||
on option to close specific MixMonitors.
|
||||
|
||||
* The SIPshowpeer manager action response field "SIP-Forcerport" has been updated
|
||||
to include information about peers configured with nat=auto_force_rport by
|
||||
returning "A" if auto_force_rport is set and nat is detected, and "a" if it is
|
||||
set and nat is not detected. "Y" and "N" are still returned if auto_force_rport
|
||||
is not enabled.
|
||||
|
||||
FAX changes
|
||||
-----------
|
||||
* FAXOPT(faxdetect) will enable a generic fax detect framehook for dialplan
|
||||
|
@@ -15276,6 +15276,21 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
|
||||
ast_log(LOG_ERROR, "Peer '%s' is trying to register, but not configured as host=dynamic\n", peer->name);
|
||||
res = AUTH_PEER_NOT_DYNAMIC;
|
||||
} else {
|
||||
if (ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
|
||||
if (p->natdetected) {
|
||||
ast_set_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT);
|
||||
} else {
|
||||
ast_clear_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT);
|
||||
}
|
||||
}
|
||||
if (ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) {
|
||||
if (p->natdetected) {
|
||||
ast_set_flag(&peer->flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
} else {
|
||||
ast_clear_flag(&peer->flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
}
|
||||
}
|
||||
|
||||
ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_NAT_FORCE_RPORT);
|
||||
if (!(res = check_auth(p, req, peer->name, peer->secret, peer->md5secret, SIP_REGISTER, uri2, XMIT_UNRELIABLE, req->ignore))) {
|
||||
if (sip_cancel_destroy(p))
|
||||
@@ -16354,6 +16369,30 @@ static void check_via(struct sip_pvt *p, struct sip_request *req)
|
||||
ast_sockaddr_set_port(&p->sa,
|
||||
port != 0 ? port : STANDARD_SIP_PORT);
|
||||
|
||||
/* Check and see if the requesting UA is likely to be behind a NAT. If they are, set the
|
||||
* natdetected flag so that later, peers with nat=auto_* can use the value. Also
|
||||
* set the flags so that Asterisk responds identically whether or not a peer exists
|
||||
* so as not to leak peer name information. */
|
||||
if (ast_sockaddr_cmp(&tmp, &p->recv)) {
|
||||
char *tmp_str = ast_strdupa(ast_sockaddr_stringify(&tmp));
|
||||
ast_debug(3, "NAT detected for %s / %s\n", tmp_str, ast_sockaddr_stringify(&p->recv));
|
||||
p->natdetected = 1;
|
||||
if (ast_test_flag(&p->flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
|
||||
ast_set_flag(&p->flags[0], SIP_NAT_FORCE_RPORT);
|
||||
}
|
||||
if (ast_test_flag(&p->flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) {
|
||||
ast_set_flag(&p->flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
}
|
||||
} else {
|
||||
p->natdetected = 0;
|
||||
if (ast_test_flag(&p->flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
|
||||
ast_clear_flag(&p->flags[0], SIP_NAT_FORCE_RPORT);
|
||||
}
|
||||
if (ast_test_flag(&p->flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) {
|
||||
ast_clear_flag(&p->flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
}
|
||||
}
|
||||
|
||||
if (sip_debug_test_pvt(p)) {
|
||||
ast_verbose("Sending to %s (%s)\n",
|
||||
ast_sockaddr_stringify(sip_real_dst(p)),
|
||||
@@ -17437,7 +17476,9 @@ static char *_sip_show_peers(int fd, int *total, struct mansession *s, const str
|
||||
snprintf(srch, sizeof(srch), FORMAT2, name,
|
||||
tmp_host,
|
||||
peer->host_dynamic ? " D " : " ", /* Dynamic or not? */
|
||||
ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? " N " : " ", /* NAT=yes? */
|
||||
ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT) ?
|
||||
ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? " A " : " a " :
|
||||
ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? " N " : " ", /* NAT=yes? */
|
||||
peer->ha ? " A " : " ", /* permit/deny */
|
||||
tmp_port, status,
|
||||
peer->description ? peer->description : "",
|
||||
@@ -17447,7 +17488,9 @@ static char *_sip_show_peers(int fd, int *total, struct mansession *s, const str
|
||||
ast_cli(fd, FORMAT2, name,
|
||||
tmp_host,
|
||||
peer->host_dynamic ? " D " : " ", /* Dynamic or not? */
|
||||
ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? " N " : " ", /* NAT=yes? */
|
||||
ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT) ?
|
||||
ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? " A " : " a " :
|
||||
ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? " N " : " ", /* NAT=yes? */
|
||||
peer->ha ? " A " : " ", /* permit/deny */
|
||||
tmp_port, status,
|
||||
peer->description ? peer->description : "",
|
||||
@@ -17462,7 +17505,10 @@ static char *_sip_show_peers(int fd, int *total, struct mansession *s, const str
|
||||
"IPaddress: %s\r\n"
|
||||
"IPport: %s\r\n"
|
||||
"Dynamic: %s\r\n"
|
||||
"AutoForcerport: %s\r\n"
|
||||
"Forcerport: %s\r\n"
|
||||
"AutoComedia: %s\r\n"
|
||||
"Comedia: %s\r\n"
|
||||
"VideoSupport: %s\r\n"
|
||||
"TextSupport: %s\r\n"
|
||||
"ACL: %s\r\n"
|
||||
@@ -17474,7 +17520,10 @@ static char *_sip_show_peers(int fd, int *total, struct mansession *s, const str
|
||||
ast_sockaddr_isnull(&peer->addr) ? "-none-" : tmp_host,
|
||||
ast_sockaddr_isnull(&peer->addr) ? "0" : tmp_port,
|
||||
peer->host_dynamic ? "yes" : "no", /* Dynamic or not? */
|
||||
ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT) ? "yes" : "no",
|
||||
ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? "yes" : "no", /* NAT=yes? */
|
||||
ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA) ? "yes" : "no",
|
||||
ast_test_flag(&peer->flags[1], SIP_PAGE2_SYMMETRICRTP) ? "yes" : "no",
|
||||
ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "yes" : "no", /* VIDEOSUPPORT=yes? */
|
||||
ast_test_flag(&peer->flags[1], SIP_PAGE2_TEXTSUPPORT) ? "yes" : "no", /* TEXTSUPPORT=yes? */
|
||||
peer->ha ? "yes" : "no", /* permit/deny */
|
||||
@@ -18142,7 +18191,8 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
|
||||
ast_cli(fd, " MaxCallBR : %d kbps\n", peer->maxcallbitrate);
|
||||
ast_cli(fd, " Expire : %ld\n", ast_sched_when(sched, peer->expire));
|
||||
ast_cli(fd, " Insecure : %s\n", insecure2str(ast_test_flag(&peer->flags[0], SIP_INSECURE)));
|
||||
ast_cli(fd, " Force rport : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT)));
|
||||
ast_cli(fd, " Force rport : %s\n", force_rport_string(peer->flags));
|
||||
ast_cli(fd, " Symmetric RTP: %s\n", comedia_string(peer->flags));
|
||||
ast_cli(fd, " ACL : %s\n", AST_CLI_YESNO(peer->ha != NULL));
|
||||
ast_cli(fd, " DirectMedACL : %s\n", AST_CLI_YESNO(peer->directmediaha != NULL));
|
||||
ast_cli(fd, " T.38 support : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT)));
|
||||
@@ -18254,7 +18304,12 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
|
||||
astman_append(s, "Callerid: %s\r\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, ""));
|
||||
astman_append(s, "RegExpire: %ld seconds\r\n", ast_sched_when(sched, peer->expire));
|
||||
astman_append(s, "SIP-AuthInsecure: %s\r\n", insecure2str(ast_test_flag(&peer->flags[0], SIP_INSECURE)));
|
||||
astman_append(s, "SIP-Forcerport: %s\r\n", (ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT)?"Y":"N"));
|
||||
astman_append(s, "SIP-Forcerport: %s\r\n", ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT) ?
|
||||
(ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? "A" : "a") :
|
||||
(ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) ? "Y" : "N"));
|
||||
astman_append(s, "SIP-Comedia: %s\r\n", ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA) ?
|
||||
(ast_test_flag(&peer->flags[1], SIP_PAGE2_SYMMETRICRTP) ? "A" : "a") :
|
||||
(ast_test_flag(&peer->flags[1], SIP_PAGE2_SYMMETRICRTP) ? "Y" : "N"));
|
||||
astman_append(s, "ACL: %s\r\n", (peer->ha?"Y":"N"));
|
||||
astman_append(s, "SIP-CanReinvite: %s\r\n", (ast_test_flag(&peer->flags[0], SIP_DIRECT_MEDIA)?"Y":"N"));
|
||||
astman_append(s, "SIP-DirectMedia: %s\r\n", (ast_test_flag(&peer->flags[0], SIP_DIRECT_MEDIA)?"Y":"N"));
|
||||
@@ -18866,7 +18921,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
|
||||
ast_cli(a->fd, " Context: %s\n", sip_cfg.default_context);
|
||||
ast_cli(a->fd, " Record on feature: %s\n", sip_cfg.default_record_on_feature);
|
||||
ast_cli(a->fd, " Record off feature: %s\n", sip_cfg.default_record_off_feature);
|
||||
ast_cli(a->fd, " Force rport: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_NAT_FORCE_RPORT)));
|
||||
ast_cli(a->fd, " Force rport: %s\n", force_rport_string(global_flags));
|
||||
ast_cli(a->fd, " DTMF: %s\n", dtmfmode2str(ast_test_flag(&global_flags[0], SIP_DTMF)));
|
||||
ast_cli(a->fd, " Qualify: %d\n", default_qualify);
|
||||
ast_cli(a->fd, " Use ClientCode: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_USECLIENTCODE)));
|
||||
@@ -19237,7 +19292,7 @@ static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_a
|
||||
ast_cli(a->fd, " Theoretical Address: %s\n", ast_sockaddr_stringify(&cur->sa));
|
||||
ast_cli(a->fd, " Received Address: %s\n", ast_sockaddr_stringify(&cur->recv));
|
||||
ast_cli(a->fd, " SIP Transfer mode: %s\n", transfermode2str(cur->allowtransfer));
|
||||
ast_cli(a->fd, " Force rport: %s\n", AST_CLI_YESNO(ast_test_flag(&cur->flags[0], SIP_NAT_FORCE_RPORT)));
|
||||
ast_cli(a->fd, " Force rport: %s\n", force_rport_string(cur->flags));
|
||||
if (ast_sockaddr_isnull(&cur->redirip)) {
|
||||
ast_cli(a->fd,
|
||||
" Audio IP: %s (local)\n",
|
||||
@@ -27692,8 +27747,8 @@ static int handle_t38_options(struct ast_flags *flags, struct ast_flags *mask, s
|
||||
|
||||
/*!
|
||||
\brief Handle flag-type options common to configuration of devices - peers
|
||||
\param flags array of two struct ast_flags
|
||||
\param mask array of two struct ast_flags
|
||||
\param flags array of three struct ast_flags
|
||||
\param mask array of three struct ast_flags
|
||||
\param v linked list of config variables to process
|
||||
\returns non-zero if any config options were handled, zero otherwise
|
||||
*/
|
||||
@@ -27743,19 +27798,7 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
|
||||
ast_set_flag(&flags[0], SIP_DTMF_RFC2833);
|
||||
}
|
||||
} else if (!strcasecmp(v->name, "nat")) {
|
||||
ast_set_flag(&mask[0], SIP_NAT_FORCE_RPORT);
|
||||
ast_set_flag(&flags[0], SIP_NAT_FORCE_RPORT); /* Default to "force_rport" */
|
||||
if (!strcasecmp(v->value, "no")) {
|
||||
ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT);
|
||||
} else if (!strcasecmp(v->value, "yes")) {
|
||||
/* We've already defaulted to force_rport */
|
||||
ast_set_flag(&mask[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
} else if (!strcasecmp(v->value, "comedia")) {
|
||||
ast_clear_flag(&flags[0], SIP_NAT_FORCE_RPORT);
|
||||
ast_set_flag(&mask[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
ast_set_flag(&flags[1], SIP_PAGE2_SYMMETRICRTP);
|
||||
}
|
||||
sip_parse_nat_option(v->value, mask, flags);
|
||||
} else if (!strcasecmp(v->name, "directmedia") || !strcasecmp(v->name, "canreinvite")) {
|
||||
ast_set_flag(&mask[0], SIP_REINVITE);
|
||||
ast_clear_flag(&flags[0], SIP_REINVITE);
|
||||
@@ -28969,7 +29012,7 @@ static int reload_config(enum channelreloadreason reason)
|
||||
struct sip_peer *peer;
|
||||
char *cat, *stringp, *context, *oldregcontext;
|
||||
char newcontexts[AST_MAX_CONTEXT], oldcontexts[AST_MAX_CONTEXT];
|
||||
struct ast_flags dummy[2];
|
||||
struct ast_flags dummy[3];
|
||||
struct ast_flags config_flags = { reason == CHANNEL_MODULE_LOAD ? 0 : ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS) ? 0 : CONFIG_FLAG_FILEUNCHANGED };
|
||||
int auto_sip_domains = FALSE;
|
||||
struct ast_sockaddr old_bindaddr = bindaddr;
|
||||
@@ -29164,7 +29207,7 @@ static int reload_config(enum channelreloadreason reason)
|
||||
ast_copy_string(default_vmexten, DEFAULT_VMEXTEN, sizeof(default_vmexten));
|
||||
ast_set_flag(&global_flags[0], SIP_DTMF_RFC2833); /*!< Default DTMF setting: RFC2833 */
|
||||
ast_set_flag(&global_flags[0], SIP_DIRECT_MEDIA); /*!< Allow re-invites */
|
||||
ast_set_flag(&global_flags[0], SIP_NAT_FORCE_RPORT); /*!< Default to nat=force_rport */
|
||||
ast_set_flag(&global_flags[2], SIP_PAGE3_NAT_AUTO_RPORT); /*!< Default to nat=auto_force_rport */
|
||||
ast_copy_string(default_engine, DEFAULT_ENGINE, sizeof(default_engine));
|
||||
ast_copy_string(default_parkinglot, DEFAULT_PARKINGLOT, sizeof(default_parkinglot));
|
||||
|
||||
|
@@ -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));
|
||||
}
|
@@ -831,17 +831,34 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
|
||||
; However, this is only useful if the external traffic can reach us.
|
||||
; The following settings are allowed (both globally and in individual sections):
|
||||
;
|
||||
; nat = no ; Use rport if the remote side says to use it.
|
||||
; nat = force_rport ; Force rport to always be on. (default)
|
||||
; nat = yes ; Force rport to always be on and perform comedia RTP handling.
|
||||
; nat = comedia ; Use rport if the remote side says to use it and perform comedia RTP handling.
|
||||
; nat = no ; Do no special NAT handling other than RFC3581
|
||||
; nat = force_rport ; Pretend there was an rport parameter even if there wasn't
|
||||
; nat = comedia ; Send media to the port Asterisk received it from regardless
|
||||
; ; of where the SDP says to send it.
|
||||
; nat = auto_force_rport ; Set the force_rport option if Asterisk detects NAT (default)
|
||||
; nat = auto_comedia ; Set the comedia option if Asterisk detects NAT
|
||||
;
|
||||
; The nat settings can be combined. For example, to set both force_rport and comedia
|
||||
; one would set nat=force_rport,comedia. If any of the comma-separated options is 'no',
|
||||
; Asterisk will ignore any other settings and set nat=no. If one of the "auto" settings
|
||||
; is used in conjunction with its non-auto counterpart (nat=comedia,auto_comedia), then
|
||||
; the non-auto option will be ignored.
|
||||
;
|
||||
; The RFC 3581-defined 'rport' parameter allows a client to request that Asterisk send
|
||||
; SIP responses to it via the source IP and port from which the request originated
|
||||
; instead of the address/port listed in the top-most Via header. This is useful if a
|
||||
; client knows that it is behind a NAT and therefore cannot guess from what address/port
|
||||
; its request will be sent. Asterisk will always honor the 'rport' parameter if it is
|
||||
; sent. The force_rport setting causes Asterisk to always send responses back to the
|
||||
; address/port from which it received requests; even if the other side doesn't support
|
||||
; adding the 'rport' parameter.
|
||||
;
|
||||
; 'comedia RTP handling' refers to the technique of sending RTP to the port that the
|
||||
; the other endpoint's RTP arrived from, and means 'connection-oriented media'. This is
|
||||
; only partially related to RFC 4145 which was referred to as COMEDIA while it was in
|
||||
; draft form. This method is used to accomodate endpoints that may be located behind
|
||||
; NAT devices, and as such the port number they tell Asterisk to send RTP packets to
|
||||
; for their media streams is not actual port number that will be used on the nearer
|
||||
; NAT devices, and as such the address/port they tell Asterisk to send RTP packets to
|
||||
; for their media streams is not the actual address/port that will be used on the nearer
|
||||
; side of the NAT.
|
||||
;
|
||||
; IT IS IMPORTANT TO NOTE that if the nat setting in the general section differs from
|
||||
|
Reference in New Issue
Block a user