Browse code

- 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 authored on 26/06/2007 15:30:07
Showing 2 changed files
... ...
@@ -30,6 +30,7 @@
30 30
  * --------
31 31
  *  2006-07-29  created by andrei
32 32
  *  2007-05-39  added hooks for add; more locks to reduce contention (andrei)
33
+ *  2007-06-26  added hooks for search (andrei)
33 34
  */
34 35
 
35 36
 
... ...
@@ -129,84 +130,149 @@ struct dst_blst_lst_head* dst_blst_hash=0;
129 130
 
130 131
 #ifdef DST_BLACKLIST_HOOKS
131 132
 
133
+/* there 2 types of callbacks supported: on add new entry to the blacklist
134
+ *  (DST_BLACKLIST_ADD_CB) and on blacklist search (DST_BLACKLIST_SEARCH_CB).
135
+ *  Both of them take a struct dest_info* and a flags pointer as parameters 
136
+ *   (unsigned char*). The flags can be changed.
137
+ *  A callback should return one of:
138
+ *    DST_BLACKLIST_CONTINUE - do nothing, let other callbacks run
139
+ *    DST_BLACKLIST_ACCEPT   - for blacklist add: force accept immediately,
140
+ *                             for blacklist search: force match and use
141
+ *                              the flags as the blacklist search return.
142
+ *                              ( so the flags should be set to some valid
143
+ *                                non zero BLST flags value )
144
+ *   DST_BLACKLIST_DENY      - for blacklist add: don't allow adding the
145
+ *                              destination to the blacklist.
146
+ *                             for blacklist search: force return not found
147
+ */
148
+
132 149
 #define MAX_BLST_HOOKS 1
133 150
 
134
-static struct blacklist_hook* blacklist_hooks;
135
-static unsigned int blacklist_max_hooks=MAX_BLST_HOOKS;
136
-static int last_blacklist_hook_idx=0;
151
+struct blst_callbacks_lst{
152
+	struct blacklist_hook* hooks;
153
+	unsigned int max_hooks;
154
+	int last_idx;
155
+};
156
+
157
+static struct blst_callbacks_lst blst_add_cb;
158
+static struct blst_callbacks_lst blst_search_cb;
137 159
 
138
-static int init_blacklist_hooks()
160
+static int init_blst_callback_lst(struct blst_callbacks_lst*  cb_lst, int max)
139 161
 {
140
-	blacklist_hooks=pkg_malloc(blacklist_max_hooks*
141
-								sizeof(struct blacklist_hook));
142
-	if (blacklist_hooks==0)
162
+
163
+	cb_lst->max_hooks=MAX_BLST_HOOKS;
164
+	cb_lst->last_idx=0;
165
+	cb_lst->hooks=pkg_malloc(cb_lst->max_hooks*sizeof(struct blacklist_hook));
166
+	if (cb_lst->hooks==0)
143 167
 		goto error;
144
-	memset(blacklist_hooks, 0,
145
-				blacklist_max_hooks*sizeof(struct blacklist_hook));
168
+	memset(cb_lst->hooks, 0, cb_lst->max_hooks*sizeof(struct blacklist_hook));
146 169
 	return 0;
147 170
 error:
148
-	LOG(L_ERR, "blacklist_hooks: memory allocation failure\n");
149 171
 	return -1;
150 172
 }
151 173
 
152 174
 
