[asterisk-dev] SIP/NAT handling again (with patch)

Luigi Rizzo rizzo at icir.org
Wed Jul 25 09:21:58 CDT 2007


In my struggling with SIP-behind-NAT issues, i found out that asterisk
is not making use of useful information coming from the remote party,
namely the 'received=' and 'rport=' fields in the Via: header,
which are used by the remote party to report the address and port
where they see us.
Note that this information is exceedingly useful in evironments
where you have symmetric NAT, and STUN and other nat traversal
techniques are useless because the external mapping depends on the
4-tuple src-ip,src-port,dst-ip,dst-port and not just on the src-ip,src-port.

I would like to commit the attached patch that deals with the issue.
If there are concerns on the reliability of this information i am
happy to make it configurable as a global or per-peer option.

	cheers
	luigi

Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 77053)
+++ channels/chan_sip.c	(working copy)
@@ -9706,6 +9706,44 @@
 
 	return -1;
 }
+
+/*! \brief check received= and rport= in a SIP response.
+ * If we get a response with received= and/or rport= in the Via:
+ * line, we can use them as 'ourip' (see RFC 3581 for rport,
+ * and RFC 3261 for received (?)
+ */
+static void check_via_response(struct sip_pvt *p, struct sip_request *req)
+{
+	char via[256];
+	char *cur, *opts;
+
+	ast_copy_string(via, get_header(req, "Via"), sizeof(via));
+
+	/* Work on the leftmost value of the topmost Via header */
+	opts = strchr(via, ',');
+	if (opts)
+		*opts = '\0';
+
+	/* parse all relevant options */
+	ast_log(LOG_WARNING, "doing Via: %s\n", via);
+	opts = strchr(via, ';');
+	if (!opts)
+		return;	/* no options to parse */
+	*opts++ = '\0';
+	while ( (cur = strsep(&opts, ";")) ) {
+		if (!strncmp(cur, "rport=", 6)) {
+			int port = strtol(cur+6, NULL, 10);
+			ast_log(LOG_WARNING, "found rport: %s\n", cur);
+			/* XXX error checking */
+			p->ourip.sin_port = ntohs(port);
+		} else if (!strncmp(cur, "received=", 9)) {
+			ast_log(LOG_WARNING, "found received: %s\n", cur);
+			if (ast_parse_arg(cur+9, PARSE_INADDR, &p->ourip))
+				;	/* XXX error checking */
+		}
+	}
+}
+
 /*! \brief check Via: header for hostname, port and rport request/answer */
 static void check_via(struct sip_pvt *p, struct sip_request *req)
 {
@@ -13344,6 +13382,7 @@
 		if (resp != 100)
 			handle_response_peerpoke(p, resp, req);
 	} else if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+		check_via_response(p, req);
 		switch(resp) {
 		case 100:	/* 100 Trying */
 		case 101:	/* 101 Dialog establishment */



More information about the asterisk-dev mailing list