diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-08-04 20:49:35 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-08-04 20:49:35 +0000 |
commit | ed4272a244d2770c42ffdb22c80cb4245fbcf538 (patch) | |
tree | 5e43c11209a67431bec2e49b2e82da64ab1f0fd0 /src/transport/gnunet-service-transport_blacklist.c | |
parent | b766cf70853e0732c0785648acd74c6958fea5a7 (diff) | |
download | gnunet-ed4272a244d2770c42ffdb22c80cb4245fbcf538.tar.gz gnunet-ed4272a244d2770c42ffdb22c80cb4245fbcf538.zip |
implementing blacklist
Diffstat (limited to 'src/transport/gnunet-service-transport_blacklist.c')
-rw-r--r-- | src/transport/gnunet-service-transport_blacklist.c | 800 |
1 files changed, 800 insertions, 0 deletions
diff --git a/src/transport/gnunet-service-transport_blacklist.c b/src/transport/gnunet-service-transport_blacklist.c new file mode 100644 index 000000000..aa4644d10 --- /dev/null +++ b/src/transport/gnunet-service-transport_blacklist.c | |||
@@ -0,0 +1,800 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010,2011 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file transport/gnunet-service-transport_blacklist.c | ||
23 | * @brief blacklisting implementation | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet-service-transport.h" | ||
28 | #include "gnunet-service-transport_blacklist.h" | ||
29 | #include "gnunet-service-transport_neighbours.h" | ||
30 | #include "transport.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Size of the blacklist hash map. | ||
35 | */ | ||
36 | #define TRANSPORT_BLACKLIST_HT_SIZE 64 | ||
37 | |||
38 | |||
39 | /** | ||
40 | * Context we use when performing a blacklist check. | ||
41 | */ | ||
42 | struct BlacklistCheck; | ||
43 | |||
44 | |||
45 | /** | ||
46 | * Information kept for each client registered to perform | ||
47 | * blacklisting. | ||
48 | */ | ||
49 | struct Blacklisters | ||
50 | { | ||
51 | /** | ||
52 | * This is a linked list. | ||
53 | */ | ||
54 | struct Blacklisters *next; | ||
55 | |||
56 | /** | ||
57 | * This is a linked list. | ||
58 | */ | ||
59 | struct Blacklisters *prev; | ||
60 | |||
61 | /** | ||
62 | * Client responsible for this entry. | ||
63 | */ | ||
64 | struct GNUNET_SERVER_Client *client; | ||
65 | |||
66 | /** | ||
67 | * Blacklist check that we're currently performing. | ||
68 | */ | ||
69 | struct BlacklistCheck *bc; | ||
70 | |||
71 | }; | ||
72 | |||
73 | |||
74 | |||
75 | /** | ||
76 | * Context we use when performing a blacklist check. | ||
77 | */ | ||
78 | struct BlacklistCheck | ||
79 | { | ||
80 | |||
81 | /** | ||
82 | * This is a linked list. | ||
83 | */ | ||
84 | struct BlacklistCheck *next; | ||
85 | |||
86 | /** | ||
87 | * This is a linked list. | ||
88 | */ | ||
89 | struct BlacklistCheck *prev; | ||
90 | |||
91 | /** | ||
92 | * Peer being checked. | ||
93 | */ | ||
94 | struct GNUNET_PeerIdentity peer; | ||
95 | |||
96 | /** | ||
97 | * Continuation to call with the result. | ||
98 | */ | ||
99 | GST_BlacklistTestContinuation cont; | ||
100 | |||
101 | /** | ||
102 | * Closure for cont. | ||
103 | */ | ||
104 | void *cont_cls; | ||
105 | |||
106 | /** | ||
107 | * Current transmission request handle for this client, or NULL if no | ||
108 | * request is pending. | ||
109 | */ | ||
110 | struct GNUNET_CONNECTION_TransmitHandle *th; | ||
111 | |||
112 | /** | ||
113 | * Our current position in the blacklisters list. | ||
114 | */ | ||
115 | struct Blacklisters *bl_pos; | ||
116 | |||
117 | /** | ||
118 | * Current task performing the check. | ||
119 | */ | ||
120 | GNUNET_SCHEDULER_TaskIdentifier task; | ||
121 | |||
122 | }; | ||
123 | |||
124 | |||
125 | /** | ||
126 | * Head of DLL of active blacklisting queries. | ||
127 | */ | ||
128 | static struct BlacklistCheck *bc_head; | ||
129 | |||
130 | /** | ||
131 | * Tail of DLL of active blacklisting queries. | ||
132 | */ | ||
133 | static struct BlacklistCheck *bc_tail; | ||
134 | |||
135 | /** | ||
136 | * Head of DLL of blacklisting clients. | ||
137 | */ | ||
138 | static struct Blacklisters *bl_head; | ||
139 | |||
140 | /** | ||
141 | * Tail of DLL of blacklisting clients. | ||
142 | */ | ||
143 | static struct Blacklisters *bl_tail; | ||
144 | |||
145 | /** | ||
146 | * Hashmap of blacklisted peers. Values are of type 'char *' (transport names), | ||
147 | * can be NULL if we have no static blacklist. | ||
148 | */ | ||
149 | static struct GNUNET_CONTAINER_MultiHashMap *blacklist; | ||
150 | |||
151 | |||
152 | /** | ||
153 | * Perform next action in the blacklist check. | ||
154 | * | ||
155 | * @param cls the 'struct BlacklistCheck*' | ||
156 | * @param tc unused | ||
157 | */ | ||
158 | static void | ||
159 | do_blacklist_check (void *cls, | ||
160 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Called whenever a client is disconnected. Frees our | ||
165 | * resources associated with that client. | ||
166 | * | ||
167 | * @param cls closure (unused) | ||
168 | * @param client identification of the client | ||
169 | */ | ||
170 | static void | ||
171 | client_disconnect_notification (void *cls, | ||
172 | struct GNUNET_SERVER_Client *client) | ||
173 | { | ||
174 | struct Blacklisters *bl; | ||
175 | struct BlacklistCheck *bc; | ||
176 | |||
177 | if (client == NULL) | ||
178 | return; | ||
179 | for (bl = bl_head; bl != NULL; bl = bl->next) | ||
180 | { | ||
181 | if (bl->client != client) | ||
182 | continue; | ||
183 | for (bc = bc_head; bc != NULL; bc = bc->next) | ||
184 | { | ||
185 | if (bc->bl_pos != bl) | ||
186 | continue; | ||
187 | bc->bl_pos = bl->next; | ||
188 | if (bc->th != NULL) | ||
189 | { | ||
190 | GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th); | ||
191 | bc->th = NULL; | ||
192 | } | ||
193 | if (bc->task == GNUNET_SCHEDULER_NO_TASK) | ||
194 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
195 | bc); | ||
196 | break; | ||
197 | } | ||
198 | GNUNET_CONTAINER_DLL_remove (bl_head, | ||
199 | bl_tail, | ||
200 | bl); | ||
201 | GNUNET_SERVER_client_drop (bl->client); | ||
202 | GNUNET_free (bl); | ||
203 | break; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Read the blacklist file, containing transport:peer entries. | ||
210 | * Provided the transport is loaded, set up hashmap with these | ||
211 | * entries to blacklist peers by transport. | ||
212 | * | ||
213 | */ | ||
214 | static void | ||
215 | read_blacklist_file () | ||
216 | { | ||
217 | char *fn; | ||
218 | char *data; | ||
219 | size_t pos; | ||
220 | size_t colon_pos; | ||
221 | int tsize; | ||
222 | struct GNUNET_PeerIdentity pid; | ||
223 | struct stat frstat; | ||
224 | struct GNUNET_CRYPTO_HashAsciiEncoded enc; | ||
225 | unsigned int entries_found; | ||
226 | char *transport_name; | ||
227 | |||
228 | if (GNUNET_OK != | ||
229 | GNUNET_CONFIGURATION_get_value_filename (GST_cfg, | ||
230 | "TRANSPORT", | ||
231 | "BLACKLIST_FILE", | ||
232 | &fn)) | ||
233 | { | ||
234 | #if DEBUG_TRANSPORT | ||
235 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
236 | "Option `%s' in section `%s' not specified!\n", | ||
237 | "BLACKLIST_FILE", | ||
238 | "TRANSPORT"); | ||
239 | #endif | ||
240 | return; | ||
241 | } | ||
242 | if (GNUNET_OK != GNUNET_DISK_file_test (fn)) | ||
243 | GNUNET_DISK_fn_write (fn, NULL, 0, | ||
244 | GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); | ||
245 | if (0 != STAT (fn, &frstat)) | ||
246 | { | ||
247 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
248 | _("Could not read blacklist file `%s'\n"), | ||
249 | fn); | ||
250 | GNUNET_free (fn); | ||
251 | return; | ||
252 | } | ||
253 | if (frstat.st_size == 0) | ||
254 | { | ||
255 | #if DEBUG_TRANSPORT | ||
256 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
257 | _("Blacklist file `%s' is empty.\n"), | ||
258 | fn); | ||
259 | #endif | ||
260 | GNUNET_free (fn); | ||
261 | return; | ||
262 | } | ||
263 | /* FIXME: use mmap */ | ||
264 | data = GNUNET_malloc_large (frstat.st_size); | ||
265 | GNUNET_assert(data != NULL); | ||
266 | if (frstat.st_size != | ||
267 | GNUNET_DISK_fn_read (fn, data, frstat.st_size)) | ||
268 | { | ||
269 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
270 | _("Failed to read blacklist from `%s'\n"), | ||
271 | fn); | ||
272 | GNUNET_free (fn); | ||
273 | GNUNET_free (data); | ||
274 | return; | ||
275 | } | ||
276 | entries_found = 0; | ||
277 | pos = 0; | ||
278 | while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos])) | ||
279 | pos++; | ||
280 | while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) && | ||
281 | (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded))) | ||
282 | { | ||
283 | colon_pos = pos; | ||
284 | while ( (colon_pos < frstat.st_size) && | ||
285 | (data[colon_pos] != ':') && | ||
286 | (! isspace ( (unsigned char) data[colon_pos])) ) | ||
287 | colon_pos++; | ||
288 | if (colon_pos >= frstat.st_size) | ||
289 | { | ||
290 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
291 | _("Syntax error in blacklist file at offset %llu, giving up!\n"), | ||
292 | (unsigned long long) colon_pos); | ||
293 | GNUNET_free (fn); | ||
294 | GNUNET_free (data); | ||
295 | return; | ||
296 | } | ||
297 | |||
298 | if (isspace( (unsigned char) data[colon_pos])) | ||
299 | { | ||
300 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
301 | _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"), | ||
302 | (unsigned long long) colon_pos); | ||
303 | pos = colon_pos; | ||
304 | while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos])) | ||
305 | pos++; | ||
306 | continue; | ||
307 | } | ||
308 | tsize = colon_pos - pos; | ||
309 | if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0)) | ||
310 | { | ||
311 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
312 | _("Syntax error in blacklist file at offset %llu, giving up!\n"), | ||
313 | (unsigned long long) colon_pos); | ||
314 | GNUNET_free (fn); | ||
315 | GNUNET_free (data); | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | if (tsize < 1) | ||
320 | continue; | ||
321 | |||
322 | transport_name = GNUNET_malloc(tsize + 1); | ||
323 | memcpy(transport_name, &data[pos], tsize); | ||
324 | pos = colon_pos + 1; | ||
325 | #if DEBUG_TRANSPORT | ||
326 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
327 | "Read transport name `%s' in blacklist file.\n", | ||
328 | transport_name); | ||
329 | #endif | ||
330 | memcpy (&enc, | ||
331 | &data[pos], | ||
332 | sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); | ||
333 | if (! isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1])) | ||
334 | { | ||
335 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
336 | _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"), | ||
337 | (unsigned long long) pos); | ||
338 | pos++; | ||
339 | while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos]))) | ||
340 | pos++; | ||
341 | GNUNET_free_non_null(transport_name); | ||
342 | continue; | ||
343 | } | ||
344 | enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; | ||
345 | if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey)) | ||
346 | { | ||
347 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
348 | _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"), | ||
349 | (unsigned long long) pos, | ||
350 | &enc); | ||
351 | } | ||
352 | else | ||
353 | { | ||
354 | if (0 != memcmp (&pid, | ||
355 | &GST_my_identity, | ||
356 | sizeof (struct GNUNET_PeerIdentity))) | ||
357 | { | ||
358 | entries_found++; | ||
359 | GST_blacklist_add_peer (&pid, | ||
360 | transport_name); | ||
361 | } | ||
362 | else | ||
363 | { | ||
364 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
365 | _("Found myself `%s' in blacklist (useless, ignored)\n"), | ||
366 | GNUNET_i2s (&pid)); | ||
367 | } | ||
368 | } | ||
369 | pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded); | ||
370 | GNUNET_free_non_null(transport_name); | ||
371 | while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos])) | ||
372 | pos++; | ||
373 | } | ||
374 | GNUNET_STATISTICS_update (GST_stats, | ||
375 | "# Transport entries blacklisted", | ||
376 | entries_found, | ||
377 | GNUNET_NO); | ||
378 | GNUNET_free (data); | ||
379 | GNUNET_free (fn); | ||
380 | } | ||
381 | |||
382 | |||
383 | /** | ||
384 | * Start blacklist subsystem. | ||
385 | * | ||
386 | * @param server server used to accept clients from | ||
387 | */ | ||
388 | void | ||
389 | GST_blacklist_start (struct GNUNET_SERVER_Handle *server) | ||
390 | { | ||
391 | read_blacklist_file (); | ||
392 | GNUNET_SERVER_disconnect_notify (server, | ||
393 | &client_disconnect_notification, | ||
394 | NULL); | ||
395 | } | ||
396 | |||
397 | |||
398 | /** | ||
399 | * Free the given entry in the blacklist. | ||
400 | * | ||
401 | * @param cls unused | ||
402 | * @param key host identity (unused) | ||
403 | * @param value the blacklist entry | ||
404 | * @return GNUNET_OK (continue to iterate) | ||
405 | */ | ||
406 | static int | ||
407 | free_blacklist_entry (void *cls, | ||
408 | const GNUNET_HashCode *key, | ||
409 | void *value) | ||
410 | { | ||
411 | char *be = value; | ||
412 | |||
413 | GNUNET_free (be); | ||
414 | return GNUNET_OK; | ||
415 | } | ||
416 | |||
417 | |||
418 | /** | ||
419 | * Stop blacklist subsystem. | ||
420 | */ | ||
421 | void | ||
422 | GST_blacklist_stop () | ||
423 | { | ||
424 | if (NULL != blacklist) | ||
425 | { | ||
426 | GNUNET_CONTAINER_multihashmap_iterate (blacklist, | ||
427 | &free_blacklist_entry, | ||
428 | NULL); | ||
429 | GNUNET_CONTAINER_multihashmap_destroy (blacklist); | ||
430 | blacklist = NULL; | ||
431 | } | ||
432 | } | ||
433 | |||
434 | |||
435 | /** | ||
436 | * Transmit blacklist query to the client. | ||
437 | * | ||
438 | * @param cls the 'struct BlacklistCheck' | ||
439 | * @param size number of bytes allowed | ||
440 | * @param buf where to copy the message | ||
441 | * @return number of bytes copied to buf | ||
442 | */ | ||
443 | static size_t | ||
444 | transmit_blacklist_message (void *cls, | ||
445 | size_t size, | ||
446 | void *buf) | ||
447 | { | ||
448 | struct BlacklistCheck *bc = cls; | ||
449 | struct Blacklisters *bl; | ||
450 | struct BlacklistMessage bm; | ||
451 | |||
452 | bc->th = NULL; | ||
453 | if (size == 0) | ||
454 | { | ||
455 | GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK); | ||
456 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
457 | bc); | ||
458 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
459 | "Failed to send blacklist test for peer `%s' to client\n", | ||
460 | GNUNET_i2s (&bc->peer)); | ||
461 | return 0; | ||
462 | } | ||
463 | #if DEBUG_TRANSPORT | ||
464 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
465 | "Sending blacklist test for peer `%s' to client\n", | ||
466 | GNUNET_i2s (&bc->peer)); | ||
467 | #endif | ||
468 | bl = bc->bl_pos; | ||
469 | bm.header.size = htons (sizeof (struct BlacklistMessage)); | ||
470 | bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY); | ||
471 | bm.is_allowed = htonl (0); | ||
472 | bm.peer = bc->peer; | ||
473 | memcpy (buf, &bm, sizeof (bm)); | ||
474 | GNUNET_SERVER_receive_done (bl->client, GNUNET_OK); | ||
475 | return sizeof (bm); | ||
476 | } | ||
477 | |||
478 | |||
479 | /** | ||
480 | * Perform next action in the blacklist check. | ||
481 | * | ||
482 | * @param cls the 'struct BlacklistCheck*' | ||
483 | * @param tc unused | ||
484 | */ | ||
485 | static void | ||
486 | do_blacklist_check (void *cls, | ||
487 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
488 | { | ||
489 | struct BlacklistCheck *bc = cls; | ||
490 | struct Blacklisters *bl; | ||
491 | |||
492 | bc->task = GNUNET_SCHEDULER_NO_TASK; | ||
493 | bl = bc->bl_pos; | ||
494 | if (bl == NULL) | ||
495 | { | ||
496 | #if DEBUG_TRANSPORT | ||
497 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
498 | "No other blacklist clients active, will allow neighbour `%s'\n", | ||
499 | GNUNET_i2s (&bc->peer)); | ||
500 | #endif | ||
501 | bc->cont (bc->cont_cls, | ||
502 | &bc->peer, | ||
503 | GNUNET_OK); | ||
504 | GNUNET_free (bc); | ||
505 | return; | ||
506 | } | ||
507 | if (bl->bc != NULL) | ||
508 | return; /* someone else busy with this client */ | ||
509 | bl->bc = bc; | ||
510 | bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client, | ||
511 | sizeof (struct BlacklistMessage), | ||
512 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
513 | &transmit_blacklist_message, | ||
514 | bc); | ||
515 | } | ||
516 | |||
517 | |||
518 | /** | ||
519 | * Got the result about an existing connection from a new blacklister. | ||
520 | * Shutdown the neighbour if necessary. | ||
521 | * | ||
522 | * @param cls unused | ||
523 | * @param peer the neighbour that was investigated | ||
524 | * @param allowed GNUNET_OK if we can keep it, | ||
525 | * GNUNET_NO if we must shutdown the connection | ||
526 | */ | ||
527 | static void | ||
528 | confirm_or_drop_neighbour (void *cls, | ||
529 | const struct GNUNET_PeerIdentity *peer, | ||
530 | int allowed) | ||
531 | { | ||
532 | if (GNUNET_OK == allowed) | ||
533 | return; /* we're done */ | ||
534 | GNUNET_STATISTICS_update (GST_stats, | ||
535 | gettext_noop ("# disconnects due to blacklist"), | ||
536 | 1, | ||
537 | GNUNET_NO); | ||
538 | GST_neighbours_force_disconnect (peer); | ||
539 | } | ||
540 | |||
541 | |||
542 | /** | ||
543 | * Closure for 'test_connection_ok'. | ||
544 | */ | ||
545 | struct TestConnectionContext | ||
546 | { | ||
547 | /** | ||
548 | * Is this the first neighbour we're checking? | ||
549 | */ | ||
550 | int first; | ||
551 | |||
552 | /** | ||
553 | * Handle to the blacklisting client we need to ask. | ||
554 | */ | ||
555 | struct Blacklisters *bl; | ||
556 | }; | ||
557 | |||
558 | |||
559 | /** | ||
560 | * Test if an existing connection is still acceptable given a new | ||
561 | * blacklisting client. | ||
562 | * | ||
563 | * @param cls the 'struct TestConnectionContest' | ||
564 | * @param pid neighbour's identity | ||
565 | */ | ||
566 | static void | ||
567 | test_connection_ok (void *cls, | ||
568 | const struct GNUNET_PeerIdentity *neighbour) | ||
569 | { | ||
570 | struct TestConnectionContext *tcc = cls; | ||
571 | struct BlacklistCheck *bc; | ||
572 | |||
573 | bc = GNUNET_malloc (sizeof (struct BlacklistCheck)); | ||
574 | GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc); | ||
575 | bc->peer = *neighbour; | ||
576 | bc->cont = &confirm_or_drop_neighbour; | ||
577 | bc->cont_cls = NULL; | ||
578 | bc->bl_pos = tcc->bl; | ||
579 | if (GNUNET_YES == tcc->first) | ||
580 | { | ||
581 | /* all would wait for the same client, no need to | ||
582 | create more than just the first task right now */ | ||
583 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
584 | bc); | ||
585 | tcc->first = GNUNET_NO; | ||
586 | } | ||
587 | } | ||
588 | |||
589 | |||
590 | |||
591 | /** | ||
592 | * Initialize a blacklisting client. We got a blacklist-init | ||
593 | * message from this client, add him to the list of clients | ||
594 | * to query for blacklisting. | ||
595 | * | ||
596 | * @param cls unused | ||
597 | * @param client the client | ||
598 | * @param message the blacklist-init message that was sent | ||
599 | */ | ||
600 | void | ||
601 | GST_blacklist_handle_init (void *cls, | ||
602 | struct GNUNET_SERVER_Client *client, | ||
603 | const struct GNUNET_MessageHeader *message) | ||
604 | { | ||
605 | struct Blacklisters *bl; | ||
606 | struct TestConnectionContext tcc; | ||
607 | |||
608 | bl = bl_head; | ||
609 | while (bl != NULL) | ||
610 | { | ||
611 | if (bl->client == client) | ||
612 | { | ||
613 | GNUNET_break (0); | ||
614 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
615 | return; | ||
616 | } | ||
617 | bl = bl->next; | ||
618 | } | ||
619 | bl = GNUNET_malloc (sizeof (struct Blacklisters)); | ||
620 | bl->client = client; | ||
621 | GNUNET_SERVER_client_keep (client); | ||
622 | GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl); | ||
623 | |||
624 | /* confirm that all existing connections are OK! */ | ||
625 | tcc.bl = bl; | ||
626 | tcc.first = GNUNET_YES; | ||
627 | GST_neighbours_iterate (&test_connection_ok, | ||
628 | &tcc); | ||
629 | } | ||
630 | |||
631 | |||
632 | /** | ||
633 | * A blacklisting client has sent us reply. Process it. | ||
634 | * | ||
635 | * @param cls unused | ||
636 | * @param client the client | ||
637 | * @param message the blacklist-init message that was sent | ||
638 | */ | ||
639 | void | ||
640 | GST_blacklist_handle_reply (void *cls, | ||
641 | struct GNUNET_SERVER_Client *client, | ||
642 | const struct GNUNET_MessageHeader *message) | ||
643 | { | ||
644 | const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message; | ||
645 | struct Blacklisters *bl; | ||
646 | struct BlacklistCheck *bc; | ||
647 | |||
648 | bl = bl_head; | ||
649 | while ( (bl != NULL) && | ||
650 | (bl->client != client) ) | ||
651 | bl = bl->next; | ||
652 | if (bl == NULL) | ||
653 | { | ||
654 | #if DEBUG_TRANSPORT | ||
655 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
656 | "Blacklist client disconnected\n"); | ||
657 | #endif | ||
658 | /* FIXME: other error handling here!? */ | ||
659 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
660 | return; | ||
661 | } | ||
662 | bc = bl->bc; | ||
663 | bl->bc = NULL; | ||
664 | if (ntohl (msg->is_allowed) == GNUNET_SYSERR) | ||
665 | { | ||
666 | #if DEBUG_TRANSPORT | ||
667 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
668 | "Blacklist check failed, peer not allowed\n"); | ||
669 | #endif | ||
670 | bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO); | ||
671 | GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc); | ||
672 | GNUNET_free (bc); | ||
673 | } | ||
674 | else | ||
675 | { | ||
676 | #if DEBUG_TRANSPORT | ||
677 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
678 | "Blacklist check succeeded, continuing with checks\n"); | ||
679 | #endif | ||
680 | bc->bl_pos = bc->bl_pos->next; | ||
681 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
682 | bc); | ||
683 | } | ||
684 | /* check if any other bc's are waiting for this blacklister */ | ||
685 | bc = bc_head; | ||
686 | while (bc != NULL) | ||
687 | { | ||
688 | if ( (bc->bl_pos == bl) && | ||
689 | (GNUNET_SCHEDULER_NO_TASK == bc->task) ) | ||
690 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
691 | bc); | ||
692 | bc = bc->next; | ||
693 | } | ||
694 | } | ||
695 | |||
696 | |||
697 | /** | ||
698 | * Add the given peer to the blacklist (for the given transport). | ||
699 | * | ||
700 | * @param peer peer to blacklist | ||
701 | * @param transport_name transport to blacklist for this peer, NULL for all | ||
702 | */ | ||
703 | void | ||
704 | GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer, | ||
705 | const char *transport_name) | ||
706 | { | ||
707 | #if DEBUG_TRANSPORT | ||
708 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
709 | "Adding peer `%s' with plugin `%s' to blacklist\n", | ||
710 | GNUNET_i2s (peer), | ||
711 | transport_name); | ||
712 | #endif | ||
713 | if (blacklist == NULL) | ||
714 | blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE); | ||
715 | GNUNET_CONTAINER_multihashmap_put (blacklist, | ||
716 | &peer->hashPubKey, | ||
717 | GNUNET_strdup (transport_name), | ||
718 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
719 | } | ||
720 | |||
721 | |||
722 | /** | ||
723 | * Test if the given blacklist entry matches. If so, | ||
724 | * abort the iteration. | ||
725 | * | ||
726 | * @param cls the transport name to match (const char*) | ||
727 | * @param key the key (unused) | ||
728 | * @param value the 'char *' (name of a blacklisted transport) | ||
729 | * @return GNUNET_OK if the entry does not match, GNUNET_NO if it matches | ||
730 | */ | ||
731 | static int | ||
732 | test_blacklisted (void *cls, | ||
733 | const GNUNET_HashCode *key, | ||
734 | void *value) | ||
735 | { | ||
736 | const char *transport_name = cls; | ||
737 | char *be = value; | ||
738 | |||
739 | if (0 == strcmp (transport_name, | ||
740 | be)) | ||
741 | return GNUNET_NO; /* abort iteration! */ | ||
742 | return GNUNET_OK; | ||
743 | } | ||
744 | |||
745 | |||
746 | /** | ||
747 | * Test if a peer/transport combination is blacklisted. | ||
748 | * | ||
749 | * @param peer the identity of the peer to test | ||
750 | * @param transport_name name of the transport to test, never NULL | ||
751 | * @param cont function to call with result | ||
752 | * @param cont_cls closure for 'cont' | ||
753 | */ | ||
754 | void | ||
755 | GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer, | ||
756 | const char *transport_name, | ||
757 | GST_BlacklistTestContinuation cont, | ||
758 | void *cont_cls) | ||
759 | { | ||
760 | struct BlacklistCheck *bc; | ||
761 | |||
762 | if ( (blacklist != NULL) && | ||
763 | (GNUNET_SYSERR == | ||
764 | GNUNET_CONTAINER_multihashmap_get_multiple (blacklist, | ||
765 | &peer->hashPubKey, | ||
766 | &test_blacklisted, | ||
767 | (void*) transport_name)) ) | ||
768 | { | ||
769 | /* disallowed by config, disapprove instantly */ | ||
770 | GNUNET_STATISTICS_update (GST_stats, | ||
771 | gettext_noop ("# disconnects due to blacklist"), | ||
772 | 1, | ||
773 | GNUNET_NO); | ||
774 | if (cont != NULL) | ||
775 | cont (cont_cls, peer, GNUNET_NO); | ||
776 | return; | ||
777 | } | ||
778 | |||
779 | if (bl_head == NULL) | ||
780 | { | ||
781 | /* no blacklist clients, approve instantly */ | ||
782 | if (cont != NULL) | ||
783 | cont (cont_cls, peer, GNUNET_OK); | ||
784 | return; | ||
785 | } | ||
786 | |||
787 | /* need to query blacklist clients */ | ||
788 | bc = GNUNET_malloc (sizeof (struct BlacklistCheck)); | ||
789 | GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc); | ||
790 | bc->peer = *peer; | ||
791 | bc->cont = cont; | ||
792 | bc->cont_cls = cont_cls; | ||
793 | bc->bl_pos = bl_head; | ||
794 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
795 | bc); | ||
796 | } | ||
797 | |||
798 | |||
799 | |||
800 | /* end of file gnunet-service-transport_blacklist.c */ | ||