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