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 129
 
130 130
 #ifdef DST_BLACKLIST_HOOKS
131 131
 
132
+/* there 2 types of callbacks supported: on add new entry to the blacklist
133
+ *  (DST_BLACKLIST_ADD_CB) and on blacklist search (DST_BLACKLIST_SEARCH_CB).
134
+ *  Both of them take a struct dest_info* and a flags pointer as parameters 
135
+ *   (unsigned char*). The flags can be changed.
136
+ *  A callback should return one of:
137
+ *    DST_BLACKLIST_CONTINUE - do nothing, let other callbacks run
138
+ *    DST_BLACKLIST_ACCEPT   - for blacklist add: force accept immediately,
139
+ *                             for blacklist search: force match and use
140
+ *                              the flags as the blacklist search return.
141
+ *                              ( so the flags should be set to some valid
142
+ *                                non zero BLST flags value )
143
+ *   DST_BLACKLIST_DENY      - for blacklist add: don't allow adding the
144
+ *                              destination to the blacklist.
145
+ *                             for blacklist search: force return not found
146
+ */
147
+
132 148
 #define MAX_BLST_HOOKS 1
133 149
 
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;
150
+struct blst_callbacks_lst{
151
+	struct blacklist_hook* hooks;
152
+	unsigned int max_hooks;
153
+	int last_idx;
154
+};
155
+
156
+static struct blst_callbacks_lst blst_add_cb;
157
+static struct blst_callbacks_lst blst_search_cb;
137 158
 
138
-static int init_blacklist_hooks()
159
+static int init_blst_callback_lst(struct blst_callbacks_lst*  cb_lst, int max)
139 160
 {
140
-	blacklist_hooks=pkg_malloc(blacklist_max_hooks*
141
-								sizeof(struct blacklist_hook));
142
-	if (blacklist_hooks==0)
161
+
162
+	cb_lst->max_hooks=MAX_BLST_HOOKS;
163
+	cb_lst->last_idx=0;
164
+	cb_lst->hooks=pkg_malloc(cb_lst->max_hooks*sizeof(struct blacklist_hook));
165
+	if (cb_lst->hooks==0)
143 166
 		goto error;
144
-	memset(blacklist_hooks, 0,
145
-				blacklist_max_hooks*sizeof(struct blacklist_hook));
167
+	memset(cb_lst->hooks, 0, cb_lst->max_hooks*sizeof(struct blacklist_hook));
146 168
 	return 0;
147 169
 error:
148
-	LOG(L_ERR, "blacklist_hooks: memory allocation failure\n");
149 170
 	return -1;
150 171
 }
151 172
 
152 173
 
153
-static void destroy_blacklist_hooks()
174
+static void destroy_blst_callback_lst(struct blst_callbacks_lst* cb_lst)
154 175
 {
155 176
 	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();
177
+	if (cb_lst && cb_lst->hooks){
178
+		for (r=0; r<cb_lst->last_idx; r++){
179
+			if (cb_lst->hooks[r].destroy)
180
+				cb_lst->hooks[r].destroy();
161 181
 		}
162
-		pkg_free(blacklist_hooks);
163
-		blacklist_hooks=0;
182
+		pkg_free(cb_lst->hooks);
183
+		cb_lst->hooks=0;
184
+		cb_lst->last_idx=0;
185
+		cb_lst->max_hooks=0;
164 186
 	}
165 187
 }
166 188
 
167 189
 
190
+static void destroy_blacklist_hooks()
191
+{
192
+	destroy_blst_callback_lst(&blst_add_cb);
193
+	destroy_blst_callback_lst(&blst_search_cb);
194
+}
195
+
196
+
197
+static int init_blacklist_hooks()
198
+{
199
+
200
+	if (init_blst_callback_lst(&blst_add_cb, MAX_BLST_HOOKS)!=0)
201
+		goto error;
202
+	if (init_blst_callback_lst(&blst_search_cb, MAX_BLST_HOOKS)!=0)
203
+		goto error;
204
+	return 0;
205
+error:
206
+	LOG(L_ERR, "blacklist_hooks: failure initializing internal lists\n");
207
+	destroy_blacklist_hooks();
208
+	return -1;
209
+}
210
+
211
+
212
+
213
+
168 214
 /* allocates a new hook
169 215
  * returns 0 on success and -1 on error
170 216
  * must be called from mod init (from the main process, before forking)*/
