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