7e1d7d43b8edb19662b33b438469c371bd432226
[oweals/gnunet.git] / src / transport / gnunet-service-transport_blacklist.c
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, Matthias Wachs
25  * @details This is the blacklisting component of transport service. With
26  * blacklisting it is possible to deny connections to specific peers of
27  * to use a specific plugin to a specific peer. Peers can be blacklisted using
28  * the configuration or a blacklist client can be asked.
29  *
30  * To blacklist peers using the configuration you have to add a section to your
31  * configuration containing the peer id of the peer to blacklist and the plugin
32  * if required.
33  *
34  * Example:
35  * To blacklist connections to P565... on peer AG2P... using tcp add:
36  * [transport-blacklist-AG2PHES1BARB9IJCPAMJTFPVJ5V3A72S3F2A8SBUB8DAQ2V0O3V8G6G2JU56FHGFOHMQVKBSQFV98TCGTC3RJ1NINP82G0RC00N1520]
37  * P565723JO1C2HSN6J29TAQ22MN6CI8HTMUU55T0FUQG4CMDGGEQ8UCNBKUMB94GC8R9G4FB2SF9LDOBAJ6AMINBP4JHHDD6L7VD801G = tcp
38  *
39  * To blacklist connections to P565... on peer AG2P... using all plugins add:
40  * [transport-blacklist-AG2PHES1BARB9IJCPAMJTFPVJ5V3A72S3F2A8SBUB8DAQ2V0O3V8G6G2JU56FHGFOHMQVKBSQFV98TCGTC3RJ1NINP82G0RC00N1520]
41  * P565723JO1C2HSN6J29TAQ22MN6CI8HTMUU55T0FUQG4CMDGGEQ8UCNBKUMB94GC8R9G4FB2SF9LDOBAJ6AMINBP4JHHDD6L7VD801G =
42  *
43  * You can also add a blacklist client usign the blacklist api. On a blacklist
44  * check, blacklisting first checks internally if the peer is blacklisted and
45  * if not, it asks the blacklisting clients. Clients are asked if it is OK to
46  * connect to a peer ID, the plugin is omitted.
47  *
48  * On blacklist check for (peer, plugin)
49  * - Do we have a local blacklist entry for this peer and this plugin?
50  *   - YES: disallow connection
51  * - Do we have a local blacklist entry for this peer and all plugins?
52  *   - YES: disallow connection
53  * - Does one of the clients disallow?
54  *   - YES: disallow connection
55  *
56  */
57 #include "platform.h"
58 #include "gnunet-service-transport.h"
59 #include "gnunet-service-transport_blacklist.h"
60 #include "gnunet-service-transport_neighbours.h"
61 #include "transport.h"
62
63 /**
64  * Size of the blacklist hash map.
65  */
66 #define TRANSPORT_BLACKLIST_HT_SIZE 64
67
68
69 /**
70  * Context we use when performing a blacklist check.
71  */
72 struct GST_BlacklistCheck;
73
74
75 /**
76  * Information kept for each client registered to perform
77  * blacklisting.
78  */
79 struct Blacklisters
80 {
81   /**
82    * This is a linked list.
83    */
84   struct Blacklisters *next;
85
86   /**
87    * This is a linked list.
88    */
89   struct Blacklisters *prev;
90
91   /**
92    * Client responsible for this entry.
93    */
94   struct GNUNET_SERVER_Client *client;
95
96   /**
97    * Blacklist check that we're currently performing (or NULL
98    * if we're performing one that has been cancelled).
99    */
100   struct GST_BlacklistCheck *bc;
101
102   /**
103    * Set to GNUNET_YES if we're currently waiting for a reply.
104    */
105   int waiting_for_reply;
106
107 };
108
109
110
111 /**
112  * Context we use when performing a blacklist check.
113  */
114 struct GST_BlacklistCheck
115 {
116
117   /**
118    * This is a linked list.
119    */
120   struct GST_BlacklistCheck *next;
121
122   /**
123    * This is a linked list.
124    */
125   struct GST_BlacklistCheck *prev;
126
127   /**
128    * Peer being checked.
129    */
130   struct GNUNET_PeerIdentity peer;
131
132   /**
133    * Continuation to call with the result.
134    */
135   GST_BlacklistTestContinuation cont;
136
137   /**
138    * Closure for cont.
139    */
140   void *cont_cls;
141
142   /**
143    * Current transmission request handle for this client, or NULL if no
144    * request is pending.
145    */
146   struct GNUNET_SERVER_TransmitHandle *th;
147
148   /**
149    * Our current position in the blacklisters list.
150    */
151   struct Blacklisters *bl_pos;
152
153   /**
154    * Current task performing the check.
155    */
156   GNUNET_SCHEDULER_TaskIdentifier task;
157
158 };
159
160
161 /**
162  * Head of DLL of active blacklisting queries.
163  */
164 static struct GST_BlacklistCheck *bc_head;
165
166 /**
167  * Tail of DLL of active blacklisting queries.
168  */
169 static struct GST_BlacklistCheck *bc_tail;
170
171 /**
172  * Head of DLL of blacklisting clients.
173  */
174 static struct Blacklisters *bl_head;
175
176 /**
177  * Tail of DLL of blacklisting clients.
178  */
179 static struct Blacklisters *bl_tail;
180
181 /**
182  * Hashmap of blacklisted peers.  Values are of type 'char *' (transport names),
183  * can be NULL if we have no static blacklist.
184  */
185 static struct GNUNET_CONTAINER_MultiPeerMap *blacklist;
186
187
188 /**
189  * Perform next action in the blacklist check.
190  *
191  * @param cls the 'struct BlacklistCheck*'
192  * @param tc unused
193  */
194 static void
195 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
196
197
198 /**
199  * Called whenever a client is disconnected.  Frees our
200  * resources associated with that client.
201  *
202  * @param cls closure (unused)
203  * @param client identification of the client
204  */
205 static void
206 client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
207 {
208   struct Blacklisters *bl;
209   struct GST_BlacklistCheck *bc;
210
211   if (client == NULL)
212     return;
213   for (bl = bl_head; bl != NULL; bl = bl->next)
214   {
215     if (bl->client != client)
216       continue;
217     for (bc = bc_head; bc != NULL; bc = bc->next)
218     {
219       if (bc->bl_pos != bl)
220         continue;
221       bc->bl_pos = bl->next;
222       if (bc->th != NULL)
223       {
224         GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
225         bc->th = NULL;
226       }
227       if (bc->task == GNUNET_SCHEDULER_NO_TASK)
228         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
229       break;
230     }
231     GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl);
232     GNUNET_SERVER_client_drop (bl->client);
233     GNUNET_free (bl);
234     break;
235   }
236 }
237
238
239 /**
240  * Function to iterate over options in the blacklisting section for a peer.
241  *
242  * @param cls closure
243  * @param section name of the section
244  * @param option name of the option
245  * @param value value of the option
246  */
247 static void
248 blacklist_cfg_iter (void *cls, const char *section,
249                     const char *option,
250                     const char *value)
251 {
252   unsigned int *res = cls;
253   struct GNUNET_PeerIdentity peer;
254   char *plugs;
255   char *pos;
256
257   if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (option,
258                                                                   strlen (option),
259                                                                   &peer.public_key))
260     return;
261
262   if ((NULL == value) || (0 == strcmp(value, "")))
263   {
264     /* Blacklist whole peer */
265     GST_blacklist_add_peer (&peer, NULL);
266     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
267                 _("Adding blacklisting entry for peer `%s'\n"), GNUNET_i2s (&peer));
268   }
269   else
270   {
271     plugs = GNUNET_strdup (value);
272     for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
273       {
274         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
275                     _("Adding blacklisting entry for peer `%s':`%s'\n"),
276                     GNUNET_i2s (&peer), pos);
277         GST_blacklist_add_peer (&peer, pos);
278       }
279     GNUNET_free (plugs);
280   }
281   (*res)++;
282 }
283
284
285 /**
286  * Read blacklist configuration
287  *
288  * @param cfg the configuration handle
289  * @param my_id my peer identity
290  */
291 static void
292 read_blacklist_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg,
293                               const struct GNUNET_PeerIdentity *my_id)
294 {
295   char cfg_sect[512];
296   unsigned int res = 0;
297
298   GNUNET_snprintf (cfg_sect,
299                    sizeof (cfg_sect),
300                    "transport-blacklist-%s",
301                    GNUNET_i2s_full (my_id));
302   GNUNET_CONFIGURATION_iterate_section_values (cfg, cfg_sect, &blacklist_cfg_iter, &res);
303   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
304               "Loaded %u blacklisting entries from configuration\n", res);
305 }
306
307
308 /**
309  * Start blacklist subsystem.
310  *
311  * @param server server used to accept clients from
312  * @param cfg configuration handle
313  * @param my_id my peer id
314  */
315 void
316 GST_blacklist_start (struct GNUNET_SERVER_Handle *server,
317                      const struct GNUNET_CONFIGURATION_Handle *cfg,
318                      const struct GNUNET_PeerIdentity *my_id)
319 {
320   GNUNET_assert (NULL != cfg);
321   GNUNET_assert (NULL != my_id);
322   read_blacklist_configuration (cfg, my_id);
323   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification,
324                                    NULL);
325 }
326
327
328 /**
329  * Free the given entry in the blacklist.
330  *
331  * @param cls unused
332  * @param key host identity (unused)
333  * @param value the blacklist entry
334  * @return GNUNET_OK (continue to iterate)
335  */
336 static int
337 free_blacklist_entry (void *cls,
338                       const struct GNUNET_PeerIdentity *key,
339                       void *value)
340 {
341   char *be = value;
342
343   GNUNET_free_non_null (be);
344   return GNUNET_OK;
345 }
346
347
348 /**
349  * Stop blacklist subsystem.
350  */
351 void
352 GST_blacklist_stop ()
353 {
354   if (NULL != blacklist)
355   {
356     GNUNET_CONTAINER_multipeermap_iterate (blacklist, &free_blacklist_entry,
357                                            NULL);
358     GNUNET_CONTAINER_multipeermap_destroy (blacklist);
359     blacklist = NULL;
360   }
361 }
362
363
364 /**
365  * Transmit blacklist query to the client.
366  *
367  * @param cls the 'struct GST_BlacklistCheck'
368  * @param size number of bytes allowed
369  * @param buf where to copy the message
370  * @return number of bytes copied to buf
371  */
372 static size_t
373 transmit_blacklist_message (void *cls, size_t size, void *buf)
374 {
375   struct GST_BlacklistCheck *bc = cls;
376   struct Blacklisters *bl;
377   struct BlacklistMessage bm;
378
379   bc->th = NULL;
380   if (size == 0)
381   {
382     GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
383     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
384     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
385                 "Failed to send blacklist test for peer `%s' to client\n",
386                 GNUNET_i2s (&bc->peer));
387     return 0;
388   }
389   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
390               "Sending blacklist test for peer `%s' to client\n",
391               GNUNET_i2s (&bc->peer));
392   bl = bc->bl_pos;
393   bm.header.size = htons (sizeof (struct BlacklistMessage));
394   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
395   bm.is_allowed = htonl (0);
396   bm.peer = bc->peer;
397   memcpy (buf, &bm, sizeof (bm));
398   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
399   bl->waiting_for_reply = GNUNET_YES;
400   return sizeof (bm);
401 }
402
403
404 /**
405  * Perform next action in the blacklist check.
406  *
407  * @param cls the 'struct GST_BlacklistCheck*'
408  * @param tc unused
409  */
410 static void
411 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
412 {
413   struct GST_BlacklistCheck *bc = cls;
414   struct Blacklisters *bl;
415
416   bc->task = GNUNET_SCHEDULER_NO_TASK;
417   bl = bc->bl_pos;
418   if (bl == NULL)
419   {
420     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421                 "No other blacklist clients active, will allow neighbour `%s'\n",
422                 GNUNET_i2s (&bc->peer));
423     bc->cont (bc->cont_cls, &bc->peer, GNUNET_OK);
424     GNUNET_CONTAINER_DLL_remove(bc_head, bc_tail, bc);
425     GNUNET_free (bc);
426     return;
427   }
428   if ((bl->bc != NULL) || (bl->waiting_for_reply != GNUNET_NO))
429     return;                     /* someone else busy with this client */
430   bl->bc = bc;
431   bc->th =
432       GNUNET_SERVER_notify_transmit_ready (bl->client,
433                                            sizeof (struct BlacklistMessage),
434                                            GNUNET_TIME_UNIT_FOREVER_REL,
435                                            &transmit_blacklist_message, bc);
436 }
437
438
439 /**
440  * Got the result about an existing connection from a new blacklister.
441  * Shutdown the neighbour if necessary.
442  *
443  * @param cls unused
444  * @param peer the neighbour that was investigated
445  * @param allowed GNUNET_OK if we can keep it,
446  *                GNUNET_NO if we must shutdown the connection
447  */
448 static void
449 confirm_or_drop_neighbour (void *cls, const struct GNUNET_PeerIdentity *peer,
450                            int allowed)
451 {
452   if (GNUNET_OK == allowed)
453     return;                     /* we're done */
454   GNUNET_STATISTICS_update (GST_stats,
455                             gettext_noop ("# disconnects due to blacklist"), 1,
456                             GNUNET_NO);
457   GST_neighbours_force_disconnect (peer);
458 }
459
460
461 /**
462  * Closure for 'test_connection_ok'.
463  */
464 struct TestConnectionContext
465 {
466   /**
467    * Is this the first neighbour we're checking?
468    */
469   int first;
470
471   /**
472    * Handle to the blacklisting client we need to ask.
473    */
474   struct Blacklisters *bl;
475 };
476
477 /**
478  * Test if an existing connection is still acceptable given a new
479  * blacklisting client.
480  *
481  * @param cls the 'struct TestConnectionContest'
482  * @param peer neighbour's identity
483  * @param address the address
484  * @param state current state this peer is in
485  * @param state_timeout timeout for the current state of the peer
486  * @param bandwidth_in bandwidth assigned inbound
487  * @param bandwidth_out bandwidth assigned outbound
488  */
489 static void
490 test_connection_ok (void *cls, const struct GNUNET_PeerIdentity *peer,
491     const struct GNUNET_HELLO_Address *address,
492     enum GNUNET_TRANSPORT_PeerState state,
493     struct GNUNET_TIME_Absolute state_timeout,
494     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
495     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
496 {
497   struct TestConnectionContext *tcc = cls;
498   struct GST_BlacklistCheck *bc;
499
500   bc = GNUNET_new (struct GST_BlacklistCheck);
501   GNUNET_CONTAINER_DLL_insert(bc_head, bc_tail, bc);
502   bc->peer = *peer;
503   bc->cont = &confirm_or_drop_neighbour;
504   bc->cont_cls = NULL;
505   bc->bl_pos = tcc->bl;
506   if (GNUNET_YES == tcc->first)
507   {
508     /* all would wait for the same client, no need to
509      * create more than just the first task right now */
510     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
511     tcc->first = GNUNET_NO;
512   }
513 }
514
515
516 /**
517  * Initialize a blacklisting client.  We got a blacklist-init
518  * message from this client, add him to the list of clients
519  * to query for blacklisting.
520  *
521  * @param cls unused
522  * @param client the client
523  * @param message the blacklist-init message that was sent
524  */
525 void
526 GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client,
527                            const struct GNUNET_MessageHeader *message)
528 {
529   struct Blacklisters *bl;
530   struct TestConnectionContext tcc;
531
532   bl = bl_head;
533   while (bl != NULL)
534   {
535     if (bl->client == client)
536     {
537       GNUNET_break (0);
538       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
539       return;
540     }
541     bl = bl->next;
542   }
543   GNUNET_SERVER_client_mark_monitor (client);
544   bl = GNUNET_new (struct Blacklisters);
545   bl->client = client;
546   GNUNET_SERVER_client_keep (client);
547   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
548
549   /* confirm that all existing connections are OK! */
550   tcc.bl = bl;
551   tcc.first = GNUNET_YES;
552   GST_neighbours_iterate (&test_connection_ok, &tcc);
553 }
554
555
556 /**
557  * A blacklisting client has sent us reply. Process it.
558  *
559  * @param cls unused
560  * @param client the client
561  * @param message the blacklist-init message that was sent
562  */
563 void
564 GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client,
565                             const struct GNUNET_MessageHeader *message)
566 {
567   const struct BlacklistMessage *msg =
568       (const struct BlacklistMessage *) message;
569   struct Blacklisters *bl;
570   struct GST_BlacklistCheck *bc;
571
572   bl = bl_head;
573   while ((bl != NULL) && (bl->client != client))
574     bl = bl->next;
575   if (bl == NULL)
576   {
577     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
578     /* FIXME: other error handling here!? */
579     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
580     return;
581   }
582   bc = bl->bc;
583   bl->bc = NULL;
584   bl->waiting_for_reply = GNUNET_NO;
585   if (NULL != bc)
586   {
587     /* only run this if the blacklist check has not been
588      * cancelled in the meantime... */
589     if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
590     {
591       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
592                   "Blacklist check failed, peer not allowed\n");
593       bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO);
594       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
595       GNUNET_free (bc);
596     }
597     else
598     {
599       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
600                   "Blacklist check succeeded, continuing with checks\n");
601       bc->bl_pos = bc->bl_pos->next;
602       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
603     }
604   }
605   /* check if any other bc's are waiting for this blacklister */
606   for (bc = bc_head; bc != NULL; bc = bc->next)
607     if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
608     {
609       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
610       break;
611     }
612 }
613
614
615 /**
616  * Add the given peer to the blacklist (for the given transport).
617  *
618  * @param peer peer to blacklist
619  * @param transport_name transport to blacklist for this peer, NULL for all
620  */
621 void
622 GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
623                         const char *transport_name)
624 {
625   char * transport = NULL;
626
627   if (NULL != transport_name)
628   {
629     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
630                 "Adding peer `%s' with plugin `%s' to blacklist\n",
631                 GNUNET_i2s (peer), transport_name);
632     transport = GNUNET_strdup (transport_name);
633   }
634   else
635     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
636                 "Adding peer `%s' with all plugins to blacklist\n",
637                 GNUNET_i2s (peer));
638   if (blacklist == NULL)
639     blacklist =
640       GNUNET_CONTAINER_multipeermap_create (TRANSPORT_BLACKLIST_HT_SIZE,
641                                             GNUNET_NO);
642
643   GNUNET_CONTAINER_multipeermap_put (blacklist, peer,
644                                      transport,
645                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
646 }
647
648
649 /**
650  * Test if the given blacklist entry matches.  If so,
651  * abort the iteration.
652  *
653  * @param cls the transport name to match (const char*)
654  * @param key the key (unused)
655  * @param value the 'char *' (name of a blacklisted transport)
656  * @return #GNUNET_OK if the entry does not match, #GNUNET_NO if it matches
657  */
658 static int
659 test_blacklisted (void *cls,
660                   const struct GNUNET_PeerIdentity *key,
661                   void *value)
662 {
663   const char *transport_name = cls;
664   char *be = value;
665
666   /* Blacklist entry be:
667    *  (NULL == be): peer is blacklisted with all plugins
668    *  (NULL != be): peer is blacklisted for a specific plugin
669    *
670    * If (NULL != transport_name) we look for a transport specific entry:
671    *  if (transport_name == be) forbidden
672    *
673    */
674
675   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
676               "Comparing BL request for peer `%4s':`%s' with BL entry: `%s'\n",
677               GNUNET_i2s (key),
678               (NULL == transport_name) ? "unspecified" : transport_name,
679               (NULL == be) ? "all plugins" : be);
680   /* all plugins for this peer were blacklisted: disallow */
681   if (NULL == value)
682                 return GNUNET_NO;
683
684   /* blacklist check for specific transport */
685   if ((NULL != transport_name) && (NULL != value))
686   {
687         if (0 == strcmp (transport_name, be))
688                         return GNUNET_NO;           /* plugin is blacklisted! */
689   }
690   return GNUNET_OK;
691 }
692
693
694 /**
695  * Test if a peer/transport combination is blacklisted.
696  *
697  * @param peer the identity of the peer to test
698  * @param transport_name name of the transport to test, never NULL
699  * @param cont function to call with result
700  * @param cont_cls closure for 'cont'
701  * @return handle to the blacklist check, NULL if the decision
702  *        was made instantly and 'cont' was already called
703  */
704 struct GST_BlacklistCheck *
705 GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
706                             const char *transport_name,
707                             GST_BlacklistTestContinuation cont, void *cont_cls)
708 {
709   struct GST_BlacklistCheck *bc;
710
711   GNUNET_assert (peer != NULL);
712   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist check for peer `%s':%s\n",
713                 GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "unspecified");
714
715   /* Check local blacklist by iterating over hashmap
716    * If iteration is aborted, we found a matching blacklist entry */
717   if ((blacklist != NULL) &&
718       (GNUNET_SYSERR ==
719        GNUNET_CONTAINER_multipeermap_get_multiple (blacklist, peer,
720                                                    &test_blacklisted,
721                                                    (void *) transport_name)))
722   {
723     /* Disallowed by config, disapprove instantly */
724     GNUNET_STATISTICS_update (GST_stats,
725                               gettext_noop ("# disconnects due to blacklist"),
726                               1, GNUNET_NO);
727     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disallowing connection to peer `%s' on transport %s\n",
728                 GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "unspecified");
729     if (cont != NULL)
730       cont (cont_cls, peer, GNUNET_NO);
731     return NULL;
732   }
733
734   if (bl_head == NULL)
735   {
736     /* no blacklist clients, approve instantly */
737     if (cont != NULL)
738       cont (cont_cls, peer, GNUNET_OK);
739     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Allowing connection to peer `%s' %s\n",
740                 GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "");
741     return NULL;
742   }
743
744   /* need to query blacklist clients */
745   bc = GNUNET_new (struct GST_BlacklistCheck);
746   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
747   bc->peer = *peer;
748   bc->cont = cont;
749   bc->cont_cls = cont_cls;
750   bc->bl_pos = bl_head;
751   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
752   return bc;
753 }
754
755
756 /**
757  * Cancel a blacklist check.
758  *
759  * @param bc check to cancel
760  */
761 void
762 GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
763 {
764   GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
765   if (bc->bl_pos != NULL)
766   {
767     if (bc->bl_pos->bc == bc)
768     {
769       /* we're at the head of the queue, remove us! */
770       bc->bl_pos->bc = NULL;
771     }
772   }
773   if (GNUNET_SCHEDULER_NO_TASK != bc->task)
774   {
775     GNUNET_SCHEDULER_cancel (bc->task);
776     bc->task = GNUNET_SCHEDULER_NO_TASK;
777   }
778   if (NULL != bc->th)
779   {
780     GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
781     bc->th = NULL;
782   }
783   GNUNET_free (bc);
784 }
785
786
787 /* end of file gnunet-service-transport_blacklist.c */