From e4614cf487c86ab85ced9a187109be6be32128fb Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Tue, 12 Aug 2003 16:48:16 +0000
Subject: [PATCH] Add optional pedantic SIP checking

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1298 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 CHANGES                 |  1 +
 channels/chan_sip.c     | 63 ++++++++++++++++++++++++++++++++---------
 configs/sip.conf.sample |  1 +
 3 files changed, 51 insertions(+), 14 deletions(-)

diff --git a/CHANGES b/CHANGES
index 85d89df303..16c88e52f4 100755
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,4 @@
+ -- Add optional pedantic SIP checking for Pingtel
  -- Allow extension names, include context, switch to use global vars.
  -- Allow variables in extensions.conf to reference previously defined ones
  -- Merge voicemail enhancements (app_voicemail2)
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 86455c321f..b847ef9255 100755
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -83,6 +83,8 @@ static char *config = "sip.conf";
 #define DEFAULT_SIP_PORT	5060	/* From RFC 2543 */
 #define SIP_MAX_PACKET	1500		/* Also from RFC 2543, should sub headers tho */
 
+#define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER"
+
 static char context[AST_MAX_EXTENSION] = "default";
 
 static char language[MAX_LANGUAGE] = "";
@@ -95,6 +97,8 @@ static char notifymime[AST_MAX_EXTENSION] = "application/simple-message-summary"
 
 static int srvlookup = 0;
 
+static int pedanticsipchecking = 0;
+
 static int usecnt =0;
 static pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
 
@@ -1459,7 +1463,45 @@ static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *si
 {
 	struct sip_pvt *p;
 	char *callid;
+	char tmp[256] = "";
+	char *cmd;
+	char *tag = "", *c;
+	int themisfrom;
 	callid = get_header(req, "Call-ID");
+
+	if (pedanticsipchecking) {
+		/* In principle Call-ID's uniquely identify a call, however some vendors
+		   (i.e. Pingtel) send multiple calls with the same Call-ID and different
+		   tags in order to simplify billing.  The RFC does state that we have to
+		   compare tags in addition to the call-id, but this generate substantially
+		   more overhead which is totally unnecessary for the vast majority of sane
+		   SIP implementations, and thus Asterisk does not enable this behavior
+		   by default. Short version: You'll need this option to support conferencing
+		   on the pingtel */
+		strncpy(tmp, req->header[0], sizeof(tmp) - 1);
+		cmd = tmp;
+		c = strchr(tmp, ' ');
+		if (c)
+			*c = '\0';
+		if (!strcasecmp(cmd, "SIP/2.0")) {
+			themisfrom = 0;
+		} else {
+			themisfrom = 1;
+		}
+		if (themisfrom)
+			strncpy(tmp, get_header(req, "From"), sizeof(tmp) - 1);
+		else
+			strncpy(tmp, get_header(req, "To"), sizeof(tmp) - 1);
+		tag = strstr(tmp, "tag=");
+		if (tag) {
+			tag += 4;
+			c = strchr(tag, ';');
+			if (c)
+				*c = '\0';
+		}
+			
+	}
+		
 	if (!strlen(callid)) {
 		ast_log(LOG_WARNING, "Call missing call ID from '%s'\n", inet_ntoa(sin->sin_addr));
 		return NULL;
@@ -1467,20 +1509,9 @@ static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *si
 	ast_pthread_mutex_lock(&iflock);
 	p = iflist;
 	while(p) {
-		if (!strcmp(p->callid, callid)) {
+		if (!strcmp(p->callid, callid) && 
+			(!pedanticsipchecking || !strlen(p->theirtag) || !strcmp(p->theirtag, tag))) {
 			/* Found the call */
-#if 0
-			if (!p->insecure && ((p->sa.sin_addr.s_addr != sin->sin_addr.s_addr) ||
-			    (p->sa.sin_port != sin->sin_port))) {
-					char orig[80];
-					char new[80];
-					snprintf(orig, sizeof(orig), "%s:%d", inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port));
-					snprintf(new, sizeof(new), "%s:%d", inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
-					ast_log(LOG_WARNING, "Looks like %s is trying to steal call '%s' from %s?\n", new, p->callid, orig);
-					ast_pthread_mutex_unlock(&iflock);
-					return NULL;
-			}
-#endif
 			ast_pthread_mutex_lock(&p->lock);
 			ast_pthread_mutex_unlock(&iflock);
 			return p;
@@ -2194,7 +2225,7 @@ static int transmit_response_with_allow(struct sip_pvt *p, char *msg, struct sip
 {
 	struct sip_request resp;
 	respprep(&resp, p, msg, req);
-	add_header(&resp, "Allow", "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER");
+	add_header(&resp, "Allow", ALLOWED_METHODS);
 	add_header(&resp, "Accept", "application/sdp");
 	add_header(&resp, "Content-Length", "0");
 	add_blank_header(&resp);
@@ -2581,6 +2612,7 @@ static int transmit_invite(struct sip_pvt *p, char *cmd, int sdp, char *auth, ch
 	{
 		add_header(&req, "Alert-info",distinctive_ring);
 	}
+	add_header(&req, "Allow", ALLOWED_METHODS);
 	if (sdp) {
 		add_sdp(&req, p, NULL, NULL);
 	} else {
@@ -5500,6 +5532,7 @@ static int reload_config(void)
 	strcpy(fromdomain, "");
 	globalcanreinvite = REINVITE_INVITE;
 	videosupport = 0;
+	pedanticsipchecking=0;
 	v = ast_variable_browse(cfg, "general");
 	while(v) {
 		/* Create the interface list */
@@ -5530,6 +5563,8 @@ static int reload_config(void)
 			globalnat = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "srvlookup")) {
 			srvlookup = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "pedantic")) {
+			pedanticsipchecking = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "canreinvite")) {
 			if (!strcasecmp(v->value, "update"))
 				globalcanreinvite = REINVITE_UPDATE;
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index aa54ea02c0..2c8a5e4d33 100755
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -6,6 +6,7 @@ port = 5060			; Port to bind to
 bindaddr = 0.0.0.0		; Address to bind to
 context = default		; Default for incoming calls
 ;srvlookup = yes		; Enable SRV lookups on outbound calls
+;pedantic = yes			; Enable slow, pedantic checking for Pingtel
 ;tos=lowdelay
 ;tos=184
 ;maxexpirey=3600		; Max length of incoming registration we allow
-- 
GitLab