/**
* @file transport/gnunet-service-transport_blacklist.c
* @brief blacklisting implementation
- * @author Christian Grothoff
+ * @author Christian Grothoff, 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.
*/
*/
int waiting_for_reply;
+ /**
+ * GNUNET_YES if we have to call receive_done for this client
+ */
+ int call_receive_done;
+
};
* 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;
/**
}
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);
* @param option name of the option
* @param value value of the option
*/
-static void
+static void
blacklist_cfg_iter (void *cls, const char *section,
const char *option,
const char *value)
char *plugs;
char *pos;
- if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string2 (option,
- strlen (option),
- &peer.hashPubKey))
+ if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (option,
+ strlen (option),
+ &peer.public_key))
return;
-
+
if ((NULL == value) || (0 == strcmp(value, "")))
{
/* Blacklist whole peer */
char cfg_sect[512];
unsigned int res = 0;
- GNUNET_snprintf (cfg_sect,
+ GNUNET_snprintf (cfg_sect,
sizeof (cfg_sect),
- "transport-blacklist-%s",
+ "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,
* @return GNUNET_OK (continue to iterate)
*/
static int
-free_blacklist_entry (void *cls, const struct GNUNET_HashCode * key, void *value)
+free_blacklist_entry (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
{
char *be = value;
{
if (NULL != blacklist)
{
- GNUNET_CONTAINER_multihashmap_iterate (blacklist, &free_blacklist_entry,
+ GNUNET_CONTAINER_multipeermap_iterate (blacklist, &free_blacklist_entry,
NULL);
- GNUNET_CONTAINER_multihashmap_destroy (blacklist);
+ GNUNET_CONTAINER_multipeermap_destroy (blacklist);
blacklist = NULL;
}
}
return 0;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending blacklist test for peer `%s' to client\n",
- GNUNET_i2s (&bc->peer));
+ "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);
+ 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);
}
struct Blacklisters *bl;
};
-
/**
* Test if an existing connection is still acceptable given a new
* blacklisting client.
*
* @param cls the 'struct TestConnectionContest'
- * @param neighbour neighbour's identity
+ * @param peer neighbour's identity
* @param address the address
- * @param bandwidth_in inbound quota in NBO
- * @param bandwidth_out outbound quota in NBO
+ * @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_HELLO_Address *address,
- struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
- struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
+test_connection_ok (void *cls, 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 GST_BlacklistCheck *bc;
- bc = GNUNET_malloc (sizeof (struct GST_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->cont = &confirm_or_drop_neighbour;
bc->cont_cls = NULL;
bc->bl_pos = tcc->bl;
}
bl = bl->next;
}
+
GNUNET_SERVER_client_mark_monitor (client);
- bl = GNUNET_malloc (sizeof (struct Blacklisters));
+ 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_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;
if (bl == NULL)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
- /* FIXME: other error handling here!? */
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;
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
"Blacklist check failed, peer not allowed\n");
bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO);
GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
+ GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
+ bl->call_receive_done = GNUNET_NO;
GNUNET_free (bc);
+ return;
}
else
{
bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
}
}
- /* check if any other bc's are waiting for this blacklister */
- bc = bc_head;
+ /* 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) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
{
GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
const char *transport_name)
{
- char * transport = NULL;
+ char * transport = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Adding peer `%s' with plugin `%s' to blacklist\n",
- GNUNET_i2s (peer), transport_name);
+ 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 (blacklist == NULL)
blacklist =
- GNUNET_CONTAINER_multihashmap_create (TRANSPORT_BLACKLIST_HT_SIZE,
+ GNUNET_CONTAINER_multipeermap_create (TRANSPORT_BLACKLIST_HT_SIZE,
GNUNET_NO);
- if (NULL != transport_name)
- transport = GNUNET_strdup ("");
- GNUNET_CONTAINER_multihashmap_put (blacklist, &peer->hashPubKey,
+ GNUNET_CONTAINER_multipeermap_put (blacklist, peer,
transport,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
}
* @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 struct GNUNET_HashCode * key, void *value)
+test_blacklisted (void *cls,
+ const struct GNUNET_PeerIdentity *key,
+ void *value)
{
const char *transport_name = cls;
char *be = value;
- /* blacklist check for specific no specific transport*/
- if (transport_name == NULL)
- return GNUNET_NO;
- /* all plugins for this peer were blacklisted */
+ /* 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;
+ return GNUNET_NO;
/* blacklist check for specific transport */
- if (0 == strcmp (transport_name, be))
- return GNUNET_NO; /* abort iteration! */
+ if ((NULL != transport_name) && (NULL != value))
+ {
+ if (0 == strcmp (transport_name, be))
+ return GNUNET_NO; /* plugin is blacklisted! */
+ }
return GNUNET_OK;
}
struct GST_BlacklistCheck *bc;
GNUNET_assert (peer != NULL);
+ 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 ((blacklist != NULL) &&
(GNUNET_SYSERR ==
- GNUNET_CONTAINER_multihashmap_get_multiple (blacklist, &peer->hashPubKey,
+ GNUNET_CONTAINER_multipeermap_get_multiple (blacklist, peer,
&test_blacklisted,
(void *) transport_name)))
{
- /* disallowed by config, disapprove instantly */
+ /* 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 (cont != NULL)
cont (cont_cls, peer, GNUNET_NO);
return NULL;
/* no blacklist clients, approve instantly */
if (cont != NULL)
cont (cont_cls, peer, 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 GST_BlacklistCheck));
+ bc = GNUNET_new (struct GST_BlacklistCheck);
GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
bc->peer = *peer;
bc->cont = cont;