You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules_s/mangler/sdp_mangler.c

568 lines
14 KiB

/*
* mangler module
*
* $Id$
*
* Copyright (C) 2001-2003 FhG Fokus
*
* This file is part of ser, a free SIP server.
*
* ser is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* ser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* History:
* --------
* 2003-04-07 first version.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
#include "sdp_mangler.h"
#include "ip_helper.h"
#include "utils.h"
#include "common.h"
#include "../../mem/mem.h"
#include "../../data_lump.h"
#include "../../parser/hf.h"
#include "../../parser/parse_content.h"
#include "../../parser/parse_uri.h"
#include "../../parser/contact/parse_contact.h"
#include "../../ut.h"
#include "../../parser/msg_parser.h" /* struct sip_msg */
regex_t *portExpression;
regex_t *ipExpression;
int
sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused)
{
int oldContentLength, newContentLength, oldlen, err, oldPort, newPort,
diff, offsetValue,len,off,ret,needToDealocate;
struct lump *l;
regmatch_t pmatch;
regex_t *re;
char *s, *pos,*begin,*key;
char buf[6];
key = PORT_REGEX;
/*
* Checking if msg has a payload
*/
if (msg == NULL)
{
LOG(L_ERR,"ERROR: sdp_mangle_port: Received NULL for msg \n");
return -1;
}
if ((msg->content_length==0) &&
((parse_headers(msg,HDR_CONTENTLENGTH_F,0)==-1) ||
(msg->content_length==0) )){
LOG(L_ERR,"ERROR: sdp_mangle_port: bad or missing "
"Content-Length \n");
return -2;
}
oldContentLength = get_content_length(msg);
if (oldContentLength <= 0)
{
LOG(L_ERR,"ERROR: sdp_mangle_port: Received <= 0 for Content-Length \n");
return -2;
}
if (offset == NULL)
return -14;
if (sscanf (offset, "%d", &offsetValue) != 1)
{
LOG(L_ERR,"ERROR: sdp_mangle_port: Invalid value for offset \n");
return -13;
}
//offsetValue = (int)offset;
#ifdef EXTRA_DEBUG
fprintf (stdout,"---START--------MANGLE PORT-----------------\n");
fprintf(stdout,"===============OFFSET = %d\n",offsetValue);
#endif
if ((offsetValue < MIN_OFFSET_VALUE) || (offsetValue > MAX_OFFSET_VALUE))
{
LOG(L_ERR,"ERROR: sdp_mangle_port: Invalid value %d for offset \n",offsetValue);
return -3;
}
begin = get_body(msg); //msg->buf + msg->first_line.len; // inlocuiesc cu begin = getbody */
ret = -1;
/* try to use pre-compiled expressions */
needToDealocate = 0;
if (portExpression != NULL)
{
re = portExpression;
#ifdef EXTRA_DEBUG
fprintf(stdout,"Using PRECOMPILED expression for port ...\n");
#endif
}
else /* we are not using pre-compiled expressions */
{
re = pkg_malloc(sizeof(regex_t));
if (re == NULL)
{
LOG(L_ERR,"ERROR: sdp_mangle_port: Unable to allocate re\n");
return -4;
}
needToDealocate = 1;
if ((regcomp (re, key, REG_EXTENDED)) != 0)
{
LOG(L_ERR,"ERROR: sdp_mangle_port: Unable to compile %s \n",key);
return -5;
}
#ifdef EXTRA_DEBUG
fprintf(stdout,"Using ALLOCATED expression for port ...\n");
#endif
}
diff = 0;
while ((begin < msg->buf + msg->len) && (regexec (re, begin, 1, &pmatch, 0) == 0))
{
off = begin - msg->buf;
if (pmatch.rm_so == -1)
{
LOG (L_ERR, "ERROR: sdp_mangle_port: offset unknown\n");
return -6;
}
#ifdef STRICT_CHECK
pmatch.rm_eo --; /* return with one space */
#endif
/*
for BSD and Solaris we avoid memrchr
pos = (char *) memrchr (begin + pmatch.rm_so, ' ',pmatch.rm_eo - pmatch.rm_so);
*/
pos = begin+pmatch.rm_eo;
#ifdef EXTRA_DEBUG
printf("begin=%c pos=%c rm_so=%d rm_eo=%d\n",*begin,*pos,pmatch.rm_so,pmatch.rm_eo);
#endif
do pos--; while (*pos != ' '); /* we should find ' ' because we matched m=audio port */
pos++; /* jumping over space */
oldlen = (pmatch.rm_eo - pmatch.rm_so) - (pos - (begin + pmatch.rm_so)); /* port length */
/* convert port to int */
oldPort = str2s (pos, oldlen, &err);
#ifdef EXTRA_DEBUG
printf("port to convert [%.*s] to int\n",oldlen,pos);
#endif
if (err)
{
LOG(L_ERR,"ERROR: sdp_mangle_port: Error converting [%.*s] to int\n",oldlen,pos);
#ifdef STRICT_CHECK
return -7;
#else
goto continue1;
#endif
}
if ((oldPort < MIN_ORIGINAL_PORT) || (oldPort > MAX_ORIGINAL_PORT)) /* we silently fail,we ignore this match or return -11 */
{
#ifdef EXTRA_DEBUG
printf("WARNING: sdp_mangle_port: Silent fail for not matching old port %d\n",oldPort);
#endif
LOG(L_WARN,"WARNING: sdp_mangle_port: Silent fail for not matching old port %d\n",oldPort);
#ifdef STRICT_CHECK
return -8;
#else
goto continue1;
#endif
}
if ((offset[0] != '+')&&(offset[0] != '-')) newPort = offsetValue;//fix value
else newPort = oldPort + offsetValue;
/* new port is between 1 and 65536, or so should be */
if ((newPort < MIN_MANGLED_PORT) || (newPort > MAX_MANGLED_PORT)) /* we silently fail,we ignore this match */
{
#ifdef EXTRA_DEBUG
printf("WARNING: sdp_mangle_port: Silent fail for not matching new port %d\n",newPort);
#endif
LOG(L_WARN,"WARNING: sdp_mangle_port: Silent fail for not matching new port %d\n",newPort);
#ifdef STRICT_CHECK
return -9;
#else
goto continue1;
#endif
}
#ifdef EXTRA_DEBUG
fprintf(stdout,"Extracted port is %d and mangling to %d\n",oldPort,newPort);
#endif
/*
len = 1;
while ((newPort = (newPort / 10)) != 0) len++;
newPort = oldPort + offsetValue;
*/
if (newPort >= 10000) len = 5;
else
if (newPort >= 1000) len = 4;
else
if (newPort >= 100) len = 3;
else
if (newPort >= 10) len = 2;
else len = 1;
/* replaced five div's + 1 add with most probably 1 comparison or 2 */
/* deleting old port */
if ((l = del_lump (msg, pmatch.rm_so + off +
(pos -(begin + pmatch.rm_so)),oldlen, 0)) == 0)
{
LOG (L_ERR,"ERROR: sdp_mangle_port: del_lump failed\n");
return -10;
}
s = pkg_malloc (len);
if (s == 0)
{
LOG (L_ERR,"ERROR: sdp_mangle_port : memory allocation failure\n");
return -11;
}
snprintf (buf, len + 1, "%u", newPort); /* converting to string */
memcpy (s, buf, len);
if (insert_new_lump_after (l, s, len, 0) == 0)
{
LOG (L_ERR, "ERROR: sdp_mangle_port: could not insert new lump\n");
pkg_free (s);
return -12;
}
diff = diff + len /*new length */ - oldlen;
/* new cycle */
ret++;
#ifndef STRICT_CHECK
continue1:
#endif
begin = begin + pmatch.rm_eo;
} /* while */
if (needToDealocate)
{
regfree (re);
pkg_free(re);
#ifdef EXTRA_DEBUG
fprintf(stdout,"Deallocating expression for port ...\n");
#endif
}
if (diff != 0)
{
newContentLength = oldContentLength + diff;
patch_content_length (msg, newContentLength);
}
#ifdef EXTRA_DEBUG
fprintf (stdout,"---END--------MANGLE PORT-----------------\n");
#endif
return ret+2;
}
int
sdp_mangle_ip (struct sip_msg *msg, char *oldip, char *newip)
{
int i, oldContentLength, newContentLength, diff, oldlen,len,off,ret,needToDealocate;
unsigned int mask, address, locatedIp;
struct lump *l;
regmatch_t pmatch;
regex_t *re;
char *s, *pos,*begin,*key;
char buffer[16]; /* 123.456.789.123\0 */
#ifdef EXTRA_DEBUG
fprintf (stdout,"---START--------MANGLE IP-----------------\n");
#endif
key = IP_REGEX;
/*
* Checking if msg has a payload
*/
if (msg == NULL)
{
LOG(L_ERR,"ERROR: sdp_mangle_ip: Received NULL for msg\n");
return -1;
}
if ((msg->content_length==0) &&
((parse_headers(msg,HDR_CONTENTLENGTH_F,0)==-1) ||
(msg->content_length==0) )){
LOG(L_ERR,"ERROR: sdp_mangle_port: bad or missing "
"Content-Length \n");
return -2;
}
oldContentLength = get_content_length(msg);
if (oldContentLength <= 0)
{
LOG(L_ERR,"ERROR: sdp_mangle_ip: Received <= for Content-Length\n");
return -2;
}
/* checking oldip */
if (oldip == NULL)
{
LOG(L_ERR,"ERROR: sdp_mangle_ip: Received NULL for oldip\n");
return -3;
}
/* checking newip */
if (newip == NULL)
{
LOG(L_ERR,"ERROR: sdp_mangle_ip: Received NULL for newip\n");
return -4;
}
i = parse_ip_netmask (oldip, &pos, &mask);
if (i == -1)
{
/* invalid value for the netmask specified in oldip */
LOG(L_ERR,"ERROR: sdp_mangle_ip: invalid value for the netmask specified in oldip\n");
return -5;
}
else
{
i = parse_ip_address (pos, &address);
if (pos != NULL) free (pos);
if (i == 0)
{
LOG(L_ERR,"ERROR: sdp_mangle_ip: invalid value for the ip specified in oldip\n");
return -6; /* parse error in ip */
}
}
/* now we have in address/netmask binary values */
begin = get_body(msg);//msg->buf + msg->first_line.len; // inlocuiesc cu begin = getbody */
ret = -1;
len = strlen (newip);
/* try to use pre-compiled expressions */
needToDealocate = 0;
if (ipExpression != NULL)
{
re = ipExpression;
#ifdef EXTRA_DEBUG
fprintf(stdout,"Using PRECOMPILED expression for ip ...\n");
#endif
}
else /* we are not using pre-compiled expressions */
{
re = pkg_malloc(sizeof(regex_t));
if (re == NULL)
{
LOG(L_ERR,"ERROR: sdp_mangle_ip: Unable to allocate re\n");
return -7;
}
needToDealocate = 1;
if ((regcomp (re, key, REG_EXTENDED)) != 0)
{
LOG(L_ERR,"ERROR: sdp_mangle_ip: Unable to compile %s \n",key);
return -8;
}
#ifdef EXTRA_DEBUG
fprintf(stdout,"Using ALLOCATED expression for ip ...\n");
#endif
}
diff = 0;
while ((begin < msg->buf + msg->len) && (regexec (re, begin, 1, &pmatch, 0) == 0))
{
off = begin - msg->buf;
if (pmatch.rm_so == -1)
{
LOG (L_ERR,"ERROR: sdp_mangler_ip: offset unknown\n");
return -9;
}
#ifdef STRICT_CHECK
pmatch.rm_eo --; /* return with one space,\n,\r */
#endif
/*
for BSD and Solaris we avoid memrchr
pos = (char *) memrchr (begin + pmatch.rm_so, ' ',pmatch.rm_eo - pmatch.rm_so);
*/
pos = begin+pmatch.rm_eo;
do pos--; while (*pos != ' '); /* we should find ' ' because we matched c=IN IP4 ip */
pos++; /* jumping over space */
oldlen = (pmatch.rm_eo - pmatch.rm_so) - (pos - (begin + pmatch.rm_so)); /* ip length */
if (oldlen > 15)
{
LOG(L_WARN,"WARNING: sdp_mangle_ip: Silent fail because oldlen > 15\n");
#ifdef STRICT_CHECK
return -10;
#else
goto continue2; /* silent fail return -10; invalid ip format ,probably like 1000.3.12341.2 */
#endif
}
buffer[0] = '\0';
strncat ((char *) buffer, pos, oldlen);
buffer[oldlen] = '\0';
i = parse_ip_address (buffer, &locatedIp);
if (i == 0)
{
LOG(L_WARN,"WARNING: sdp_mangle_ip: Silent fail on parsing matched address \n");
#ifdef STRICT_CHECK
return -11;
#else
goto continue2;
#endif
}
if (same_net (locatedIp, address, mask) == 0)
{
LOG(L_WARN,"WARNING: sdp_mangle_ip: Silent fail because matched address is not in network\n");
#ifdef EXTRA_DEBUG
fprintf(stdout,"Extracted ip is %s and not mangling \n",buffer);
#endif
goto continue2; /* not in the same net, skipping */
}
#ifdef EXTRA_DEBUG
fprintf(stdout,"Extracted ip is %s and mangling to %s\n",buffer,newip);
#endif
/* replacing ip */
/* deleting old ip */
if ((l = del_lump (msg,pmatch.rm_so + off +
(pos - (begin + pmatch.rm_so)),oldlen, 0)) == 0)
{
LOG (L_ERR,"ERROR: sdp_mangle_ip: del_lump failed\n");
return -12;
}
s = pkg_malloc (len);
if (s == 0)
{
LOG (L_ERR,"ERROR: sdp_mangle_ip: mem. allocation failure\n");
return -13;
}
memcpy (s, newip, len);
if (insert_new_lump_after (l, s, len, 0) == 0)
{
LOG (L_ERR, "ERROR: sdp_mangle_ip: could not insert new lump\n");
pkg_free (s);
return -14;
}
diff = diff + len /*new length */ - oldlen;
/* new cycle */
ret++;
continue2:
begin = begin + pmatch.rm_eo;
} /* while */
if (needToDealocate)
{
regfree (re); /* if I am going to use pre-compiled expressions to be removed */
pkg_free(re);
#ifdef EXTRA_DEBUG
fprintf(stdout,"Deallocating expression for ip ...\n");
#endif
}
if (diff != 0)
{
newContentLength = oldContentLength + diff;
patch_content_length (msg, newContentLength);
}
#ifdef EXTRA_DEBUG
fprintf (stdout,"---END--------MANGLE IP-----------------\n");
#endif
return ret+2;
}
int compile_expresions(char *port,char *ip)
{
portExpression = NULL;
portExpression = pkg_malloc(sizeof(regex_t));
if (portExpression != NULL)
{
if ((regcomp (portExpression,port, REG_EXTENDED)) != 0)
{
LOG(L_ERR,"ERROR: compile_expresions: Unable to compile portExpression [%s]\n",port);
pkg_free(portExpression);
portExpression = NULL;
}
}
else
{
LOG(L_ERR,"ERROR: compile_expresions: Unable to alloc portExpression \n");
}
ipExpression = NULL;
ipExpression = pkg_malloc(sizeof(regex_t));
if (ipExpression != NULL)
{
if ((regcomp (ipExpression,ip, REG_EXTENDED)) != 0)
{
LOG(L_ERR,"ERROR: compile_expresions: Unable to compile ipExpression [%s]\n",ip);
pkg_free(ipExpression);
ipExpression = NULL;
}
}
else
{
LOG(L_ERR,"ERROR: compile_expresions: Unable to alloc ipExpression \n");
}
return 0;
}
int free_compiled_expresions()
{
if (portExpression != NULL)
{
regfree(portExpression);
pkg_free(portExpression);
portExpression = NULL;
}
if (ipExpression != NULL)
{
regfree(ipExpression);
pkg_free(ipExpression);
ipExpression = NULL;
}
return 0;
}