4 * resolver related functions
6 * Copyright (C) 2006 iptelorg GmbH
8 * This file is part of ser, a free SIP server.
10 * ser is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version
15 * For a license to use the ser software under conditions
16 * other than those described here, or to purchase support for this
17 * software, please contact iptel.org by e-mail at the following addresses:
20 * ser is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 * 2006-07-29 created by andrei
32 * 2007-05-39 added hooks for add; more locks to reduce contention (andrei)
33 * 2007-06-26 added hooks for search (andrei)
34 * 2007-07-30 added dst_blacklist_del() and dst_blacklist_add_to() (andrei)
35 * 2007-07-30 dst blacklist measurements added (Gergo)
39 #ifdef USE_DST_BLACKLIST
41 #include "dst_blacklist.h"
42 #include "mem/shm_mem.h"
46 #include "timer_ticks.h"
50 #include "compiler_opt.h"
51 #include "resolve.h" /* for str2ip */
52 #ifdef USE_DST_BLACKLIST_STATS
59 struct dst_blst_entry{
60 struct dst_blst_entry* next;
64 unsigned char flags; /* contains the address type + error flags */
65 unsigned char ip[4]; /* 4 for ipv4, 16 for ipv6 */
68 #define DST_BLST_ENTRY_SIZE(b) \
69 (sizeof(struct dst_blst_entry)+((b).flags&BLST_IS_IPV6)*12)
72 #define DST_BLST_HASH_SIZE 1024
73 #define DEFAULT_BLST_MAX_MEM 250 /* 1 Kb FIXME (debugging)*/
74 #define DEFAULT_BLST_TIMER_INTERVAL 60 /* 1 min */
78 #ifdef GEN_LOCK_T_UNLIMITED
79 #define BLST_LOCK_PER_BUCKET
80 #elif defined GEN_LOCK_SET_T_UNLIMITED
87 #ifdef BLST_LOCK_PER_BUCKET
88 /* lock included in the hash bucket */
89 #define LOCK_BLST(h) lock_get(&dst_blst_hash[(h)].lock)
90 #define UNLOCK_BLST(h) lock_release(&dst_blst_hash[(h)].lock)
91 #elif defined BLST_LOCK_SET
92 static gen_lock_set_t* blst_lock_set=0;
93 #define LOCK_BLST(h) lock_set_get(blst_lock_set, (h))
94 #define UNLOCK_BLST(h) lock_set_release(blst_lock_set, (h))
96 /* use only one lock */
97 static gen_lock_t* blst_lock=0;
98 #define LOCK_BLST(h) lock_get(blst_lock)
99 #define UNLOCK_BLST(h) lock_release(blst_lock)
105 #define BLST_HASH_STATS
107 #ifdef BLST_HASH_STATS
108 #define BLST_HASH_STATS_DEC(h) dst_blst_hash[(h)].entries--
109 #define BLST_HASH_STATS_INC(h) dst_blst_hash[(h)].entries++
111 #define BLST_HASH_STATS_DEC(h) do{}while(0)
112 #define BLST_HASH_STATS_INC(h) do{}while(0)
115 struct dst_blst_lst_head{
116 struct dst_blst_entry* first;
117 #ifdef BLST_LOCK_PER_BUCKET
120 #ifdef BLST_HASH_STATS
121 unsigned int entries;
125 static struct timer_ln* blst_timer_h=0;
127 static volatile unsigned int* blst_mem_used=0;
128 unsigned int blst_max_mem=DEFAULT_BLST_MAX_MEM; /* maximum memory used
129 for the blacklist entries*/
130 unsigned int blst_timeout=DEFAULT_BLST_TIMEOUT;
131 unsigned int blst_timer_interval=DEFAULT_BLST_TIMER_INTERVAL;
132 struct dst_blst_lst_head* dst_blst_hash=0;
134 #ifdef USE_DST_BLACKLIST_STATS
135 struct t_dst_blacklist_stats* dst_blacklist_stats=0;
138 #ifdef DST_BLACKLIST_HOOKS
140 /* there 2 types of callbacks supported: on add new entry to the blacklist
141 * (DST_BLACKLIST_ADD_CB) and on blacklist search (DST_BLACKLIST_SEARCH_CB).
142 * Both of them take a struct dest_info*, a flags pointer(unsigned char*),
143 * and a struct sip_msg* as parameters. The flags can be changed.
144 * A callback should return one of:
145 * DST_BLACKLIST_CONTINUE - do nothing, let other callbacks run
146 * DST_BLACKLIST_ACCEPT - for blacklist add: force accept immediately,
147 * for blacklist search: force match and use
148 * the flags as the blacklist search return.
149 * ( so the flags should be set to some valid
150 * non zero BLST flags value )
151 * DST_BLACKLIST_DENY - for blacklist add: don't allow adding the
152 * destination to the blacklist.
153 * for blacklist search: force return not found
156 #define MAX_BLST_HOOKS 1
158 struct blst_callbacks_lst{
159 struct blacklist_hook* hooks;
160 unsigned int max_hooks;
164 static struct blst_callbacks_lst blst_add_cb;
165 static struct blst_callbacks_lst blst_search_cb;
167 static int init_blst_callback_lst(struct blst_callbacks_lst* cb_lst, int max)
170 cb_lst->max_hooks=MAX_BLST_HOOKS;
172 cb_lst->hooks=pkg_malloc(cb_lst->max_hooks*sizeof(struct blacklist_hook));
173 if (cb_lst->hooks==0)
175 memset(cb_lst->hooks, 0, cb_lst->max_hooks*sizeof(struct blacklist_hook));
182 static void destroy_blst_callback_lst(struct blst_callbacks_lst* cb_lst)
185 if (cb_lst && cb_lst->hooks){
186 for (r=0; r<cb_lst->last_idx; r++){
187 if (cb_lst->hooks[r].destroy)
188 cb_lst->hooks[r].destroy();
190 pkg_free(cb_lst->hooks);
198 static void destroy_blacklist_hooks()
200 destroy_blst_callback_lst(&blst_add_cb);
201 destroy_blst_callback_lst(&blst_search_cb);
205 static int init_blacklist_hooks()
208 if (init_blst_callback_lst(&blst_add_cb, MAX_BLST_HOOKS)!=0)
210 if (init_blst_callback_lst(&blst_search_cb, MAX_BLST_HOOKS)!=0)
214 LOG(L_ERR, "blacklist_hooks: failure initializing internal lists\n");
215 destroy_blacklist_hooks();
222 /* allocates a new hook
223 * returns 0 on success and -1 on error
224 * must be called from mod init (from the main process, before forking)*/
225 int register_blacklist_hook(struct blacklist_hook *h, int type)
227 struct blst_callbacks_lst* cb_lst;
228 struct blacklist_hook* tmp;
232 case DST_BLACKLIST_ADD_CB:
235 case DST_BLACKLIST_SEARCH_CB:
236 cb_lst=&blst_search_cb;
239 BUG("register_blacklist_hook: invalid type %d\n", type);
242 if (cb_lst==0 || cb_lst->hooks==0 || cb_lst->max_hooks==0){
243 BUG("register_blacklist_hook: intialization error\n");
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));
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;
262 cb_lst->hooks[cb_lst->last_idx]=*h;
270 inline static int blacklist_run_hooks(struct blst_callbacks_lst *cb_lst,
271 struct dest_info* si, unsigned char* flags,
277 ret=DST_BLACKLIST_CONTINUE; /* default, if no hook installed accept
278 blacklist operation */
279 if (likely(cb_lst->last_idx==0))
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;
289 #endif /* DST_BLACKLIST_HOOKS */
292 inline static void blst_destroy_entry(struct dst_blst_entry* e)
298 static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data);
301 inline static void dst_blst_entry2ip(struct ip_addr* ip,
302 struct dst_blst_entry* e)
304 if (e->flags & BLST_IS_IPV6){
311 memcpy(ip->u.addr, e->ip, ip->len);
316 inline static unsigned short dst_blst_hash_no(unsigned char proto,
323 s1.s=(char*)ip->u.addr;
326 s2.len=sizeof(unsigned short);
327 return get_hash2_raw(&s1, &s2)%DST_BLST_HASH_SIZE;
332 void destroy_dst_blacklist()
335 struct dst_blst_entry** crt;
336 struct dst_blst_entry* e;
339 timer_del(blst_timer_h);
340 timer_free(blst_timer_h);
343 #ifdef BLST_LOCK_PER_BUCKET
344 for(r=0; r<DST_BLST_HASH_SIZE; r++)
345 lock_destroy(&dst_blst_hash[r].lock);
346 #elif defined BLST_LOCK_SET
348 lock_set_destroy(blst_lock_set);
349 lock_set_dealloc(blst_lock_set);
354 lock_destroy(blst_lock);
355 lock_dealloc(blst_lock);
361 for(r=0; r<DST_BLST_HASH_SIZE; r++){
362 crt=&dst_blst_hash[r].first;
366 blst_destroy_entry(e);
369 shm_free(dst_blst_hash);
373 shm_free((void*)blst_mem_used);
376 #ifdef DST_BLACKLIST_HOOKS
377 destroy_blacklist_hooks();
380 #ifdef USE_DST_BLACKLIST_STATS
381 if (dst_blacklist_stats)
382 shm_free(dst_blacklist_stats);
388 int init_dst_blacklist()
391 #ifdef BLST_LOCK_PER_BUCKET
396 #ifdef DST_BLACKLIST_HOOKS
397 if (init_blacklist_hooks()!=0){
402 blst_mem_used=shm_malloc(sizeof(*blst_mem_used));
403 if (blst_mem_used==0){
408 dst_blst_hash=shm_malloc(sizeof(struct dst_blst_lst_head) *
410 if (dst_blst_hash==0){
414 memset(dst_blst_hash, 0, sizeof(struct dst_blst_lst_head) *
416 #ifdef BLST_LOCK_PER_BUCKET
417 for (r=0; r<DST_BLST_HASH_SIZE; r++){
418 if (lock_init(&dst_blst_hash[r].lock)==0){
423 #elif defined BLST_LOCK_SET
424 blst_lock_set=lock_set_alloc(DST_BLST_HASH_SIZE);
425 if (blst_lock_set==0){
429 if (lock_set_init(blst_lock_set)==0){
430 lock_set_dealloc(blst_lock_set);
435 #else /* BLST_ONE_LOCK */
436 blst_lock=lock_alloc();
441 if (lock_init(blst_lock)==0){
442 lock_dealloc(blst_lock);
447 #endif /* BLST*LOCK*/
448 blst_timer_h=timer_alloc();
449 if (blst_timer_h==0){
454 blst_max_mem<<=10; /* in Kb */ /* TODO: test with 0 */
455 if (blst_timer_interval){
456 timer_init(blst_timer_h, blst_timer, 0 ,0); /* slow timer */
457 if (timer_add(blst_timer_h, S_TO_TICKS(blst_timer_interval))<0){
458 LOG(L_CRIT, "BUG: init_dst_blacklist: failed to add the timer\n");
459 timer_free(blst_timer_h);
466 destroy_dst_blacklist();
470 #ifdef USE_DST_BLACKLIST_STATS
471 int init_dst_blacklist_stats(int iproc_num)
473 /* if it is already initialized */
474 if (dst_blacklist_stats)
475 shm_free(dst_blacklist_stats);
477 dst_blacklist_stats=shm_malloc(sizeof(*dst_blacklist_stats) * iproc_num);
478 if (dst_blacklist_stats==0){
481 memset(dst_blacklist_stats, 0, sizeof(*dst_blacklist_stats) * iproc_num);
487 /* must be called with the lock held
488 * struct dst_blst_entry** head, struct dst_blst_entry* e */
489 #define dst_blacklist_lst_add(head, e)\
497 /* must be called with the lock held
498 * returns a pointer to the blacklist entry if found, 0 otherwise
499 * it also deletes expired elements (expire<=now) as it searches
500 * proto==PROTO_NONE = wildcard */
501 inline static struct dst_blst_entry* _dst_blacklist_lst_find(
508 struct dst_blst_entry** crt;
509 struct dst_blst_entry** tmp;
510 struct dst_blst_entry* e;
511 struct dst_blst_entry** head;
514 head=&dst_blst_hash[hash].first;
515 type=(ip->af==AF_INET6)*BLST_IS_IPV6;
516 for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
518 prefetch_loc_r((*crt)->next, 1);
519 /* remove old expired entries */
520 if ((s_ticks_t)(now-(*crt)->expire)>=0){
523 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
524 BLST_HASH_STATS_DEC(hash);
525 blst_destroy_entry(e);
526 }else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
527 ((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
528 (e->proto==proto)) &&
529 (memcmp(ip->u.addr, e->ip, ip->len)==0)){
538 /* must be called with the lock held
539 * returns 1 if a matching entry was deleted, 0 otherwise
540 * it also deletes expired elements (expire<=now) as it searches
541 * proto==PROTO_NONE = wildcard */
542 inline static int _dst_blacklist_del(
549 struct dst_blst_entry** crt;
550 struct dst_blst_entry** tmp;
551 struct dst_blst_entry* e;
552 struct dst_blst_entry** head;
555 head=&dst_blst_hash[hash].first;
556 type=(ip->af==AF_INET6)*BLST_IS_IPV6;
557 for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
559 prefetch_loc_r((*crt)->next, 1);
560 /* remove old expired entries */
561 if ((s_ticks_t)(now-(*crt)->expire)>=0){
564 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
565 BLST_HASH_STATS_DEC(hash);
566 blst_destroy_entry(e);
567 }else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
568 ((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
569 (e->proto==proto)) &&
570 (memcmp(ip->u.addr, e->ip, ip->len)==0)){
573 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
574 BLST_HASH_STATS_DEC(hash);
575 blst_destroy_entry(e);
584 /* frees all the expired entries until either there are no more of them
585 * or the total memory used is <= target (to free all of them use -1 for
587 * params: target - free expired entries until no more then taget memory
588 * is used (use 0 to free all of them)
589 * delta - consider an entry expired if it expires after delta
591 * timeout - exit after timeout ticks
593 * returns: number of deleted entries
594 * This function should be called periodically from a timer
596 inline static int dst_blacklist_clean_expired(unsigned int target,
600 static unsigned int start=0;
602 struct dst_blst_entry** crt;
603 struct dst_blst_entry** tmp;
604 struct dst_blst_entry* e;
610 now=start_time=get_ticks_raw();
611 for(h=start; h!=(start+DST_BLST_HASH_SIZE); h++){
612 i=h%DST_BLST_HASH_SIZE;
613 if (dst_blst_hash[i].first){
615 for (crt=&dst_blst_hash[i].first, tmp=&(*crt)->next;
616 *crt; crt=tmp, tmp=&(*crt)->next){
618 prefetch_loc_r((*crt)->next, 1);
619 if ((s_ticks_t)(now+delta-(*crt)->expire)>=0){
622 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
623 blst_destroy_entry(e);
624 BLST_HASH_STATS_DEC(i);
626 if (*blst_mem_used<=target){
633 /* check for timeout only "between" hash cells */
635 if ((now-start_time)>=timeout){
636 DBG("_dst_blacklist_clean_expired_unsafe: timeout: %d > %d\n",
637 TICKS_TO_MS(now-start_time), TICKS_TO_MS(timeout));
643 start=h; /* next time we start where we left */
645 DBG("dst_blacklist_clean_expired, %d entries removed\n", no);
653 static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data)
655 dst_blacklist_clean_expired(0, 0, 2); /*spend max. 2 ticks*/
656 return (ticks_t)(-1);
661 /* adds a proto ip:port combination to the blacklist
662 * returns 0 on success, -1 on error (blacklist full -- would use more then
663 * blst:_max_mem, or out of shm. mem.)
665 inline static int dst_blacklist_add_ip(unsigned char err_flags,
667 struct ip_addr* ip, unsigned short port,
671 struct dst_blst_entry* e;
677 if (ip->af==AF_INET){
678 err_flags&=~BLST_IS_IPV6; /* make sure the ipv6 flag is reset */
679 size=sizeof(struct dst_blst_entry);
681 err_flags|=BLST_IS_IPV6;
682 size=sizeof(struct dst_blst_entry)+12 /* ipv6 addr - 4 */;
685 hash=dst_blst_hash_no(proto, ip, port);
686 /* check if the entry already exists */
688 e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
691 e->expire=now+timeout; /* update the timeout */
693 if (unlikely((*blst_mem_used+size)>=blst_max_mem)){
694 #ifdef USE_DST_BLACKLIST_STATS
695 dst_blacklist_stats[process_no].bkl_lru_cnt++;
698 /* first try to free some memory (~ 12%), but don't
699 * spend more then 250 ms*/
700 dst_blacklist_clean_expired(*blst_mem_used/16*14, 0,
702 if (unlikely(*blst_mem_used+size>=blst_max_mem)){
714 *blst_mem_used+=size;
718 memcpy(e->ip, ip->u.addr, ip->len);
719 e->expire=now+timeout; /* update the timeout */
721 dst_blacklist_lst_add(&dst_blst_hash[hash].first, e);
722 BLST_HASH_STATS_INC(hash);
731 /* if no blacklisted returns 0, else returns the blacklist flags */
732 inline static int dst_is_blacklisted_ip(unsigned char proto,
736 struct dst_blst_entry* e;
743 hash=dst_blst_hash_no(proto, ip, port);
744 if (unlikely(dst_blst_hash[hash].first)){
746 e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
757 int dst_blacklist_add_to(unsigned char err_flags, struct dest_info* si,
758 struct sip_msg* msg, ticks_t timeout)
762 #ifdef DST_BLACKLIST_HOOKS
763 if (unlikely (blacklist_run_hooks(&blst_add_cb, si, &err_flags, msg) ==
767 #ifdef USE_DST_BLACKLIST_STATS
768 /* if hooks are defined then increment hit counter only when a
769 * destination is added into blacklist
771 dst_blacklist_stats[process_no].bkl_hit_cnt++;
773 su2ip_addr(&ip, &si->to);
774 return dst_blacklist_add_ip(err_flags, si->proto, &ip,
775 su_getport(&si->to), timeout);
780 int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg)
784 #ifdef DST_BLACKLIST_HOOKS
785 unsigned char err_flags;
788 su2ip_addr(&ip, &si->to);
790 #ifdef DST_BLACKLIST_HOOKS
792 if (unlikely((action=(blacklist_run_hooks(&blst_search_cb, si, &err_flags, msg))
793 ) != DST_BLACKLIST_CONTINUE)){
794 if (action==DST_BLACKLIST_DENY)
796 else /* if (action==DST_BLACKLIST_ACCEPT) */
800 ires=dst_is_blacklisted_ip(si->proto, &ip, su_getport(&si->to));
801 #ifdef USE_DST_BLACKLIST_STATS
803 dst_blacklist_stats[process_no].bkl_hit_cnt++;
810 /* returns 1 if the entry was deleted, 0 if not found */
811 int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg)
820 su2ip_addr(&ip, &si->to);
821 port=su_getport(&si->to);
823 hash=dst_blst_hash_no(si->proto, &ip, port);
824 if (unlikely(dst_blst_hash[hash].first)){
826 ret=_dst_blacklist_del(hash, &ip, si->proto, port, now);
835 void dst_blst_mem_info(rpc_t* rpc, void* ctx)
837 rpc->add(ctx, "dd", *blst_mem_used, blst_max_mem);
842 static char* get_proto_name(unsigned char proto)
859 #ifdef USE_DST_BLACKLIST_STATS
860 void dst_blst_stats_get(rpc_t* rpc, void* c)
866 char* dst_blacklist_stats_names[] = {
871 unsigned long stat_sum(int ivar, int breset) {
872 unsigned long isum=0;
875 for (; i1 < get_max_procs(); i1++)
878 isum+=dst_blacklist_stats[i1].bkl_hit_cnt;
880 dst_blacklist_stats[i1].bkl_hit_cnt=0;
883 isum+=dst_blacklist_stats[i1].bkl_lru_cnt;
885 dst_blacklist_stats[i1].bkl_lru_cnt=0;
892 if (rpc->scan(c, "s", &name) < 0)
894 if (rpc->scan(c, "d", &reset) < 0)
896 if (!strcasecmp(name, DST_BLACKLIST_ALL_STATS)) {
897 /* dump all the dns cache stat values */
898 rpc->add(c, "{", &handle);
899 for (i=0; dst_blacklist_stats_names[i]; i++)
900 rpc->struct_add(handle, "d",
901 dst_blacklist_stats_names[i],
906 for (i=0; dst_blacklist_stats_names[i]; i++)
907 if (!strcasecmp(dst_blacklist_stats_names[i], name)) {
908 rpc->add(c, "{", &handle);
909 rpc->struct_add(handle, "d",
910 dst_blacklist_stats_names[i],
917 rpc->fault(c, 500, "unknown dst blacklist stat parameter");
921 #endif /* USE_DST_BLACKLIST_STATS */
923 /* only for debugging, it helds the lock too long for "production" use */
924 void dst_blst_debug(rpc_t* rpc, void* ctx)
927 struct dst_blst_entry* e;
932 for(h=0; h<DST_BLST_HASH_SIZE; h++){
934 for(e=dst_blst_hash[h].first; e; e=e->next){
935 dst_blst_entry2ip(&ip, e);
936 rpc->add(ctx, "ssddd", get_proto_name(e->proto),
937 ip_addr2a(&ip), e->port,
938 (s_ticks_t)(now-e->expire)<=0?
939 TICKS_TO_S(e->expire-now):
940 -TICKS_TO_S(now-e->expire) ,
947 /* only for debugging, it helds the lock too long for "production" use */
948 void dst_blst_hash_stats(rpc_t* rpc, void* ctx)
951 struct dst_blst_entry* e;
952 #ifdef BLST_HASH_STATS
958 for(h=0; h<DST_BLST_HASH_SIZE; h++){
959 #ifdef BLST_HASH_STATS
961 for(e=dst_blst_hash[h].first; e; e=e->next) n++;
963 rpc->add(ctx, "dd", h, n);
965 rpc->add(ctx, "dd", h, dst_blst_hash[h].entries);
970 /* dumps the content of the blacklist in a human-readable format */
971 void dst_blst_view(rpc_t* rpc, void* ctx)
974 struct dst_blst_entry* e;
979 for(h=0; h<DST_BLST_HASH_SIZE; h++) {
981 for(e=dst_blst_hash[h].first; e; e=e->next) {
982 dst_blst_entry2ip(&ip, e);
983 rpc->printf(ctx, "{\n protocol: %s", get_proto_name(e->proto));
984 rpc->printf(ctx, " ip: %s", ip_addr2a(&ip));
985 rpc->printf(ctx, " port: %d", e->port);
986 rpc->printf(ctx, " expires in (s):", (s_ticks_t)(now-e->expire)<=0?
987 TICKS_TO_S(e->expire-now): -TICKS_TO_S(now-e->expire));
988 rpc->printf(ctx, " flags: %d\n}", e->flags);
994 /* deletes all the entries from the blacklist except the permanent ones
995 * (which are marked with BLST_PERMANENT)
997 void dst_blst_flush(void)
1000 struct dst_blst_entry* e;
1001 struct dst_blst_entry** crt;
1002 struct dst_blst_entry** tmp;
1004 for(h=0; h<DST_BLST_HASH_SIZE; h++){
1006 for (crt=&dst_blst_hash[h].first, tmp=&(*crt)->next;
1007 *crt; crt=tmp, tmp=&(*crt)->next){
1009 prefetch_loc_r((*crt)->next, 1);
1010 if (!(e->flags & BLST_PERMANENT)){
1013 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
1014 blst_destroy_entry(e);
1015 BLST_HASH_STATS_DEC(h);
1022 /* rpc wrapper function for dst_blst_flush() */
1023 void dst_blst_delete_all(rpc_t* rpc, void* ctx)
1028 /* Adds a new entry to the blacklist */
1029 void dst_blst_add(rpc_t* rpc, void* ctx)
1032 int port, proto, flags;
1033 unsigned char err_flags;
1034 struct ip_addr *ip_addr;
1036 if (rpc->scan(ctx, "Sddd", &ip, &port, &proto, &flags) < 4)
1039 err_flags = (unsigned char)flags;
1041 if ((unsigned char)proto > PROTO_SCTP) {
1042 rpc->fault(ctx, 400, "Unknown protocol");
1046 if (err_flags & BLST_IS_IPV6) {
1047 /* IPv6 address is specified */
1048 ip_addr = str2ip6(&ip);
1050 /* try IPv4 first, than IPv6 */
1051 ip_addr = str2ip(&ip);
1053 ip_addr = str2ip6(&ip);
1054 err_flags |= BLST_IS_IPV6;
1058 rpc->fault(ctx, 400, "Malformed ip address");
1062 if (dst_blacklist_add_ip(err_flags, proto, ip_addr, port,
1063 S_TO_TICKS(blst_timeout)))
1064 rpc->fault(ctx, 400, "Failed to add the entry to the blacklist");
1067 #endif /* USE_DST_BLACKLIST */