[asterisk-commits] mmichelson: branch mmichelson/trunk_spiral r132785 - in /team/mmichelson/trun...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jul 22 17:09:43 CDT 2008


Author: mmichelson
Date: Tue Jul 22 17:09:43 2008
New Revision: 132785

URL: http://svn.digium.com/view/asterisk?view=rev&rev=132785
Log:
This is in the "it compiles" state now. Will now test


Modified:
    team/mmichelson/trunk_spiral/   (props changed)
    team/mmichelson/trunk_spiral/channels/chan_dahdi.c
    team/mmichelson/trunk_spiral/channels/chan_iax2.c
    team/mmichelson/trunk_spiral/channels/chan_sip.c
    team/mmichelson/trunk_spiral/configs/iax.conf.sample

Propchange: team/mmichelson/trunk_spiral/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Propchange: team/mmichelson/trunk_spiral/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Tue Jul 22 17:09:43 2008
@@ -1,1 +1,1 @@
-/trunk:1-132773
+/trunk:1-132781

Modified: team/mmichelson/trunk_spiral/channels/chan_dahdi.c
URL: http://svn.digium.com/view/asterisk/team/mmichelson/trunk_spiral/channels/chan_dahdi.c?view=diff&rev=132785&r1=132784&r2=132785
==============================================================================
--- team/mmichelson/trunk_spiral/channels/chan_dahdi.c (original)
+++ team/mmichelson/trunk_spiral/channels/chan_dahdi.c Tue Jul 22 17:09:43 2008
@@ -8232,7 +8232,6 @@
 #if 1
 	struct dahdi_bufferinfo bi;
 #endif
-	struct dahdi_spaninfo si;
 
 	int res;
 	int span = 0;

Modified: team/mmichelson/trunk_spiral/channels/chan_iax2.c
URL: http://svn.digium.com/view/asterisk/team/mmichelson/trunk_spiral/channels/chan_iax2.c?view=diff&rev=132785&r1=132784&r2=132785
==============================================================================
--- team/mmichelson/trunk_spiral/channels/chan_iax2.c (original)
+++ team/mmichelson/trunk_spiral/channels/chan_iax2.c Tue Jul 22 17:09:43 2008
@@ -276,6 +276,7 @@
 	IAX_DELAYPBXSTART =	(1 << 25),	/*!< Don't start a PBX on the channel until the peer sends us a
 						     response, so that we've achieved a three-way handshake with
 						     them before sending voice or anything else*/
+	IAX_ALLOWFWDOWNLOAD = (1 << 26),	/*!< Allow the FWDOWNL command? */
 };
 
 static int global_rtautoclear = 120;
@@ -1727,10 +1728,10 @@
 			snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
 
 		now = ast_tvnow();
-		start = 1 + (ast_random() % (TRUNK_CALL_START - 1));
+		start = 2 + (ast_random() % (TRUNK_CALL_START - 1));
 		for (x = start; 1; x++) {
 			if (x == TRUNK_CALL_START) {
-				x = 0;
+				x = 1;
 				continue;
 			}
 
@@ -3482,6 +3483,15 @@
 	char *context;
 	char *options;
 };
+
+static int send_apathetic_reply(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int command, int ts, unsigned char seqno)
+{
+	struct ast_iax2_full_hdr f = { .scallno = htons(0x8000 | callno), .dcallno = htons(dcallno),
+		.ts = htonl(ts), .iseqno = seqno, .oseqno = seqno, .type = AST_FRAME_IAX,
+		.csub = compress_subclass(command) };
+
+	return sendto(defaultsockfd, &f, sizeof(f), 0, (struct sockaddr *)sin, sizeof(*sin));
+}
 
 /*!
  * \brief Parses an IAX dial string into its component parts.
@@ -7995,6 +8005,17 @@
 		} else {
 			f.subclass = uncompress_subclass(fh->csub);
 		}
+
+		/* Deal with POKE/PONG without allocating a callno */
+		if (f.frametype == AST_FRAME_IAX && f.subclass == IAX_COMMAND_POKE) {
+			/* Reply back with a PONG, but don't care about the result. */
+			send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_PONG, ntohs(fh->ts), fh->oseqno);
+			return 1;
+		} else if (f.frametype == AST_FRAME_IAX && f.subclass == IAX_COMMAND_ACK && dcallno == 1) {
+			/* Ignore */
+			return 1;
+		}
+
 		if ((f.frametype == AST_FRAME_IAX) && ((f.subclass == IAX_COMMAND_NEW) || (f.subclass == IAX_COMMAND_REGREQ) ||
 						       (f.subclass == IAX_COMMAND_POKE) || (f.subclass == IAX_COMMAND_FWDOWNL) ||
 						       (f.subclass == IAX_COMMAND_REGREL)))
