270fe81f6748ab32a12c614b203dd7868dbfddb4
[sip-router] / modules_k / uac_redirect / redirect.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2005 Voice Sistem SRL
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  *
23  * History:
24  * ---------
25  *  2005-06-22  first version (bogdan)
26  */
27
28 #include <sys/types.h> /* for regex */
29 #include <regex.h>
30
31 #include "../../sr_module.h"
32 #include "../../str.h"
33 #include "../../dprint.h"
34 #include "../../mem/mem.h"
35 #include "../tm/tm_load.h"
36 #include "rd_funcs.h"
37 #include "rd_filter.h"
38
39 MODULE_VERSION
40
41 /* internal global variables */
42 struct tm_binds rd_tmb;           /*imported functions from tm */
43 cmd_function    rd_acc_fct = 0;   /*imported function from acc */
44
45 /* global parameter variables */
46 char *acc_db_table = "acc";
47 char *acc_fct_s    = "acc_log_request";
48
49 /* private parameter variables */
50 char *deny_filter_s = 0;
51 char *accept_filter_s = 0;
52 char *def_filter_s = 0;
53
54 unsigned int bflags = 0;
55
56 #define ACCEPT_RULE_STR "accept"
57 #define DENY_RULE_STR   "deny"
58
59
60
61 static int redirect_init(void);
62 static int w_set_deny(struct sip_msg* msg, char *dir, char *foo);
63 static int w_set_accept(struct sip_msg* msg, char *dir, char *foo);
64 static int w_get_redirect1(struct sip_msg* msg, char *dir, char *foo);
65 static int w_get_redirect2(struct sip_msg* msg, char *dir, char *foo);
66 static int regexp_compile(char *re_s, regex_t **re);
67 static int get_redirect_fixup(void** param, int param_no);
68 static int setf_fixup(void** param, int param_no);
69
70
71 static cmd_export_t cmds[] = {
72         {"set_deny_filter",   (cmd_function)w_set_deny,      2,  setf_fixup, 0,
73                         FAILURE_ROUTE },
74         {"set_accept_filter", (cmd_function)w_set_accept,    2,  setf_fixup, 0,
75                         FAILURE_ROUTE },
76         {"get_redirects",     (cmd_function)w_get_redirect2,  2,  get_redirect_fixup, 0,
77                         FAILURE_ROUTE },
78         {"get_redirects",     (cmd_function)w_get_redirect1,  1,  get_redirect_fixup, 0,
79                         FAILURE_ROUTE },
80         {0, 0, 0, 0, 0, 0}
81 };
82
83 static param_export_t params[] = {
84         {"deny_filter",     STR_PARAM,  &deny_filter_s    },
85         {"accept_filter",   STR_PARAM,  &accept_filter_s  },
86         {"default_filter",  STR_PARAM,  &def_filter_s     },
87         {"acc_function",    STR_PARAM,  &acc_fct_s        },
88         {"acc_db_table",    STR_PARAM,  &acc_db_table     },
89         {"bflags",              INT_PARAM,  &bflags                       },
90         {0, 0, 0}
91 };
92
93
94 struct module_exports exports = {
95         "uac_redirect",
96         DEFAULT_DLFLAGS, /* dlopen flags */
97         cmds,     /* Exported functions */
98         params,   /* Exported parameters */
99         0,        /* exported statistics */
100         0,        /* exported MI functions */
101         0,        /* exported pseudo-variables */
102         0,        /* extra processes */
103         redirect_init, /* Module initialization function */
104         0,
105         0,
106         (child_init_function) 0 /* per-child init function */
107 };
108
109
110
111 int get_nr_max(char *s, unsigned char *max)
112 {
113         unsigned short nr;
114         int err;
115
116         if ( s[0]=='*' && s[1]==0 ) {
117                 /* is '*' -> infinit ;-) */
118                 *max = 0;
119                 return 0;
120         } else {
121                 /* must be a positive number less than 255 */
122                 nr = str2s(s, strlen(s), &err);
123                 if (err==0){
124                         if (nr>255){
125                                 LM_ERR("number too big <%d> (max=255)\n",nr);
126                                 return -1;
127                         }
128                         *max = (unsigned char)nr;
129                         return 0;
130                 }else{
131                         LM_ERR("bad  number <%s>\n",s);
132                         return -1;
133                 }
134         }
135 }
136
137
138 static int get_redirect_fixup(void** param, int param_no)
139 {
140         unsigned char maxb,maxt;
141         struct acc_param *accp;
142         cmd_function fct;
143         char *p;
144         char *s;
145
146         s = (char*)*param;
147         if (param_no==1) {
148                 if ( (p=strchr(s,':'))!=0 ) {
149                         /* have max branch also */
150                         *p = 0;
151                         if (get_nr_max(p+1, &maxb)!=0)
152                                 return E_UNSPEC;
153                 } else {
154                         maxb = 0; /* infinit */
155                 }
156
157                 /* get max total */
158                 if (get_nr_max(s, &maxt)!=0)
159                         return E_UNSPEC;
160
161                 pkg_free(*param);
162                 *param=(void*)(long)( (((unsigned short)maxt)<<8) | maxb);
163
164         } else if (param_no==2) {
165                 /* acc function loaded? */
166                 if (rd_acc_fct!=0)
167                         return 0;
168                 /* must import the acc stuff */
169                 if (acc_fct_s==0 || acc_fct_s[0]==0) {
170                         LM_ERR("acc support enabled, but no acc function defined\n");
171                         return E_UNSPEC;
172                 }
173                 fct = find_export(acc_fct_s, 2, REQUEST_ROUTE);
174                 if ( fct==0 )
175                         fct = find_export(acc_fct_s, 1, REQUEST_ROUTE);
176                 if ( fct==0 ) {
177                         LM_ERR("cannot import %s function; is acc loaded and proper "
178                                 "compiled?\n", acc_fct_s);
179                         return E_UNSPEC;
180                 }
181                 rd_acc_fct = fct;
182                 /* set the reason str */
183                 accp = (struct acc_param*)pkg_malloc(sizeof(struct acc_param));
184                 if (accp==0) {
185                         LM_ERR("no more pkg mem\n");
186                         return E_UNSPEC;
187                 }
188                 memset( accp, 0, sizeof(struct acc_param));
189                 if (s!=0 && *s!=0) {
190                         accp->reason.s = s;
191                         accp->reason.len = strlen(s);
192                 } else {
193                         accp->reason.s = "n/a";
194                         accp->reason.len = 3;
195                 }
196                 *param=(void*)accp;
197         }
198
199         return 0;
200 }
201
202
203 static int setf_fixup(void** param, int param_no)
204 {
205         unsigned short nr;
206         regex_t *filter;
207         char *s;
208
209         s = (char*)*param;
210         if (param_no==1) {
211                 /* compile the filter */
212                 if (regexp_compile( s, &filter)<0) {
213                         LM_ERR("cannot init filter <%s>\n", s);
214                         return E_BAD_RE;
215                 }
216                 pkg_free(*param);
217                 *param = (void*)filter;
218         } else if (param_no==2) {
219                 if (s==0 || s[0]==0) {
220                         nr = 0;
221                 } else if (strcasecmp(s,"reset_all")==0) {
222                         nr = RESET_ADDED|RESET_DEFAULT;
223                 } else if (strcasecmp(s,"reset_default")==0) {
224                         nr = RESET_DEFAULT;
225                 } else if (strcasecmp(s,"reset_added")==0) {
226                         nr = RESET_ADDED;
227                 } else {
228                         LM_ERR("unknown reset type <%s>\n",s);
229                         return E_UNSPEC;
230                 }
231                 pkg_free(*param);
232                 *param = (void*)(long)nr;
233         }
234
235         return 0;
236 }
237
238
239
240 static int regexp_compile(char *re_s, regex_t **re)
241 {
242         *re = 0;
243         if (re_s==0 || strlen(re_s)==0 ) {
244                 return 0;
245         } else {
246                 if ((*re=pkg_malloc(sizeof(regex_t)))==0)
247                         return E_OUT_OF_MEM;
248                 if (regcomp(*re, re_s, REG_EXTENDED|REG_ICASE|REG_NEWLINE) ){
249                         pkg_free(*re);
250                         *re = 0;
251                         LM_ERR("regexp_compile:bad regexp <%s>\n", re_s);
252                         return E_BAD_RE;
253                 }
254         }
255         return 0;
256 }
257
258
259
260 static int redirect_init(void)
261 {
262         regex_t *filter;
263
264         /* load the TM API */
265         if (load_tm_api(&rd_tmb)!=0) {
266                 LM_ERR("failed to load TM API\n");
267                 goto error;
268         }
269
270         /* init filter */
271         init_filters();
272
273         /* what's the default rule? */
274         if (def_filter_s) {
275                 if ( !strcasecmp(def_filter_s,ACCEPT_RULE_STR) ) {
276                         set_default_rule( ACCEPT_RULE );
277                 } else if ( !strcasecmp(def_filter_s,DENY_RULE_STR) ) {
278                         set_default_rule( DENY_RULE );
279                 } else {
280                         LM_ERR("unknown default filter <%s>\n",def_filter_s);
281                 }
282         }
283
284         /* if accept filter specify, compile it */
285         if (regexp_compile(accept_filter_s, &filter)<0) {
286                 LM_ERR("failed to init accept filter\n");
287                 goto error;
288         }
289         add_default_filter( ACCEPT_FILTER, filter);
290
291         /* if deny filter specify, compile it */
292         if (regexp_compile(deny_filter_s, &filter)<0) {
293                 LM_ERR("failed to init deny filter\n");
294                 goto error;
295         }
296         add_default_filter( DENY_FILTER, filter);
297
298         return 0;
299 error:
300         return -1;
301 }
302
303
304 static inline void msg_tracer(struct sip_msg* msg, int reset)
305 {
306         static unsigned int id  = 0;
307         static unsigned int set = 0;
308
309         if (reset) {
310                 set = 0;
311         } else {
312                 if (set) {
313                         if (id!=msg->id) {
314                                 LM_WARN("filters set but not used -> reseting to default\n");
315                                 reset_filters();
316                                 id = msg->id;
317                         }
318                 } else {
319                         id = msg->id;
320                         set = 1;
321                 }
322         }
323 }
324
325
326 static int w_set_deny(struct sip_msg* msg, char *re, char *flags)
327 {
328         msg_tracer( msg, 0);
329         return (add_filter( DENY_FILTER, (regex_t*)re, (int)(long)flags)==0)?1:-1;
330 }
331
332
333 static int w_set_accept(struct sip_msg* msg, char *re, char *flags)
334 {
335         msg_tracer( msg, 0);
336         return (add_filter( ACCEPT_FILTER, (regex_t*)re, (int)(long)flags)==0)?1:-1;
337 }
338
339
340 static int w_get_redirect2(struct sip_msg* msg, char *max_c, char *reason)
341 {
342         int n;
343         unsigned short max;
344
345         msg_tracer( msg, 0);
346         /* get the contacts */
347         max = (unsigned short)(long)max_c;
348         n = get_redirect(msg , (max>>8)&0xff, max&0xff, (struct acc_param*)reason, bflags);
349         reset_filters();
350         /* reset the tracer */
351         msg_tracer( msg, 1);
352
353         return n;
354 }
355
356
357 static int w_get_redirect1(struct sip_msg* msg, char *max_c, char *foo)
358 {
359         return w_get_redirect2(msg, max_c, 0);
360 }
361