From 2134d1a1eaa421d42e93ce0be1f718758c4a6e4b Mon Sep 17 00:00:00 2001 From: Matthias Wachs Date: Thu, 16 Jan 2014 17:02:54 +0000 Subject: [PATCH] perform blacklist before address switch this commit adds the blacklist check before address switch in the next step the old blacklist check has to be removed --- .../gnunet-service-transport_neighbours.c | 381 +++++++++++------- 1 file changed, 244 insertions(+), 137 deletions(-) diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c index ad649ec0a..871b6c2cf 100644 --- a/src/transport/gnunet-service-transport_neighbours.c +++ b/src/transport/gnunet-service-transport_neighbours.c @@ -462,6 +462,16 @@ static struct BlackListCheckContext *bc_head; */ static struct BlackListCheckContext *bc_tail; +/** + * List of pending blacklist checks: head + */ +static struct BlacklistCheckSwitchContext *pending_bc_head; + +/** + * List of pending blacklist checks: tail + */ +static struct BlacklistCheckSwitchContext *pending_bc_tail; + /** * Closure for #connect_notify_cb, #disconnect_notify_cb and #neighbour_change_cb */ @@ -2240,94 +2250,75 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message, return GNUNET_OK; } +struct BlacklistCheckSwitchContext +{ + struct BlacklistCheckSwitchContext *prev; + struct BlacklistCheckSwitchContext *next; -/** - * For an existing neighbour record, set the active connection to - * use the given address. - * - * @param peer identity of the peer to switch the address for - * @param address address of the other peer, NULL if other peer - * connected to us - * @param session session to use (or NULL) - * @param ats performance data - * @param ats_count number of entries in ats - * @param bandwidth_in inbound quota to be used when connection is up, - * 0 to disconnect from peer - * @param bandwidth_out outbound quota to be used when connection is up, - * 0 to disconnect from peer - */ -void -GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Address *address, - struct Session *session, - const struct GNUNET_ATS_Information *ats, - uint32_t ats_count, - struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, - struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) + struct GNUNET_HELLO_Address *address; + struct Session *session; + struct GNUNET_ATS_Information *ats; + uint32_t ats_count; + + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in; + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out; +}; + +static void +switch_address_bl_check_cont (void *cls, + const struct GNUNET_PeerIdentity *peer, int result) { - struct NeighbourMapEntry *n; + struct BlacklistCheckSwitchContext *blc_ctx = cls; struct GNUNET_TRANSPORT_PluginFunctions *papi; + struct NeighbourMapEntry *n; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "ATS has decided on an address for peer %s\n", - GNUNET_i2s (peer)); - GNUNET_assert (NULL != address->transport_name); - if (NULL == (n = lookup_neighbour (peer))) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Peer %s is unknown, suggestion ignored\n", - GNUNET_i2s (peer)); - return; - } - /* Obtain an session for this address from plugin */ - if (NULL == (papi = GST_plugins_find (address->transport_name))) - { - /* we don't have the plugin for this address */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Plugin `%s' is unknown, suggestion for peer %s ignored\n", - address->transport_name, - GNUNET_i2s (peer)); - GNUNET_ATS_address_destroyed (GST_ats, address, NULL); - return; - } - if ((NULL == session) && - (GNUNET_HELLO_address_check_option (address, GNUNET_HELLO_ADDRESS_INFO_INBOUND))) + if ( (NULL == (n = lookup_neighbour (peer))) || (result == GNUNET_NO) || + (NULL == (papi = GST_plugins_find (blc_ctx->address->transport_name))) ) { - /* This is a inbound address and we do not have a session to use! */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Inbound address without session `%s'! Destroying address...\n", - GST_plugins_a2s (address)); - GNUNET_ATS_address_destroyed (GST_ats, address, NULL); + if (NULL == n) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %s is unknown, suggestion ignored\n", + GNUNET_i2s (peer)); + } + if (result == GNUNET_NO) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklist denied to switch to suggested address `%s' sesion %p for peer `%s'\n", + GST_plugins_a2s (blc_ctx->address), + blc_ctx->session, + GNUNET_i2s (&blc_ctx->address->peer)); + } + /* Delete address (or session if existing) in ATS */ + GNUNET_ATS_address_destroyed (GST_ats, blc_ctx->address, blc_ctx->session); + + GNUNET_CONTAINER_DLL_remove (pending_bc_head, pending_bc_tail, blc_ctx); + GNUNET_HELLO_address_free(blc_ctx->address); + GNUNET_free_non_null (blc_ctx->ats); + GNUNET_free (blc_ctx); return; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "ATS tells us to switch to %s address '%s' session %p for " - "peer `%s' in state %s/%d (quota in/out %u %u )\n", - GNUNET_HELLO_address_check_option (address, - GNUNET_HELLO_ADDRESS_INFO_INBOUND) ? "inbound" : "", - GST_plugins_a2s (address), - session, - GNUNET_i2s (peer), - GNUNET_TRANSPORT_ps2s (n->state), - n->send_connect_ack, - ntohl (bandwidth_in.value__), - ntohl (bandwidth_out.value__)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklist accepted to switch to suggested address `%s' for peer `%s'\n", + GST_plugins_a2s (blc_ctx->address), + blc_ctx->session, + GNUNET_i2s (&blc_ctx->address->peer)); - if (NULL == session) + if (NULL == blc_ctx->session) { - session = papi->get_session (papi->cls, address); + blc_ctx->session = papi->get_session (papi->cls, blc_ctx->address); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Obtained new session for peer `%s' and address '%s': %p\n", - GNUNET_i2s (&address->peer), GST_plugins_a2s (address), session); + GNUNET_i2s (&blc_ctx->address->peer), GST_plugins_a2s (blc_ctx->address), blc_ctx->session); } - if (NULL == session) + if (NULL == blc_ctx->session) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to obtain new session for peer `%s' and address '%s'\n", - GNUNET_i2s (&address->peer), GST_plugins_a2s (address)); - GNUNET_ATS_address_destroyed (GST_ats, address, NULL); + "Failed to obtain new session for peer `%s' and address '%s'\n", + GNUNET_i2s (&blc_ctx->address->peer), GST_plugins_a2s (blc_ctx->address)); + GNUNET_ATS_address_destroyed (GST_ats, blc_ctx->address, NULL); return; } switch (n->state) @@ -2337,102 +2328,101 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, free_neighbour (n, GNUNET_NO); return; case GNUNET_TRANSPORT_PS_INIT_ATS: - set_primary_address (n, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); - set_state_and_timeout (n, GNUNET_TRANSPORT_PS_INIT_BLACKLIST, GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); - check_blacklist (&n->id, - n->connect_ack_timestamp, - address, session); + set_primary_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out, GNUNET_NO); + set_state_and_timeout (n, GNUNET_TRANSPORT_PS_INIT_BLACKLIST, + GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); + check_blacklist (&n->id, n->connect_ack_timestamp, + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_INIT_BLACKLIST: /* ATS suggests a different address, switch again */ - set_primary_address (n, - address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + set_primary_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out, GNUNET_NO); set_timeout (n, GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); - check_blacklist (&n->id, - n->connect_ack_timestamp, - address, session); + check_blacklist (&n->id, n->connect_ack_timestamp, + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_CONNECT_SENT: /* ATS suggests a different address, switch again */ - set_primary_address (n, address, session, bandwidth_in, bandwidth_out, GNUNET_NO); - set_state_and_timeout (n, GNUNET_TRANSPORT_PS_INIT_BLACKLIST, GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); - check_blacklist (&n->id, - n->connect_ack_timestamp, - address, session); + set_primary_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out, GNUNET_NO); + set_state_and_timeout (n, GNUNET_TRANSPORT_PS_INIT_BLACKLIST, + GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); + check_blacklist (&n->id, n->connect_ack_timestamp, + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_CONNECT_RECV_ATS: - set_primary_address (n, - address, session, bandwidth_in, bandwidth_out, GNUNET_NO); - set_state_and_timeout (n, GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST, GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); - check_blacklist (&n->id, - n->connect_ack_timestamp, - address, session); + set_primary_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out, GNUNET_NO); + set_state_and_timeout (n, GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST, + GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); + check_blacklist (&n->id, n->connect_ack_timestamp, + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST_INBOUND: set_timeout (n, GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); - check_blacklist (&n->id, - n->connect_ack_timestamp, - address, session); + check_blacklist (&n->id, n->connect_ack_timestamp, + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST: case GNUNET_TRANSPORT_PS_CONNECT_RECV_ACK: /* ATS asks us to switch while we were trying to connect; switch to new address and check blacklist again */ - set_primary_address (n, - address, session, bandwidth_in, bandwidth_out, GNUNET_NO); - set_state_and_timeout (n, GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST, GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); - check_blacklist (&n->id, - n->connect_ack_timestamp, - address, session); + set_primary_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out, GNUNET_NO); + set_state_and_timeout (n, GNUNET_TRANSPORT_PS_CONNECT_RECV_BLACKLIST, + GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); + check_blacklist (&n->id, n->connect_ack_timestamp, + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_CONNECTED: GNUNET_assert (NULL != n->primary_address.address); GNUNET_assert (NULL != n->primary_address.session); - if (n->primary_address.session == session) + if (n->primary_address.session == blc_ctx->session) { /* not an address change, just a quota change */ - set_primary_address (n, - address, session, bandwidth_in, bandwidth_out, GNUNET_YES); + set_primary_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out, GNUNET_YES); break; } /* ATS asks us to switch a life connection; see if we can get a CONNECT_ACK on it before we actually do this! */ set_state (n, GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_BLACKLIST); - set_alternative_address (n, address, session, bandwidth_in, bandwidth_out); - check_blacklist (&n->id, - GNUNET_TIME_absolute_get (), - address, session); + set_alternative_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out); + check_blacklist (&n->id, GNUNET_TIME_absolute_get (), + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_RECONNECT_ATS: - set_primary_address (n, - address, session, bandwidth_in, bandwidth_out, GNUNET_NO); - set_state_and_timeout (n, GNUNET_TRANSPORT_PS_RECONNECT_BLACKLIST, GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); - check_blacklist (&n->id, - n->connect_ack_timestamp, - address, session); + set_primary_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out, GNUNET_NO); + set_state_and_timeout (n, GNUNET_TRANSPORT_PS_RECONNECT_BLACKLIST, + GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); + check_blacklist (&n->id, n->connect_ack_timestamp, + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_RECONNECT_BLACKLIST: /* ATS asks us to switch while we were trying to reconnect; switch to new address and check blacklist again */ - set_primary_address (n, - address, session, bandwidth_in, bandwidth_out, GNUNET_NO); + set_primary_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out, GNUNET_NO); set_timeout (n, GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); - check_blacklist (&n->id, - n->connect_ack_timestamp, - address, session); + check_blacklist (&n->id, n->connect_ack_timestamp, + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_RECONNECT_SENT: /* ATS asks us to switch while we were trying to reconnect; switch to new address and check blacklist again */ - set_primary_address (n, - address, session, bandwidth_in, bandwidth_out, GNUNET_NO); - set_state_and_timeout (n, GNUNET_TRANSPORT_PS_RECONNECT_BLACKLIST, GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); - check_blacklist (&n->id, - n->connect_ack_timestamp, - address, session); + set_primary_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out, GNUNET_NO); + set_state_and_timeout (n, GNUNET_TRANSPORT_PS_RECONNECT_BLACKLIST, + GNUNET_TIME_relative_to_absolute (BLACKLIST_RESPONSE_TIMEOUT)); + check_blacklist (&n->id, n->connect_ack_timestamp, + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_BLACKLIST: - if (n->primary_address.session == session) + if (n->primary_address.session == blc_ctx->session) { /* ATS switches back to still-active session */ set_state(n, GNUNET_TRANSPORT_PS_CONNECTED); @@ -2440,14 +2430,13 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, break; } /* ATS asks us to switch a life connection, update blacklist check */ - set_primary_address (n, - address, session, bandwidth_in, bandwidth_out, GNUNET_NO); - check_blacklist (&n->id, - GNUNET_TIME_absolute_get (), - address, session); + set_primary_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out, GNUNET_NO); + check_blacklist (&n->id, GNUNET_TIME_absolute_get (), + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_CONNECT_SENT: - if (n->primary_address.session == session) + if (n->primary_address.session == blc_ctx->session) { /* ATS switches back to still-active session */ free_address (&n->alternative_address); @@ -2456,10 +2445,10 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, } /* ATS asks us to switch a life connection, update blacklist check */ set_state (n, GNUNET_TRANSPORT_PS_CONNECTED_SWITCHING_BLACKLIST); - set_alternative_address (n, address, session, bandwidth_in, bandwidth_out); - check_blacklist (&n->id, - GNUNET_TIME_absolute_get (), - address, session); + set_alternative_address (n, blc_ctx->address, blc_ctx->session, + blc_ctx->bandwidth_in, blc_ctx->bandwidth_out); + check_blacklist (&n->id, GNUNET_TIME_absolute_get (), + blc_ctx->address, blc_ctx->session); break; case GNUNET_TRANSPORT_PS_DISCONNECT: /* not going to switch addresses while disconnecting */ @@ -2474,6 +2463,109 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, GNUNET_break (0); break; } + + GNUNET_CONTAINER_DLL_remove (pending_bc_head, pending_bc_tail, blc_ctx); + GNUNET_HELLO_address_free(blc_ctx->address); + GNUNET_free_non_null (blc_ctx->ats); + GNUNET_free (blc_ctx); + return; +} + + +/** + * For the given peer, switch to this address. + * + * Before accepting this addresses and actively using it, a blacklist check + * is performed. If this blacklist check fails the address will be destroyed. + * + * @param peer identity of the peer to switch the address for + * @param address address of the other peer, + * @param session session to use or NULL if transport should initiate a session + * @param ats performance data + * @param ats_count number of entries in ats + * @param bandwidth_in inbound quota to be used when connection is up, + * 0 to disconnect from peer + * @param bandwidth_out outbound quota to be used when connection is up, + * 0 to disconnect from peer + */ +void +GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct Session *session, + const struct GNUNET_ATS_Information *ats, + uint32_t ats_count, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, + struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) +{ + struct NeighbourMapEntry *n; + struct GNUNET_TRANSPORT_PluginFunctions *papi; + struct BlacklistCheckSwitchContext *blc_ctx; + int c; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "ATS has decided on an address for peer %s\n", + GNUNET_i2s (peer)); + GNUNET_assert (NULL != address->transport_name); + if (NULL == (n = lookup_neighbour (peer))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer %s is unknown, suggestion ignored\n", + GNUNET_i2s (peer)); + return; + } + + /* Obtain an session for this address from plugin */ + if (NULL == (papi = GST_plugins_find (address->transport_name))) + { + /* we don't have the plugin for this address */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Plugin `%s' is unknown, suggestion for peer %s ignored\n", + address->transport_name, + GNUNET_i2s (peer)); + GNUNET_ATS_address_destroyed (GST_ats, address, NULL); + return; + } + if ((NULL == session) && + (GNUNET_HELLO_address_check_option (address, GNUNET_HELLO_ADDRESS_INFO_INBOUND))) + { + /* This is a inbound address and we do not have a session to use! */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Inbound address without session `%s'! Destroying address...\n", + GST_plugins_a2s (address)); + GNUNET_ATS_address_destroyed (GST_ats, address, NULL); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "ATS tells us to switch to %s address '%s' session %p for " + "peer `%s' in state %s/%d (quota in/out %u %u )\n", + GNUNET_HELLO_address_check_option (address, + GNUNET_HELLO_ADDRESS_INFO_INBOUND) ? "inbound" : "", + GST_plugins_a2s (address), session, GNUNET_i2s (peer), + GNUNET_TRANSPORT_ps2s (n->state), n->send_connect_ack, + ntohl (bandwidth_in.value__), ntohl (bandwidth_out.value__)); + + /* Perform blacklist check */ + blc_ctx = GNUNET_new (struct BlacklistCheckSwitchContext); + blc_ctx->address = GNUNET_HELLO_address_copy (address); + blc_ctx->session = session; + blc_ctx->bandwidth_in = bandwidth_in; + blc_ctx->bandwidth_out = bandwidth_out; + blc_ctx->ats_count = ats_count; + blc_ctx->ats = NULL; + if (ats_count > 0) + { + blc_ctx->ats = GNUNET_malloc (ats_count * sizeof (struct GNUNET_ATS_Information)); + for (c = 0; c < ats_count; c++) + { + blc_ctx->ats[c].type = ats[c].type; + blc_ctx->ats[c].value = ats[c].value; + } + } + + GNUNET_CONTAINER_DLL_insert (pending_bc_head, pending_bc_tail, blc_ctx); + GST_blacklist_test_allowed (peer, address->transport_name, + &switch_address_bl_check_cont, blc_ctx); } @@ -3549,6 +3641,9 @@ disconnect_all_neighbours (void *cls, void GST_neighbours_stop () { + struct BlacklistCheckSwitchContext *cur; + struct BlacklistCheckSwitchContext *next; + if (NULL == neighbours) return; if (GNUNET_SCHEDULER_NO_TASK != util_transmission_tk) @@ -3561,6 +3656,18 @@ GST_neighbours_stop () &disconnect_all_neighbours, NULL); GNUNET_CONTAINER_multipeermap_destroy (neighbours); + + next = pending_bc_head; + for (cur = next; NULL != cur; cur = next ) + { + next = cur->next; + + GNUNET_CONTAINER_DLL_remove (pending_bc_head, pending_bc_tail, cur); + GNUNET_HELLO_address_free (cur->address); + GNUNET_free_non_null (cur->ats); + GNUNET_free (cur); + } + neighbours = NULL; callback_cls = NULL; connect_notify_cb = NULL; -- 2.25.1