@@ -9382,6 +9403,10 @@
 				break;
 			case IAX_COMMAND_FWDOWNL:
 				/* Firmware download */
+				if (!ast_test_flag(&globalflags, IAX_ALLOWFWDOWNLOAD)) {
+					send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_UNSUPPORT, 0, NULL, 0, -1);
+					break;
+				}
 				memset(&ied0, 0, sizeof(ied0));
 				res = iax_firmware_append(&ied0, (unsigned char *)ies.devicetype, ies.fwdesc);
 				if (res < 0)
@@ -11029,6 +11054,8 @@
 			ast_set2_flag((&globalflags), ast_true(v->value), IAX_FORCEJITTERBUF);	
 		else if (!strcasecmp(v->name, "delayreject"))
 			delayreject = ast_true(v->value);
+		else if (!strcasecmp(v->name, "allowfwdownload"))
+			ast_set2_flag((&globalflags), ast_true(v->value), IAX_ALLOWFWDOWNLOAD);
 		else if (!strcasecmp(v->name, "rtcachefriends"))
 			ast_set2_flag((&globalflags), ast_true(v->value), IAX_RTCACHEFRIENDS);	
 		else if (!strcasecmp(v->name, "rtignoreregexpire"))

Modified: team/mmichelson/trunk_spiral/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/mmichelson/trunk_spiral/channels/chan_sip.c?view=diff&rev=132785&r1=132784&r2=132785
==============================================================================
--- team/mmichelson/trunk_spiral/channels/chan_sip.c (original)
+++ team/mmichelson/trunk_spiral/channels/chan_sip.c Tue Jul 22 17:09:43 2008
@@ -9144,7 +9144,7 @@
 		}
 	}
 
-	if (!p->initreq.headers)
+	if (!p->initreq.headers || init > 2)
 		initialize_initreq(p, &req);
 	p->lastinvite = p->ocseq;
 	return send_request(p, &req, init ? XMIT_CRITICAL : XMIT_RELIABLE, p->ocseq);
@@ -16744,6 +16744,263 @@
 	return 0;
 }
 
