Browse Source

- callback support also for search/is_blacklisted (can be used to
implement permanent blacklists, whitelists a.s.o.)
- lock only if the hash bucket list is non-empty

Andrei Pelinescu-Onciul 18 years ago
parent
commit
2b813af104
2 changed files with 135 additions and 47 deletions
  1. 127 43
      dst_blacklist.c
  2. 8 4
      dst_blacklist.h

+ 127 - 43
dst_blacklist.c

@@ -30,6 +30,7 @@
  * --------
  * --------
  *  2006-07-29  created by andrei
  *  2006-07-29  created by andrei
  *  2007-05-39  added hooks for add; more locks to reduce contention (andrei)
  *  2007-05-39  added hooks for add; more locks to reduce contention (andrei)
+ *  2007-06-26  added hooks for search (andrei)
  */
  */
 
 
 
 
@@ -129,84 +130,149 @@ struct dst_blst_lst_head* dst_blst_hash=0;
 
 
 #ifdef DST_BLACKLIST_HOOKS
 #ifdef DST_BLACKLIST_HOOKS
 
 
+/* there 2 types of callbacks supported: on add new entry to the blacklist
+ *  (DST_BLACKLIST_ADD_CB) and on blacklist search (DST_BLACKLIST_SEARCH_CB).
+ *  Both of them take a struct dest_info* and a flags pointer as parameters 
+ *   (unsigned char*). The flags can be changed.
+ *  A callback should return one of:
+ *    DST_BLACKLIST_CONTINUE - do nothing, let other callbacks run
+ *    DST_BLACKLIST_ACCEPT   - for blacklist add: force accept immediately,
+ *                             for blacklist search: force match and use
+ *                              the flags as the blacklist search return.
+ *                              ( so the flags should be set to some valid
+ *                                non zero BLST flags value )
+ *   DST_BLACKLIST_DENY      - for blacklist add: don't allow adding the
+ *                              destination to the blacklist.
+ *                             for blacklist search: force return not found
+ */
+
 #define MAX_BLST_HOOKS 1
 #define MAX_BLST_HOOKS 1
 
 
-static struct blacklist_hook* blacklist_hooks;
-static unsigned int blacklist_max_hooks=MAX_BLST_HOOKS;
-static int last_blacklist_hook_idx=0;
+struct blst_callbacks_lst{
+	struct blacklist_hook* hooks;
+	unsigned int max_hooks;
+	int last_idx;
+};
+
+static struct blst_callbacks_lst blst_add_cb;
+static struct blst_callbacks_lst blst_search_cb;
 
 
-static int init_blacklist_hooks()
+static int init_blst_callback_lst(struct blst_callbacks_lst*  cb_lst, int max)
 {
 {
-	blacklist_hooks=pkg_malloc(blacklist_max_hooks*
-								sizeof(struct blacklist_hook));
-	if (blacklist_hooks==0)
+
+	cb_lst->max_hooks=MAX_BLST_HOOKS;
+	cb_lst->last_idx=0;
+	cb_lst->hooks=pkg_malloc(cb_lst->max_hooks*sizeof(struct blacklist_hook));
+	if (cb_lst->hooks==0)
 		goto error;
 		goto error;
-	memset(blacklist_hooks, 0,
-				blacklist_max_hooks*sizeof(struct blacklist_hook));
+	memset(cb_lst->hooks, 0, cb_lst->max_hooks*sizeof(struct blacklist_hook));
 	return 0;
 	return 0;
 error:
 error:
-	LOG(L_ERR, "blacklist_hooks: memory allocation failure\n");
 	return -1;
 	return -1;
 }
 }
 
 
 
 
-static void destroy_blacklist_hooks()
+static void destroy_blst_callback_lst(struct blst_callbacks_lst* cb_lst)
 {
 {
 	int r;
 	int r;
-
-	if (blacklist_hooks){
-		for (r=0; r<last_blacklist_hook_idx; r++){
-			if (blacklist_hooks[r].destroy)
-				blacklist_hooks[r].destroy();
+	if (cb_lst && cb_lst->hooks){
+		for (r=0; r<cb_lst->last_idx; r++){
+			if (cb_lst->hooks[r].destroy)
+				cb_lst->hooks[r].destroy();
 		}
 		}
-		pkg_free(blacklist_hooks);
-		blacklist_hooks=0;
+		pkg_free(cb_lst->hooks);
+		cb_lst->hooks=0;
+		cb_lst->last_idx=0;
+		cb_lst->max_hooks=0;
 	}
 	}
 }
 }
 
 
 
 
