mangler: pkg free in case of errors
[sip-router] / src / modules / mangler / sdp_mangler.c
1 /*
2  * mangler module
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License 
19  * along with this program; if not, write to the Free Software 
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <regex.h>
28
29 #include "sdp_mangler.h"
30 #include "ip_helper.h"
31 #include "utils.h"
32 #include "common.h"
33 #include "../../core/mem/mem.h"
34 #include "../../core/data_lump.h"
35 #include "../../core/parser/hf.h"
36 #include "../../core/parser/parse_content.h"
37 #include "../../core/parser/parse_uri.h"
38 #include "../../core/parser/contact/parse_contact.h"
39 #include "../../core/ut.h"
40 #include "../../core/parser/msg_parser.h"       /* struct sip_msg */
41
42 regex_t *portExpression;
43 regex_t *ipExpression;
44
45
46
47 int
48 sdp_mangle_port (struct sip_msg *msg, char *offset, char *unused)
49 {
50         int oldContentLength, newContentLength, oldlen, err, oldPort, newPort,
51                 diff, offsetValue,len,off,ret,needToDealocate;
52         struct lump *l;
53         regmatch_t pmatch;
54         regex_t *re;
55         char *s, *pos,*begin,*key;
56         char buf[6];
57         
58         
59         
60         key = PORT_REGEX;
61         /*
62          * Checking if msg has a payload
63          */
64         if (msg == NULL)
65                 {
66                 LOG(L_ERR,"ERROR: sdp_mangle_port: Received NULL for msg \n");
67                 return -1;
68                 }
69                 
70         if ((msg->content_length==0) &&
71                         ((parse_headers(msg,HDR_CONTENTLENGTH_F,0)==-1) ||
72                          (msg->content_length==0) )){
73                 LOG(L_ERR,"ERROR: sdp_mangle_port: bad or missing "
74                                 "Content-Length \n");
75                 return -2;
76         }
77
78         oldContentLength = get_content_length(msg);
79         
80         if (oldContentLength <= 0)
81                 {
82                 LOG(L_ERR,"ERROR: sdp_mangle_port: Received <= 0 for Content-Length \n");
83                 return -2;
84                 }
85         
86         if (offset == NULL)
87                 return -14;
88         if (sscanf (offset, "%d", &offsetValue) != 1)
89         {
90                 LOG(L_ERR,"ERROR: sdp_mangle_port: Invalid value for offset \n");
91                 return -13;
92         }
93         
94         //offsetValue = (int)offset;
95 #ifdef EXTRA_DEBUG
96         fprintf (stdout,"---START--------MANGLE PORT-----------------\n");
97         fprintf(stdout,"===============OFFSET = %d\n",offsetValue);
98 #endif
99         
100         if ((offsetValue < MIN_OFFSET_VALUE) || (offsetValue > MAX_OFFSET_VALUE))
101         {
102                 LOG(L_ERR,"ERROR: sdp_mangle_port: Invalid value %d for offset \n",offsetValue);
103                 return -3;
104         }
105         begin = get_body(msg); //msg->buf + msg->first_line.len;        // inlocuiesc cu begin = getbody */
106         ret = -1;
107
108         /* try to use pre-compiled expressions */
109         needToDealocate = 0;
110         if (portExpression != NULL) 
111                 {
112                 re = portExpression;
113 #ifdef EXTRA_DEBUG
114                 fprintf(stdout,"Using PRECOMPILED expression for port ...\n");
115 #endif
116                 }
117                 else /* we are not using pre-compiled expressions */
118                         {
119                         re = pkg_malloc(sizeof(regex_t));
120                         if (re == NULL)
121                                 {
122                                 LOG(L_ERR,"ERROR: sdp_mangle_port: Unable to allocate re\n");
123                                 return -4;
124                                 }
125                         needToDealocate = 1;
126                         if ((regcomp (re, key, REG_EXTENDED)) != 0)
127                                 {
128                                 LOG(L_ERR,"ERROR: sdp_mangle_port: Unable to compile %s \n",key);
129                                 return -5;
130                                 }
131 #ifdef EXTRA_DEBUG
132                 fprintf(stdout,"Using ALLOCATED expression for port ...\n");
133 #endif
134
135                         }
136         
137         diff = 0;
138         while ((begin < msg->buf + msg->len) && (regexec (re, begin, 1, &pmatch, 0) == 0))
139         {
140                 off = begin - msg->buf;
141                 if (pmatch.rm_so == -1)
142                 {
143                         LOG (L_ERR, "ERROR: sdp_mangle_port: offset unknown\n");
144                         return -6;
145                 }
146         
147 #ifdef STRICT_CHECK
148                 pmatch.rm_eo --; /* return with one space */
149 #endif
150         
151                 /* 
152                 for BSD and Solaris we avoid memrchr
153                 pos = (char *) memrchr (begin + pmatch.rm_so, ' ',pmatch.rm_eo - pmatch.rm_so); 
154                 */
155                 pos = begin+pmatch.rm_eo;
156 #ifdef EXTRA_DEBUG
157                 printf("begin=%c pos=%c rm_so=%d rm_eo=%d\n",*begin,*pos,pmatch.rm_so,pmatch.rm_eo);
158 #endif
159                 do pos--; while (*pos != ' '); /* we should find ' ' because we matched m=audio port */
160                 
161                 pos++;          /* jumping over space */
162                 oldlen = (pmatch.rm_eo - pmatch.rm_so) - (pos - (begin + pmatch.rm_so));        /* port length */
163
164                 /* convert port to int */
165                 oldPort = str2s (pos, oldlen, &err);
166 #ifdef EXTRA_DEBUG
167                 printf("port to convert [%.*s] to int\n",oldlen,pos);
168 #endif
169                 if (err)
170                         {
171                         LOG(L_ERR,"ERROR: sdp_mangle_port: Error converting [%.*s] to int\n",oldlen,pos);
172 #ifdef STRICT_CHECK
173                         return -7;
174 #else
175                         goto continue1;
176 #endif
177                         }
178                 if ((oldPort < MIN_ORIGINAL_PORT) || (oldPort > MAX_ORIGINAL_PORT))     /* we silently fail,we ignore this match or return -11 */
179                 {
180 #ifdef EXTRA_DEBUG
181                 printf("WARNING: sdp_mangle_port: Silent fail for not matching old port %d\n",oldPort);
182 #endif
183
184                         LOG(L_WARN,"WARNING: sdp_mangle_port: Silent fail for not matching old port %d\n",oldPort);
185 #ifdef STRICT_CHECK
186                         return -8;
187 #else
188                         goto continue1;
189 #endif
190                 }
191                 if ((offset[0] != '+')&&(offset[0] != '-')) newPort = offsetValue;//fix value
192                 else newPort = oldPort + offsetValue;
193                 /* new port is between 1 and 65536, or so should be */
194                 if ((newPort < MIN_MANGLED_PORT) || (newPort > MAX_MANGLED_PORT))       /* we silently fail,we ignore this match */
195                 {
196 #ifdef EXTRA_DEBUG
197                 printf("WARNING: sdp_mangle_port: Silent fail for not matching new port %d\n",newPort);
198 #endif
199                 
200                         LOG(L_WARN,"WARNING: sdp_mangle_port: Silent fail for not matching new port %d\n",newPort);
201 #ifdef STRICT_CHECK
202                         return -9;
203 #else
204                         goto continue1;
205 #endif
206                 }
207
208 #ifdef EXTRA_DEBUG
209                 fprintf(stdout,"Extracted port is %d and mangling to %d\n",oldPort,newPort);
210 #endif
211
212                 /*
213                 len = 1;
214                 while ((newPort = (newPort / 10)) != 0) len++;
215                 newPort = oldPort + offsetValue;
216                 */
217                 if (newPort >= 10000) len = 5;
218                         else
219                                 if (newPort >= 1000) len = 4;
220                                         else
221                                                 if (newPort >= 100) len = 3;
222                                                         else
223                                                                 if (newPort >= 10) len = 2;
224                                                                         else len = 1;
225
226                 /* replaced five div's + 1 add with most probably 1 comparison or 2 */                                                  
227                 
228                 /* deleting old port */
229                 if ((l = del_lump (msg, pmatch.rm_so + off + 
230                                                 (pos -(begin + pmatch.rm_so)),oldlen, 0)) == 0)
231                 {
232                         LOG (L_ERR,"ERROR: sdp_mangle_port: del_lump failed\n");
233                         return -10;
234                 }
235                 s = pkg_malloc (len);
236                 if (s == 0)
237                 {
238                         LOG (L_ERR,"ERROR: sdp_mangle_port : memory allocation failure\n");
239                         return -11;
240                 }
241                 snprintf (buf, len + 1, "%u", newPort); /* converting to string */
242                 memcpy (s, buf, len);
243
244                 if (insert_new_lump_after (l, s, len, 0) == 0)
245                 {
246                         LOG (L_ERR, "ERROR: sdp_mangle_port: could not insert new lump\n");
247                         pkg_free (s);
248                         return -12;
249                 }
250                 diff = diff + len /*new length */  - oldlen;
251                 /* new cycle */
252                 ret++;
253 #ifndef STRICT_CHECK
254 continue1:
255 #endif
256                 begin = begin + pmatch.rm_eo;
257
258         }                       /* while  */
259         if (needToDealocate)
260                 {
261                 regfree (re);
262                 pkg_free(re);
263 #ifdef EXTRA_DEBUG
264                 fprintf(stdout,"Deallocating expression for port ...\n");
265 #endif
266                 }
267         
268         if (diff != 0)
269         {
270                 newContentLength = oldContentLength + diff;
271                 patch_content_length (msg, newContentLength);
272         }
273
274 #ifdef EXTRA_DEBUG
275         fprintf (stdout,"---END--------MANGLE PORT-----------------\n");
276 #endif
277
278         return ret+2;
279 }
280
281
282 int sdp_mangle_ip(struct sip_msg *msg, char *oldip, char *newip)
283 {
284         int i, oldContentLength, newContentLength, diff, oldlen, len, off, ret,
285                         needToDealocate;
286         unsigned int mask, address, locatedIp;
287         struct lump *l;
288         regmatch_t pmatch;
289         regex_t *re;
290         char *s, *pos, *begin, *key;
291         char buffer[16]; /* 123.456.789.123\0 */
292
293 #ifdef EXTRA_DEBUG
294         fprintf(stdout, "---START--------MANGLE IP-----------------\n");
295 #endif
296
297         pos = NULL;
298         key = IP_REGEX;
299
300         /*
301          * Checking if msg has a payload
302          */
303         if(msg == NULL) {
304                 LOG(L_ERR, "ERROR: sdp_mangle_ip: Received NULL for msg\n");
305                 return -1;
306         }
307         if((msg->content_length == 0)
308                         && ((parse_headers(msg, HDR_CONTENTLENGTH_F, 0) == -1)
309                                            || (msg->content_length == 0))) {
310                 LOG(L_ERR, "ERROR: sdp_mangle_port: bad or missing "
311                                    "Content-Length \n");
312                 return -2;
313         }
314         oldContentLength = get_content_length(msg);
315
316         if(oldContentLength <= 0) {
317                 LOG(L_ERR, "ERROR: sdp_mangle_ip: Received <= for Content-Length\n");
318                 return -2;
319         }
320
321         /* checking oldip */
322         if(oldip == NULL) {
323                 LOG(L_ERR, "ERROR: sdp_mangle_ip: Received NULL for oldip\n");
324                 return -3;
325         }
326         /* checking newip */
327         if(newip == NULL) {
328                 LOG(L_ERR, "ERROR: sdp_mangle_ip: Received NULL for newip\n");
329                 return -4;
330         }
331         i = parse_ip_netmask(oldip, &pos, &mask);
332
333         if(i == -1 || pos == NULL) {
334                 /* invalid value for the netmask specified in oldip */
335                 LOG(L_ERR, "ERROR: sdp_mangle_ip: invalid value for the netmask "
336                                    "specified in oldip\n");
337                 if(pos)
338                         free(pos);
339                 return -5;
340         } else {
341                 i = parse_ip_address(pos, &address);
342                 free(pos);
343                 if(i == 0) {
344                         LOG(L_ERR, "ERROR: sdp_mangle_ip: invalid value for the ip "
345                                            "specified in oldip\n");
346                         return -6; /* parse error in ip */
347                 }
348         }
349
350         /* now we have in address/netmask binary values */
351
352         begin = get_body(
353                         msg); //msg->buf + msg->first_line.len; // inlocuiesc cu begin = getbody */
354         ret = -1;
355         len = strlen(newip);
356
357         /* try to use pre-compiled expressions */
358         needToDealocate = 0;
359         if(ipExpression != NULL) {
360                 re = ipExpression;
361 #ifdef EXTRA_DEBUG
362                 fprintf(stdout, "Using PRECOMPILED expression for ip ...\n");
363 #endif
364
365         } else /* we are not using pre-compiled expressions */
366         {
367                 re = pkg_malloc(sizeof(regex_t));
368                 if(re == NULL) {
369                         LOG(L_ERR, "ERROR: sdp_mangle_ip: Unable to allocate re\n");
370                         return -7;
371                 }
372                 needToDealocate = 1;
373                 if((regcomp(re, key, REG_EXTENDED)) != 0) {
374                         LOG(L_ERR, "ERROR: sdp_mangle_ip: Unable to compile %s \n", key);
375                         pkg_free(re);
376                         return -8;
377                 }
378 #ifdef EXTRA_DEBUG
379                 fprintf(stdout, "Using ALLOCATED expression for ip ...\n");
380 #endif
381         }
382
383         diff = 0;
384         while((begin < msg->buf + msg->len)
385                         && (regexec(re, begin, 1, &pmatch, 0) == 0)) {
386                 off = begin - msg->buf;
387                 if(pmatch.rm_so == -1) {
388                         LOG(L_ERR, "ERROR: sdp_mangler_ip: offset unknown\n");
389                         pkg_free(re);
390                         return -9;
391                 }
392
393 #ifdef STRICT_CHECK
394                 pmatch.rm_eo--; /* return with one space,\n,\r */
395 #endif
396
397                 /* 
398                 for BSD and Solaris we avoid memrchr
399                 pos = (char *) memrchr (begin + pmatch.rm_so, ' ',pmatch.rm_eo - pmatch.rm_so); 
400                 */
401                 pos = begin + pmatch.rm_eo;
402                 do {
403                         pos--;
404                 } while(*pos
405                                 != ' '); /* we should find ' ' because we matched c=IN IP4 ip */
406
407                 pos++; /* jumping over space */
408                 oldlen = (pmatch.rm_eo - pmatch.rm_so)
409                                  - (pos - (begin + pmatch.rm_so)); /* ip length */
410                 if(oldlen > 15) {
411                         LOG(L_WARN, "WARNING: sdp_mangle_ip: Silent fail because oldlen > "
412                                                 "15\n");
413 #ifdef STRICT_CHECK
414                         pkg_free(re);
415                         return -10;
416 #else
417                         goto continue2; /* silent fail return -10; invalid ip format ,probably like 1000.3.12341.2 */
418 #endif
419                 }
420                 buffer[0] = '\0';
421                 strncat((char *)buffer, pos, oldlen);
422                 buffer[oldlen] = '\0';
423                 i = parse_ip_address(buffer, &locatedIp);
424                 if(i == 0) {
425                         LOG(L_WARN, "WARNING: sdp_mangle_ip: Silent fail on parsing "
426                                                 "matched address \n");
427
428 #ifdef STRICT_CHECK
429                         pkg_free(re);
430                         return -11;
431 #else
432                         goto continue2;
433 #endif
434                 }
435                 if(same_net(locatedIp, address, mask) == 0) {
436                         LOG(L_WARN, "WARNING: sdp_mangle_ip: Silent fail because matched "
437                                                 "address is not in network\n");
438 #ifdef EXTRA_DEBUG
439                         fprintf(stdout, "Extracted ip is %s and not mangling \n", buffer);
440 #endif
441                         goto continue2; /* not in the same net, skipping */
442                 }
443 #ifdef EXTRA_DEBUG
444                 fprintf(stdout, "Extracted ip is %s and mangling to %s\n", buffer,
445                                 newip);
446 #endif
447
448                 /* replacing ip */
449
450                 /* deleting old ip */
451                 if((l = del_lump(msg,
452                                         pmatch.rm_so + off + (pos - (begin + pmatch.rm_so)), oldlen,
453                                         0))
454                                 == 0) {
455                         LOG(L_ERR, "ERROR: sdp_mangle_ip: del_lump failed\n");
456                         pkg_free(re);
457                         return -12;
458                 }
459                 s = pkg_malloc(len);
460                 if(s == 0) {
461                         LOG(L_ERR, "ERROR: sdp_mangle_ip: mem. allocation failure\n");
462                         pkg_free(re);
463                         return -13;
464                 }
465                 memcpy(s, newip, len);
466
467                 if(insert_new_lump_after(l, s, len, 0) == 0) {
468                         LOG(L_ERR, "ERROR: sdp_mangle_ip: could not insert new lump\n");
469                         pkg_free(re);
470                         pkg_free(s);
471                         return -14;
472                 }
473                 diff = diff + len /*new length */ - oldlen;
474                 /* new cycle */
475                 ret++;
476         continue2:
477                 begin = begin + pmatch.rm_eo;
478
479         } /* while */
480         if(needToDealocate) {
481                 regfree(re); /* if I am going to use pre-compiled expressions to be removed */
482                 pkg_free(re);
483 #ifdef EXTRA_DEBUG
484                 fprintf(stdout, "Deallocating expression for ip ...\n");
485 #endif
486         }
487
488         if(diff != 0) {
489                 newContentLength = oldContentLength + diff;
490                 patch_content_length(msg, newContentLength);
491         }
492
493 #ifdef EXTRA_DEBUG
494         fprintf(stdout, "---END--------MANGLE IP-----------------\n");
495 #endif
496
497         return ret + 2;
498 }
499
500 int compile_expresions(char *port,char *ip)
501 {
502         portExpression = NULL;
503         portExpression = pkg_malloc(sizeof(regex_t));
504         if (portExpression != NULL)
505                 {
506                 if ((regcomp (portExpression,port, REG_EXTENDED)) != 0)
507                         {
508                         LOG(L_ERR,"ERROR: compile_expresions: Unable to compile portExpression [%s]\n",port);
509                         pkg_free(portExpression);
510                         portExpression = NULL;
511                         }
512                 }
513         else
514                 {
515                         LOG(L_ERR,"ERROR: compile_expresions: Unable to alloc portExpression \n");
516                 }
517         
518         ipExpression = NULL;
519         ipExpression = pkg_malloc(sizeof(regex_t));
520         if (ipExpression != NULL)
521                 {
522                 if ((regcomp (ipExpression,ip, REG_EXTENDED)) != 0)
523                         {
524                         LOG(L_ERR,"ERROR: compile_expresions: Unable to compile ipExpression [%s]\n",ip);
525                         pkg_free(ipExpression);
526                         ipExpression = NULL;
527                         }
528                 }
529         else
530                 {
531                         LOG(L_ERR,"ERROR: compile_expresions: Unable to alloc ipExpression \n");
532                 }
533         
534         return 0;
535 }
536
537 int free_compiled_expresions()
538 {
539         if (portExpression != NULL) 
540                 {
541                 regfree(portExpression);
542                 pkg_free(portExpression);
543                 portExpression = NULL;
544                 }
545         if (ipExpression != NULL) 
546                 {
547                 regfree(ipExpression);
548                 pkg_free(ipExpression);
549                 ipExpression = NULL;
550                 }
551         return 0;
552 }
553