171
-int register_blacklist_hook(struct blacklist_hook *h)
217
+int register_blacklist_hook(struct blacklist_hook *h, int type)
172 218
 {
219
+	struct blst_callbacks_lst* cb_lst;
173 220
 	struct blacklist_hook* tmp;
174 221
 	int new_max_hooks;
175 222
 	
176
-	if (blacklist_max_hooks==0)
223
+	switch(type){
224
+		case DST_BLACKLIST_ADD_CB:
225
+			cb_lst=&blst_add_cb;
226
+			break;
227
+		case DST_BLACKLIST_SEARCH_CB:
228
+			cb_lst=&blst_search_cb;
229
+			break;
230
+		default:
231
+			BUG("register_blacklist_hook: invalid type %d\n", type);
232
+			goto error;
233
+	}
234
+	if (cb_lst==0 || cb_lst->hooks==0 || cb_lst->max_hooks==0){
235
+		BUG("register_blacklist_hook: intialization error\n");
177 236
 		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, 
237
+	}
238
+
239
+	if (cb_lst->last_idx >= cb_lst->max_hooks){
240
+		new_max_hooks=2*cb_lst->max_hooks;
241
+		tmp=pkg_realloc(cb_lst->hooks, 
181 242
 				new_max_hooks*sizeof(struct blacklist_hook));
182 243
 		if (tmp==0){
183 244
 			goto error;
184 245
 		}
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)*
246
+		cb_lst->hooks=tmp;
247
+		/* init the new chunk (but not the current entry which is 
248
+		 * overwritten anyway) */
249
+		memset(&cb_lst->hooks[cb_lst->max_hooks+1], 0, 
250
+					(new_max_hooks-cb_lst->max_hooks-1)*
189 251
 						sizeof(struct blacklist_hook));
190
-		blacklist_max_hooks=new_max_hooks;
252
+		cb_lst->max_hooks=new_max_hooks;
191 253
 	}
192
-	blacklist_hooks[last_blacklist_hook_idx]=*h;
193
-	last_blacklist_hook_idx++;
254
+	cb_lst->hooks[cb_lst->last_idx]=*h;
255
+	cb_lst->last_idx++;
194 256
 	return 0;
195 257
 error:
196 258
 	return -1;
197 259
 }
198 260
 
199 261
 
200
-int blacklist_run_hooks(struct dest_info* si, unsigned char* flags)
262
+inline static int blacklist_run_hooks(struct blst_callbacks_lst *cb_lst,
263
+							struct dest_info* si, unsigned char* flags)
201 264
 {
202 265
 	int r;
203 266
 	int ret;
204 267
 	
205
-	ret=DST_BLACKLIST_ACCEPT; /* default, if no hook installed accept 
268
+	ret=DST_BLACKLIST_CONTINUE; /* default, if no hook installed accept 
206 269
 								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;
270
+	if (likely(cb_lst->last_idx==0))
271
+		return ret;
272
+	for (r=0; r<cb_lst->last_idx; r++){
273
+		ret=cb_lst->hooks[r].on_blst_add(si, flags);
274
+		if (ret!=DST_BLACKLIST_CONTINUE) break;
210 275
 	}
211 276
 	return ret;
212 277
 }
... ...
@@ -593,13 +659,15 @@ inline static int dst_is_blacklisted_ip(unsigned char proto,
593 593
 	ret=0;
594 594
 	now=get_ticks_raw();
595 595
 	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);
596
+	if (unlikely(dst_blst_hash[hash].first)){
597
+		LOCK_BLST(hash);
598
+			e=_dst_blacklist_lst_find(&dst_blst_hash[hash].first, ip, proto,
599
+										port, now);
600
+			if (e){
601
+				ret=e->flags;
602
+			}
603
+		UNLOCK_BLST(hash);
604
+	}
603 605
 	return ret;
604 606
 }
605 607
 
... ...
@@ -610,7 +678,8 @@ int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si)
610 610
 	struct ip_addr ip;
611 611
 
612 612
 #ifdef DST_BLACKLIST_HOOKS
613
-	if (blacklist_run_hooks(si, &err_flags)!=DST_BLACKLIST_ACCEPT)
613
+	if (unlikely (blacklist_run_hooks(&blst_add_cb, si, &err_flags) ==
614
+					DST_BLACKLIST_DENY))
614 615
 		return 0;
615 616
 #endif
616 617
 	su2ip_addr(&ip, &si->to);
... ...
@@ -623,7 +692,22 @@ int dst_blacklist_add(unsigned char err_flags,  struct dest_info* si)
623 623
 int dst_is_blacklisted(struct dest_info* si)
624 624
 {
625 625
 	struct ip_addr ip;
626
+#ifdef DST_BLACKLIST_HOOKS
627
+	unsigned char err_flags;
628
+	int action;
629
+#endif
626 630
 	su2ip_addr(&ip, &si->to);
631
+
632
+#ifdef DST_BLACKLIST_HOOKS
633
+	err_flags=0;
634
+	if (unlikely((action=(blacklist_run_hooks(&blst_search_cb, si, &err_flags))
635
+					) != DST_BLACKLIST_CONTINUE)){
636
+		if (action==DST_BLACKLIST_DENY)
637
+			return 0;
638
+		else  /* if (action==DST_BLACKLIST_ACCEPT) */
639
+			return err_flags;
640
+	}
641
+#endif
627 642
 	return dst_is_blacklisted_ip(si->proto, &ip, su_getport(&si->to));
628 643
 }
629 644
 
... ...
@@ -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 59
 	void (*destroy)(void);
60 60
 };
61 61
 
62
-int register_blacklist_hook(struct blacklist_hook *h);
62
+int register_blacklist_hook(struct blacklist_hook *h, int type);
63 63
 #endif /* DST_BLACKLIST_HOOKS */
64 64
 
65 65
 int init_dst_blacklist();