+/*! \brief helper routine for sip_uri_cmp
+ *
+ * This takes the parameters from two SIP URIs and determines
+ * if the URIs match. The rules for parameters *suck*. Here's a breakdown
+ * 1. If a parameter appears in both URIs, then they must have the same value
+ *    in order for the URIs to match
+ * 2. If one URI has a user, maddr, ttl, or method parameter, then the other
+ *    URI must also have that parameter and must have the same value
+ *    in order for the URIs to match
+ * 3. All other headers appearing in only one URI are not considered when
+ *    determining if URIs match
+ *
+ * \param input1 Parameters from URI 1
+ * \param input2 Parameters from URI 2
+ * \return Return 0 if the URIs' parameters match, 1 if they do not
+ */
+static int sip_uri_params_cmp(const char *input1, const char *input2) 
+{
+	char *params1 = ast_strdupa(input1);
+	char *params2 = ast_strdupa(input2);
+	char *pos1;
+	char *pos2;
+	int maddrmatch = 0;
+	int ttlmatch = 0;
+	int usermatch = 0;
+	int methodmatch = 0;
+
+	/*Quick optimization. If both params are zero-length, then
+	 * they match
+	 */
+	if (ast_strlen_zero(params1) && ast_strlen_zero(params2)) {
+		return 0;
+	}
+
+	pos1 = params1;
+	while (!ast_strlen_zero(pos1)) {
+		char *name1 = pos1;
+		char *value1 = strchr(pos1, '=');
+		char *semicolon1 = strchr(pos1, ';');
+		int matched = 0;
+		if (semicolon1) {
+			*semicolon1++ = '\0';
+		}
+		if (!value1) {
+			goto fail;
+		}
+		*value1++ = '\0';
+		/* Checkpoint reached. We have the name and value parsed for param1 
+		 * We have to duplicate params2 each time through the second loop
+		 * or else we can't search and replace the semicolons with \0 each
+		 * time
+		 */
+		pos2 = ast_strdupa(params2);
+		while (!ast_strlen_zero(pos2)) {
+			char *name2 = pos2;
+			char *value2 = strchr(pos2, '=');
+			char *semicolon2 = strchr(pos2, ';');
+			if (semicolon2) {
+				*semicolon2++ = '\0';
+			}
+			if (!value2) {
+				goto fail;
+			}
+			if (!strcasecmp(name1, name2)) {
+				if (strcasecmp(value1, value2)) {
+					goto fail;
+				} else {
+					matched = 1;
+					break;
+				}
+			}
+			pos2 = semicolon2;
+		}
+		/* Need to see if the parameter we're looking at is one of the 'must-match' parameters */
+		if (!strcasecmp(name1, "maddr")) {
+			if (matched) {
+				maddrmatch = 1;
+			} else {
+				goto fail;
+			}
+		} else if (!strcasecmp(name1, "ttl")) {
+			if (matched) {
+				ttlmatch = 1;
+			} else {
+				goto fail;
+			}
+		} else if (!strcasecmp(name1, "user")) {
+			if (matched) {
+				usermatch = 1;
+			} else {
+				goto fail;
+			}
+		} else if (!strcasecmp(name1, "method")) {
+			if (matched) {
+				methodmatch = 1;
+			} else {
+				goto fail;
+			}
+		}
+		pos1 = semicolon1;
+	}
+
+	/* We've made it out of that horrible O(m*n) construct and there are no
+	 * failures yet. We're not done yet, though, because params2 could have
+	 * an maddr, ttl, user, or method header and params1 did not.
+	 */
+	pos2 = params2;
+	while (!ast_strlen_zero(pos2)) {
+		char *name2 = pos2;
+		char *value2 = strchr(pos2, '=');
+		char *semicolon2 = strchr(pos2, ';');
+		if (semicolon2) {
+			*semicolon2++ = '\0';
+		}
+		if (!value2) {
+			goto fail;
+		}
+		if ((!strcasecmp(name2, "maddr") && !maddrmatch) ||
+				(!strcasecmp(name2, "ttl") && !ttlmatch) ||
+				(!strcasecmp(name2, "user") && !usermatch) ||
+				(!strcasecmp(name2, "method") && !methodmatch)) {
+			goto fail;
+		}
+	}
+	return 0;
+
+fail:
+	return 1;
+}
+
+/*! \brief helper routine for sip_uri_cmp
+ *
+ * This takes the "headers" from two SIP URIs and determines
+ * if the URIs match. The rules for headers is simple. If a header
+ * appears in one URI, then it must also appear in the other URI. The
+ * order in which the headers appear does not matter.
+ *
+ * \param input1 Headers from URI 1
+ * \param input2 Headers from URI 2
+ * \return Return 0 if the URIs' headers match, 1 if they do not
+ */
+static int sip_uri_headers_cmp(const char *input1, const char *input2)
+{
+	char *headers1 = ast_strdupa(input1);
+	char *headers2 = ast_strdupa(input2);
+	int zerolength1 = ast_strlen_zero(headers1);
+	int zerolength2 = ast_strlen_zero(headers2);
+	int different = 0;
+	char *header1;
+
+	if ((zerolength1 && !zerolength2) ||
+			(zerolength2 && !zerolength1))
+		return 1;
+
+	if (zerolength1 && zerolength2)
+		return 0;
+
+	/* At this point, we can definitively state that both inputs are
+	 * not zero-length. First, one more optimization. If the length
+	 * of the headers is not equal, then we definitely have no match
+	 */
+	if (strlen(headers1) != strlen(headers2)) {
+		return 1;
+	}
+
+	for (header1 = strsep(&headers1, "&"); header1; header1 = strsep(&headers1, "&")) {
+		if (!strcasestr(headers2, header1)) {
+			different = 1;
+			break;
+		}
+	}
+
+	return different;
+}
+
+static int sip_uri_cmp(const char *input1, const char *input2)
+{
+	char *uri1 = ast_strdupa(input1);
+	char *uri2 = ast_strdupa(input2);
+	char *host1;
+	char *host2;
+	char *params1;
+	char *params2;
+	char *headers1;
+	char *headers2;
+
+	/* Strip off "sip:" from the URI. We know this is present
+	 * because it was checked back in parse_request()
+	 */
+	strsep(&uri1, ":");
+	strsep(&uri2, ":");
+
+	if ((host1 = strchr(uri1, '@'))) {
+		*host1++ = '\0';
+	}
+	if ((host2 = strchr(uri2, '@'))) {
+		*host2++ = '\0';
+	}
+
+	/* Check for mismatched username and passwords. This is the
+	 * only case-sensitive comparison of a SIP URI
+	 */
+	if ((host1 && !host2) ||
+			(host2 && !host1) ||
+			(host1 && host2 && strcmp(uri1, uri2))) {
+		return 1;
+	}
+
+	if (!host1)
+		host1 = uri1;
+	if (!host2)
+		host2 = uri2;
+
+	/* Strip off the parameters and headers so we can compare
+	 * host and port
+	 */
+
+	if ((params1 = strchr(host1, ';'))) {
+		*params1++ = '\0';
+	}
+	if ((params2 = strchr(host2, ';'))) {
+		*params2++ = '\0';
+	}
+
+	/* Headers come after parameters, but there may be headers without
+	 * parameters, thus the S_OR
+	 */
+	if ((headers1 = strchr(S_OR(params1, host1), '?'))) {
+		*headers1++ = '\0';
+	}
+	if ((headers2 = strchr(S_OR(params2, host2), '?'))) {
+		*headers2++ = '\0';
+	}
+
+	/* Now the host/port are properly isolated. We can get by with a string comparison
+	 * because the SIP URI checking rules have some interesting exceptions that make
+	 * this possible. I will note 2 in particular
+	 * 1. hostnames which resolve to the same IP address as well as a hostname and its
+	 *    IP address are not considered a match with SIP URI's.
+	 * 2. If one URI specifies a port and the other does not, then the URIs do not match.
+	 *    This includes if one URI explicitly contains port 5060 and the other implies it
+	 *    by not having a port specified.
+	 */
+
+	if (strcasecmp(host1, host2)) {
+		return 1;
+	}
+
+	/* Headers have easier rules to follow, so do those first */
+	if (sip_uri_headers_cmp(headers1, headers2)) {
+		return 1;
+	}
+
+	/* And now the parameters. Ugh */
+	return sip_uri_params_cmp(params1, params2);
+}
+
 
 /*! \brief Handle incoming INVITE request
 \note 	If the INVITE has a Replaces header, it is part of an
@@ -16807,10 +17064,44 @@
 	   	being able to call yourself */
 		/* If pedantic is on, we need to check the tags. If they're different, this is
 	   	in fact a forked call through a SIP proxy somewhere. */
