1 /*
2 * Copyright (C) 2005 Voice Sistem SRL
3 *
4 * This file is part of Kamailio, a free SIP server.
5 *
6 * Kamailio is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * Kamailio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 */
21
22 #include <sys/types.h> /* for regex */
23 #include <regex.h>
24
25 #include "../../core/sr_module.h"
26 #include "../../core/str.h"
27 #include "../../core/dprint.h"
28 #include "../../core/mem/mem.h"
29 #include "../../core/utils/sruid.h"
30 #include "../../modules/tm/tm_load.h"
31 #include "../../core/kemi.h"
32 #include "rd_funcs.h"
33 #include "rd_filter.h"
34
35 MODULE_VERSION
36
37 /* internal global variables */
38 struct tm_binds rd_tmb; /*imported functions from tm */
39 cmd_function rd_acc_fct = 0; /*imported function from acc */
40
41 /* global parameter variables */
42 char *acc_db_table = "acc";
43 char *acc_fct_s = "acc_log_request";
44
45 /* private parameter variables */
46 char *deny_filter_s = 0;
47 char *accept_filter_s = 0;
48 char *def_filter_s = 0;
49
50 unsigned int bflags = 0;
51 int flags_hdr_mode = 0;
52
53 #define ACCEPT_RULE_STR "accept"
54 #define DENY_RULE_STR "deny"
55
56 /* sruid to get internal uid */
57 sruid_t _redirect_sruid;
58
59
60 static int redirect_init(void);
61 static int child_init(int rank);
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", PARAM_STRING, &deny_filter_s },
85 {"accept_filter", PARAM_STRING, &accept_filter_s },
86 {"default_filter", PARAM_STRING, &def_filter_s },
87 {"acc_function", PARAM_STRING, &acc_fct_s },
88 {"acc_db_table", PARAM_STRING, &acc_db_table },
89 {"bflags", INT_PARAM, &bflags },
90 {"flags_hdr_mode", INT_PARAM, &flags_hdr_mode },
91 {0, 0, 0}
92 };
93
94
95 struct module_exports exports = {
96 "uac_redirect", /* module name */
97 DEFAULT_DLFLAGS, /* dlopen flags */
98 cmds, /* exported functions */
99 params, /* exported parameters */
100 0, /* exported RPC functions */
101 0, /* exported pseudo-variables */
102 0, /* response handling function */
103 redirect_init, /* module initialization function */
104 child_init, /* per-child init function */
105 0 /* module destroy function */
106 };
107
108
109
get_nr_max(char * s,unsigned char * max)110 int get_nr_max(char *s, unsigned char *max)
111 {
112 unsigned short nr;
113 int err;
114
115 if ( s[0]=='*' && s[1]==0 ) {
116 /* is '*' -> infinit ;-) */
117 *max = 0;
118 return 0;
119 } else {
120 /* must be a positive number less than 255 */
121 nr = str2s(s, strlen(s), &err);
122 if (err==0){
123 if (nr>255){
124 LM_ERR("number too big <%d> (max=255)\n",nr);
125 return -1;
126 }
127 *max = (unsigned char)nr;
128 return 0;
129 }else{
130 LM_ERR("bad number <%s>\n",s);
131 return -1;
132 }
133 }
134 }
135
136
get_redirect_fixup(void ** param,int param_no)137 static int get_redirect_fixup(void** param, int param_no)
138 {
139 unsigned char maxb,maxt;
140 struct acc_param *accp;
141 cmd_function fct;
142 char *p;
143 char *s;
144
145 s = (char*)*param;
146 if (param_no==1) {
147 if ( (p=strchr(s,':'))!=0 ) {
148 /* have max branch also */
149 *p = 0;
150 if (get_nr_max(p+1, &maxb)!=0)
151 return E_UNSPEC;
152 } else {
153 maxb = 0; /* infinit */
154 }
155
156 /* get max total */
157 if (get_nr_max(s, &maxt)!=0)
158 return E_UNSPEC;
159
160 pkg_free(*param);
161 *param=(void*)(long)( (((unsigned short)maxt)<<8) | maxb);
162 } else if (param_no==2) {
163 /* acc function loaded? */
164 if (rd_acc_fct==0) {
165 /* must import the acc stuff */
166 if (acc_fct_s==0 || acc_fct_s[0]==0) {
167 LM_ERR("acc support enabled, but no acc function defined\n");
168 return E_UNSPEC;
169 }
170 fct = find_export(acc_fct_s, 2, REQUEST_ROUTE);
171 if ( fct==0 )
172 fct = find_export(acc_fct_s, 1, REQUEST_ROUTE);
173 if ( fct==0 ) {
174 LM_ERR("cannot import %s function; is acc loaded and proper "
175 "compiled?\n", acc_fct_s);
176 return E_UNSPEC;
177 }
178 rd_acc_fct = fct;
179 }
180 /* set the reason str */
181 accp = (struct acc_param*)pkg_malloc(sizeof(struct acc_param));
182 if (accp==0) {
183 PKG_MEM_ERROR;
184 return E_UNSPEC;
185 }
186 memset( accp, 0, sizeof(struct acc_param));
187 if (s!=0 && *s!=0) {
188 accp->reason.s = s;
189 accp->reason.len = strlen(s);
190 } else {
191 accp->reason.s = "n/a";
192 accp->reason.len = 3;
193 }
194 *param=(void*)accp;
195 }
196
197 return 0;
198 }
199
200
setf_fixup(void ** param,int param_no)201 static int setf_fixup(void** param, int param_no)
202 {
203 unsigned short nr;
204 regex_t *filter;
205 char *s;
206
207 s = (char*)*param;
208 if (param_no==1) {
209 /* compile the filter */
210 if (regexp_compile( s, &filter)<0) {
211 LM_ERR("cannot init filter <%s>\n", s);
212 return E_BAD_RE;
213 }
214 pkg_free(*param);
215 *param = (void*)filter;
216 } else if (param_no==2) {
217 if (s==0 || s[0]==0) {
218 nr = 0;
219 } else if (strcasecmp(s,"reset_all")==0) {
220 nr = RESET_ADDED|RESET_DEFAULT;
221 } else if (strcasecmp(s,"reset_default")==0) {
222 nr = RESET_DEFAULT;
223 } else if (strcasecmp(s,"reset_added")==0) {
224 nr = RESET_ADDED;
225 } else {
226 LM_ERR("unknown reset type <%s>\n",s);
227 return E_UNSPEC;
228 }
229 pkg_free(*param);
230 *param = (void*)(long)nr;
231 }
232
233 return 0;
234 }
235
236
237
regexp_compile(char * re_s,regex_t ** re)238 static int regexp_compile(char *re_s, regex_t **re)
239 {
240 *re = 0;
241 if (re_s==0 || strlen(re_s)==0 ) {
242 return 0;
243 } else {
244 if ((*re=pkg_malloc(sizeof(regex_t)))==0) {
245 PKG_MEM_ERROR;
246 return E_OUT_OF_MEM;
247 }
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
redirect_init(void)260 static int redirect_init(void)
261 {
262 regex_t *filter;
263 void *p;
264 cmd_function fct;
265
266 /* load the TM API */
267 if (load_tm_api(&rd_tmb)!=0) {
268 LM_ERR("failed to load TM API\n");
269 goto error;
270 }
271
272 p = (void*)acc_db_table;
273 /* fixup table name */
274 if(fixup_var_pve_str_12(&p, 1)<0) {
275 LM_ERR("failed to fixup acc db table\n");
276 goto error;
277 }
278 acc_db_table = p;
279
280 /* init filter */
281 init_filters();
282
283 /* what's the default rule? */
284 if (def_filter_s) {
285 if ( !strcasecmp(def_filter_s,ACCEPT_RULE_STR) ) {
286 set_default_rule( ACCEPT_RULE );
287 } else if ( !strcasecmp(def_filter_s,DENY_RULE_STR) ) {
288 set_default_rule( DENY_RULE );
289 } else {
290 LM_ERR("unknown default filter <%s>\n",def_filter_s);
291 }
292 }
293
294 /* if accept filter specify, compile it */
295 if (regexp_compile(accept_filter_s, &filter)<0) {
296 LM_ERR("failed to init accept filter\n");
297 goto error;
298 }
299 add_default_filter( ACCEPT_FILTER, filter);
300
301 /* if deny filter specify, compile it */
302 if (regexp_compile(deny_filter_s, &filter)<0) {
303 LM_ERR("failed to init deny filter\n");
304 goto error;
305 }
306 add_default_filter( DENY_FILTER, filter);
307
308 if(sruid_init(&_redirect_sruid, '-', "rdir", SRUID_INC)<0)
309 return -1;
310
311 if(rd_acc_fct == 0) {
312 /* import the acc stuff */
313 if(acc_fct_s != 0 && acc_fct_s[0] == '\0') {
314 fct = find_export(acc_fct_s, 2, REQUEST_ROUTE);
315 if(fct == 0)
316 fct = find_export(acc_fct_s, 1, REQUEST_ROUTE);
317 if(fct == 0) {
318 LM_ERR("cannot import %s function; is acc loaded and"
319 " configured\n", acc_fct_s);
320 return E_UNSPEC;
321 }
322 rd_acc_fct = fct;
323 }
324 }
325
326 return 0;
327 error:
328 return -1;
329 }
330
child_init(int rank)331 static int child_init(int rank)
332 {
333 if(sruid_init(&_redirect_sruid, '-', "rdir", SRUID_INC)<0)
334 return -1;
335 return 0;
336 }
337
msg_tracer(struct sip_msg * msg,int reset)338 static inline void msg_tracer(struct sip_msg* msg, int reset)
339 {
340 static unsigned int id = 0;
341 static unsigned int set = 0;
342
343 if (reset) {
344 set = 0;
345 } else {
346 if (set) {
347 if (id!=msg->id) {
348 LM_WARN("filters set but not used -> resetting to default\n");
349 reset_filters();
350 id = msg->id;
351 }
352 } else {
353 id = msg->id;
354 set = 1;
355 }
356 }
357 }
358
359
w_set_deny(struct sip_msg * msg,char * re,char * flags)360 static int w_set_deny(struct sip_msg* msg, char *re, char *flags)
361 {
362 msg_tracer( msg, 0);
363 return (add_filter( DENY_FILTER, (regex_t*)re, (int)(long)flags)==0)?1:-1;
364 }
365
366
w_set_accept(struct sip_msg * msg,char * re,char * flags)367 static int w_set_accept(struct sip_msg* msg, char *re, char *flags)
368 {
369 msg_tracer( msg, 0);
370 return (add_filter( ACCEPT_FILTER, (regex_t*)re, (int)(long)flags)==0)?1:-1;
371 }
372
373
w_get_redirect2(struct sip_msg * msg,char * max_c,char * reason)374 static int w_get_redirect2(struct sip_msg* msg, char *max_c, char *reason)
375 {
376 int n;
377 unsigned short max;
378
379 msg_tracer( msg, 0);
380 /* get the contacts */
381 max = (unsigned short)(long)max_c;
382 n = get_redirect(msg , (max>>8)&0xff, max&0xff, (struct acc_param*)reason, bflags);
383 reset_filters();
384 /* reset the tracer */
385 msg_tracer( msg, 1);
386
387 return n;
388 }
389
390
w_get_redirect1(struct sip_msg * msg,char * max_c,char * foo)391 static int w_get_redirect1(struct sip_msg* msg, char *max_c, char *foo)
392 {
393 return w_get_redirect2(msg, max_c, 0);
394 }
395
ki_get_redirects_acc(sip_msg_t * msg,int max_c,int max_b,str * reason)396 static int ki_get_redirects_acc(sip_msg_t* msg, int max_c, int max_b,
397 str *reason)
398 {
399 int n;
400 acc_param_t accp;
401
402 if(reason && reason->len>0) {
403 memset(&accp, 0, sizeof(acc_param_t));
404 accp.reason.s = reason->s;
405 accp.reason.len = reason->len;
406 }
407 msg_tracer(msg, 0);
408 /* get the contacts */
409 n = get_redirect(msg, max_c, max_b, (reason && reason->len>0)?&accp:NULL,
410 bflags);
411 reset_filters();
412 /* reset the tracer */
413 msg_tracer(msg, 1);
414
415 return n;
416 }
417
ki_get_redirects(sip_msg_t * msg,int max_c,int max_b)418 static int ki_get_redirects(sip_msg_t* msg, int max_c, int max_b)
419 {
420 int n;
421
422 msg_tracer(msg, 0);
423 /* get the contacts */
424 n = get_redirect(msg, max_c, max_b, NULL, bflags);
425 reset_filters();
426 /* reset the tracer */
427 msg_tracer(msg, 1);
428
429 return n;
430 }
431
ki_get_redirects_all(sip_msg_t * msg)432 static int ki_get_redirects_all(sip_msg_t* msg)
433 {
434 int n;
435
436 msg_tracer(msg, 0);
437 /* get the contacts */
438 n = get_redirect(msg, 0, 0, NULL, bflags);
439 reset_filters();
440 /* reset the tracer */
441 msg_tracer(msg, 1);
442
443 return n;
444 }
445
446 /**
447 *
448 */
449 /* clang-format off */
450 static sr_kemi_t sr_kemi_uac_redirect_exports[] = {
451 { str_init("uac_redirect"), str_init("get_redirects_all"),
452 SR_KEMIP_INT, ki_get_redirects_all,
453 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
454 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
455 },
456 { str_init("uac_redirect"), str_init("get_redirects"),
457 SR_KEMIP_INT, ki_get_redirects,
458 { SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_NONE,
459 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
460 },
461 { str_init("uac_redirect"), str_init("get_redirects_acc"),
462 SR_KEMIP_INT, ki_get_redirects_acc,
463 { SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_STR,
464 SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
465 },
466
467 { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
468 };
469 /* clang-format on */
470
mod_register(char * path,int * dlflags,void * p1,void * p2)471 int mod_register(char *path, int *dlflags, void *p1, void *p2)
472 {
473 sr_kemi_modules_add(sr_kemi_uac_redirect_exports);
474 return 0;
475 }
476