/*
This file is part of GNUnet.
- (C) 2010,2011 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2010,2011 Christian Grothoff (and other contributing authors)
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
* @file transport/gnunet-service-transport_blacklist.c
* @brief blacklisting implementation
* @author Christian Grothoff
+ * @author Matthias Wachs
+ * @details This is the blacklisting component of transport service. With
+ * blacklisting it is possible to deny connections to specific peers of
+ * to use a specific plugin to a specific peer. Peers can be blacklisted using
+ * the configuration or a blacklist client can be asked.
+ *
+ * To blacklist peers using the configuration you have to add a section to your
+ * configuration containing the peer id of the peer to blacklist and the plugin
+ * if required.
+ *
+ * Example:
+ * To blacklist connections to P565... on peer AG2P... using tcp add:
+ * [transport-blacklist-AG2PHES1BARB9IJCPAMJTFPVJ5V3A72S3F2A8SBUB8DAQ2V0O3V8G6G2JU56FHGFOHMQVKBSQFV98TCGTC3RJ1NINP82G0RC00N1520]
+ * P565723JO1C2HSN6J29TAQ22MN6CI8HTMUU55T0FUQG4CMDGGEQ8UCNBKUMB94GC8R9G4FB2SF9LDOBAJ6AMINBP4JHHDD6L7VD801G = tcp
+ *
+ * To blacklist connections to P565... on peer AG2P... using all plugins add:
+ * [transport-blacklist-AG2PHES1BARB9IJCPAMJTFPVJ5V3A72S3F2A8SBUB8DAQ2V0O3V8G6G2JU56FHGFOHMQVKBSQFV98TCGTC3RJ1NINP82G0RC00N1520]
+ * P565723JO1C2HSN6J29TAQ22MN6CI8HTMUU55T0FUQG4CMDGGEQ8UCNBKUMB94GC8R9G4FB2SF9LDOBAJ6AMINBP4JHHDD6L7VD801G =
+ *
+ * You can also add a blacklist client usign the blacklist api. On a blacklist
+ * check, blacklisting first checks internally if the peer is blacklisted and
+ * if not, it asks the blacklisting clients. Clients are asked if it is OK to
+ * connect to a peer ID, the plugin is omitted.
+ *
+ * On blacklist check for (peer, plugin)
+ * - Do we have a local blacklist entry for this peer and this plugin?
+ * - YES: disallow connection
+ * - Do we have a local blacklist entry for this peer and all plugins?
+ * - YES: disallow connection
+ * - Does one of the clients disallow?
+ * - YES: disallow connection
+ *
*/
#include "platform.h"
#include "gnunet-service-transport.h"
#include "gnunet-service-transport_neighbours.h"
#include "transport.h"
-
/**
* Size of the blacklist hash map.
*/
/**
* Context we use when performing a blacklist check.
*/
-struct BlacklistCheck;
+struct GST_BlacklistCheck;
/**
struct GNUNET_SERVER_Client *client;
/**
- * Blacklist check that we're currently performing.
+ * Blacklist check that we're currently performing (or NULL
+ * if we're performing one that has been cancelled).
+ */
+ struct GST_BlacklistCheck *bc;
+
+ /**
+ * Set to #GNUNET_YES if we're currently waiting for a reply.
+ */
+ int waiting_for_reply;
+
+ /**
+ * #GNUNET_YES if we have to call receive_done for this client
*/
- struct BlacklistCheck *bc;
+ int call_receive_done;
};
/**
* Context we use when performing a blacklist check.
*/
-struct BlacklistCheck
+struct GST_BlacklistCheck
{
/**
* This is a linked list.
*/
- struct BlacklistCheck *next;
+ struct GST_BlacklistCheck *next;
/**
* This is a linked list.
*/
- struct BlacklistCheck *prev;
+ struct GST_BlacklistCheck *prev;
/**
* Peer being checked.
GST_BlacklistTestContinuation cont;
/**
- * Closure for cont.
+ * Closure for @e cont.
*/
void *cont_cls;
+ /**
+ * Address for #GST_blacklist_abort_matching(), can be NULL.
+ */
+ struct GNUNET_HELLO_Address *address;
+
+ /**
+ * Session for #GST_blacklist_abort_matching(), can be NULL.
+ */
+ struct Session *session;
+
/**
* Current transmission request handle for this client, or NULL if no
* request is pending.
*/
- struct GNUNET_CONNECTION_TransmitHandle *th;
+ struct GNUNET_SERVER_TransmitHandle *th;
/**
* Our current position in the blacklisters list.
/**
* Current task performing the check.
*/
- GNUNET_SCHEDULER_TaskIdentifier task;
+ struct GNUNET_SCHEDULER_Task *task;
};
/**
* Head of DLL of active blacklisting queries.
*/
-static struct BlacklistCheck *bc_head;
+static struct GST_BlacklistCheck *bc_head;
/**
* Tail of DLL of active blacklisting queries.
*/
-static struct BlacklistCheck *bc_tail;
+static struct GST_BlacklistCheck *bc_tail;
/**
* Head of DLL of blacklisting clients.
* Hashmap of blacklisted peers. Values are of type 'char *' (transport names),
* can be NULL if we have no static blacklist.
*/
-static struct GNUNET_CONTAINER_MultiHashMap *blacklist;
+static struct GNUNET_CONTAINER_MultiPeerMap *blacklist;
/**
* Perform next action in the blacklist check.
*
- * @param cls the 'struct BlacklistCheck*'
+ * @param cls the `struct BlacklistCheck*`
* @param tc unused
*/
static void
-do_blacklist_check (void *cls,
+do_blacklist_check (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc);
*/
static void
client_disconnect_notification (void *cls,
- struct GNUNET_SERVER_Client *client)
+ struct GNUNET_SERVER_Client *client)
{
struct Blacklisters *bl;
- struct BlacklistCheck *bc;
+ struct GST_BlacklistCheck *bc;
- if (client == NULL)
+ if (NULL == client)
return;
for (bl = bl_head; bl != NULL; bl = bl->next)
+ {
+ if (bl->client != client)
+ continue;
+ for (bc = bc_head; NULL != bc; bc = bc->next)
{
- if (bl->client != client)
- continue;
- for (bc = bc_head; bc != NULL; bc = bc->next)
- {
- if (bc->bl_pos != bl)
- continue;
- bc->bl_pos = bl->next;
- if (bc->th != NULL)
- {
- GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
- bc->th = NULL;
- }
- if (bc->task == GNUNET_SCHEDULER_NO_TASK)
- bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
- bc);
- break;
- }
- GNUNET_CONTAINER_DLL_remove (bl_head,
- bl_tail,
- bl);
- GNUNET_SERVER_client_drop (bl->client);
- GNUNET_free (bl);
- break;
+ if (bc->bl_pos != bl)
+ continue;
+ bc->bl_pos = bl->next;
+ if (NULL != bc->th)
+ {
+ GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
+ bc->th = NULL;
+ }
+ if (NULL == bc->task)
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
}
+ GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl);
+ GNUNET_SERVER_client_drop (bl->client);
+ GNUNET_free (bl);
+ break;
+ }
}
/**
- * Read the blacklist file, containing transport:peer entries.
- * Provided the transport is loaded, set up hashmap with these
- * entries to blacklist peers by transport.
+ * Function to iterate over options in the blacklisting section for a peer.
*
+ * @param cls closure
+ * @param section name of the section
+ * @param option name of the option
+ * @param value value of the option
*/
static void
-read_blacklist_file ()
+blacklist_cfg_iter (void *cls,
+ const char *section,
+ const char *option,
+ const char *value)
{
- char *fn;
- char *data;
- size_t pos;
- size_t colon_pos;
- int tsize;
- struct GNUNET_PeerIdentity pid;
- struct stat frstat;
- struct GNUNET_CRYPTO_HashAsciiEncoded enc;
- unsigned int entries_found;
- char *transport_name;
+ unsigned int *res = cls;
+ struct GNUNET_PeerIdentity peer;
+ char *plugs;
+ char *pos;
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (GST_cfg,
- "TRANSPORT",
- "BLACKLIST_FILE",
- &fn))
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Option `%s' in section `%s' not specified!\n",
- "BLACKLIST_FILE",
- "TRANSPORT");
-#endif
- return;
- }
- if (GNUNET_OK != GNUNET_DISK_file_test (fn))
- GNUNET_DISK_fn_write (fn, NULL, 0,
- GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
- if (0 != STAT (fn, &frstat))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Could not read blacklist file `%s'\n"),
- fn);
- GNUNET_free (fn);
- return;
- }
- if (frstat.st_size == 0)
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _("Blacklist file `%s' is empty.\n"),
- fn);
-#endif
- GNUNET_free (fn);
- return;
- }
- /* FIXME: use mmap */
- data = GNUNET_malloc_large (frstat.st_size);
- GNUNET_assert(data != NULL);
- if (frstat.st_size !=
- GNUNET_DISK_fn_read (fn, data, frstat.st_size))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to read blacklist from `%s'\n"),
- fn);
- GNUNET_free (fn);
- GNUNET_free (data);
- return;
- }
- entries_found = 0;
- pos = 0;
- while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
- pos++;
- while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
- (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
- {
- colon_pos = pos;
- while ( (colon_pos < frstat.st_size) &&
- (data[colon_pos] != ':') &&
- (! isspace ( (unsigned char) data[colon_pos])) )
- colon_pos++;
- if (colon_pos >= frstat.st_size)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Syntax error in blacklist file at offset %llu, giving up!\n"),
- (unsigned long long) colon_pos);
- GNUNET_free (fn);
- GNUNET_free (data);
- return;
- }
-
- if (isspace( (unsigned char) data[colon_pos]))
+ GNUNET_CRYPTO_eddsa_public_key_from_string (option,
+ strlen (option),
+ &peer.public_key))
+ return;
+
+ if ((NULL == value) || (0 == strcmp(value, "")))
+ {
+ /* Blacklist whole peer */
+ GST_blacklist_add_peer (&peer, NULL);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Adding blacklisting entry for peer `%s'\n"),
+ GNUNET_i2s (&peer));
+ }
+ else
+ {
+ plugs = GNUNET_strdup (value);
+ for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
- (unsigned long long) colon_pos);
- pos = colon_pos;
- while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
- pos++;
- continue;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Adding blacklisting entry for peer `%s':`%s'\n"),
+ GNUNET_i2s (&peer), pos);
+ GST_blacklist_add_peer (&peer, pos);
}
- tsize = colon_pos - pos;
- if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Syntax error in blacklist file at offset %llu, giving up!\n"),
- (unsigned long long) colon_pos);
- GNUNET_free (fn);
- GNUNET_free (data);
- return;
- }
-
- if (tsize < 1)
- continue;
+ GNUNET_free (plugs);
+ }
+ (*res)++;
+}
- transport_name = GNUNET_malloc(tsize + 1);
- memcpy(transport_name, &data[pos], tsize);
- pos = colon_pos + 1;
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Read transport name `%s' in blacklist file.\n",
- transport_name);
-#endif
- memcpy (&enc,
- &data[pos],
- sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
- if (! isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
- (unsigned long long) pos);
- pos++;
- while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
- pos++;
- GNUNET_free_non_null(transport_name);
- continue;
- }
- enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
- if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
- (unsigned long long) pos,
- &enc);
- }
- else
- {
- if (0 != memcmp (&pid,
- &GST_my_identity,
- sizeof (struct GNUNET_PeerIdentity)))
- {
- entries_found++;
- GST_blacklist_add_peer (&pid,
- transport_name);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Found myself `%s' in blacklist (useless, ignored)\n"),
- GNUNET_i2s (&pid));
- }
- }
- pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
- GNUNET_free_non_null(transport_name);
- while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
- pos++;
- }
- GNUNET_STATISTICS_update (GST_stats,
- "# Transport entries blacklisted",
- entries_found,
- GNUNET_NO);
- GNUNET_free (data);
- GNUNET_free (fn);
+
+/**
+ * Read blacklist configuration
+ *
+ * @param cfg the configuration handle
+ * @param my_id my peer identity
+ */
+static void
+read_blacklist_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_PeerIdentity *my_id)
+{
+ char cfg_sect[512];
+ unsigned int res = 0;
+
+ GNUNET_snprintf (cfg_sect,
+ sizeof (cfg_sect),
+ "transport-blacklist-%s",
+ GNUNET_i2s_full (my_id));
+ GNUNET_CONFIGURATION_iterate_section_values (cfg,
+ cfg_sect,
+ &blacklist_cfg_iter,
+ &res);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Loaded %u blacklisting entries from configuration\n",
+ res);
}
* Start blacklist subsystem.
*
* @param server server used to accept clients from
+ * @param cfg configuration handle
+ * @param my_id my peer id
*/
void
-GST_blacklist_start (struct GNUNET_SERVER_Handle *server)
+GST_blacklist_start (struct GNUNET_SERVER_Handle *server,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_PeerIdentity *my_id)
{
- read_blacklist_file ();
+ GNUNET_assert (NULL != cfg);
+ GNUNET_assert (NULL != my_id);
+ read_blacklist_configuration (cfg, my_id);
GNUNET_SERVER_disconnect_notify (server,
- &client_disconnect_notification,
- NULL);
+ &client_disconnect_notification,
+ NULL);
}
* @param cls unused
* @param key host identity (unused)
* @param value the blacklist entry
- * @return GNUNET_OK (continue to iterate)
+ * @return #GNUNET_OK (continue to iterate)
*/
static int
free_blacklist_entry (void *cls,
- const GNUNET_HashCode *key,
+ const struct GNUNET_PeerIdentity *key,
void *value)
{
char *be = value;
- GNUNET_free (be);
+ GNUNET_free_non_null (be);
return GNUNET_OK;
}
void
GST_blacklist_stop ()
{
- if (NULL != blacklist)
- {
- GNUNET_CONTAINER_multihashmap_iterate (blacklist,
- &free_blacklist_entry,
- NULL);
- GNUNET_CONTAINER_multihashmap_destroy (blacklist);
- blacklist = NULL;
- }
+ if (NULL == blacklist)
+ return;
+ GNUNET_CONTAINER_multipeermap_iterate (blacklist,
+ &free_blacklist_entry,
+ NULL);
+ GNUNET_CONTAINER_multipeermap_destroy (blacklist);
+ blacklist = NULL;
}
/**
* Transmit blacklist query to the client.
*
- * @param cls the 'struct BlacklistCheck'
+ * @param cls the `struct GST_BlacklistCheck`
* @param size number of bytes allowed
* @param buf where to copy the message
- * @return number of bytes copied to buf
+ * @return number of bytes copied to @a buf
*/
static size_t
-transmit_blacklist_message (void *cls,
+transmit_blacklist_message (void *cls,
size_t size,
void *buf)
{
- struct BlacklistCheck *bc = cls;
+ struct GST_BlacklistCheck *bc = cls;
struct Blacklisters *bl;
struct BlacklistMessage bm;
bc->th = NULL;
- if (size == 0)
- {
- GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
- bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
- bc);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to send blacklist test for peer `%s' to client\n",
- GNUNET_i2s (&bc->peer));
- return 0;
- }
-#if DEBUG_TRANSPORT
+ if (0 == size)
+ {
+ GNUNET_assert (NULL == bc->task);
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+ bc);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to send blacklist test for peer `%s' to client\n",
+ GNUNET_i2s (&bc->peer));
+ return 0;
+ }
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending blacklist test for peer `%s' to client\n",
- GNUNET_i2s (&bc->peer));
-#endif
+ "Sending blacklist test for peer `%s' to client %p\n",
+ GNUNET_i2s (&bc->peer),
+ bc->bl_pos->client);
bl = bc->bl_pos;
bm.header.size = htons (sizeof (struct BlacklistMessage));
bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
bm.is_allowed = htonl (0);
bm.peer = bc->peer;
- memcpy (buf, &bm, sizeof (bm));
- GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
+ memcpy (buf,
+ &bm,
+ sizeof (bm));
+ if (GNUNET_YES == bl->call_receive_done)
+ {
+ GNUNET_SERVER_receive_done (bl->client,
+ GNUNET_OK);
+ bl->call_receive_done = GNUNET_NO;
+ }
+
+ bl->waiting_for_reply = GNUNET_YES;
return sizeof (bm);
}
/**
* Perform next action in the blacklist check.
*
- * @param cls the 'struct BlacklistCheck*'
+ * @param cls the `struct GST_BlacklistCheck *`
* @param tc unused
*/
static void
do_blacklist_check (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct BlacklistCheck *bc = cls;
+ struct GST_BlacklistCheck *bc = cls;
struct Blacklisters *bl;
- bc->task = GNUNET_SCHEDULER_NO_TASK;
+ bc->task = NULL;
bl = bc->bl_pos;
- if (bl == NULL)
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "No other blacklist clients active, will allow neighbour `%s'\n",
- GNUNET_i2s (&bc->peer));
-#endif
- bc->cont (bc->cont_cls,
- &bc->peer,
- GNUNET_OK);
- GNUNET_free (bc);
- return;
- }
- if (bl->bc != NULL)
- return; /* someone else busy with this client */
+ if (NULL == bl)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "No other blacklist clients active, will allow neighbour `%s'\n",
+ GNUNET_i2s (&bc->peer));
+
+ bc->cont (bc->cont_cls,
+ &bc->peer,
+ bc->address,
+ bc->session,
+ GNUNET_OK);
+ GST_blacklist_test_cancel (bc);
+ return;
+ }
+ if ( (NULL != bl->bc) ||
+ (GNUNET_NO != bl->waiting_for_reply) )
+ return; /* someone else busy with this client */
bl->bc = bc;
- bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
- sizeof (struct BlacklistMessage),
- GNUNET_TIME_UNIT_FOREVER_REL,
- &transmit_blacklist_message,
- bc);
+ bc->th =
+ GNUNET_SERVER_notify_transmit_ready (bl->client,
+ sizeof (struct BlacklistMessage),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &transmit_blacklist_message,
+ bc);
}
*
* @param cls unused
* @param peer the neighbour that was investigated
- * @param allowed GNUNET_OK if we can keep it,
- * GNUNET_NO if we must shutdown the connection
+ * @param address address associated with the request
+ * @param session session associated with the request
+ * @param allowed #GNUNET_OK if we can keep it,
+ * #GNUNET_NO if we must shutdown the connection
*/
static void
confirm_or_drop_neighbour (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- int allowed)
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ int allowed)
{
if (GNUNET_OK == allowed)
- return; /* we're done */
+ return; /* we're done */
GNUNET_STATISTICS_update (GST_stats,
- gettext_noop ("# disconnects due to blacklist"),
+ gettext_noop ("# disconnects due to blacklist"),
1,
- GNUNET_NO);
+ GNUNET_NO);
GST_neighbours_force_disconnect (peer);
}
/**
- * Closure for 'test_connection_ok'.
+ * Closure for #test_connection_ok().
*/
struct TestConnectionContext
{
/**
* Is this the first neighbour we're checking?
- */
+ */
int first;
/**
* Test if an existing connection is still acceptable given a new
* blacklisting client.
*
- * @param cls the 'struct TestConnectionContest'
- * @param pid neighbour's identity
- * @param ats performance data
- * @param ats_count number of entries in ats (excluding 0-termination)
+ * @param cls the `struct TestConnectionContext *`
+ * @param peer identity of the peer
+ * @param address the address
+ * @param state current state this peer is in
+ * @param state_timeout timeout for the current state of the peer
+ * @param bandwidth_in bandwidth assigned inbound
+ * @param bandwidth_out bandwidth assigned outbound
*/
static void
test_connection_ok (void *cls,
- const struct GNUNET_PeerIdentity *neighbour,
- const struct GNUNET_TRANSPORT_ATS_Information *ats,
- uint32_t ats_count)
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address *address,
+ enum GNUNET_TRANSPORT_PeerState state,
+ struct GNUNET_TIME_Absolute state_timeout,
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
{
struct TestConnectionContext *tcc = cls;
- struct BlacklistCheck *bc;
+ struct GST_BlacklistCheck *bc;
- bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
- GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
- bc->peer = *neighbour;
+ bc = GNUNET_new (struct GST_BlacklistCheck);
+ GNUNET_CONTAINER_DLL_insert (bc_head,
+ bc_tail,
+ bc);
+ bc->peer = *peer;
+ bc->address = GNUNET_HELLO_address_copy (address);
bc->cont = &confirm_or_drop_neighbour;
bc->cont_cls = NULL;
bc->bl_pos = tcc->bl;
if (GNUNET_YES == tcc->first)
- {
- /* all would wait for the same client, no need to
- create more than just the first task right now */
- bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
- bc);
- tcc->first = GNUNET_NO;
- }
+ {
+ /* all would wait for the same client, no need to
+ * create more than just the first task right now */
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+ tcc->first = GNUNET_NO;
+ }
}
-
/**
* Initialize a blacklisting client. We got a blacklist-init
* message from this client, add him to the list of clients
void
GST_blacklist_handle_init (void *cls,
struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
+ const struct GNUNET_MessageHeader *message)
{
struct Blacklisters *bl;
struct TestConnectionContext tcc;
- bl = bl_head;
- while (bl != NULL)
+ for (bl = bl_head; NULL != bl; bl = bl->next)
+ if (bl->client == client)
{
- if (bl->client == client)
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- bl = bl->next;
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
}
- bl = GNUNET_malloc (sizeof (struct Blacklisters));
+
+ GNUNET_SERVER_client_mark_monitor (client);
+ bl = GNUNET_new (struct Blacklisters);
bl->client = client;
+ bl->call_receive_done = GNUNET_YES;
GNUNET_SERVER_client_keep (client);
- GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
+ GNUNET_CONTAINER_DLL_insert_after (bl_head,
+ bl_tail,
+ bl_tail,
+ bl);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "New blacklist client %p\n",
+ client);
/* confirm that all existing connections are OK! */
tcc.bl = bl;
tcc.first = GNUNET_YES;
- GST_neighbours_iterate (&test_connection_ok,
- &tcc);
+ GST_neighbours_iterate (&test_connection_ok, &tcc);
}
void
GST_blacklist_handle_reply (void *cls,
struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
+ const struct GNUNET_MessageHeader *message)
{
- const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
+ const struct BlacklistMessage *msg =
+ (const struct BlacklistMessage *) message;
struct Blacklisters *bl;
- struct BlacklistCheck *bc;
+ struct GST_BlacklistCheck *bc;
bl = bl_head;
- while ( (bl != NULL) &&
- (bl->client != client) )
+ while ((bl != NULL) && (bl->client != client))
bl = bl->next;
- if (bl == NULL)
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Blacklist client disconnected\n");
-#endif
- /* FIXME: other error handling here!? */
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
+ if (NULL == bl)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Blacklist client disconnected\n");
+ GNUNET_SERVER_receive_done (client,
+ GNUNET_SYSERR);
+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Blacklist client %p sent reply for `%s'\n",
+ client,
+ GNUNET_i2s (&msg->peer));
+
bc = bl->bc;
bl->bc = NULL;
- if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
+ bl->waiting_for_reply = GNUNET_NO;
+ bl->call_receive_done = GNUNET_YES; /* Remember to call receive_done */
+ if (NULL != bc)
+ {
+ /* only run this if the blacklist check has not been
+ * cancelled in the meantime... */
+ GNUNET_assert (bc->bl_pos == bl);
+ if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
{
-#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Blacklist check failed, peer not allowed\n");
-#endif
- bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO);
- GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
- GNUNET_free (bc);
+ "Blacklist check failed, peer not allowed\n");
+ /* For the duration of the continuation, make the ongoing
+ check invisible (to avoid double-cancellation); then
+ add it back again so we can re-use GST_blacklist_test_cancel() */
+ GNUNET_CONTAINER_DLL_remove (bc_head,
+ bc_tail,
+ bc);
+ bc->cont (bc->cont_cls,
+ &bc->peer,
+ bc->address,
+ bc->session,
+ GNUNET_NO);
+ GNUNET_CONTAINER_DLL_insert (bc_head,
+ bc_tail,
+ bc);
+ GST_blacklist_test_cancel (bc);
+ GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
+ bl->call_receive_done = GNUNET_NO;
+ return;
}
- else
+ else
{
-#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Blacklist check succeeded, continuing with checks\n");
-#endif
- bc->bl_pos = bc->bl_pos->next;
- bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+ "Blacklist check succeeded, continuing with checks\n");
+ GNUNET_SERVER_receive_done (bl->client,
+ GNUNET_OK);
+ bl->call_receive_done = GNUNET_NO;
+ bc->bl_pos = bl->next;
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
bc);
}
- /* check if any other bc's are waiting for this blacklister */
- bc = bc_head;
- while (bc != NULL)
+ }
+ /* check if any other blacklist checks are waiting for this blacklister */
+ for (bc = bc_head; bc != NULL; bc = bc->next)
+ if ((bc->bl_pos == bl) && (NULL == bc->task))
{
- if ( (bc->bl_pos == bl) &&
- (GNUNET_SCHEDULER_NO_TASK == bc->task) )
- bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
- bc);
- bc = bc->next;
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+ bc);
+ break;
}
}
/**
* Add the given peer to the blacklist (for the given transport).
- *
+ *
* @param peer peer to blacklist
* @param transport_name transport to blacklist for this peer, NULL for all
*/
void
GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
- const char *transport_name)
+ const char *transport_name)
{
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Adding peer `%s' with plugin `%s' to blacklist\n",
- GNUNET_i2s (peer),
- transport_name);
-#endif
- if (blacklist == NULL)
- blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
- GNUNET_CONTAINER_multihashmap_put (blacklist,
- &peer->hashPubKey,
- GNUNET_strdup (transport_name),
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ char *transport = NULL;
+
+ if (NULL != transport_name)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Adding peer `%s' with plugin `%s' to blacklist\n",
+ GNUNET_i2s (peer), transport_name);
+ transport = GNUNET_strdup (transport_name);
+ }
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Adding peer `%s' with all plugins to blacklist\n",
+ GNUNET_i2s (peer));
+ if (NULL == blacklist)
+ blacklist =
+ GNUNET_CONTAINER_multipeermap_create (TRANSPORT_BLACKLIST_HT_SIZE,
+ GNUNET_NO);
+
+ GNUNET_CONTAINER_multipeermap_put (blacklist, peer,
+ transport,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+}
+
+
+/**
+ * Abort blacklist if @a address and @a session match.
+ *
+ * @param address address used to abort matching checks
+ * @param session session used to abort matching checks
+ */
+void
+GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address,
+ struct Session *session)
+{
+ struct GST_BlacklistCheck *bc;
+ struct GST_BlacklistCheck *n;
+
+ n = bc_head;
+ while (NULL != (bc = n))
+ {
+ n = bc->next;
+ if ( (bc->session == session) &&
+ (0 == GNUNET_HELLO_address_cmp (bc->address,
+ address)) )
+ {
+ bc->cont (bc->cont_cls,
+ &bc->peer,
+ bc->address,
+ bc->session,
+ GNUNET_SYSERR);
+ GST_blacklist_test_cancel (bc);
+ }
+ }
}
* @param cls the transport name to match (const char*)
* @param key the key (unused)
* @param value the 'char *' (name of a blacklisted transport)
- * @return GNUNET_OK if the entry does not match, GNUNET_NO if it matches
+ * @return #GNUNET_OK if the entry does not match, #GNUNET_NO if it matches
*/
static int
test_blacklisted (void *cls,
- const GNUNET_HashCode *key,
+ const struct GNUNET_PeerIdentity *key,
void *value)
{
const char *transport_name = cls;
char *be = value;
- if (0 == strcmp (transport_name,
- be))
- return GNUNET_NO; /* abort iteration! */
+ /* Blacklist entry be:
+ * (NULL == be): peer is blacklisted with all plugins
+ * (NULL != be): peer is blacklisted for a specific plugin
+ *
+ * If (NULL != transport_name) we look for a transport specific entry:
+ * if (transport_name == be) forbidden
+ *
+ */
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Comparing BL request for peer `%4s':`%s' with BL entry: `%s'\n",
+ GNUNET_i2s (key),
+ (NULL == transport_name) ? "unspecified" : transport_name,
+ (NULL == be) ? "all plugins" : be);
+ /* all plugins for this peer were blacklisted: disallow */
+ if (NULL == value)
+ return GNUNET_NO;
+
+ /* blacklist check for specific transport */
+ if ((NULL != transport_name) && (NULL != value))
+ {
+ if (0 == strcmp (transport_name,
+ be))
+ return GNUNET_NO; /* plugin is blacklisted! */
+ }
return GNUNET_OK;
}
* @param peer the identity of the peer to test
* @param transport_name name of the transport to test, never NULL
* @param cont function to call with result
- * @param cont_cls closure for 'cont'
+ * @param cont_cls closure for @a cont
+ * @param address address to pass back to @a cont, can be NULL
+ * @param session session to pass back to @a cont, can be NULL
+ * @return handle to the blacklist check, NULL if the decision
+ * was made instantly and @a cont was already called
*/
-void
+struct GST_BlacklistCheck *
GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
- const char *transport_name,
- GST_BlacklistTestContinuation cont,
- void *cont_cls)
+ const char *transport_name,
+ GST_BlacklistTestContinuation cont,
+ void *cont_cls,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session)
{
- struct BlacklistCheck *bc;
-
- if ( (blacklist != NULL) &&
- (GNUNET_SYSERR ==
- GNUNET_CONTAINER_multihashmap_get_multiple (blacklist,
- &peer->hashPubKey,
- &test_blacklisted,
- (void*) transport_name)) )
- {
- /* disallowed by config, disapprove instantly */
- GNUNET_STATISTICS_update (GST_stats,
- gettext_noop ("# disconnects due to blacklist"),
- 1,
- GNUNET_NO);
- if (cont != NULL)
- cont (cont_cls, peer, GNUNET_NO);
- return;
- }
+ struct GST_BlacklistCheck *bc;
- if (bl_head == NULL)
- {
- /* no blacklist clients, approve instantly */
- if (cont != NULL)
- cont (cont_cls, peer, GNUNET_OK);
- return;
- }
+ GNUNET_assert (NULL != peer);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Blacklist check for peer `%s':%s\n",
+ GNUNET_i2s (peer),
+ (NULL != transport_name) ? transport_name : "unspecified");
+
+ /* Check local blacklist by iterating over hashmap
+ * If iteration is aborted, we found a matching blacklist entry */
+ if ((NULL != blacklist) &&
+ (GNUNET_SYSERR ==
+ GNUNET_CONTAINER_multipeermap_get_multiple (blacklist, peer,
+ &test_blacklisted,
+ (void *) transport_name)))
+ {
+ /* Disallowed by config, disapprove instantly */
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# disconnects due to blacklist"),
+ 1,
+ GNUNET_NO);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Disallowing connection to peer `%s' on transport %s\n"),
+ GNUNET_i2s (peer),
+ (NULL != transport_name) ? transport_name : "unspecified");
+ if (NULL != cont)
+ cont (cont_cls,
+ peer,
+ address,
+ session,
+ GNUNET_NO);
+ return NULL;
+ }
+
+ if (NULL == bl_head)
+ {
+ /* no blacklist clients, approve instantly */
+ if (NULL != cont)
+ cont (cont_cls,
+ peer,
+ address,
+ session,
+ GNUNET_OK);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Allowing connection to peer `%s' %s\n",
+ GNUNET_i2s (peer),
+ (NULL != transport_name) ? transport_name : "");
+ return NULL;
+ }
/* need to query blacklist clients */
- bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
- GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
+ bc = GNUNET_new (struct GST_BlacklistCheck);
+ GNUNET_CONTAINER_DLL_insert (bc_head,
+ bc_tail,
+ bc);
bc->peer = *peer;
+ bc->address = GNUNET_HELLO_address_copy (address);
+ bc->session = session;
bc->cont = cont;
bc->cont_cls = cont_cls;
bc->bl_pos = bl_head;
- bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
- bc);
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+ return bc;
+}
+
+
+/**
+ * Cancel a blacklist check.
+ *
+ * @param bc check to cancel
+ */
+void
+GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
+{
+ GNUNET_CONTAINER_DLL_remove (bc_head,
+ bc_tail,
+ bc);
+ if (NULL != bc->bl_pos)
+ {
+ if (bc->bl_pos->bc == bc)
+ {
+ /* we're at the head of the queue, remove us! */
+ bc->bl_pos->bc = NULL;
+ }
+ }
+ if (NULL != bc->task)
+ {
+ GNUNET_SCHEDULER_cancel (bc->task);
+ bc->task = NULL;
+ }
+ if (NULL != bc->th)
+ {
+ GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
+ bc->th = NULL;
+ }
+ GNUNET_free_non_null (bc->address);
+ GNUNET_free (bc);
}
-
/* end of file gnunet-service-transport_blacklist.c */