[asterisk-commits] twilson: trunk r354597 - in /trunk: ./ channels/ channels/sip/ channels/sip/i...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Feb 9 12:14:45 CST 2012


Author: twilson
Date: Thu Feb  9 12:14:39 2012
New Revision: 354597

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=354597
Log:
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/

Added:
    trunk/channels/sip/utils.c   (with props)
Modified:
    trunk/CHANGES
    trunk/channels/chan_sip.c
    trunk/channels/sip/config_parser.c
    trunk/channels/sip/include/config_parser.h
    trunk/channels/sip/include/sip.h
    trunk/channels/sip/include/sip_utils.h
    trunk/configs/sip.conf.sample

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=354597&r1=354596&r2=354597
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Thu Feb  9 12:14:39 2012
@@ -59,6 +59,12 @@
    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
 ------------------
@@ -124,6 +130,12 @@
  * MixMonitor will now show IDs associated with the mixmonitor upon creating them
    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
 -----------

Modified: trunk/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_sip.c?view=diff&rev=354597&r1=354596&r2=354597
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Thu Feb  9 12:14:39 2012
@@ -15276,6 +15276,21 @@
 			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 @@
 		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 @@
 		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 @@
 			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 @@
 			"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 @@
 			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 @@
 		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 @@
 		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 @@
 	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 @@
 			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 @@
 
 /*!
   \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 @@
 			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 @@
 	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 @@
 	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));
 

Modified: trunk/channels/sip/config_parser.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sip/config_parser.c?view=diff&rev=354597&r1=354596&r2=354597
==============================================================================
--- trunk/channels/sip/config_parser.c (original)
+++ trunk/channels/sip/config_parser.c Thu Feb  9 12:14:39 2012
@@ -765,11 +765,128 @@
 
 }
 
+/*! \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 @@
 {
 	AST_TEST_UNREGISTER(sip_parse_register_line_test);
 	AST_TEST_UNREGISTER(sip_parse_host_line_test);
-}
-
+	AST_TEST_UNREGISTER(sip_parse_nat_test);
+}
+

Modified: trunk/channels/sip/include/config_parser.h
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sip/include/config_parser.h?view=diff&rev=354597&r1=354596&r2=354597
==============================================================================
--- trunk/channels/sip/include/config_parser.h (original)
+++ trunk/channels/sip/include/config_parser.h Thu Feb  9 12:14:39 2012
@@ -43,6 +43,18 @@
  */
 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
  */

Modified: trunk/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sip/include/sip.h?view=diff&rev=354597&r1=354596&r2=354597
==============================================================================
--- trunk/channels/sip/include/sip.h (original)
+++ trunk/channels/sip/include/sip.h Thu Feb  9 12:14:39 2012
@@ -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 @@
 	                                       *   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 */

Modified: trunk/channels/sip/include/sip_utils.h
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sip/include/sip_utils.h?view=diff&rev=354597&r1=354596&r2=354597
==============================================================================
--- trunk/channels/sip/include/sip_utils.h (original)
+++ trunk/channels/sip/include/sip_utils.h Thu Feb  9 12:14:39 2012
@@ -80,4 +80,10 @@
 */
 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

Added: trunk/channels/sip/utils.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sip/utils.c?view=auto&rev=354597
==============================================================================
--- trunk/channels/sip/utils.c (added)
+++ trunk/channels/sip/utils.c Thu Feb  9 12:14:39 2012
@@ -1,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 at 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));
+}

Propchange: trunk/channels/sip/utils.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: trunk/channels/sip/utils.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: trunk/channels/sip/utils.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: trunk/configs/sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/trunk/configs/sip.conf.sample?view=diff&rev=354597&r1=354596&r2=354597
==============================================================================
--- trunk/configs/sip.conf.sample (original)
+++ trunk/configs/sip.conf.sample Thu Feb  9 12:14:39 2012
@@ -831,17 +831,34 @@
 ; 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




More information about the asterisk-commits mailing list