-doxygen
[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 /**
479  * Test if an existing connection is still acceptable given a new
480  * blacklisting client.
481  *
482  * @param cls the 'struct TestConnectionContest'
483  * @param neighbour neighbour's identity
484  * @param address the address
485  * @param bandwidth_in inbound quota in NBO
486  * @param bandwidth_out outbound quota in NBO
487  */
488 static void
489 test_connection_ok (void *cls, const struct GNUNET_PeerIdentity *neighbour,
490                     const struct GNUNET_HELLO_Address *address,
491                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
492                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
493 {
494   struct TestConnectionContext *tcc = cls;
495   struct GST_BlacklistCheck *bc;
496
497   bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck));
498   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
499   bc->peer = *neighbour;
500   bc->cont = &confirm_or_drop_neighbour;
501   bc->cont_cls = NULL;
502   bc->bl_pos = tcc->bl;
503   if (GNUNET_YES == tcc->first)
504   {
505     /* all would wait for the same client, no need to
506      * create more than just the first task right now */
507     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
508     tcc->first = GNUNET_NO;
509   }
510 }
511
512
513 /**
514  * Initialize a blacklisting client.  We got a blacklist-init
515  * message from this client, add him to the list of clients
516  * to query for blacklisting.
517  *
518  * @param cls unused
519  * @param client the client
520  * @param message the blacklist-init message that was sent
521  */
522 void
523 GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client,
524                            const struct GNUNET_MessageHeader *message)
525 {
526   struct Blacklisters *bl;
527   struct TestConnectionContext tcc;
528
529   bl = bl_head;
530   while (bl != NULL)
531   {
532     if (bl->client == client)
533     {
534       GNUNET_break (0);
535       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
536       return;
537     }
538     bl = bl->next;
539   }
540   GNUNET_SERVER_client_mark_monitor (client);
541   bl = GNUNET_malloc (sizeof (struct Blacklisters));
542   bl->client = client;
543   GNUNET_SERVER_client_keep (client);
544   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
545
546   /* confirm that all existing connections are OK! */
547   tcc.bl = bl;
548   tcc.first = GNUNET_YES;
549   GST_neighbours_iterate (&test_connection_ok, &tcc);
550 }
551
552
553 /**
554  * A blacklisting client has sent us reply. Process it.
555  *
556  * @param cls unused
557  * @param client the client
558  * @param message the blacklist-init message that was sent
559  */
560 void
561 GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client,
562                             const struct GNUNET_MessageHeader *message)
563 {
564   const struct BlacklistMessage *msg =
565       (const struct BlacklistMessage *) message;
566   struct Blacklisters *bl;
567   struct GST_BlacklistCheck *bc;
568
569   bl = bl_head;
570   while ((bl != NULL) && (bl->client != client))
571     bl = bl->next;
572   if (bl == NULL)
573   {
574     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
575     /* FIXME: other error handling here!? */
576     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
577     return;
578   }
579   bc = bl->bc;
580   bl->bc = NULL;
581   bl->waiting_for_reply = GNUNET_NO;
582   if (NULL != bc)
583   {
584     /* only run this if the blacklist check has not been
585      * cancelled in the meantime... */
586     if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
587     {
588       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
589                   "Blacklist check failed, peer not allowed\n");
590       bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO);
591       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
592       GNUNET_free (bc);
593     }
594     else
595     {
596       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
597                   "Blacklist check succeeded, continuing with checks\n");
598       bc->bl_pos = bc->bl_pos->next;
599       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
600     }
601   }
602   /* check if any other bc's are waiting for this blacklister */
603   for (bc = bc_head; bc != NULL; bc = bc->next)
604     if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
605     {
606       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
607       break;
608     }
609 }
610
611
612 /**
613  * Add the given peer to the blacklist (for the given transport).
614  *
615  * @param peer peer to blacklist
616  * @param transport_name transport to blacklist for this peer, NULL for all
617  */
618 void
619 GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
620                         const char *transport_name)
621 {
622   char * transport = NULL;
623
624   if (NULL != transport_name)
625   {
626     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
627                 "Adding peer `%s' with plugin `%s' to blacklist\n",
628                 GNUNET_i2s (peer), transport_name);
629     transport = GNUNET_strdup (transport_name);
630   }
631   else
632     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
633                 "Adding peer `%s' with all plugins to blacklist\n",
634                 GNUNET_i2s (peer));
635   if (blacklist == NULL)
636     blacklist =
637       GNUNET_CONTAINER_multipeermap_create (TRANSPORT_BLACKLIST_HT_SIZE,
638                                             GNUNET_NO);
639
640   GNUNET_CONTAINER_multipeermap_put (blacklist, peer,
641                                      transport,
642                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
643 }
644
645
646 /**
647  * Test if the given blacklist entry matches.  If so,
648  * abort the iteration.
649  *
650  * @param cls the transport name to match (const char*)
651  * @param key the key (unused)
652  * @param value the 'char *' (name of a blacklisted transport)
653  * @return #GNUNET_OK if the entry does not match, #GNUNET_NO if it matches
654  */
655 static int
656 test_blacklisted (void *cls,
657                   const struct GNUNET_PeerIdentity *key,
658                   void *value)
659 {
660   const char *transport_name = cls;
661   char *be = value;
662
663   /* Blacklist entry be:
664    *  (NULL == be): peer is blacklisted with all plugins
665    *  (NULL != be): peer is blacklisted for a specific plugin
666    *
667    * If (NULL != transport_name) we look for a transport specific entry:
668    *  if (transport_name == be) forbidden
669    *
670    */
671
672   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
673               "Comparing BL request for peer `%4s':`%s' with BL entry: `%s'\n",
674               GNUNET_i2s (key),
675               (NULL == transport_name) ? "unspecified" : transport_name,
676               (NULL == be) ? "all plugins" : be);
677   /* all plugins for this peer were blacklisted: disallow */
678   if (NULL == value)
679                 return GNUNET_NO;
680
681   /* blacklist check for specific transport */
682   if ((NULL != transport_name) && (NULL != value))
683   {
684         if (0 == strcmp (transport_name, be))
685                         return GNUNET_NO;           /* plugin is blacklisted! */
686   }
687   return GNUNET_OK;
688 }
689
690
691 /**
692  * Test if a peer/transport combination is blacklisted.
693  *
694  * @param peer the identity of the peer to test
695  * @param transport_name name of the transport to test, never NULL
696  * @param cont function to call with result
697  * @param cont_cls closure for 'cont'
698  * @return handle to the blacklist check, NULL if the decision
699  *        was made instantly and 'cont' was already called
700  */
701 struct GST_BlacklistCheck *
702 GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
703                             const char *transport_name,
704                             GST_BlacklistTestContinuation cont, void *cont_cls)
705 {
706   struct GST_BlacklistCheck *bc;
707
708   GNUNET_assert (peer != NULL);
709   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist check for peer `%s':%s\n",
710                 GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "unspecified");
711
712   /* Check local blacklist by iterating over hashmap
713    * If iteration is aborted, we found a matching blacklist entry */
714   if ((blacklist != NULL) &&
715       (GNUNET_SYSERR ==
716        GNUNET_CONTAINER_multipeermap_get_multiple (blacklist, peer,
717                                                    &test_blacklisted,
718                                                    (void *) transport_name)))
719   {
720     /* Disallowed by config, disapprove instantly */
721     GNUNET_STATISTICS_update (GST_stats,
722                               gettext_noop ("# disconnects due to blacklist"),
723                               1, GNUNET_NO);
724     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disallowing connection to peer `%s' on transport %s\n",
725                 GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "unspecified");
726     if (cont != NULL)
727       cont (cont_cls, peer, GNUNET_NO);
728     return NULL;
729   }
730
731   if (bl_head == NULL)
732   {
733     /* no blacklist clients, approve instantly */
734     if (cont != NULL)
735       cont (cont_cls, peer, GNUNET_OK);
736     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Allowing connection to peer `%s' %s\n",
737                 GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "");
738     return NULL;
739   }
740
741   /* need to query blacklist clients */
742   bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck));
743   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
744   bc->peer = *peer;
745   bc->cont = cont;
746   bc->cont_cls = cont_cls;
747   bc->bl_pos = bl_head;
748   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
749   return bc;
750 }
751
752
753 /**
754  * Cancel a blacklist check.
755  *
756  * @param bc check to cancel
757  */
758 void
759 GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
760 {
761   GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
762   if (bc->bl_pos != NULL)
763   {
764     if (bc->bl_pos->bc == bc)
765     {
766       /* we're at the head of the queue, remove us! */
767       bc->bl_pos->bc = NULL;
768     }
769   }
770   if (GNUNET_SCHEDULER_NO_TASK != bc->task)
771   {
772     GNUNET_SCHEDULER_cancel (bc->task);
773     bc->task = GNUNET_SCHEDULER_NO_TASK;
774   }
775   if (NULL != bc->th)
776   {
777     GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
778     bc->th = NULL;
779   }
780   GNUNET_free (bc);
781 }
782
783
784 /* end of file gnunet-service-transport_blacklist.c */