Browse code

- added support for deleting an entry from the blacklist (dst_blacklist_del()) - added support for adding an entry to the blacklist with a specific timeout (dst_blacklist_add_to()) - fixed missing hash stats for _dst_blacklist_lst_find - added a special flag for 503 replies

Andrei Pelinescu-Onciul authored on 30/07/2007 19:42:03
Showing 2 changed files
... ...
@@ -31,6 +31,7 @@
31 31
  *  2006-07-29  created by andrei
32 32
  *  2007-05-39  added hooks for add; more locks to reduce contention (andrei)
33 33
  *  2007-06-26  added hooks for search (andrei)
34
+ *  2007-07-30  added dst_blacklist_del() and dst_blacklist_add_to()  (andrei)
34 35
  */
35 36
 
36 37
 
... ...
@@ -65,7 +66,6 @@ struct dst_blst_entry{
65 66
 
66 67
 
67 68
 #define DST_BLST_HASH_SIZE		1024
68
-#define DEFAULT_BLST_TIMEOUT		60  /* 1 min. */
69 69
 #define DEFAULT_BLST_MAX_MEM	250 /* 1 Kb FIXME (debugging)*/
70 70
 #define DEFAULT_BLST_TIMER_INTERVAL		60 /* 1 min */
71 71
 
... ...
@@ -262,7 +262,8 @@ error:
262 262
 
263 263
 
264 264
 inline static int blacklist_run_hooks(struct blst_callbacks_lst *cb_lst,
265
-							struct dest_info* si, unsigned char* flags, struct sip_msg* msg)
265
+							struct dest_info* si, unsigned char* flags,
266
+							struct sip_msg* msg)
266 267
 {
267 268
 	int r;
268 269
 	int ret;
... ...
@@ -472,7 +473,7 @@ do{ \
472 473
  * it also deletes expired elements (expire<=now) as it searches
473 474
  * proto==PROTO_NONE = wildcard */
474 475
 inline static struct dst_blst_entry* _dst_blacklist_lst_find(
475
-												struct dst_blst_entry** head,
476
+												unsigned short hash,
476 477
 												struct ip_addr* ip,
477 478
 												unsigned char proto,
478 479
 												unsigned short port,
... ...
@@ -481,8 +482,10 @@ inline static struct dst_blst_entry* _dst_blacklist_lst_find(
481 482
 	struct dst_blst_entry** crt;
482 483
 	struct dst_blst_entry** tmp;
483 484
 	struct dst_blst_entry* e;
485
+	struct dst_blst_entry** head;
484 486
 	unsigned char type;
485 487
 	
488
+	head=&dst_blst_hash[hash].first;
486 489
 	type=(ip->af==AF_INET6)*BLST_IS_IPV6;
487 490
 	for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
488 491
 		e=*crt;
... ...
@@ -491,6 +494,7 @@ inline static struct dst_blst_entry* _dst_blacklist_lst_find(
491 494
 		if ((s_ticks_t)(now-(*crt)->expire)>=0){
492 495
 			*crt=(*crt)->next;
493 496
 			*blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
497
+			BLST_HASH_STATS_DEC(hash);
494 498
 			blst_destroy_entry(e);
495 499
 		}else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
496 500
 				((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
... ...
@@ -504,6 +508,50 @@ inline static struct dst_blst_entry* _dst_blacklist_lst_find(
504 508
 
505 509
 
506 510
 
511
+/* must be called with the lock held
512
+ * returns 1 if a matching entry was deleted, 0 otherwise
513
+ * it also deletes expired elements (expire<=now) as it searches
514
+ * proto==PROTO_NONE = wildcard */
515
+inline static int _dst_blacklist_del(
516
+												unsigned short hash,
517
+												struct ip_addr* ip,
518
+												unsigned char proto,
519
+												unsigned short port,
520
+												ticks_t now)
521
+{
522
+	struct dst_blst_entry** crt;
523
+	struct dst_blst_entry** tmp;
524
+	struct dst_blst_entry* e;
525
+	struct dst_blst_entry** head;
526
+	unsigned char type;
527
+	
528
+	head=&dst_blst_hash[hash].first;
529
+	type=(ip->af==AF_INET6)*BLST_IS_IPV6;
530
+	for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
531
+		e=*crt;
532
+		prefetch_loc_r((*crt)->next, 1);
533
+		/* remove old expired entries */
534
+		if ((s_ticks_t)(now-(*crt)->expire)>=0){
535
+			*crt=(*crt)->next;
536
+			*blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
537
+			BLST_HASH_STATS_DEC(hash);
538
+			blst_destroy_entry(e);
539
+		}else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
540
+				((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
541
+					(e->proto==proto)) && 
542
+					(memcmp(ip->u.addr, e->ip, ip->len)==0)){
543
+			*crt=(*crt)->next;
544
+			*blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
545
+			BLST_HASH_STATS_DEC(hash);
546
+			blst_destroy_entry(e);
547
+			return 1;
548
+		}
549
+	}
550
+	return 0;
551
+}
552
+
553
+
554
+
507 555
 /* frees all the expired entries until either there are no more of them
508 556
  *  or the total memory used is <= target (to free all of them use -1 for 
509 557
  *  targer)
... ...
@@ -586,7 +634,8 @@ static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data)
586 634
  */
587 635
 inline static int dst_blacklist_add_ip(unsigned char err_flags, 
588 636
 									unsigned char proto,
589
-									struct ip_addr* ip, unsigned short port)
637
+									struct ip_addr* ip, unsigned short port,
638
+									ticks_t timeout)
590 639
 {
591 640
 	int size;
592 641
 	struct dst_blst_entry* e;
... ...
@@ -606,11 +655,10 @@ inline static int dst_blacklist_add_ip(unsigned char err_flags,
606 655
 	hash=dst_blst_hash_no(proto, ip, port);
607 656
 	/* check if the entry already exists */
608 657
 	LOCK_BLST(hash);
609
-		e=_dst_blacklist_lst_find(&dst_blst_hash[hash].first, ip, proto,
610
-																port, now);
658
+		e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
611 659
 		if (e){
612 660
 			e->flags|=err_flags;
613
-			e->expire=now+S_TO_TICKS(blst_timeout); /* update the timeout */
661
+			e->expire=now+timeout; /* update the timeout */
614 662
 		}else{
615 663
 			if (unlikely((*blst_mem_used+size)>=blst_max_mem)){
616 664
 				UNLOCK_BLST(hash);
... ...
@@ -635,7 +683,7 @@ inline static int dst_blacklist_add_ip(unsigned char err_flags,
635 683
 			e->proto=proto;
636 684
 			e->port=port;
637 685
 			memcpy(e->ip, ip->u.addr, ip->len);
638
-			e->expire=now+S_TO_TICKS(blst_timeout); /* update the timeout */
686
+			e->expire=now+timeout; /* update the timeout */
639 687
 			e->next=0;
640 688
 			dst_blacklist_lst_add(&dst_blst_hash[hash].first, e);
641 689
 			BLST_HASH_STATS_INC(hash);
... ...
@@ -655,15 +703,14 @@ inline static int dst_is_blacklisted_ip(unsigned char proto,
655 703
 	struct dst_blst_entry* e;
656 704
 	unsigned short hash;
657 705
 	ticks_t now;
658
-	int ret=0;
706
+	int ret;
659 707
 	
660 708
 	ret=0;
661 709
 	now=get_ticks_raw();
662 710
 	hash=dst_blst_hash_no(proto, ip, port);
663 711
 	if (unlikely(dst_blst_hash[hash].first)){
664 712
 		LOCK_BLST(hash);
665
-			e=_dst_blacklist_lst_find(&dst_blst_hash[hash].first, ip, proto,
666
-										port, now);
713
+			e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
667 714
 			if (e){
668 715
 				ret=e->flags;
669 716
 			}
... ...
@@ -674,7 +721,8 @@ inline static int dst_is_blacklisted_ip(unsigned char proto,
674 721
 
675 722
 
676 723
 
677
-int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si, struct sip_msg* msg)
724
+int dst_blacklist_add_to(unsigned char err_flags,  struct dest_info* si,
725
+						struct sip_msg* msg, ticks_t timeout)
678 726
 {
679 727
 	struct ip_addr ip;
680 728
 
... ...
@@ -685,7 +733,7 @@ int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si, struct sip
685 733
 #endif
686 734
 	su2ip_addr(&ip, &si->to);
687 735
 	return dst_blacklist_add_ip(err_flags, si->proto, &ip,
688
-								su_getport(&si->to));
736
+								su_getport(&si->to), timeout);
689 737
 }
690 738
 
691 739
 
... ...
@@ -714,6 +762,30 @@ int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg)
714 762
 
715 763
 
716 764
 
765
+/* returns 1 if the entry was deleted, 0 if not found */
766
+int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg)
767
+{
768
+	unsigned short hash;
769
+	struct ip_addr ip;
770
+	ticks_t now;
771
+	int ret;
772
+	unsigned short port;
773
+	
774
+	ret=0;
775
+	su2ip_addr(&ip, &si->to);
776
+	port=su_getport(&si->to);
777
+	now=get_ticks_raw();
778
+	hash=dst_blst_hash_no(si->proto, &ip, port);
779
+	if (unlikely(dst_blst_hash[hash].first)){
780
+		LOCK_BLST(hash);
781
+			ret=_dst_blacklist_del(hash, &ip, si->proto, port, now);
782
+		UNLOCK_BLST(hash);
783
+	}
784
+	return ret;
785
+}
786
+
787
+
788
+
717 789
 /* rpc functions */
718 790
 void dst_blst_mem_info(rpc_t* rpc, void* ctx)
719 791
 {
... ...
@@ -888,7 +960,8 @@ void dst_blst_add(rpc_t* rpc, void* ctx)
888 960
 		return;
889 961
 	}
890 962
 
891
-	if (dst_blacklist_add_ip(err_flags, proto, ip_addr, port))
963
+	if (dst_blacklist_add_ip(err_flags, proto, ip_addr, port, 
964
+											S_TO_TICKS(blst_timeout)))
892 965
 		rpc->fault(ctx, 400, "Failed to add the entry to the blacklist");
893 966
 }
894 967
 
... ...
@@ -36,6 +36,9 @@
36 36
 
37 37
 #include "ip_addr.h"
38 38
 #include "parser/msg_parser.h"
39
+#include "timer_ticks.h"
40
+
41
+#define DEFAULT_BLST_TIMEOUT		60  /* 1 min. */
39 42
 
40 43
 /* flags: */
41 44
 #define BLST_IS_IPV6		1		/* set if the address is ipv6 */
... ...
@@ -43,7 +46,7 @@
43 46
 #define BLST_ERR_CONNECT	(1<<2)	/* set if connect failed (tcp/tls) */
44 47
 #define BLST_ICMP_RCVD		(1<<3)	/* set if icmp error */
45 48
 #define BLST_ERR_TIMEOUT	(1<<4)	/* set if sip timeout */
46
-#define BLST_RESERVED		(1<<5)	/* not used yet */
49
+#define BLST_503			(1<<5)	/* set for 503 replies */
47 50
 #define BLST_ADM_PROHIBITED	(1<<6)	/* administratively prohibited */
48 51
 #define BLST_PERMANENT		(1<<7)  /* never deleted, never expires */
49 52
 
... ...
@@ -62,7 +65,8 @@ struct blacklist_hook{
62 65
 	/* WARNING: msg might be NULL, and it might point to shared memory
63 66
 	 * without locking, do not modify it! msg can be used typically for checking
64 67
 	 * the message flags with isflagset() */
65
-	int (*on_blst_action)(struct dest_info* si, unsigned char* err_flags, struct sip_msg* msg);
68
+	int (*on_blst_action)(struct dest_info* si, unsigned char* err_flags,
69
+							struct sip_msg* msg);
66 70
 	/* called before ser shutdown */
67 71
 	void (*destroy)(void);
68 72
 };
... ...
@@ -73,9 +77,18 @@ int register_blacklist_hook(struct blacklist_hook *h, int type);
73 77
 int init_dst_blacklist();
74 78
 void destroy_dst_blacklist();
75 79
 
76
-int dst_blacklist_add(unsigned char err_flags, struct dest_info* si, struct sip_msg* msg);
80
+
81
+/* like dst_blacklist_add, but the timeout can be also set */
82
+int dst_blacklist_add_to(unsigned char err_flags, struct dest_info* si,
83
+						struct sip_msg* msg, ticks_t timeout);
84
+
85
+/* adds a dst to the blacklist with default timeout */
86
+#define dst_blacklist_add(err_flags, si, msg) \
87
+	dst_blacklist_add_to((err_flags), (si), (msg), S_TO_TICKS(blst_timeout))
77 88
 
78 89
 int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg);
90
+/* delete an entry from the blacklist */
91
+int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg);
79 92
 
80 93
 /* deletes all the entries from the blacklist except the permanent ones
81 94
  * (which are marked with BLST_PERMANENT)