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 65
 
66 66
 
67 67
 #define DST_BLST_HASH_SIZE		1024
68
-#define DEFAULT_BLST_TIMEOUT		60  /* 1 min. */
69 68
 #define DEFAULT_BLST_MAX_MEM	250 /* 1 Kb FIXME (debugging)*/
70 69
 #define DEFAULT_BLST_TIMER_INTERVAL		60 /* 1 min */
71 70
 
... ...
@@ -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 472
  * it also deletes expired elements (expire<=now) as it searches
473 473
  * proto==PROTO_NONE = wildcard */
474 474
 inline static struct dst_blst_entry* _dst_blacklist_lst_find(
475
-												struct dst_blst_entry** head,
475
+												unsigned short hash,
476 476
 												struct ip_addr* ip,
477 477
 												unsigned char proto,
478 478
 												unsigned short port,
... ...
@@ -481,8 +482,10 @@ inline static struct dst_blst_entry* _dst_blacklist_lst_find(
481 481
 	struct dst_blst_entry** crt;
482 482
 	struct dst_blst_entry** tmp;
483 483
 	struct dst_blst_entry* e;
484
+	struct dst_blst_entry** head;
484 485
 	unsigned char type;
485 486
 	
487
+	head=&dst_blst_hash[hash].first;
486 488
 	type=(ip->af==AF_INET6)*BLST_IS_IPV6;
487 489
 	for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
488 490
 		e=*crt;
... ...
@@ -491,6 +494,7 @@ inline static struct dst_blst_entry* _dst_blacklist_lst_find(
491 491
 		if ((s_ticks_t)(now-(*crt)->expire)>=0){
492 492
 			*crt=(*crt)->next;
493 493
 			*blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
494
+			BLST_HASH_STATS_DEC(hash);
494 495
 			blst_destroy_entry(e);
495 496
 		}else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
496 497
 				((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
... ...
@@ -504,6 +508,50 @@ inline static struct dst_blst_entry* _dst_blacklist_lst_find(
504 504
 
505 505
 
506 506
 
507
+/* must be called with the lock held
508
+ * returns 1 if a matching entry was deleted, 0 otherwise
509
+ * it also deletes expired elements (expire<=now) as it searches
510
+ * proto==PROTO_NONE = wildcard */
511
+inline static int _dst_blacklist_del(
512
+												unsigned short hash,
513
+												struct ip_addr* ip,
514
+												unsigned char proto,
515
+												unsigned short port,
516
+												ticks_t now)
517
+{
518
+	struct dst_blst_entry** crt;
519
+	struct dst_blst_entry** tmp;
520
+	struct dst_blst_entry* e;
521
+	struct dst_blst_entry** head;
522
+	unsigned char type;
523
+	
524
+	head=&dst_blst_hash[hash].first;
525
+	type=(ip->af==AF_INET6)*BLST_IS_IPV6;
526
+	for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
527
+		e=*crt;
528
+		prefetch_loc_r((*crt)->next, 1);
529
+		/* remove old expired entries */
530
+		if ((s_ticks_t)(now-(*crt)->expire)>=0){
531
+			*crt=(*crt)->next;
532
+			*blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
533
+			BLST_HASH_STATS_DEC(hash);
534
+			blst_destroy_entry(e);
535
+		}else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
536
+				((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
537
+					(e->proto==proto)) && 
538
+					(memcmp(ip->u.addr, e->ip, ip->len)==0)){
539
+			*crt=(*crt)->next;
540
+			*blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
541
+			BLST_HASH_STATS_DEC(hash);
542
+			blst_destroy_entry(e);
543
+			return 1;
544
+		}
545
+	}
546
+	return 0;
547
+}
548
+
549
+
550
+
507 551
 /* frees all the expired entries until either there are no more of them
508 552
  *  or the total memory used is <= target (to free all of them use -1 for 
509 553
  *  targer)
... ...
@@ -586,7 +634,8 @@ static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data)
586 586
  */
587 587
 inline static int dst_blacklist_add_ip(unsigned char err_flags, 
588 588
 									unsigned char proto,
589
-									struct ip_addr* ip, unsigned short port)
589
+									struct ip_addr* ip, unsigned short port,
590
+									ticks_t timeout)
590 591
 {
591 592
 	int size;
592 593
 	struct dst_blst_entry* e;
... ...
@@ -606,11 +655,10 @@ inline static int dst_blacklist_add_ip(unsigned char err_flags,
606 606
 	hash=dst_blst_hash_no(proto, ip, port);
607 607
 	/* check if the entry already exists */
608 608
 	LOCK_BLST(hash);
609
-		e=_dst_blacklist_lst_find(&dst_blst_hash[hash].first, ip, proto,
610
-																port, now);
609
+		e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
611 610
 		if (e){
612 611
 			e->flags|=err_flags;
613
-			e->expire=now+S_TO_TICKS(blst_timeout); /* update the timeout */
612
+			e->expire=now+timeout; /* update the timeout */
614 613
 		}else{
615 614
 			if (unlikely((*blst_mem_used+size)>=blst_max_mem)){
616 615
 				UNLOCK_BLST(hash);
... ...
@@ -635,7 +683,7 @@ inline static int dst_blacklist_add_ip(unsigned char err_flags,
635 635
 			e->proto=proto;
636 636
 			e->port=port;
637 637
 			memcpy(e->ip, ip->u.addr, ip->len);
638
-			e->expire=now+S_TO_TICKS(blst_timeout); /* update the timeout */
638
+			e->expire=now+timeout; /* update the timeout */
639 639
 			e->next=0;
640 640
 			dst_blacklist_lst_add(&dst_blst_hash[hash].first, e);
641 641
 			BLST_HASH_STATS_INC(hash);
... ...
@@ -655,15 +703,14 @@ inline static int dst_is_blacklisted_ip(unsigned char proto,
655 655
 	struct dst_blst_entry* e;
656 656
 	unsigned short hash;
657 657
 	ticks_t now;
658
-	int ret=0;
658
+	int ret;
659 659
 	
660 660
 	ret=0;
661 661
 	now=get_ticks_raw();
662 662
 	hash=dst_blst_hash_no(proto, ip, port);
663 663
 	if (unlikely(dst_blst_hash[hash].first)){
664 664
 		LOCK_BLST(hash);
665
-			e=_dst_blacklist_lst_find(&dst_blst_hash[hash].first, ip, proto,
666
-										port, now);
665
+			e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
667 666
 			if (e){
668 667
 				ret=e->flags;
669 668
 			}
... ...
@@ -674,7 +721,8 @@ inline static int dst_is_blacklisted_ip(unsigned char proto,
674 674
 
675 675
 
676 676
 
677
-int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si, struct sip_msg* msg)
677
+int dst_blacklist_add_to(unsigned char err_flags,  struct dest_info* si,
678
+						struct sip_msg* msg, ticks_t timeout)
678 679
 {
679 680
 	struct ip_addr ip;
680 681
 
... ...
@@ -685,7 +733,7 @@ int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si, struct sip
685 685
 #endif
686 686
 	su2ip_addr(&ip, &si->to);
687 687
 	return dst_blacklist_add_ip(err_flags, si->proto, &ip,
688
-								su_getport(&si->to));
688
+								su_getport(&si->to), timeout);
689 689
 }
690 690
 
691 691
 
... ...
@@ -714,6 +762,30 @@ int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg)
714 714
 
715 715
 
716 716
 
717
+/* returns 1 if the entry was deleted, 0 if not found */
718
+int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg)
719
+{
720
+	unsigned short hash;
721
+	struct ip_addr ip;
722
+	ticks_t now;
723
+	int ret;
724
+	unsigned short port;
725
+	
726
+	ret=0;
727
+	su2ip_addr(&ip, &si->to);
728
+	port=su_getport(&si->to);
729
+	now=get_ticks_raw();
730
+	hash=dst_blst_hash_no(si->proto, &ip, port);
731
+	if (unlikely(dst_blst_hash[hash].first)){
732
+		LOCK_BLST(hash);
733
+			ret=_dst_blacklist_del(hash, &ip, si->proto, port, now);
734
+		UNLOCK_BLST(hash);
735
+	}
736
+	return ret;
737
+}
738
+
739
+
740
+
717 741
 /* rpc functions */
718 742
 void dst_blst_mem_info(rpc_t* rpc, void* ctx)
719 743
 {
... ...
@@ -888,7 +960,8 @@ void dst_blst_add(rpc_t* rpc, void* ctx)
888 888
 		return;
889 889
 	}
890 890
 
891
-	if (dst_blacklist_add_ip(err_flags, proto, ip_addr, port))
891
+	if (dst_blacklist_add_ip(err_flags, proto, ip_addr, port, 
892
+											S_TO_TICKS(blst_timeout)))
892 893
 		rpc->fault(ctx, 400, "Failed to add the entry to the blacklist");
893 894
 }
894 895
 
... ...
@@ -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 43
 #define BLST_ERR_CONNECT	(1<<2)	/* set if connect failed (tcp/tls) */
44 44
 #define BLST_ICMP_RCVD		(1<<3)	/* set if icmp error */
45 45
 #define BLST_ERR_TIMEOUT	(1<<4)	/* set if sip timeout */
46
-#define BLST_RESERVED		(1<<5)	/* not used yet */
46
+#define BLST_503			(1<<5)	/* set for 503 replies */
47 47
 #define BLST_ADM_PROHIBITED	(1<<6)	/* administratively prohibited */
48 48
 #define BLST_PERMANENT		(1<<7)  /* never deleted, never expires */
49 49
 
... ...
@@ -62,7 +65,8 @@ struct blacklist_hook{
62 62
 	/* WARNING: msg might be NULL, and it might point to shared memory
63 63
 	 * without locking, do not modify it! msg can be used typically for checking
64 64
 	 * the message flags with isflagset() */
65
-	int (*on_blst_action)(struct dest_info* si, unsigned char* err_flags, struct sip_msg* msg);
65
+	int (*on_blst_action)(struct dest_info* si, unsigned char* err_flags,
66
+							struct sip_msg* msg);
66 67
 	/* called before ser shutdown */
67 68
 	void (*destroy)(void);
68 69
 };
... ...
@@ -73,9 +77,18 @@ int register_blacklist_hook(struct blacklist_hook *h, int type);
73 73
 int init_dst_blacklist();
74 74
 void destroy_dst_blacklist();
75 75
 
76
-int dst_blacklist_add(unsigned char err_flags, struct dest_info* si, struct sip_msg* msg);
76
+
77
+/* like dst_blacklist_add, but the timeout can be also set */
78
+int dst_blacklist_add_to(unsigned char err_flags, struct dest_info* si,
79
+						struct sip_msg* msg, ticks_t timeout);
80
+
81
+/* adds a dst to the blacklist with default timeout */
82
+#define dst_blacklist_add(err_flags, si, msg) \
83
+	dst_blacklist_add_to((err_flags), (si), (msg), S_TO_TICKS(blst_timeout))
77 84
 
78 85
 int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg);
86
+/* delete an entry from the blacklist */
87
+int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg);
79 88
 
80 89
 /* deletes all the entries from the blacklist except the permanent ones
81 90
  * (which are marked with BLST_PERMANENT)