docu
[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_MultiHashMap *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_hash_from_string2 (option,
258                                                     strlen (option), 
259                                                     &peer.hashPubKey))
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, const struct GNUNET_HashCode * key, void *value)
338 {
339   char *be = value;
340
341   GNUNET_free_non_null (be);
342   return GNUNET_OK;
343 }
344
345
346 /**
347  * Stop blacklist subsystem.
348  */
349 void
350 GST_blacklist_stop ()
351 {
352   if (NULL != blacklist)
353   {
354     GNUNET_CONTAINER_multihashmap_iterate (blacklist, &free_blacklist_entry,
355                                            NULL);
356     GNUNET_CONTAINER_multihashmap_destroy (blacklist);
357     blacklist = NULL;
358   }
359 }
360
361
362 /**
363  * Transmit blacklist query to the client.
364  *
365  * @param cls the 'struct GST_BlacklistCheck'
366  * @param size number of bytes allowed
367  * @param buf where to copy the message
368  * @return number of bytes copied to buf
369  */
370 static size_t
371 transmit_blacklist_message (void *cls, size_t size, void *buf)
372 {
373   struct GST_BlacklistCheck *bc = cls;
374   struct Blacklisters *bl;
375   struct BlacklistMessage bm;
376
377   bc->th = NULL;
378   if (size == 0)
379   {
380     GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
381     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
382     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
383                 "Failed to send blacklist test for peer `%s' to client\n",
384                 GNUNET_i2s (&bc->peer));
385     return 0;
386   }
387   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
388               "Sending blacklist test for peer `%s' to client\n",
389               GNUNET_i2s (&bc->peer));
390   bl = bc->bl_pos;
391   bm.header.size = htons (sizeof (struct BlacklistMessage));
392   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
393   bm.is_allowed = htonl (0);
394   bm.peer = bc->peer;
395   memcpy (buf, &bm, sizeof (bm));
396   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
397   bl->waiting_for_reply = GNUNET_YES;
398   return sizeof (bm);
399 }
400
401
402 /**
403  * Perform next action in the blacklist check.
404  *
405  * @param cls the 'struct GST_BlacklistCheck*'
406  * @param tc unused
407  */
408 static void
409 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
410 {
411   struct GST_BlacklistCheck *bc = cls;
412   struct Blacklisters *bl;
413
414   bc->task = GNUNET_SCHEDULER_NO_TASK;
415   bl = bc->bl_pos;
416   if (bl == NULL)
417   {
418     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419                 "No other blacklist clients active, will allow neighbour `%s'\n",
420                 GNUNET_i2s (&bc->peer));
421     bc->cont (bc->cont_cls, &bc->peer, GNUNET_OK);
422     GNUNET_CONTAINER_DLL_remove(bc_head, bc_tail, bc);
423     GNUNET_free (bc);
424     return;
425   }
426   if ((bl->bc != NULL) || (bl->waiting_for_reply != GNUNET_NO))
427     return;                     /* someone else busy with this client */
428   bl->bc = bc;
429   bc->th =
430       GNUNET_SERVER_notify_transmit_ready (bl->client,
431                                            sizeof (struct BlacklistMessage),
432                                            GNUNET_TIME_UNIT_FOREVER_REL,
433                                            &transmit_blacklist_message, bc);
434 }
435
436
437 /**
438  * Got the result about an existing connection from a new blacklister.
439  * Shutdown the neighbour if necessary.
440  *
441  * @param cls unused
442  * @param peer the neighbour that was investigated
443  * @param allowed GNUNET_OK if we can keep it,
444  *                GNUNET_NO if we must shutdown the connection
445  */
446 static void
447 confirm_or_drop_neighbour (void *cls, const struct GNUNET_PeerIdentity *peer,
448                            int allowed)
449 {
450   if (GNUNET_OK == allowed)
451     return;                     /* we're done */
452   GNUNET_STATISTICS_update (GST_stats,
453                             gettext_noop ("# disconnects due to blacklist"), 1,
454                             GNUNET_NO);
455   GST_neighbours_force_disconnect (peer);
456 }
457
458
459 /**
460  * Closure for 'test_connection_ok'.
461  */
462 struct TestConnectionContext
463 {
464   /**
465    * Is this the first neighbour we're checking?
466    */
467   int first;
468
469   /**
470    * Handle to the blacklisting client we need to ask.
471    */
472   struct Blacklisters *bl;
473 };
474
475
476 /**
477  * Test if an existing connection is still acceptable given a new
478  * blacklisting client.
479  *
480  * @param cls the 'struct TestConnectionContest'
481  * @param neighbour neighbour's identity
482  * @param address the address
483  * @param bandwidth_in inbound quota in NBO
484  * @param bandwidth_out outbound quota in NBO
485  */
486 static void
487 test_connection_ok (void *cls, const struct GNUNET_PeerIdentity *neighbour,
488                     const struct GNUNET_HELLO_Address *address,
489                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
490                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
491 {
492   struct TestConnectionContext *tcc = cls;
493   struct GST_BlacklistCheck *bc;
494
495   bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck));
496   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
497   bc->peer = *neighbour;
498   bc->cont = &confirm_or_drop_neighbour;
499   bc->cont_cls = NULL;
500   bc->bl_pos = tcc->bl;
501   if (GNUNET_YES == tcc->first)
502   {
503     /* all would wait for the same client, no need to
504      * create more than just the first task right now */
505     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
506     tcc->first = GNUNET_NO;
507   }
508 }
509
510
511 /**
512  * Initialize a blacklisting client.  We got a blacklist-init
513  * message from this client, add him to the list of clients
514  * to query for blacklisting.
515  *
516  * @param cls unused
517  * @param client the client
518  * @param message the blacklist-init message that was sent
519  */
520 void
521 GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client,
522                            const struct GNUNET_MessageHeader *message)
523 {
524   struct Blacklisters *bl;
525   struct TestConnectionContext tcc;
526
527   bl = bl_head;
528   while (bl != NULL)
529   {
530     if (bl->client == client)
531     {
532       GNUNET_break (0);
533       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
534       return;
535     }
536     bl = bl->next;
537   }
538   GNUNET_SERVER_client_mark_monitor (client);
539   bl = GNUNET_malloc (sizeof (struct Blacklisters));
540   bl->client = client;
541   GNUNET_SERVER_client_keep (client);
542   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
543
544   /* confirm that all existing connections are OK! */
545   tcc.bl = bl;
546   tcc.first = GNUNET_YES;
547   GST_neighbours_iterate (&test_connection_ok, &tcc);
548 }
549
550
551 /**
552  * A blacklisting client has sent us reply. Process it.
553  *
554  * @param cls unused
555  * @param client the client
556  * @param message the blacklist-init message that was sent
557  */
558 void
559 GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client,
560                             const struct GNUNET_MessageHeader *message)
561 {
562   const struct BlacklistMessage *msg =
563       (const struct BlacklistMessage *) message;
564   struct Blacklisters *bl;
565   struct GST_BlacklistCheck *bc;
566
567   bl = bl_head;
568   while ((bl != NULL) && (bl->client != client))
569     bl = bl->next;
570   if (bl == NULL)
571   {
572     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
573     /* FIXME: other error handling here!? */
574     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
575     return;
576   }
577   bc = bl->bc;
578   bl->bc = NULL;
579   bl->waiting_for_reply = GNUNET_NO;
580   if (NULL != bc)
581   {
582     /* only run this if the blacklist check has not been
583      * cancelled in the meantime... */
584     if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
585     {
586       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
587                   "Blacklist check failed, peer not allowed\n");
588       bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO);
589       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
590       GNUNET_free (bc);
591     }
592     else
593     {
594       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
595                   "Blacklist check succeeded, continuing with checks\n");
596       bc->bl_pos = bc->bl_pos->next;
597       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
598     }
599   }
600   /* check if any other bc's are waiting for this blacklister */
601   bc = bc_head;
602   for (bc = bc_head; bc != NULL; bc = bc->next)
603     if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
604     {
605       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
606       break;
607     }
608 }
609
610
611 /**
612  * Add the given peer to the blacklist (for the given transport).
613  *
614  * @param peer peer to blacklist
615  * @param transport_name transport to blacklist for this peer, NULL for all
616  */
617 void
618 GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
619                         const char *transport_name)
620 {
621         char * transport = NULL;
622         if (NULL != transport_name)
623         {
624                         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
625               "Adding peer `%s' with plugin `%s' to blacklist\n",
626               GNUNET_i2s (peer), transport_name);
627                         transport = GNUNET_strdup (transport_name);
628         }
629         else
630                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
631             "Adding peer `%s' with all plugins to blacklist\n",
632             GNUNET_i2s (peer));
633   if (blacklist == NULL)
634     blacklist =
635       GNUNET_CONTAINER_multihashmap_create (TRANSPORT_BLACKLIST_HT_SIZE,
636                                             GNUNET_NO);
637
638   GNUNET_CONTAINER_multihashmap_put (blacklist, &peer->hashPubKey,
639                                      transport,
640                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
641 }
642
643
644 /**
645  * Test if the given blacklist entry matches.  If so,
646  * abort the iteration.
647  *
648  * @param cls the transport name to match (const char*)
649  * @param key the key (unused)
650  * @param value the 'char *' (name of a blacklisted transport)
651  * @return GNUNET_OK if the entry does not match, GNUNET_NO if it matches
652  */
653 static int
654 test_blacklisted (void *cls, const struct GNUNET_HashCode * key, void *value)
655 {
656   const char *transport_name = cls;
657   char *be = value;
658
659   /* Blacklist entry be:
660    *  (NULL == be): peer is blacklisted with all plugins
661    *  (NULL != be): peer is blacklisted for a specific plugin
662    *
663    * If (NULL != transport_name) we look for a transport specific entry:
664    *  if (transport_name == be) forbidden
665    *
666    */
667
668   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
669                                                 "Comparing BL request for peer `%4s':`%s' with BL entry: `%s'\n",
670                 GNUNET_h2s (key),
671                 (NULL == transport_name) ? "unspecified" : transport_name,
672                 (NULL == be) ? "all plugins" : be);
673   /* all plugins for this peer were blacklisted: disallow */
674   if (NULL == value)
675                 return GNUNET_NO;
676
677   /* blacklist check for specific transport */
678   if ((NULL != transport_name) && (NULL != value))
679   {
680         if (0 == strcmp (transport_name, be))
681                         return GNUNET_NO;           /* plugin is blacklisted! */
682   }
683   return GNUNET_OK;
684 }
685
686
687 /**
688  * Test if a peer/transport combination is blacklisted.
689  *
690  * @param peer the identity of the peer to test
691  * @param transport_name name of the transport to test, never NULL
692  * @param cont function to call with result
693  * @param cont_cls closure for 'cont'
694  * @return handle to the blacklist check, NULL if the decision
695  *        was made instantly and 'cont' was already called
696  */
697 struct GST_BlacklistCheck *
698 GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
699                             const char *transport_name,
700                             GST_BlacklistTestContinuation cont, void *cont_cls)
701 {
702   struct GST_BlacklistCheck *bc;
703
704   GNUNET_assert (peer != NULL);
705   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist check for peer `%s':%s\n",
706                 GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "unspecified");
707
708   /* Check local blacklist by iterating over hashmap
709    * If iteration is aborted, we found a matching blacklist entry */
710   if ((blacklist != NULL) &&
711       (GNUNET_SYSERR ==
712        GNUNET_CONTAINER_multihashmap_get_multiple (blacklist, &peer->hashPubKey,
713                                                    &test_blacklisted,
714                                                    (void *) transport_name)))
715   {
716     /* Disallowed by config, disapprove instantly */
717     GNUNET_STATISTICS_update (GST_stats,
718                               gettext_noop ("# disconnects due to blacklist"),
719                               1, GNUNET_NO);
720     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disallowing connection to peer `%s' on transport %s\n",
721                 GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "unspecified");
722     if (cont != NULL)
723       cont (cont_cls, peer, GNUNET_NO);
724     return NULL;
725   }
726
727   if (bl_head == NULL)
728   {
729     /* no blacklist clients, approve instantly */
730     if (cont != NULL)
731       cont (cont_cls, peer, GNUNET_OK);
732     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Allowing connection to peer `%s' %s\n",
733                 GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "");
734     return NULL;
735   }
736
737   /* need to query blacklist clients */
738   bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck));
739   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
740   bc->peer = *peer;
741   bc->cont = cont;
742   bc->cont_cls = cont_cls;
743   bc->bl_pos = bl_head;
744   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
745   return bc;
746 }
747
748
749 /**
750  * Cancel a blacklist check.
751  *
752  * @param bc check to cancel
753  */
754 void
755 GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
756 {
757   GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
758   if (bc->bl_pos != NULL)
759   {
760     if (bc->bl_pos->bc == bc)
761     {
762       /* we're at the head of the queue, remove us! */
763       bc->bl_pos->bc = NULL;
764     }
765   }
766   if (GNUNET_SCHEDULER_NO_TASK != bc->task)
767   {
768     GNUNET_SCHEDULER_cancel (bc->task);
769     bc->task = GNUNET_SCHEDULER_NO_TASK;
770   }
771   if (NULL != bc->th)
772   {
773     GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
774     bc->th = NULL;
775   }
776   GNUNET_free (bc);
777 }
778
779
780 /* end of file gnunet-service-transport_blacklist.c */