redirect.c

00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2005 Voice Sistem SRL
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License
00010  * as published by the Free Software Foundation; either version 2
00011  * of the License, or (at your option) any later version.
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00021  *
00022  *
00023  * History:
00024  * ---------
00025  *  2005-06-22  first version (bogdan)
00026  */
00027 
00028 #include <sys/types.h> /* for regex */
00029 #include <regex.h>
00030 
00031 #include "../../sr_module.h"
00032 #include "../../str.h"
00033 #include "../../dprint.h"
00034 #include "../../mem/mem.h"
00035 #include "../../modules/tm/tm_load.h"
00036 #include "rd_funcs.h"
00037 #include "rd_filter.h"
00038 
00039 MODULE_VERSION
00040 
00041 /* internal global variables */
00042 struct tm_binds rd_tmb;           /*imported functions from tm */
00043 cmd_function    rd_acc_fct = 0;   /*imported function from acc */
00044 
00045 /* global parameter variables */
00046 char *acc_db_table = "acc";
00047 char *acc_fct_s    = "acc_log_request";
00048 
00049 /* private parameter variables */
00050 char *deny_filter_s = 0;
00051 char *accept_filter_s = 0;
00052 char *def_filter_s = 0;
00053 
00054 unsigned int bflags = 0;
00055 
00056 #define ACCEPT_RULE_STR "accept"
00057 #define DENY_RULE_STR   "deny"
00058 
00059 
00060 
00061 static int redirect_init(void);
00062 static int w_set_deny(struct sip_msg* msg, char *dir, char *foo);
00063 static int w_set_accept(struct sip_msg* msg, char *dir, char *foo);
00064 static int w_get_redirect1(struct sip_msg* msg, char *dir, char *foo);
00065 static int w_get_redirect2(struct sip_msg* msg, char *dir, char *foo);
00066 static int regexp_compile(char *re_s, regex_t **re);
00067 static int get_redirect_fixup(void** param, int param_no);
00068 static int setf_fixup(void** param, int param_no);
00069 
00070 
00071 static cmd_export_t cmds[] = {
00072         {"set_deny_filter",   (cmd_function)w_set_deny,      2,  setf_fixup, 0,
00073                         FAILURE_ROUTE },
00074         {"set_accept_filter", (cmd_function)w_set_accept,    2,  setf_fixup, 0,
00075                         FAILURE_ROUTE },
00076         {"get_redirects",     (cmd_function)w_get_redirect2,  2,  get_redirect_fixup, 0,
00077                         FAILURE_ROUTE },
00078         {"get_redirects",     (cmd_function)w_get_redirect1,  1,  get_redirect_fixup, 0,
00079                         FAILURE_ROUTE },
00080         {0, 0, 0, 0, 0, 0}
00081 };
00082 
00083 static param_export_t params[] = {
00084         {"deny_filter",     STR_PARAM,  &deny_filter_s    },
00085         {"accept_filter",   STR_PARAM,  &accept_filter_s  },
00086         {"default_filter",  STR_PARAM,  &def_filter_s     },
00087         {"acc_function",    STR_PARAM,  &acc_fct_s        },
00088         {"acc_db_table",    STR_PARAM,  &acc_db_table     },
00089         {"bflags",              INT_PARAM,  &bflags                       },
00090         {0, 0, 0}
00091 };
00092 
00093 
00094 struct module_exports exports = {
00095         "uac_redirect",
00096         DEFAULT_DLFLAGS, /* dlopen flags */
00097         cmds,     /* Exported functions */
00098         params,   /* Exported parameters */
00099         0,        /* exported statistics */
00100         0,        /* exported MI functions */
00101         0,        /* exported pseudo-variables */
00102         0,        /* extra processes */
00103         redirect_init, /* Module initialization function */
00104         0,
00105         0,
00106         (child_init_function) 0 /* per-child init function */
00107 };
00108 
00109 
00110 
00111 int get_nr_max(char *s, unsigned char *max)
00112 {
00113         unsigned short nr;
00114         int err;
00115 
00116         if ( s[0]=='*' && s[1]==0 ) {
00117                 /* is '*' -> infinit ;-) */
00118                 *max = 0;
00119                 return 0;
00120         } else {
00121                 /* must be a positive number less than 255 */
00122                 nr = str2s(s, strlen(s), &err);
00123                 if (err==0){
00124                         if (nr>255){
00125                                 LM_ERR("number too big <%d> (max=255)\n",nr);
00126                                 return -1;
00127                         }
00128                         *max = (unsigned char)nr;
00129                         return 0;
00130                 }else{
00131                         LM_ERR("bad  number <%s>\n",s);
00132                         return -1;
00133                 }
00134         }
00135 }
00136 
00137 
00138 static int get_redirect_fixup(void** param, int param_no)
00139 {
00140         unsigned char maxb,maxt;
00141         struct acc_param *accp;
00142         cmd_function fct;
00143         char *p;
00144         char *s;
00145 
00146         s = (char*)*param;
00147         if (param_no==1) {
00148                 if ( (p=strchr(s,':'))!=0 ) {
00149                         /* have max branch also */
00150                         *p = 0;
00151                         if (get_nr_max(p+1, &maxb)!=0)
00152                                 return E_UNSPEC;
00153                 } else {
00154                         maxb = 0; /* infinit */
00155                 }
00156 
00157                 /* get max total */
00158                 if (get_nr_max(s, &maxt)!=0)
00159                         return E_UNSPEC;
00160 
00161                 pkg_free(*param);
00162                 *param=(void*)(long)( (((unsigned short)maxt)<<8) | maxb);
00163 
00164         } else if (param_no==2) {
00165                 /* acc function loaded? */
00166                 if (rd_acc_fct!=0)
00167                         return 0;
00168                 /* must import the acc stuff */
00169                 if (acc_fct_s==0 || acc_fct_s[0]==0) {
00170                         LM_ERR("acc support enabled, but no acc function defined\n");
00171                         return E_UNSPEC;
00172                 }
00173                 fct = find_export(acc_fct_s, 2, REQUEST_ROUTE);
00174                 if ( fct==0 )
00175                         fct = find_export(acc_fct_s, 1, REQUEST_ROUTE);
00176                 if ( fct==0 ) {
00177                         LM_ERR("cannot import %s function; is acc loaded and proper "
00178                                 "compiled?\n", acc_fct_s);
00179                         return E_UNSPEC;
00180                 }
00181                 rd_acc_fct = fct;
00182                 /* set the reason str */
00183                 accp = (struct acc_param*)pkg_malloc(sizeof(struct acc_param));
00184                 if (accp==0) {
00185                         LM_ERR("no more pkg mem\n");
00186                         return E_UNSPEC;
00187                 }
00188                 memset( accp, 0, sizeof(struct acc_param));
00189                 if (s!=0 && *s!=0) {
00190                         accp->reason.s = s;
00191                         accp->reason.len = strlen(s);
00192                 } else {
00193                         accp->reason.s = "n/a";
00194                         accp->reason.len = 3;
00195                 }
00196                 *param=(void*)accp;
00197         }
00198 
00199         return 0;
00200 }
00201 
00202 
00203 static int setf_fixup(void** param, int param_no)
00204 {
00205         unsigned short nr;
00206         regex_t *filter;
00207         char *s;
00208 
00209         s = (char*)*param;
00210         if (param_no==1) {
00211                 /* compile the filter */
00212                 if (regexp_compile( s, &filter)<0) {
00213                         LM_ERR("cannot init filter <%s>\n", s);
00214                         return E_BAD_RE;
00215                 }
00216                 pkg_free(*param);
00217                 *param = (void*)filter;
00218         } else if (param_no==2) {
00219                 if (s==0 || s[0]==0) {
00220                         nr = 0;
00221                 } else if (strcasecmp(s,"reset_all")==0) {
00222                         nr = RESET_ADDED|RESET_DEFAULT;
00223                 } else if (strcasecmp(s,"reset_default")==0) {
00224                         nr = RESET_DEFAULT;
00225                 } else if (strcasecmp(s,"reset_added")==0) {
00226                         nr = RESET_ADDED;
00227                 } else {
00228                         LM_ERR("unknown reset type <%s>\n",s);
00229                         return E_UNSPEC;
00230                 }
00231                 pkg_free(*param);
00232                 *param = (void*)(long)nr;
00233         }
00234 
00235         return 0;
00236 }
00237 
00238 
00239 
00240 static int regexp_compile(char *re_s, regex_t **re)
00241 {
00242         *re = 0;
00243         if (re_s==0 || strlen(re_s)==0 ) {
00244                 return 0;
00245         } else {
00246                 if ((*re=pkg_malloc(sizeof(regex_t)))==0)
00247                         return E_OUT_OF_MEM;
00248                 if (regcomp(*re, re_s, REG_EXTENDED|REG_ICASE|REG_NEWLINE) ){
00249                         pkg_free(*re);
00250                         *re = 0;
00251                         LM_ERR("regexp_compile:bad regexp <%s>\n", re_s);
00252                         return E_BAD_RE;
00253                 }
00254         }
00255         return 0;
00256 }
00257 
00258 
00259 
00260 static int redirect_init(void)
00261 {
00262         regex_t *filter;
00263 
00264         /* load the TM API */
00265         if (load_tm_api(&rd_tmb)!=0) {
00266                 LM_ERR("failed to load TM API\n");
00267                 goto error;
00268         }
00269 
00270         /* init filter */
00271         init_filters();
00272 
00273         /* what's the default rule? */
00274         if (def_filter_s) {
00275                 if ( !strcasecmp(def_filter_s,ACCEPT_RULE_STR) ) {
00276                         set_default_rule( ACCEPT_RULE );
00277                 } else if ( !strcasecmp(def_filter_s,DENY_RULE_STR) ) {
00278                         set_default_rule( DENY_RULE );
00279                 } else {
00280                         LM_ERR("unknown default filter <%s>\n",def_filter_s);
00281                 }
00282         }
00283 
00284         /* if accept filter specify, compile it */
00285         if (regexp_compile(accept_filter_s, &filter)<0) {
00286                 LM_ERR("failed to init accept filter\n");
00287                 goto error;
00288         }
00289         add_default_filter( ACCEPT_FILTER, filter);
00290 
00291         /* if deny filter specify, compile it */
00292         if (regexp_compile(deny_filter_s, &filter)<0) {
00293                 LM_ERR("failed to init deny filter\n");
00294                 goto error;
00295         }
00296         add_default_filter( DENY_FILTER, filter);
00297 
00298         return 0;
00299 error:
00300         return -1;
00301 }
00302 
00303 
00304 static inline void msg_tracer(struct sip_msg* msg, int reset)
00305 {
00306         static unsigned int id  = 0;
00307         static unsigned int set = 0;
00308 
00309         if (reset) {
00310                 set = 0;
00311         } else {
00312                 if (set) {
00313                         if (id!=msg->id) {
00314                                 LM_WARN("filters set but not used -> reseting to default\n");
00315                                 reset_filters();
00316                                 id = msg->id;
00317                         }
00318                 } else {
00319                         id = msg->id;
00320                         set = 1;
00321                 }
00322         }
00323 }
00324 
00325 
00326 static int w_set_deny(struct sip_msg* msg, char *re, char *flags)
00327 {
00328         msg_tracer( msg, 0);
00329         return (add_filter( DENY_FILTER, (regex_t*)re, (int)(long)flags)==0)?1:-1;
00330 }
00331 
00332 
00333 static int w_set_accept(struct sip_msg* msg, char *re, char *flags)
00334 {
00335         msg_tracer( msg, 0);
00336         return (add_filter( ACCEPT_FILTER, (regex_t*)re, (int)(long)flags)==0)?1:-1;
00337 }
00338 
00339 
00340 static int w_get_redirect2(struct sip_msg* msg, char *max_c, char *reason)
00341 {
00342         int n;
00343         unsigned short max;
00344 
00345         msg_tracer( msg, 0);
00346         /* get the contacts */
00347         max = (unsigned short)(long)max_c;
00348         n = get_redirect(msg , (max>>8)&0xff, max&0xff, (struct acc_param*)reason, bflags);
00349         reset_filters();
00350         /* reset the tracer */
00351         msg_tracer( msg, 1);
00352 
00353         return n;
00354 }
00355 
00356 
00357 static int w_get_redirect1(struct sip_msg* msg, char *max_c, char *foo)
00358 {
00359         return w_get_redirect2(msg, max_c, 0);
00360 }
00361