+static void destroy_blacklist_hooks()
+{
+	destroy_blst_callback_lst(&blst_add_cb);
+	destroy_blst_callback_lst(&blst_search_cb);
+}
+
+
+static int init_blacklist_hooks()
+{
+
+	if (init_blst_callback_lst(&blst_add_cb, MAX_BLST_HOOKS)!=0)
+		goto error;
+	if (init_blst_callback_lst(&blst_search_cb, MAX_BLST_HOOKS)!=0)
+		goto error;
+	return 0;
+error:
+	LOG(L_ERR, "blacklist_hooks: failure initializing internal lists\n");
+	destroy_blacklist_hooks();
+	return -1;
+}
+
+
+
+
 /* allocates a new hook
 /* allocates a new hook
  * returns 0 on success and -1 on error
  * returns 0 on success and -1 on error
  * must be called from mod init (from the main process, before forking)*/
  * must be called from mod init (from the main process, before forking)*/
-int register_blacklist_hook(struct blacklist_hook *h)
+int register_blacklist_hook(struct blacklist_hook *h, int type)
 {
 {
+	struct blst_callbacks_lst* cb_lst;
 	struct blacklist_hook* tmp;
 	struct blacklist_hook* tmp;
 	int new_max_hooks;
 	int new_max_hooks;
 	
 	
-	if (blacklist_max_hooks==0)
+	switch(type){
+		case DST_BLACKLIST_ADD_CB:
+			cb_lst=&blst_add_cb;
+			break;
+		case DST_BLACKLIST_SEARCH_CB:
+			cb_lst=&blst_search_cb;
+			break;
+		default:
+			BUG("register_blacklist_hook: invalid type %d\n", type);
+			goto error;
+	}
+	if (cb_lst==0 || cb_lst->hooks==0 || cb_lst->max_hooks==0){
+		BUG("register_blacklist_hook: intialization error\n");
 		goto error;
 		goto error;
-	if (last_blacklist_hook_idx >= blacklist_max_hooks){
-		new_max_hooks=2*blacklist_max_hooks;
-		tmp=pkg_realloc(blacklist_hooks, 
+	}
+
+	if (cb_lst->last_idx >= cb_lst->max_hooks){
+		new_max_hooks=2*cb_lst->max_hooks;
+		tmp=pkg_realloc(cb_lst->hooks, 
 				new_max_hooks*sizeof(struct blacklist_hook));
 				new_max_hooks*sizeof(struct blacklist_hook));
 		if (tmp==0){
 		if (tmp==0){
 			goto error;
 			goto error;
 		}
 		}
-		blacklist_hooks=tmp;
-		/* init the new chunk */
-		memset(&blacklist_hooks[last_blacklist_hook_idx+1], 0, 
-					(new_max_hooks-blacklist_max_hooks-1)*
+		cb_lst->hooks=tmp;
+		/* init the new chunk (but not the current entry which is 
+		 * overwritten anyway) */
+		memset(&cb_lst->hooks[cb_lst->max_hooks+1], 0, 
+					(new_max_hooks-cb_lst->max_hooks-1)*
 						sizeof(struct blacklist_hook));
 						sizeof(struct blacklist_hook));
-		blacklist_max_hooks=new_max_hooks;
+		cb_lst->max_hooks=new_max_hooks;
 	}
 	}
-	blacklist_hooks[last_blacklist_hook_idx]=*h;
-	last_blacklist_hook_idx++;
+	cb_lst->hooks[cb_lst->last_idx]=*h;
+	cb_lst->last_idx++;
 	return 0;
 	return 0;
 error:
 error:
 	return -1;
 	return -1;
 }
 }
 
 
 
 
-int blacklist_run_hooks(struct dest_info* si, unsigned char* flags)
+inline static int blacklist_run_hooks(struct blst_callbacks_lst *cb_lst,
+							struct dest_info* si, unsigned char* flags)
 {
 {
 	int r;
 	int r;
 	int ret;
 	int ret;
 	
 	
-	ret=DST_BLACKLIST_ACCEPT; /* default, if no hook installed accept 
+	ret=DST_BLACKLIST_CONTINUE; /* default, if no hook installed accept 
 								blacklist operation */
 								blacklist operation */
-	for (r=0; r<last_blacklist_hook_idx; r++){
-		ret=blacklist_hooks[r].on_blst_add(si, flags);
-		if (ret!=DST_BLACKLIST_ACCEPT) break;
+	if (likely(cb_lst->last_idx==0))
+		return ret;
+	for (r=0; r<cb_lst->last_idx; r++){
+		ret=cb_lst->hooks[r].on_blst_add(si, flags);
+		if (ret!=DST_BLACKLIST_CONTINUE) break;
 	}
 	}
 	return ret;
 	return ret;
 }
 }