153
-static void destroy_blacklist_hooks()
175
+static void destroy_blst_callback_lst(struct blst_callbacks_lst* cb_lst)
154 176
 {
155 177
 	int r;
156
-
157
-	if (blacklist_hooks){
158
-		for (r=0; r<last_blacklist_hook_idx; r++){
159
-			if (blacklist_hooks[r].destroy)
160
-				blacklist_hooks[r].destroy();
178
+	if (cb_lst && cb_lst->hooks){
179
+		for (r=0; r<cb_lst->last_idx; r++){
180
+			if (cb_lst->hooks[r].destroy)
181
+				cb_lst->hooks[r].destroy();
161 182
 		}
162
-		pkg_free(blacklist_hooks);
163
-		blacklist_hooks=0;
183
+		pkg_free(cb_lst->hooks);
184
+		cb_lst->hooks=0;
185
+		cb_lst->last_idx=0;
186
+		cb_lst->max_hooks=0;
164 187
 	}
165 188
 }
166 189
 
167 190
 
191
+static void destroy_blacklist_hooks()
192
+{
193
+	destroy_blst_callback_lst(&blst_add_cb);
194
+	destroy_blst_callback_lst(&blst_search_cb);
195
+}
196
+
197
+
198
+static int init_blacklist_hooks()
199
+{
200
+
201
+	if (init_blst_callback_lst(&blst_add_cb, MAX_BLST_HOOKS)!=0)
202
+		goto error;
203
+	if (init_blst_callback_lst(&blst_search_cb, MAX_BLST_HOOKS)!=0)
204
+		goto error;
205
+	return 0;
206
+error:
207
+	LOG(L_ERR, "blacklist_hooks: failure initializing internal lists\n");
208
+	destroy_blacklist_hooks();
209
+	return -1;
210
+}
211
+
212
+
213
+
214
+
168 215
 /* allocates a new hook
169 216
  * returns 0 on success and -1 on error
170 217
  * must be called from mod init (from the main process, before forking)*/
171
-int register_blacklist_hook(struct blacklist_hook *h)
218
+int register_blacklist_hook(struct blacklist_hook *h, int type)
172 219
 {
220
+	struct blst_callbacks_lst* cb_lst;
173 221
 	struct blacklist_hook* tmp;
174 222
 	int new_max_hooks;
175 223
 	
176
-	if (blacklist_max_hooks==0)
224
+	switch(type){
225
+		case DST_BLACKLIST_ADD_CB:
226
+			cb_lst=&blst_add_cb;
227
+			break;
228
+		case DST_BLACKLIST_SEARCH_CB:
229
+			cb_lst=&blst_search_cb;
230
+			break;
231
+		default:
232
+			BUG("register_blacklist_hook: invalid type %d\n", type);
233
+			goto error;
234
+	}
235
+	if (cb_lst==0 || cb_lst->hooks==0 || cb_lst->max_hooks==0){
236
+		BUG("register_blacklist_hook: intialization error\n");
177 237
 		goto error;
178
-	if (last_blacklist_hook_idx >= blacklist_max_hooks){
179
-		new_max_hooks=2*blacklist_max_hooks;
180
-		tmp=pkg_realloc(blacklist_hooks, 
238
+	}
239
+
240
+	if (cb_lst->last_idx >= cb_lst->max_hooks){
241
+		new_max_hooks=2*cb_lst->max_hooks;
242
+		tmp=pkg_realloc(cb_lst->hooks, 
181 243
 				new_max_hooks*sizeof(struct blacklist_hook));
182 244
 		if (tmp==0){
183 245
 			goto error;
184 246
 		}
185
-		blacklist_hooks=tmp;
186
-		/* init the new chunk */
187
-		memset(&blacklist_hooks[last_blacklist_hook_idx+1], 0, 
188
-					(new_max_hooks-blacklist_max_hooks-1)*
247
+		cb_lst->hooks=tmp;
248
+		/* init the new chunk (but not the current entry which is 
249
+		 * overwritten anyway) */
250
+		memset(&cb_lst->hooks[cb_lst->max_hooks+1], 0, 
251
+					(new_max_hooks-cb_lst->max_hooks-1)*
189 252
 						sizeof(struct blacklist_hook));
190
-		blacklist_max_hooks=new_max_hooks;
253
+		cb_lst->max_hooks=new_max_hooks;
191 254
 	}
192
-	blacklist_hooks[last_blacklist_hook_idx]=*h;
193
-	last_blacklist_hook_idx++;
255
+	cb_lst->hooks[cb_lst->last_idx]=*h;
256
+	cb_lst->last_idx++;
194 257
 	return 0;
195 258
 error:
196 259
 	return -1;
197 260
 }
198 261
 
199 262
 
200
-int blacklist_run_hooks(struct dest_info* si, unsigned char* flags)
263
+inline static int blacklist_run_hooks(struct blst_callbacks_lst *cb_lst,
264
+							struct dest_info* si, unsigned char* flags)
201 265
 {
202 266
 	int r;
203 267
 	int ret;
204 268
 	
205
-	ret=DST_BLACKLIST_ACCEPT; /* default, if no hook installed accept 
269
+	ret=DST_BLACKLIST_CONTINUE; /* default, if no hook installed accept 
206 270
 								blacklist operation */
207
-	for (r=0; r<last_blacklist_hook_idx; r++){
208
-		ret=blacklist_hooks[r].on_blst_add(si, flags);
209
-		if (ret!=DST_BLACKLIST_ACCEPT) break;
271
+	if (likely(cb_lst->last_idx==0))
272
+		return ret;
273
+	for (r=0; r<cb_lst->last_idx; r++){
274
+		ret=cb_lst->hooks[r].on_blst_add(si, flags);
275
+		if (ret!=DST_BLACKLIST_CONTINUE) break;
210 276
 	}
211 277
 	return ret;
212 278
 }
... ...
@@ -593,13 +659,15 @@ inline static int dst_is_blacklisted_ip(unsigned char proto,
593 659
 	ret=0;
594 660
 	now=get_ticks_raw();
595 661
 	hash=dst_blst_hash_no(proto, ip, port);
596
-	LOCK_BLST(hash);
597
-		e=_dst_blacklist_lst_find(&dst_blst_hash[hash].first, ip, proto,
598
-									port, now);
599
-		if (e){
600
-			ret=e->flags;
601
-		}
602
-	UNLOCK_BLST(hash);
662
+	if (unlikely(dst_blst_hash[hash].first)){
663
+		LOCK_BLST(hash);
664
+			e=_dst_blacklist_lst_find(&dst_blst_hash[hash].first, ip, proto,
665
+										port, now);
666
+			if (e){
667
+				ret=e->flags;
668
+			}
669
+		UNLOCK_BLST(hash);
670
+	}
603 671
 	return ret;
604 672
 }
605 673
 
... ...
@@ -610,7 +678,8 @@ int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si)
610 678
 	struct ip_addr ip;
611 679
 
612 680
 #ifdef DST_BLACKLIST_HOOKS
613
-	if (blacklist_run_hooks(si, &err_flags)!=DST_BLACKLIST_ACCEPT)
681
+	if (unlikely (blacklist_run_hooks(&blst_add_cb, si, &err_flags) ==
682
+					DST_BLACKLIST_DENY))
614 683
 		return 0;
615 684
 #endif
616 685
 	su2ip_addr(&ip, &si->to);
... ...
@@ -623,7 +692,22 @@ int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si)
623 692
 int dst_is_blacklisted(struct dest_info* si)
624 693
 {
625 694
 	struct ip_addr ip;
695
+#ifdef DST_BLACKLIST_HOOKS
696
+	unsigned char err_flags;
697
+	int action;
698
+#endif
626 699
 	su2ip_addr(&ip, &si->to);
700
+
701
+#ifdef DST_BLACKLIST_HOOKS
702
+	err_flags=0;
703
+	if (unlikely((action=(blacklist_run_hooks(&blst_search_cb, si, &err_flags))
704
+					) != DST_BLACKLIST_CONTINUE)){
705
+		if (action==DST_BLACKLIST_DENY)
706
+			return 0;
707
+		else  /* if (action==DST_BLACKLIST_ACCEPT) */
708
+			return err_flags;
709
+	}
710
+#endif
627 711
 	return dst_is_blacklisted_ip(si->proto, &ip, su_getport(&si->to));
628 712
 }
629 713
 
... ...
@@ -46,11 +46,15 @@
46 46
 #define BLST_ADM_PROHIBITED	(1<<6)	/* administratively prohibited */
47 47
 #define BLST_PERMANENT		(1<<7)  /* never deleted, never expires */
48 48
 
49
-
49
+/* uncomment the define above to enable blacklist callbacks support */
50 50
 /*#define DST_BLACKLIST_HOOKS*/
51 51
 
52
-#define DST_BLACKLIST_ACCEPT 0
53
-#define DST_BLACKLIST_DENY  -1
52
+#define DST_BLACKLIST_CONTINUE 0 /* add: do nothing/ignore, search: ignore */
53
+#define DST_BLACKLIST_ACCEPT 1   /* add: force accept, search: force match */
54
+#define DST_BLACKLIST_DENY  -1   /* add: deny, search: force no match */
55
+
56
+#define DST_BLACKLIST_ADD_CB 1
57
+#define DST_BLACKLIST_SEARCH_CB 2
54 58
 
55 59
 #ifdef DST_BLACKLIST_HOOKS
56 60
 struct blacklist_hook{
... ...
@@ -59,7 +63,7 @@ struct blacklist_hook{
59 63
 	void (*destroy)(void);
60 64
 };
61 65
 
62
-int register_blacklist_hook(struct blacklist_hook *h);
66
+int register_blacklist_hook(struct blacklist_hook *h, int type);
63 67
 #endif /* DST_BLACKLIST_HOOKS */
64 68
 
65 69
 int init_dst_blacklist();