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