瀏覽代碼

- 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 18 年之前
父節點
當前提交
5bd736c7b9
共有 2 個文件被更改,包括 103 次插入17 次删除
  1. 87 14
      dst_blacklist.c
  2. 16 3
      dst_blacklist.h

+ 87 - 14
dst_blacklist.c

@@ -31,6 +31,7 @@
  *  2006-07-29  created by andrei
  *  2007-05-39  added hooks for add; more locks to reduce contention (andrei)
  *  2007-06-26  added hooks for search (andrei)
+ *  2007-07-30  added dst_blacklist_del() and dst_blacklist_add_to()  (andrei)
  */
 
 
@@ -65,7 +66,6 @@ struct dst_blst_entry{
 
 
 #define DST_BLST_HASH_SIZE		1024
-#define DEFAULT_BLST_TIMEOUT		60  /* 1 min. */
 #define DEFAULT_BLST_MAX_MEM	250 /* 1 Kb FIXME (debugging)*/
 #define DEFAULT_BLST_TIMER_INTERVAL		60 /* 1 min */
 
@@ -262,7 +262,8 @@ error:
 
 
 inline static int blacklist_run_hooks(struct blst_callbacks_lst *cb_lst,
-							struct dest_info* si, unsigned char* flags, struct sip_msg* msg)
+							struct dest_info* si, unsigned char* flags,
+							struct sip_msg* msg)
 {
 	int r;
 	int ret;
@@ -472,7 +473,7 @@ do{ \
  * it also deletes expired elements (expire<=now) as it searches
  * proto==PROTO_NONE = wildcard */
 inline static struct dst_blst_entry* _dst_blacklist_lst_find(
-												struct dst_blst_entry** head,
+												unsigned short hash,
 												struct ip_addr* ip,
 												unsigned char proto,
 												unsigned short port,
@@ -481,8 +482,10 @@ inline static struct dst_blst_entry* _dst_blacklist_lst_find(
 	struct dst_blst_entry** crt;
 	struct dst_blst_entry** tmp;
 	struct dst_blst_entry* e;
+	struct dst_blst_entry** head;
 	unsigned char type;
 	
+	head=&dst_blst_hash[hash].first;
 	type=(ip->af==AF_INET6)*BLST_IS_IPV6;
 	for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
 		e=*crt;
@@ -491,6 +494,7 @@ inline static struct dst_blst_entry* _dst_blacklist_lst_find(
 		if ((s_ticks_t)(now-(*crt)->expire)>=0){
 			*crt=(*crt)->next;
 			*blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
+			BLST_HASH_STATS_DEC(hash);
 			blst_destroy_entry(e);
 		}else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
 				((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
@@ -504,6 +508,50 @@ inline static struct dst_blst_entry* _dst_blacklist_lst_find(
 
 
 
+/* must be called with the lock held
+ * returns 1 if a matching entry was deleted, 0 otherwise
+ * it also deletes expired elements (expire<=now) as it searches
+ * proto==PROTO_NONE = wildcard */
+inline static int _dst_blacklist_del(
+												unsigned short hash,
+												struct ip_addr* ip,
+												unsigned char proto,
+												unsigned short port,
+												ticks_t now)
+{
+	struct dst_blst_entry** crt;
+	struct dst_blst_entry** tmp;
+	struct dst_blst_entry* e;
+	struct dst_blst_entry** head;
+	unsigned char type;
+	
+	head=&dst_blst_hash[hash].first;
+	type=(ip->af==AF_INET6)*BLST_IS_IPV6;
+	for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
+		e=*crt;
+		prefetch_loc_r((*crt)->next, 1);
+		/* remove old expired entries */
+		if ((s_ticks_t)(now-(*crt)->expire)>=0){
+			*crt=(*crt)->next;
+			*blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
+			BLST_HASH_STATS_DEC(hash);
+			blst_destroy_entry(e);
+		}else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
+				((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
+					(e->proto==proto)) && 
+					(memcmp(ip->u.addr, e->ip, ip->len)==0)){
+			*crt=(*crt)->next;
+			*blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
+			BLST_HASH_STATS_DEC(hash);
+			blst_destroy_entry(e);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+
+
 /* frees all the expired entries until either there are no more of them
  *  or the total memory used is <= target (to free all of them use -1 for 
  *  targer)
@@ -586,7 +634,8 @@ static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data)
  */
 inline static int dst_blacklist_add_ip(unsigned char err_flags, 
 									unsigned char proto,
-									struct ip_addr* ip, unsigned short port)
+									struct ip_addr* ip, unsigned short port,
+									ticks_t timeout)
 {
 	int size;
 	struct dst_blst_entry* e;
@@ -606,11 +655,10 @@ inline static int dst_blacklist_add_ip(unsigned char err_flags,
 	hash=dst_blst_hash_no(proto, ip, port);
 	/* check if the entry already exists */
 	LOCK_BLST(hash);
-		e=_dst_blacklist_lst_find(&dst_blst_hash[hash].first, ip, proto,
-																port, now);
+		e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
 		if (e){
 			e->flags|=err_flags;
-			e->expire=now+S_TO_TICKS(blst_timeout); /* update the timeout */
+			e->expire=now+timeout; /* update the timeout */
 		}else{
 			if (unlikely((*blst_mem_used+size)>=blst_max_mem)){
 				UNLOCK_BLST(hash);
@@ -635,7 +683,7 @@ inline static int dst_blacklist_add_ip(unsigned char err_flags,
 			e->proto=proto;
 			e->port=port;
 			memcpy(e->ip, ip->u.addr, ip->len);
-			e->expire=now+S_TO_TICKS(blst_timeout); /* update the timeout */
+			e->expire=now+timeout; /* update the timeout */
 			e->next=0;
 			dst_blacklist_lst_add(&dst_blst_hash[hash].first, e);
 			BLST_HASH_STATS_INC(hash);
@@ -655,15 +703,14 @@ inline static int dst_is_blacklisted_ip(unsigned char proto,
 	struct dst_blst_entry* e;
 	unsigned short hash;
 	ticks_t now;
-	int ret=0;
+	int ret;
 	
 	ret=0;
 	now=get_ticks_raw();
 	hash=dst_blst_hash_no(proto, ip, port);
 	if (unlikely(dst_blst_hash[hash].first)){
 		LOCK_BLST(hash);
-			e=_dst_blacklist_lst_find(&dst_blst_hash[hash].first, ip, proto,
-										port, now);
+			e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
 			if (e){
 				ret=e->flags;
 			}
@@ -674,7 +721,8 @@ inline static int dst_is_blacklisted_ip(unsigned char proto,
 
 
 
-int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si, struct sip_msg* msg)
+int dst_blacklist_add_to(unsigned char err_flags,  struct dest_info* si,
+						struct sip_msg* msg, ticks_t timeout)
 {
 	struct ip_addr ip;
 
@@ -685,7 +733,7 @@ int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si, struct sip
 #endif
 	su2ip_addr(&ip, &si->to);
 	return dst_blacklist_add_ip(err_flags, si->proto, &ip,
-								su_getport(&si->to));
+								su_getport(&si->to), timeout);
 }
 
 
@@ -714,6 +762,30 @@ int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg)
 
 
 
+/* returns 1 if the entry was deleted, 0 if not found */
+int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg)
+{
+	unsigned short hash;
+	struct ip_addr ip;
+	ticks_t now;
+	int ret;
+	unsigned short port;
+	
+	ret=0;
+	su2ip_addr(&ip, &si->to);
+	port=su_getport(&si->to);
+	now=get_ticks_raw();
+	hash=dst_blst_hash_no(si->proto, &ip, port);
+	if (unlikely(dst_blst_hash[hash].first)){
+		LOCK_BLST(hash);
+			ret=_dst_blacklist_del(hash, &ip, si->proto, port, now);
+		UNLOCK_BLST(hash);
+	}
+	return ret;
+}
+
+
+
 /* rpc functions */
 void dst_blst_mem_info(rpc_t* rpc, void* ctx)
 {
@@ -888,7 +960,8 @@ void dst_blst_add(rpc_t* rpc, void* ctx)
 		return;
 	}
 
-	if (dst_blacklist_add_ip(err_flags, proto, ip_addr, port))
+	if (dst_blacklist_add_ip(err_flags, proto, ip_addr, port, 
+											S_TO_TICKS(blst_timeout)))
 		rpc->fault(ctx, 400, "Failed to add the entry to the blacklist");
 }
 

+ 16 - 3
dst_blacklist.h

@@ -36,6 +36,9 @@
 
 #include "ip_addr.h"
 #include "parser/msg_parser.h"
+#include "timer_ticks.h"
+
+#define DEFAULT_BLST_TIMEOUT		60  /* 1 min. */
 
 /* flags: */
 #define BLST_IS_IPV6		1		/* set if the address is ipv6 */
@@ -43,7 +46,7 @@
 #define BLST_ERR_CONNECT	(1<<2)	/* set if connect failed (tcp/tls) */
 #define BLST_ICMP_RCVD		(1<<3)	/* set if icmp error */
 #define BLST_ERR_TIMEOUT	(1<<4)	/* set if sip timeout */
-#define BLST_RESERVED		(1<<5)	/* not used yet */
+#define BLST_503			(1<<5)	/* set for 503 replies */
 #define BLST_ADM_PROHIBITED	(1<<6)	/* administratively prohibited */
 #define BLST_PERMANENT		(1<<7)  /* never deleted, never expires */
 
@@ -62,7 +65,8 @@ struct blacklist_hook{
 	/* WARNING: msg might be NULL, and it might point to shared memory
 	 * without locking, do not modify it! msg can be used typically for checking
 	 * the message flags with isflagset() */
-	int (*on_blst_action)(struct dest_info* si, unsigned char* err_flags, struct sip_msg* msg);
+	int (*on_blst_action)(struct dest_info* si, unsigned char* err_flags,
+							struct sip_msg* msg);
 	/* called before ser shutdown */
 	void (*destroy)(void);
 };
@@ -73,9 +77,18 @@ int register_blacklist_hook(struct blacklist_hook *h, int type);
 int init_dst_blacklist();
 void destroy_dst_blacklist();
 
-int dst_blacklist_add(unsigned char err_flags, struct dest_info* si, struct sip_msg* msg);
+
+/* like dst_blacklist_add, but the timeout can be also set */
+int dst_blacklist_add_to(unsigned char err_flags, struct dest_info* si,
+						struct sip_msg* msg, ticks_t timeout);
+
+/* adds a dst to the blacklist with default timeout */
+#define dst_blacklist_add(err_flags, si, msg) \
+	dst_blacklist_add_to((err_flags), (si), (msg), S_TO_TICKS(blst_timeout))
 
 int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg);
+/* delete an entry from the blacklist */
+int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg);
 
 /* deletes all the entries from the blacklist except the permanent ones
  * (which are marked with BLST_PERMANENT)