1 /*
2 * resolver related functions
3 *
4 * Copyright (C) 2006 iptelorg GmbH
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 /*!
24 * \file
25 * \brief Kamailio core :: resolver related functions
26 * \ingroup core
27 * Module: \ref core
28 */
29
30
31 #ifdef USE_DST_BLACKLIST
32
33 #include "dst_blacklist.h"
34 #include "globals.h"
35 #include "cfg_core.h"
36 #include "mem/shm_mem.h"
37 #include "hashes.h"
38 #include "locking.h"
39 #include "timer.h"
40 #include "timer_ticks.h"
41 #include "ip_addr.h"
42 #include "error.h"
43 #include "rpc.h"
44 #include "compiler_opt.h"
45 #include "resolve.h" /* for str2ip */
46 #ifdef USE_DST_BLACKLIST_STATS
47 #include "pt.h"
48 #endif
49
50
51
52
53 struct dst_blst_entry{
54 struct dst_blst_entry* next;
55 ticks_t expire;
56 unsigned short port;
57 unsigned char proto;
58 unsigned char flags; /* contains the address type + error flags */
59 unsigned char ip[4]; /* 4 for ipv4, 16 for ipv6 */
60 };
61
62 #define DST_BLST_ENTRY_SIZE(b) \
63 (sizeof(struct dst_blst_entry)+((b).flags&BLST_IS_IPV6)*12)
64
65
66 #define DST_BLST_HASH_SIZE 1024
67 #define DEFAULT_BLST_TIMER_INTERVAL 60 /* 1 min */
68
69
70 /* lock method */
71 #ifdef GEN_LOCK_T_UNLIMITED
72 #define BLST_LOCK_PER_BUCKET
73 #elif defined GEN_LOCK_SET_T_UNLIMITED
74 #define BLST_LOCK_SET
75 #else
76 #define BLST_ONE_LOCK
77 #endif
78
79
80 #ifdef BLST_LOCK_PER_BUCKET
81 /* lock included in the hash bucket */
82 #define LOCK_BLST(h) lock_get(&dst_blst_hash[(h)].lock)
83 #define UNLOCK_BLST(h) lock_release(&dst_blst_hash[(h)].lock)
84 #elif defined BLST_LOCK_SET
85 static gen_lock_set_t* blst_lock_set=0;
86 #define LOCK_BLST(h) lock_set_get(blst_lock_set, (h))
87 #define UNLOCK_BLST(h) lock_set_release(blst_lock_set, (h))
88 #else
89 /* use only one lock */
90 static gen_lock_t* blst_lock=0;
91 #define LOCK_BLST(h) lock_get(blst_lock)
92 #define UNLOCK_BLST(h) lock_release(blst_lock)
93 #endif
94
95
96
97
98 #define BLST_HASH_STATS
99
100 #ifdef BLST_HASH_STATS
101 #define BLST_HASH_STATS_DEC(h) dst_blst_hash[(h)].entries--
102 #define BLST_HASH_STATS_INC(h) dst_blst_hash[(h)].entries++
103 #else
104 #define BLST_HASH_STATS_DEC(h) do{}while(0)
105 #define BLST_HASH_STATS_INC(h) do{}while(0)
106 #endif
107
108 struct dst_blst_lst_head{
109 struct dst_blst_entry* first;
110 #ifdef BLST_LOCK_PER_BUCKET
111 gen_lock_t lock;
112 #endif
113 #ifdef BLST_HASH_STATS
114 unsigned int entries;
115 #endif
116 };
117
118 int dst_blacklist_init=1; /* if 0, the dst blacklist is not initialized at startup */
119 static struct timer_ln* blst_timer_h=0;
120
121 static volatile unsigned int* blst_mem_used=0;
122 unsigned int blst_timer_interval=DEFAULT_BLST_TIMER_INTERVAL;
123 struct dst_blst_lst_head* dst_blst_hash=0;
124
125 #ifdef USE_DST_BLACKLIST_STATS
126 struct t_dst_blacklist_stats* dst_blacklist_stats=0;
127 #endif
128
129 /* blacklist per protocol event ignore mask array */
130 unsigned blst_proto_imask[PROTO_LAST+1];
131
132 #ifdef DST_BLACKLIST_HOOKS
133
134 /* there 2 types of callbacks supported: on add new entry to the blacklist
135 * (DST_BLACKLIST_ADD_CB) and on blacklist search (DST_BLACKLIST_SEARCH_CB).
136 * Both of them take a struct dest_info*, a flags pointer(unsigned char*),
137 * and a struct sip_msg* as parameters. The flags can be changed.
138 * A callback should return one of:
139 * DST_BLACKLIST_CONTINUE - do nothing, let other callbacks run
140 * DST_BLACKLIST_ACCEPT - for blacklist add: force accept immediately,
141 * for blacklist search: force match and use
142 * the flags as the blacklist search return.
143 * ( so the flags should be set to some valid
144 * non zero BLST flags value )
145 * DST_BLACKLIST_DENY - for blacklist add: don't allow adding the
146 * destination to the blacklist.
147 * for blacklist search: force return not found
148 */
149
150 #define MAX_BLST_HOOKS 1
151
152 struct blst_callbacks_lst{
153 struct blacklist_hook* hooks;
154 unsigned int max_hooks;
155 int last_idx;
156 };
157
158 static struct blst_callbacks_lst blst_add_cb;
159 static struct blst_callbacks_lst blst_search_cb;
160
init_blst_callback_lst(struct blst_callbacks_lst * cb_lst,int max)161 static int init_blst_callback_lst(struct blst_callbacks_lst* cb_lst, int max)
162 {
163
164 cb_lst->max_hooks=MAX_BLST_HOOKS;
165 cb_lst->last_idx=0;
166 cb_lst->hooks=pkg_malloc(cb_lst->max_hooks*sizeof(struct blacklist_hook));
167 if (cb_lst->hooks==0) {
168 PKG_MEM_ERROR;
169 return -1;
170 }
171 memset(cb_lst->hooks, 0, cb_lst->max_hooks*sizeof(struct blacklist_hook));
172 return 0;
173 }
174
175
destroy_blst_callback_lst(struct blst_callbacks_lst * cb_lst)176 static void destroy_blst_callback_lst(struct blst_callbacks_lst* cb_lst)
177 {
178 int r;
179 if (cb_lst && cb_lst->hooks){
180 for (r=0; r<cb_lst->last_idx; r++){
181 if (cb_lst->hooks[r].destroy)
182 cb_lst->hooks[r].destroy();
183 }
184 pkg_free(cb_lst->hooks);
185 cb_lst->hooks=0;
186 cb_lst->last_idx=0;
187 cb_lst->max_hooks=0;
188 }
189 }
190
191
destroy_blacklist_hooks()192 static void destroy_blacklist_hooks()
193 {
194 destroy_blst_callback_lst(&blst_add_cb);
195 destroy_blst_callback_lst(&blst_search_cb);
196 }
197
198
init_blacklist_hooks()199 static int init_blacklist_hooks()
200 {
201
202 if (init_blst_callback_lst(&blst_add_cb, MAX_BLST_HOOKS)!=0)
203 goto error;
204 if (init_blst_callback_lst(&blst_search_cb, MAX_BLST_HOOKS)!=0)
205 goto error;
206 return 0;
207 error:
208 LM_ERR("failure initializing internal lists\n");
209 destroy_blacklist_hooks();
210 return -1;
211 }
212
213
214
215
216 /* allocates a new hook
217 * returns 0 on success and -1 on error
218 * must be called from mod init (from the main process, before forking)*/
register_blacklist_hook(struct blacklist_hook * h,int type)219 int register_blacklist_hook(struct blacklist_hook *h, int type)
220 {
221 struct blst_callbacks_lst* cb_lst;
222 struct blacklist_hook* tmp;
223 int new_max_hooks;
224
225 if (dst_blacklist_init==0) {
226 LM_ERR("blacklist is turned off, "
227 "the hook cannot be registered\n");
228 goto error;
229 }
230
231 switch(type){
232 case DST_BLACKLIST_ADD_CB:
233 cb_lst=&blst_add_cb;
234 break;
235 case DST_BLACKLIST_SEARCH_CB:
236 cb_lst=&blst_search_cb;
237 break;
238 default:
239 BUG("register_blacklist_hook: invalid type %d\n", type);
240 goto error;
241 }
242 if (cb_lst==0 || cb_lst->hooks==0 || cb_lst->max_hooks==0){
243 BUG("register_blacklist_hook: intialization error\n");
244 goto error;
245 }
246
247 if (cb_lst->last_idx >= cb_lst->max_hooks){
248 new_max_hooks=2*cb_lst->max_hooks;
249 tmp=pkg_realloc(cb_lst->hooks,
250 new_max_hooks*sizeof(struct blacklist_hook));
251 if (tmp==0){
252 goto error;
253 }
254 cb_lst->hooks=tmp;
255 /* init the new chunk (but not the current entry which is
256 * overwritten anyway) */
257 memset(&cb_lst->hooks[cb_lst->max_hooks+1], 0,
258 (new_max_hooks-cb_lst->max_hooks-1)*
259 sizeof(struct blacklist_hook));
260 cb_lst->max_hooks=new_max_hooks;
261 }
262 cb_lst->hooks[cb_lst->last_idx]=*h;
263 cb_lst->last_idx++;
264 return 0;
265 error:
266 return -1;
267 }
268
269
blacklist_run_hooks(struct blst_callbacks_lst * cb_lst,struct dest_info * si,unsigned char * flags,struct sip_msg * msg)270 inline static int blacklist_run_hooks(struct blst_callbacks_lst *cb_lst,
271 struct dest_info* si, unsigned char* flags,
272 struct sip_msg* msg)
273 {
274 int r;
275 int ret;
276
277 ret=DST_BLACKLIST_CONTINUE; /* default, if no hook installed accept
278 blacklist operation */
279 if (likely(cb_lst->last_idx==0))
280 return ret;
281 for (r=0; r<cb_lst->last_idx; r++){
282 ret=cb_lst->hooks[r].on_blst_action(si, flags, msg);
283 if (ret!=DST_BLACKLIST_CONTINUE) break;
284 }
285 return ret;
286 }
287
288
289 #endif /* DST_BLACKLIST_HOOKS */
290
291
292 /** init per protocol blacklist event ignore masks.
293 * @return 0 on success, < 0 on error.
294 */
blst_init_ign_masks(void)295 int blst_init_ign_masks(void)
296 {
297 if ((PROTO_UDP > PROTO_LAST) || (PROTO_TCP > PROTO_LAST) ||
298 (PROTO_TLS > PROTO_LAST) || (PROTO_SCTP > PROTO_LAST)){
299 BUG("protocol array too small\n");
300 return -1;
301 }
302 blst_proto_imask[PROTO_UDP]=cfg_get(core, core_cfg, blst_udp_imask);
303 blst_proto_imask[PROTO_TCP]=cfg_get(core, core_cfg, blst_tcp_imask);
304 blst_proto_imask[PROTO_TLS]=cfg_get(core, core_cfg, blst_tls_imask);
305 blst_proto_imask[PROTO_SCTP]=cfg_get(core, core_cfg, blst_sctp_imask);
306 blst_proto_imask[PROTO_NONE]=blst_proto_imask[PROTO_UDP];
307 return 0;
308 }
309
310
311
blst_destroy_entry(struct dst_blst_entry * e)312 inline static void blst_destroy_entry(struct dst_blst_entry* e)
313 {
314 shm_free(e);
315 }
316
317
318 static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data);
319
320
dst_blst_entry2ip(struct ip_addr * ip,struct dst_blst_entry * e)321 inline static void dst_blst_entry2ip(struct ip_addr* ip,
322 struct dst_blst_entry* e)
323 {
324 if (e->flags & BLST_IS_IPV6){
325 ip->af=AF_INET6;
326 ip->len=16;
327 }else
328 {
329 ip->af=AF_INET;
330 ip->len=4;
331 }
332 memcpy(ip->u.addr, e->ip, ip->len);
333 }
334
335
336
dst_blst_hash_no(unsigned char proto,struct ip_addr * ip,unsigned short port)337 inline static unsigned short dst_blst_hash_no(unsigned char proto,
338 struct ip_addr* ip,
339 unsigned short port)
340 {
341 str s1;
342 str s2;
343
344 s1.s=(char*)ip->u.addr;
345 s1.len=ip->len;
346 s2.s=(char*)&port;
347 s2.len=sizeof(unsigned short);
348 return get_hash2_raw(&s1, &s2)%DST_BLST_HASH_SIZE;
349 }
350
351
352
destroy_dst_blacklist()353 void destroy_dst_blacklist()
354 {
355 int r;
356 struct dst_blst_entry** crt;
357 struct dst_blst_entry* e;
358
359 if (blst_timer_h){
360 timer_del(blst_timer_h);
361 timer_free(blst_timer_h);
362 blst_timer_h=0;
363 }
364 #ifdef BLST_LOCK_PER_BUCKET
365 if (dst_blst_hash)
366 for(r=0; r<DST_BLST_HASH_SIZE; r++)
367 lock_destroy(&dst_blst_hash[r].lock);
368 #elif defined BLST_LOCK_SET
369 if (blst_lock_set){
370 lock_set_destroy(blst_lock_set);
371 lock_set_dealloc(blst_lock_set);
372 blst_lock_set=0;
373 }
374 #else
375 if (blst_lock){
376 lock_destroy(blst_lock);
377 lock_dealloc(blst_lock);
378 blst_lock=0;
379 }
380 #endif
381
382 if (dst_blst_hash){
383 for(r=0; r<DST_BLST_HASH_SIZE; r++){
384 crt=&dst_blst_hash[r].first;
385 while(*crt){
386 e=*crt;
387 *crt=(*crt)->next;
388 blst_destroy_entry(e);
389 }
390 }
391 shm_free(dst_blst_hash);
392 dst_blst_hash=0;
393 }
394 if (blst_mem_used){
395 shm_free((void*)blst_mem_used);
396 blst_mem_used=0;
397 }
398 #ifdef DST_BLACKLIST_HOOKS
399 destroy_blacklist_hooks();
400 #endif
401
402 #ifdef USE_DST_BLACKLIST_STATS
403 if (dst_blacklist_stats)
404 shm_free(dst_blacklist_stats);
405 #endif
406 }
407
408
409
init_dst_blacklist()410 int init_dst_blacklist()
411 {
412 int ret;
413 #ifdef BLST_LOCK_PER_BUCKET
414 int r;
415 #endif
416
417 if (dst_blacklist_init==0) {
418 /* the dst blacklist is turned off */
419 default_core_cfg.use_dst_blacklist=0;
420 return 0;
421 }
422
423 ret=-1;
424 #ifdef DST_BLACKLIST_HOOKS
425 if (init_blacklist_hooks()!=0){
426 ret=E_OUT_OF_MEM;
427 goto error;
428 }
429 #endif
430 blst_mem_used=shm_malloc(sizeof(*blst_mem_used));
431 if (blst_mem_used==0){
432 SHM_MEM_ERROR;
433 ret=E_OUT_OF_MEM;
434 goto error;
435 }
436 *blst_mem_used=0;
437 dst_blst_hash=shm_malloc(sizeof(struct dst_blst_lst_head) *
438 DST_BLST_HASH_SIZE);
439 if (dst_blst_hash==0){
440 SHM_MEM_ERROR;
441 ret=E_OUT_OF_MEM;
442 goto error;
443 }
444 memset(dst_blst_hash, 0, sizeof(struct dst_blst_lst_head) *
445 DST_BLST_HASH_SIZE);
446 #ifdef BLST_LOCK_PER_BUCKET
447 for (r=0; r<DST_BLST_HASH_SIZE; r++){
448 if (lock_init(&dst_blst_hash[r].lock)==0){
449 ret=-1;
450 goto error;
451 }
452 }
453 #elif defined BLST_LOCK_SET
454 blst_lock_set=lock_set_alloc(DST_BLST_HASH_SIZE);
455 if (blst_lock_set==0){
456 ret=E_OUT_OF_MEM;
457 goto error;
458 }
459 if (lock_set_init(blst_lock_set)==0){
460 lock_set_dealloc(blst_lock_set);
461 blst_lock_set=0;
462 ret=-1;
463 goto error;
464 }
465 #else /* BLST_ONE_LOCK */
466 blst_lock=lock_alloc();
467 if (blst_lock==0){
468 ret=E_OUT_OF_MEM;
469 goto error;
470 }
471 if (lock_init(blst_lock)==0){
472 lock_dealloc(blst_lock);
473 blst_lock=0;
474 ret=-1;
475 goto error;
476 }
477 #endif /* BLST*LOCK*/
478 blst_timer_h=timer_alloc();
479 if (blst_timer_h==0){
480 ret=E_OUT_OF_MEM;
481 goto error;
482 }
483 /* fix options */
484 default_core_cfg.blst_max_mem<<=10; /* in Kb */ /* TODO: test with 0 */
485 if (blst_timer_interval){
486 timer_init(blst_timer_h, blst_timer, 0 ,0); /* slow timer */
487 if (timer_add(blst_timer_h, S_TO_TICKS(blst_timer_interval))<0){
488 LM_CRIT("failed to add the timer\n");
489 timer_free(blst_timer_h);
490 blst_timer_h=0;
491 goto error;
492 }
493 }
494 if (blst_init_ign_masks() < 0){
495 ret=E_BUG;
496 goto error;
497 }
498 return 0;
499 error:
500 destroy_dst_blacklist();
501 return ret;
502 }
503
504 #ifdef USE_DST_BLACKLIST_STATS
init_dst_blacklist_stats(int iproc_num)505 int init_dst_blacklist_stats(int iproc_num)
506 {
507 /* do not initialize the stats array if the dst blacklist will not be used */
508 if (dst_blacklist_init==0) return 0;
509
510 /* if it is already initialized */
511 if (dst_blacklist_stats)
512 shm_free(dst_blacklist_stats);
513
514 dst_blacklist_stats=shm_malloc(sizeof(*dst_blacklist_stats) * iproc_num);
515 if (dst_blacklist_stats==0){
516 SHM_MEM_ERROR;
517 return E_OUT_OF_MEM;
518 }
519 memset(dst_blacklist_stats, 0, sizeof(*dst_blacklist_stats) * iproc_num);
520
521 return 0;
522 }
523 #endif
524
525 /* must be called with the lock held
526 * struct dst_blst_entry** head, struct dst_blst_entry* e */
527 #define dst_blacklist_lst_add(head, e)\
528 do{ \
529 (e)->next=*(head); \
530 *(head)=(e); \
531 }while(0)
532
533
534
535 /* must be called with the lock held
536 * returns a pointer to the blacklist entry if found, 0 otherwise
537 * it also deletes expired elements (expire<=now) as it searches
538 * proto==PROTO_NONE = wildcard */
_dst_blacklist_lst_find(unsigned short hash,struct ip_addr * ip,unsigned char proto,unsigned short port,ticks_t now)539 inline static struct dst_blst_entry* _dst_blacklist_lst_find(
540 unsigned short hash,
541 struct ip_addr* ip,
542 unsigned char proto,
543 unsigned short port,
544 ticks_t now)
545 {
546 struct dst_blst_entry** crt;
547 struct dst_blst_entry** tmp;
548 struct dst_blst_entry* e;
549 struct dst_blst_entry** head;
550 unsigned char type;
551
552 head=&dst_blst_hash[hash].first;
553 type=(ip->af==AF_INET6)*BLST_IS_IPV6;
554 for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
555 e=*crt;
556 prefetch_loc_r((*crt)->next, 1);
557 /* remove old expired entries */
558 if ((s_ticks_t)(now-(*crt)->expire)>=0){
559 *crt=(*crt)->next;
560 tmp=crt;
561 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
562 BLST_HASH_STATS_DEC(hash);
563 blst_destroy_entry(e);
564 }else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
565 ((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
566 (e->proto==proto)) &&
567 (memcmp(ip->u.addr, e->ip, ip->len)==0)){
568 return e;
569 }
570 }
571 return 0;
572 }
573
574
575
576 /* must be called with the lock held
577 * returns 1 if a matching entry was deleted, 0 otherwise
578 * it also deletes expired elements (expire<=now) as it searches
579 * proto==PROTO_NONE = wildcard */
_dst_blacklist_del(unsigned short hash,struct ip_addr * ip,unsigned char proto,unsigned short port,ticks_t now)580 inline static int _dst_blacklist_del(
581 unsigned short hash,
582 struct ip_addr* ip,
583 unsigned char proto,
584 unsigned short port,
585 ticks_t now)
586 {
587 struct dst_blst_entry** crt;
588 struct dst_blst_entry** tmp;
589 struct dst_blst_entry* e;
590 struct dst_blst_entry** head;
591 unsigned char type;
592
593 head=&dst_blst_hash[hash].first;
594 type=(ip->af==AF_INET6)*BLST_IS_IPV6;
595 for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
596 e=*crt;
597 prefetch_loc_r((*crt)->next, 1);
598 /* remove old expired entries */
599 if ((s_ticks_t)(now-(*crt)->expire)>=0){
600 *crt=(*crt)->next;
601 tmp=crt;
602 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
603 BLST_HASH_STATS_DEC(hash);
604 blst_destroy_entry(e);
605 }else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
606 ((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
607 (e->proto==proto)) &&
608 (memcmp(ip->u.addr, e->ip, ip->len)==0)){
609 *crt=(*crt)->next;
610 tmp=crt;
611 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
612 BLST_HASH_STATS_DEC(hash);
613 blst_destroy_entry(e);
614 return 1;
615 }
616 }
617 return 0;
618 }
619
620
621
622 /* frees all the expired entries until either there are no more of them
623 * or the total memory used is <= target (to free all of them use -1 for
624 * targer)
625 * params: target - free expired entries until no more then taget memory
626 * is used (use 0 to free all of them)
627 * delta - consider an entry expired if it expires after delta
628 * ticks from now
629 * timeout - exit after timeout ticks
630 *
631 * returns: number of deleted entries
632 * This function should be called periodically from a timer
633 */
dst_blacklist_clean_expired(unsigned int target,ticks_t delta,ticks_t timeout)634 inline static int dst_blacklist_clean_expired(unsigned int target,
635 ticks_t delta,
636 ticks_t timeout)
637 {
638 static unsigned int start=0;
639 unsigned int h;
640 struct dst_blst_entry** crt;
641 struct dst_blst_entry** tmp;
642 struct dst_blst_entry* e;
643 ticks_t start_time;
644 ticks_t now;
645 int no=0;
646 int i;
647
648 now=start_time=get_ticks_raw();
649 for(h=start; h!=(start+DST_BLST_HASH_SIZE); h++){
650 i=h%DST_BLST_HASH_SIZE;
651 if (dst_blst_hash[i].first){
652 LOCK_BLST(i);
653 for (crt=&dst_blst_hash[i].first, tmp=&(*crt)->next;
654 *crt; crt=tmp, tmp=&(*crt)->next){
655 e=*crt;
656 prefetch_loc_r((*crt)->next, 1);
657 if ((s_ticks_t)(now+delta-(*crt)->expire)>=0){
658 *crt=(*crt)->next;
659 tmp=crt;
660 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
661 blst_destroy_entry(e);
662 BLST_HASH_STATS_DEC(i);
663 no++;
664 if (*blst_mem_used<=target){
665 UNLOCK_BLST(i);
666 goto skip;
667 }
668 }
669 }
670 UNLOCK_BLST(i);
671 /* check for timeout only "between" hash cells */
672 now=get_ticks_raw();
673 if ((now-start_time)>=timeout){
674 LM_DBG("timeout: %d > %d\n",
675 TICKS_TO_MS(now-start_time), TICKS_TO_MS(timeout));
676 goto skip;
677 }
678 }
679 }
680 skip:
681 start=h; /* next time we start where we left */
682 if (no){
683 LM_DBG("%d entries removed\n", no);
684 }
685 return no;
686 }
687
688
689
690 /* timer */
blst_timer(ticks_t ticks,struct timer_ln * tl,void * data)691 static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data)
692 {
693 dst_blacklist_clean_expired(0, 0, 2); /*spend max. 2 ticks*/
694 return (ticks_t)(-1);
695 }
696
697
698
699 /* adds a proto ip:port combination to the blacklist
700 * returns 0 on success, -1 on error (blacklist full -- would use more then
701 * blst:_max_mem, or out of shm. mem.)
702 */
dst_blacklist_add_ip(unsigned char err_flags,unsigned char proto,struct ip_addr * ip,unsigned short port,ticks_t timeout)703 inline static int dst_blacklist_add_ip(unsigned char err_flags,
704 unsigned char proto,
705 struct ip_addr* ip, unsigned short port,
706 ticks_t timeout)
707 {
708 int size;
709 struct dst_blst_entry* e;
710 unsigned short hash;
711 ticks_t now;
712 int ret;
713
714 ret=0;
715 if (ip->af==AF_INET){
716 err_flags&=~BLST_IS_IPV6; /* make sure the ipv6 flag is reset */
717 size=sizeof(struct dst_blst_entry);
718 }else{
719 err_flags|=BLST_IS_IPV6;
720 size=sizeof(struct dst_blst_entry)+12 /* ipv6 addr - 4 */;
721 }
722 now=get_ticks_raw();
723 hash=dst_blst_hash_no(proto, ip, port);
724 /* check if the entry already exists */
725 LOCK_BLST(hash);
726 e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
727 if (e){
728 e->flags|=err_flags;
729 e->expire=now+timeout; /* update the timeout */
730 }else{
731 if (unlikely((*blst_mem_used+size) >=
732 cfg_get(core, core_cfg, blst_max_mem))){
733 #ifdef USE_DST_BLACKLIST_STATS
734 dst_blacklist_stats[process_no].bkl_lru_cnt++;
735 #endif
736 UNLOCK_BLST(hash);
737 /* first try to free some memory (~ 12%), but don't
738 * spend more then 250 ms*/
739 dst_blacklist_clean_expired(*blst_mem_used/16*14, 0,
740 MS_TO_TICKS(250));
741 if (unlikely(*blst_mem_used+size >=
742 cfg_get(core, core_cfg, blst_max_mem))){
743 ret=-1;
744 goto error;
745 }
746 LOCK_BLST(hash);
747 }
748 e=shm_malloc(size);
749 if (e==0){
750 SHM_MEM_ERROR;
751 UNLOCK_BLST(hash);
752 ret=E_OUT_OF_MEM;
753 goto error;
754 }
755 *blst_mem_used+=size;
756 e->flags=err_flags;
757 e->proto=proto;
758 e->port=port;
759 memcpy(e->ip, ip->u.addr, ip->len);
760 e->expire=now+timeout; /* update the timeout */
761 e->next=0;
762 dst_blacklist_lst_add(&dst_blst_hash[hash].first, e);
763 BLST_HASH_STATS_INC(hash);
764 }
765 UNLOCK_BLST(hash);
766 error:
767 return ret;
768 }
769
770
771
772 /* if no blacklisted returns 0, else returns the blacklist flags */
dst_is_blacklisted_ip(unsigned char proto,struct ip_addr * ip,unsigned short port)773 inline static int dst_is_blacklisted_ip(unsigned char proto,
774 struct ip_addr* ip,
775 unsigned short port)
776 {
777 struct dst_blst_entry* e;
778 unsigned short hash;
779 ticks_t now;
780 int ret;
781
782 ret=0;
783 now=get_ticks_raw();
784 hash=dst_blst_hash_no(proto, ip, port);
785 if (unlikely(dst_blst_hash[hash].first)){
786 LOCK_BLST(hash);
787 e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
788 if (e){
789 ret=e->flags;
790 }
791 UNLOCK_BLST(hash);
792 }
793 return ret;
794 }
795
796
797
798 /** add dst to the blacklist, specifying the timeout.
799 * @param err_flags - reason (bitmap)
800 * @param si - destination (protocol, ip and port)
801 * @param msg - sip message that triggered the blacklisting (can be 0 if
802 * not known)
803 * @param timeout - timeout in ticks
804 * @return 0 on success, -1 on error
805 */
dst_blacklist_force_add_to(unsigned char err_flags,struct dest_info * si,struct sip_msg * msg,ticks_t timeout)806 int dst_blacklist_force_add_to(unsigned char err_flags, struct dest_info* si,
807 struct sip_msg* msg, ticks_t timeout)
808 {
809 struct ip_addr ip;
810
811 #ifdef DST_BLACKLIST_HOOKS
812 if (unlikely (blacklist_run_hooks(&blst_add_cb, si, &err_flags, msg) ==
813 DST_BLACKLIST_DENY))
814 return 0;
815 #endif
816 su2ip_addr(&ip, &si->to);
817 return dst_blacklist_add_ip(err_flags, si->proto, &ip,
818 su_getport(&si->to), timeout);
819 }
820
821
822
823 /** add dst to the blacklist, specifying the timeout.
824 * (like @function dst_blacklist_force_add_to)= above, but uses
825 * (proto, sockaddr_union) instead of struct dest_info)
826 */
dst_blacklist_force_su_to(unsigned char err_flags,unsigned char proto,union sockaddr_union * dst,struct sip_msg * msg,ticks_t timeout)827 int dst_blacklist_force_su_to(unsigned char err_flags, unsigned char proto,
828 union sockaddr_union* dst,
829 struct sip_msg* msg, ticks_t timeout)
830 {
831 struct ip_addr ip;
832 #ifdef DST_BLACKLIST_HOOKS
833 struct dest_info si;
834
835 init_dest_info(&si);
836 si.to=*dst;
837 si.proto=proto;
838 if (unlikely (blacklist_run_hooks(&blst_add_cb, &si, &err_flags, msg) ==
839 DST_BLACKLIST_DENY))
840 return 0;
841 #endif
842 su2ip_addr(&ip, dst);
843 return dst_blacklist_add_ip(err_flags, proto, &ip,
844 su_getport(dst), timeout);
845 }
846
847
848
dst_is_blacklisted(struct dest_info * si,struct sip_msg * msg)849 int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg)
850 {
851 int ires;
852 struct ip_addr ip;
853 #ifdef DST_BLACKLIST_HOOKS
854 unsigned char err_flags;
855 int action;
856 #endif
857 su2ip_addr(&ip, &si->to);
858
859 #ifdef DST_BLACKLIST_HOOKS
860 err_flags=0;
861 if (unlikely((action=(blacklist_run_hooks(&blst_search_cb, si, &err_flags, msg))
862 ) != DST_BLACKLIST_CONTINUE)){
863 if (action==DST_BLACKLIST_DENY)
864 return 0;
865 else /* if (action==DST_BLACKLIST_ACCEPT) */
866 return err_flags;
867 }
868 #endif
869 ires=dst_is_blacklisted_ip(si->proto, &ip, su_getport(&si->to));
870 #ifdef USE_DST_BLACKLIST_STATS
871 if (ires)
872 dst_blacklist_stats[process_no].bkl_hit_cnt++;
873 #endif
874 return ires;
875 }
876
877
878
879 /* returns 1 if the entry was deleted, 0 if not found */
dst_blacklist_del(struct dest_info * si,struct sip_msg * msg)880 int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg)
881 {
882 unsigned short hash;
883 struct ip_addr ip;
884 ticks_t now;
885 int ret;
886 unsigned short port;
887
888 ret=0;
889 su2ip_addr(&ip, &si->to);
890 port=su_getport(&si->to);
891 now=get_ticks_raw();
892 hash=dst_blst_hash_no(si->proto, &ip, port);
893 if (unlikely(dst_blst_hash[hash].first)){
894 LOCK_BLST(hash);
895 ret=_dst_blacklist_del(hash, &ip, si->proto, port, now);
896 UNLOCK_BLST(hash);
897 }
898 return ret;
899 }
900
901
902
903 /* rpc functions */
dst_blst_mem_info(rpc_t * rpc,void * ctx)904 void dst_blst_mem_info(rpc_t* rpc, void* ctx)
905 {
906 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
907 rpc->fault(ctx, 500, "dst blacklist support disabled");
908 return;
909 }
910 rpc->add(ctx, "dd", *blst_mem_used, cfg_get(core, core_cfg, blst_max_mem));
911 }
912
913
914
915
916 #ifdef USE_DST_BLACKLIST_STATS
917
stat_sum(int ivar,int breset)918 static unsigned long stat_sum(int ivar, int breset) {
919 unsigned long isum=0;
920 int i1=0;
921
922 for (; i1 < get_max_procs(); i1++)
923 switch (ivar) {
924 case 0:
925 isum+=dst_blacklist_stats[i1].bkl_hit_cnt;
926 if (breset)
927 dst_blacklist_stats[i1].bkl_hit_cnt=0;
928 break;
929 case 1:
930 isum+=dst_blacklist_stats[i1].bkl_lru_cnt;
931 if (breset)
932 dst_blacklist_stats[i1].bkl_lru_cnt=0;
933 break;
934 }
935
936 return isum;
937 }
938
939
dst_blst_stats_get(rpc_t * rpc,void * c)940 void dst_blst_stats_get(rpc_t* rpc, void* c)
941 {
942 char *name=NULL;
943 void *handle;
944 int found=0,i=0;
945 int reset=0;
946 char* dst_blacklist_stats_names[] = {
947 "bkl_hit_cnt",
948 "bkl_lru_cnt",
949 NULL
950 };
951
952 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
953 rpc->fault(c, 500, "dst blacklist support disabled");
954 return;
955 }
956 if (rpc->scan(c, "s", &name) < 0)
957 return;
958 if (rpc->scan(c, "d", &reset) < 0)
959 return;
960 if (!strcasecmp(name, DST_BLACKLIST_ALL_STATS)) {
961 /* dump all the dns cache stat values */
962 rpc->add(c, "{", &handle);
963 for (i=0; dst_blacklist_stats_names[i]; i++)
964 rpc->struct_add(handle, "d",
965 dst_blacklist_stats_names[i],
966 stat_sum(i, reset));
967
968 found=1;
969 } else {
970 for (i=0; dst_blacklist_stats_names[i]; i++)
971 if (!strcasecmp(dst_blacklist_stats_names[i], name)) {
972 rpc->add(c, "{", &handle);
973 rpc->struct_add(handle, "d",
974 dst_blacklist_stats_names[i],
975 stat_sum(i, reset));
976 found=1;
977 break;
978 }
979 }
980 if(!found)
981 rpc->fault(c, 500, "unknown dst blacklist stat parameter");
982
983 return;
984 }
985 #endif /* USE_DST_BLACKLIST_STATS */
986
987 /* only for debugging, it helds the lock too long for "production" use */
dst_blst_debug(rpc_t * rpc,void * ctx)988 void dst_blst_debug(rpc_t* rpc, void* ctx)
989 {
990 int h;
991 struct dst_blst_entry* e;
992 ticks_t now;
993 struct ip_addr ip;
994
995 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
996 rpc->fault(ctx, 500, "dst blacklist support disabled");
997 return;
998 }
999 now=get_ticks_raw();
1000 for(h=0; h<DST_BLST_HASH_SIZE; h++){
1001 LOCK_BLST(h);
1002 for(e=dst_blst_hash[h].first; e; e=e->next){
1003 dst_blst_entry2ip(&ip, e);
1004 rpc->add(ctx, "ssddd", get_proto_name(e->proto),
1005 ip_addr2a(&ip), e->port,
1006 (s_ticks_t)(now-e->expire)<=0?
1007 TICKS_TO_S(e->expire-now):
1008 -TICKS_TO_S(now-e->expire) ,
1009 e->flags);
1010 }
1011 UNLOCK_BLST(h);
1012 }
1013 }
1014
1015 /* only for debugging, it helds the lock too long for "production" use */
dst_blst_hash_stats(rpc_t * rpc,void * ctx)1016 void dst_blst_hash_stats(rpc_t* rpc, void* ctx)
1017 {
1018 int h;
1019 struct dst_blst_entry* e;
1020 #ifdef BLST_HASH_STATS
1021 int n;
1022
1023 n=0;
1024 #endif
1025 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
1026 rpc->fault(ctx, 500, "dst blacklist support disabled");
1027 return;
1028 }
1029 for(h=0; h<DST_BLST_HASH_SIZE; h++){
1030 #ifdef BLST_HASH_STATS
1031 LOCK_BLST(h);
1032 for(e=dst_blst_hash[h].first; e; e=e->next) n++;
1033 UNLOCK_BLST(h);
1034 rpc->add(ctx, "dd", h, n);
1035 #else
1036 rpc->add(ctx, "dd", h, dst_blst_hash[h].entries);
1037 #endif
1038 }
1039 }
1040
1041 /* dumps the content of the blacklist in a human-readable format */
dst_blst_view(rpc_t * rpc,void * ctx)1042 void dst_blst_view(rpc_t* rpc, void* ctx)
1043 {
1044 int h;
1045 int expires;
1046 struct dst_blst_entry* e;
1047 ticks_t now;
1048 struct ip_addr ip;
1049
1050 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
1051 rpc->fault(ctx, 500, "dst blacklist support disabled");
1052 return;
1053 }
1054 now=get_ticks_raw();
1055 for(h=0; h<DST_BLST_HASH_SIZE; h++) {
1056 LOCK_BLST(h);
1057 for(e=dst_blst_hash[h].first; e; e=e->next) {
1058 expires = (s_ticks_t)(now-e->expire)<=0?
1059 TICKS_TO_S(e->expire-now): -TICKS_TO_S(now-e->expire);
1060 /* don't include expired entries into view report */
1061 if (expires < 0) {
1062 continue;
1063 }
1064 dst_blst_entry2ip(&ip, e);
1065 rpc->rpl_printf(ctx, "{\n protocol: %s", get_proto_name(e->proto));
1066 rpc->rpl_printf(ctx, " ip: %s", ip_addr2a(&ip));
1067 rpc->rpl_printf(ctx, " port: %d", e->port);
1068 rpc->rpl_printf(ctx, " expires in (s): %d", expires);
1069 rpc->rpl_printf(ctx, " flags: %d\n}", e->flags);
1070 }
1071 UNLOCK_BLST(h);
1072 }
1073 }
1074
1075
1076 /* deletes all the entries from the blacklist except the permanent ones
1077 * (which are marked with BLST_PERMANENT)
1078 */
dst_blst_flush(void)1079 void dst_blst_flush(void)
1080 {
1081 int h;
1082 struct dst_blst_entry* e;
1083 struct dst_blst_entry** crt;
1084 struct dst_blst_entry** tmp;
1085
1086 for(h=0; h<DST_BLST_HASH_SIZE; h++){
1087 LOCK_BLST(h);
1088 for (crt=&dst_blst_hash[h].first, tmp=&(*crt)->next;
1089 *crt; crt=tmp, tmp=&(*crt)->next){
1090 e=*crt;
1091 prefetch_loc_r((*crt)->next, 1);
1092 if (!(e->flags & BLST_PERMANENT)){
1093 *crt=(*crt)->next;
1094 tmp=crt;
1095 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
1096 blst_destroy_entry(e);
1097 BLST_HASH_STATS_DEC(h);
1098 }
1099 }
1100 UNLOCK_BLST(h);
1101 }
1102 }
1103
1104 /* rpc wrapper function for dst_blst_flush() */
dst_blst_delete_all(rpc_t * rpc,void * ctx)1105 void dst_blst_delete_all(rpc_t* rpc, void* ctx)
1106 {
1107 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
1108 rpc->fault(ctx, 500, "dst blacklist support disabled");
1109 return;
1110 }
1111 dst_blst_flush();
1112 }
1113
1114 /* Adds a new entry to the blacklist */
dst_blst_add(rpc_t * rpc,void * ctx)1115 void dst_blst_add(rpc_t* rpc, void* ctx)
1116 {
1117 str ip;
1118 int port, proto, flags;
1119 unsigned char err_flags;
1120 struct ip_addr *ip_addr;
1121
1122 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
1123 rpc->fault(ctx, 500, "dst blacklist support disabled");
1124 return;
1125 }
1126 if (rpc->scan(ctx, "Sddd", &ip, &port, &proto, &flags) < 4)
1127 return;
1128
1129 err_flags = (unsigned char)flags;
1130 /* sanity checks */
1131 if ((unsigned char)proto > PROTO_SCTP) {
1132 rpc->fault(ctx, 400, "Unknown protocol");
1133 return;
1134 }
1135
1136 if (err_flags & BLST_IS_IPV6) {
1137 /* IPv6 address is specified */
1138 ip_addr = str2ip6(&ip);
1139 } else {
1140 /* try IPv4 first, than IPv6 */
1141 ip_addr = str2ip(&ip);
1142 if (!ip_addr) {
1143 ip_addr = str2ip6(&ip);
1144 err_flags |= BLST_IS_IPV6;
1145 }
1146 }
1147 if (!ip_addr) {
1148 rpc->fault(ctx, 400, "Malformed ip address");
1149 return;
1150 }
1151
1152 if (dst_blacklist_add_ip(err_flags, proto, ip_addr, port,
1153 S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout))))
1154 rpc->fault(ctx, 400, "Failed to add the entry to the blacklist");
1155 }
1156
1157 /* fixup function for use_dst_blacklist
1158 * verifies that dst_blacklist_init is set to 1
1159 */
use_dst_blacklist_fixup(void * handle,str * gname,str * name,void ** val)1160 int use_dst_blacklist_fixup(void *handle, str *gname, str *name, void **val)
1161 {
1162 if ((int)(long)(*val) && !dst_blacklist_init) {
1163 LM_ERR("dst blacklist is turned off by dst_blacklist_init=0, "
1164 "it cannot be enabled runtime.\n");
1165 return -1;
1166 }
1167 return 0;
1168 }
1169
1170 /* KByte to Byte conversion */
blst_max_mem_fixup(void * handle,str * gname,str * name,void ** val)1171 int blst_max_mem_fixup(void *handle, str *gname, str *name, void **val)
1172 {
1173 unsigned int u;
1174
1175 u = ((unsigned int)(long)(*val))<<10;
1176 (*val) = (void *)(long)u;
1177 return 0;
1178 }
1179
1180
1181
1182 /** re-inint per child blst_proto_ign_mask array. */
blst_reinit_ign_masks(str * gname,str * name)1183 void blst_reinit_ign_masks(str* gname, str* name)
1184 {
1185 blst_init_ign_masks();
1186 }
1187
1188
1189 #endif /* USE_DST_BLACKLIST */
1190
1191