@@ -593,13 +659,15 @@ inline static int dst_is_blacklisted_ip(unsigned char proto,
 	ret=0;
 	ret=0;
 	now=get_ticks_raw();
 	now=get_ticks_raw();
 	hash=dst_blst_hash_no(proto, ip, port);
 	hash=dst_blst_hash_no(proto, ip, port);
-	LOCK_BLST(hash);
-		e=_dst_blacklist_lst_find(&dst_blst_hash[hash].first, ip, proto,
-									port, now);
-		if (e){
-			ret=e->flags;
-		}
-	UNLOCK_BLST(hash);
+	if (unlikely(dst_blst_hash[hash].first)){
+		LOCK_BLST(hash);
+			e=_dst_blacklist_lst_find(&dst_blst_hash[hash].first, ip, proto,
+										port, now);
+			if (e){
+				ret=e->flags;
+			}
+		UNLOCK_BLST(hash);
+	}
 	return ret;
 	return ret;
 }
 }
 
 
@@ -610,7 +678,8 @@ int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si)
 	struct ip_addr ip;
 	struct ip_addr ip;
 
 
 #ifdef DST_BLACKLIST_HOOKS
 #ifdef DST_BLACKLIST_HOOKS
-	if (blacklist_run_hooks(si, &err_flags)!=DST_BLACKLIST_ACCEPT)
+	if (unlikely (blacklist_run_hooks(&blst_add_cb, si, &err_flags) ==
+					DST_BLACKLIST_DENY))
 		return 0;
 		return 0;
 #endif
 #endif
 	su2ip_addr(&ip, &si->to);
 	su2ip_addr(&ip, &si->to);
@@ -623,7 +692,22 @@ int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si)
 int dst_is_blacklisted(struct dest_info* si)
 int dst_is_blacklisted(struct dest_info* si)
 {
 {
 	struct ip_addr ip;
 	struct ip_addr ip;
+#ifdef DST_BLACKLIST_HOOKS
+	unsigned char err_flags;
+	int action;
+#endif
 	su2ip_addr(&ip, &si->to);
 	su2ip_addr(&ip, &si->to);
+
+#ifdef DST_BLACKLIST_HOOKS
+	err_flags=0;
+	if (unlikely((action=(blacklist_run_hooks(&blst_search_cb, si, &err_flags))
+					) != DST_BLACKLIST_CONTINUE)){
+		if (action==DST_BLACKLIST_DENY)
+			return 0;
+		else  /* if (action==DST_BLACKLIST_ACCEPT) */
+			return err_flags;
+	}
+#endif
 	return dst_is_blacklisted_ip(si->proto, &ip, su_getport(&si->to));
 	return dst_is_blacklisted_ip(si->proto, &ip, su_getport(&si->to));
 }
 }
 
 

+ 8 - 4
dst_blacklist.h

@@ -46,11 +46,15 @@
 #define BLST_ADM_PROHIBITED	(1<<6)	/* administratively prohibited */
 #define BLST_ADM_PROHIBITED	(1<<6)	/* administratively prohibited */
 #define BLST_PERMANENT		(1<<7)  /* never deleted, never expires */
 #define BLST_PERMANENT		(1<<7)  /* never deleted, never expires */
 
 
-
+/* uncomment the define above to enable blacklist callbacks support */
 /*#define DST_BLACKLIST_HOOKS*/
 /*#define DST_BLACKLIST_HOOKS*/
 
 
-#define DST_BLACKLIST_ACCEPT 0
-#define DST_BLACKLIST_DENY  -1
+#define DST_BLACKLIST_CONTINUE 0 /* add: do nothing/ignore, search: ignore */
+#define DST_BLACKLIST_ACCEPT 1   /* add: force accept, search: force match */
+#define DST_BLACKLIST_DENY  -1   /* add: deny, search: force no match */
+
+#define DST_BLACKLIST_ADD_CB 1
+#define DST_BLACKLIST_SEARCH_CB 2
 
 
 #ifdef DST_BLACKLIST_HOOKS
 #ifdef DST_BLACKLIST_HOOKS
 struct blacklist_hook{
 struct blacklist_hook{
@@ -59,7 +63,7 @@ struct blacklist_hook{
 	void (*destroy)(void);
 	void (*destroy)(void);
 };
 };
 
 
-int register_blacklist_hook(struct blacklist_hook *h);
+int register_blacklist_hook(struct blacklist_hook *h, int type);
 #endif /* DST_BLACKLIST_HOOKS */
 #endif /* DST_BLACKLIST_HOOKS */
 
 
 int init_dst_blacklist();
 int init_dst_blacklist();