-		transmit_response_reliable(p, "482 Loop Detected", req);
-		p->invitestate = INV_COMPLETED;
-		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-		return 0;
+		int different;
+		if (pedanticsipchecking)
+			different = sip_uri_cmp(p->initreq.rlPart2, req->rlPart2);
+		else
+			different = strcmp(p->initreq.rlPart2, req->rlPart2);
+		if (!different) {
+			transmit_response(p, "482 Loop Detected", req);
+			p->invitestate = INV_COMPLETED;
+			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+			return 0;
+		} else {
+			/* This is a spiral. What we need to do is to just change the outgoing INVITE
+			 * so that it now routes to the new Request URI. Since we created the INVITE ourselves
+			 * that should be all we need to do.
+			 */
+			char *uri = ast_strdupa(req->rlPart2);
+			char *at = strchr(uri, '@');
+			char *peerorhost;
+			struct sip_pkt *pkt = NULL;
+			if (option_debug > 2) {
+				ast_log(LOG_DEBUG, "Potential spiral detected. Original RURI was %s, new RURI is %s\n", p->initreq.rlPart2, req->rlPart2);
+			}
+			if (at) {
+				*at = '\0';
+			}
+			/* Parse out "sip:" */
+			if ((peerorhost = strchr(uri, ':'))) {
+				*peerorhost++ = '\0';
+			}
+			create_addr(p, peerorhost, NULL);
+			ast_string_field_set(p, theirtag, NULL);
+			for (pkt = p->packets; pkt; pkt = pkt->next) {
+				if (pkt->seqno == p->icseq && pkt->method == SIP_INVITE) {
+					AST_SCHED_DEL(sched, pkt->retransid);
+				}
+			}
+			return transmit_invite(p, SIP_INVITE, 1, 3);
+		}
 	}
 	
 	if (!req->ignore && p->pendinginvite) {

Modified: team/mmichelson/trunk_spiral/configs/iax.conf.sample
URL: http://svn.digium.com/view/asterisk/team/mmichelson/trunk_spiral/configs/iax.conf.sample?view=diff&rev=132785&r1=132784&r2=132785
==============================================================================
--- team/mmichelson/trunk_spiral/configs/iax.conf.sample (original)
+++ team/mmichelson/trunk_spiral/configs/iax.conf.sample Tue Jul 22 17:09:43 2008
@@ -264,6 +264,16 @@
 ; The default value is 'host'
 ;
 ;codecpriority=host
+;
+; allowfwdownload controls whether this host will serve out firmware to
+; IAX clients which request it.  This has only been used for the IAXy,
+; and it has been recently proven that this firmware distribution method
+; can be used as a source of traffic amplification attacks.  Also, the
+; IAXy firmware has not been updated for at least 18 months, so unless
+; you are provisioning IAXys in a secure network, we recommend that you
+; leave this option to the default, off.
+;
+;allowfwdownload=yes
 
 ;rtcachefriends=yes	; Cache realtime friends by adding them to the internal list
 			; just like friends added from the config file only on a




More information about the asterisk-commits mailing list