/** * Force plugin to terminate session due to communication * issue. * * @param plugin_name name of the plugin * @param session session to termiante */ static void kill_session (const char *plugin_name, struct GNUNET_ATS_Session *session) { struct GNUNET_TRANSPORT_PluginFunctions *plugin; struct GNUNET_ATS_SessionKiller *sk; for (sk = sk_head; NULL != sk; sk = sk->next) if (sk->session == session) return; plugin = GST_plugins_find (plugin_name); if (NULL == plugin) { GNUNET_break(0); return; } /* need to issue disconnect asynchronously */ sk = GNUNET_new (struct GNUNET_ATS_SessionKiller); sk->session = session; sk->plugin = plugin; sk->task = GNUNET_SCHEDULER_add_now (&kill_session_task, sk); GNUNET_CONTAINER_DLL_insert (sk_head, sk_tail, sk); }
/** * Send the given PONG to the given address. * * @param cls the PONG message * @param public_key public key for the peer, never NULL * @param valid_until is ZERO if we never validated the address, * otherwise a time up to when we consider it (or was) valid * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO) * is ZERO if the address is considered valid (no validation needed) * otherwise a time in the future if we're currently denying re-validation * @param address target address */ static void multicast_pong (void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, struct GNUNET_TIME_Absolute valid_until, struct GNUNET_TIME_Absolute validation_block, const struct GNUNET_HELLO_Address *address) { struct TransportPongMessage *pong = cls; struct GNUNET_TRANSPORT_PluginFunctions *papi; papi = GST_plugins_find (address->transport_name); if (papi == NULL) return; GNUNET_assert (papi->send != NULL); GNUNET_assert (papi->get_session != NULL); struct Session * session = papi->get_session(papi->cls, address); if (session == NULL) { GNUNET_break (0); return; } papi->send (papi->cls, session, (const char *) pong, ntohs (pong->header.size), PONG_PRIORITY, ACCEPTABLE_PING_DELAY, NULL, NULL); }
/** * Convert a given address to a human-readable format. Note that the * return value will be overwritten on the next call to this function. * * @param address the address to convert * @return statically allocated (!) human-readable address */ const char * GST_plugins_a2s (const struct GNUNET_HELLO_Address *address) { struct GNUNET_TRANSPORT_PluginFunctions *api; static char unable_to_show[1024]; if (address == NULL) return "<inbound>"; api = GST_plugins_find (address->transport_name); if (NULL == api) return "<plugin unknown>"; if (0 == address->address_length) { GNUNET_snprintf (unable_to_show, sizeof (unable_to_show), "<unable to stringify %u-byte long address of %s transport>", (unsigned int) address->address_length, address->transport_name); return unable_to_show; } return api->address_to_string (NULL, address->address, address->address_length); }
/** * We've received a PING. If appropriate, generate a PONG. * * @param sender peer sending the PING * @param hdr the PING * @param sender_address the sender address as we got it * @param session session we got the PING from */ void GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_MessageHeader *hdr, const struct GNUNET_HELLO_Address *sender_address, struct Session *session) { const struct TransportPingMessage *ping; struct TransportPongMessage *pong; struct GNUNET_TRANSPORT_PluginFunctions *papi; struct GNUNET_CRYPTO_RsaSignature *sig_cache; struct GNUNET_TIME_Absolute *sig_cache_exp; const char *addr; const char *addrend; size_t alen; size_t slen; ssize_t ret; struct GNUNET_HELLO_Address address; if (ntohs (hdr->size) < sizeof (struct TransportPingMessage)) { GNUNET_break_op (0); return; } ping = (const struct TransportPingMessage *) hdr; if (0 != memcmp (&ping->target, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PING message for different peer received"), 1, GNUNET_NO); return; } GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PING messages received"), 1, GNUNET_NO); addr = (const char *) &ping[1]; alen = ntohs (hdr->size) - sizeof (struct TransportPingMessage); /* peer wants to confirm that this is one of our addresses, this is what is * used for address validation */ sig_cache = NULL; sig_cache_exp = NULL; if (0 < alen) { addrend = memchr (addr, '\0', alen); if (NULL == addrend) { GNUNET_break_op (0); return; } addrend++; slen = strlen (addr) + 1; alen -= slen; address.address = addrend; address.address_length = alen; address.transport_name = addr; address.peer = *sender; if (GNUNET_YES != GST_hello_test_address (&address, &sig_cache, &sig_cache_exp)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Not confirming PING with address `%s' since I cannot confirm having this address.\n"), GST_plugins_a2s (&address)); return; } } else { addrend = NULL; /* make gcc happy */ slen = 0; static struct GNUNET_CRYPTO_RsaSignature no_address_signature; static struct GNUNET_TIME_Absolute no_address_signature_expiration; sig_cache = &no_address_signature; sig_cache_exp = &no_address_signature_expiration; } pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen); pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen); pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG); pong->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + alen + slen); pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN); pong->challenge = ping->challenge; pong->addrlen = htonl (alen + slen); memcpy (&pong[1], addr, slen); memcpy (&((char *) &pong[1])[slen], addrend, alen); if (GNUNET_TIME_absolute_get_remaining (*sig_cache_exp).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) { /* create / update cached sig */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating PONG signature to indicate ownership.\n"); *sig_cache_exp = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME); pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (GST_my_private_key, &pong->purpose, sig_cache)); } else { pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp); } pong->signature = *sig_cache; GNUNET_assert (sender_address != NULL); /* first see if the session we got this PING from can be used to transmit * a response reliably */ papi = GST_plugins_find (sender_address->transport_name); if (papi == NULL) ret = -1; else { GNUNET_assert (papi->send != NULL); GNUNET_assert (papi->get_session != NULL); if (session == NULL) { session = papi->get_session (papi->cls, sender_address); } if (session == NULL) { GNUNET_break (0); ret = -1; } else { ret = papi->send (papi->cls, session, (const char *) pong, ntohs (pong->header.size), PONG_PRIORITY, ACCEPTABLE_PING_DELAY, NULL, NULL); } } if (ret != -1) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitted PONG to `%s' via reliable mechanism\n", GNUNET_i2s (sender)); /* done! */ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PONGs unicast via reliable transport"), 1, GNUNET_NO); GNUNET_free (pong); return; } /* no reliable method found, try transmission via all known addresses */ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PONGs multicast to all available addresses"), 1, GNUNET_NO); GST_validation_get_addresses (sender, &multicast_pong, pong); GNUNET_free (pong); }
/** * Function called with the result from blacklisting. * Send a PING to the other peer if a communication is allowed. * * @param cls our 'struct ValidationEntry' * @param pid identity of the other peer * @param result GNUNET_OK if the connection is allowed, GNUNET_NO if not */ static void transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid, int result) { struct ValidationEntry *ve = cls; struct TransportPingMessage ping; struct GNUNET_TRANSPORT_PluginFunctions *papi; const struct GNUNET_MessageHeader *hello; ssize_t ret; size_t tsize; size_t slen; uint16_t hsize; ve->bc = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s' %s\n", GNUNET_i2s (pid), GST_plugins_a2s (ve->address)); slen = strlen (ve->address->transport_name) + 1; hello = GST_hello_get (); hsize = ntohs (hello->size); tsize = sizeof (struct TransportPingMessage) + ve->address->address_length + slen + hsize; ping.header.size = htons (sizeof (struct TransportPingMessage) + ve->address->address_length + slen); ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING); ping.challenge = htonl (ve->challenge); ping.target = *pid; if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Not transmitting `%s' with `%s', message too big (%u bytes!). This should not happen.\n"), "HELLO", "PING", (unsigned int) tsize); /* message too big (!?), get rid of HELLO */ hsize = 0; tsize = sizeof (struct TransportPingMessage) + ve->address->address_length + slen + hsize; } { char message_buf[tsize]; /* build message with structure: * [HELLO][TransportPingMessage][Transport name][Address] */ memcpy (message_buf, hello, hsize); memcpy (&message_buf[hsize], &ping, sizeof (struct TransportPingMessage)); memcpy (&message_buf[sizeof (struct TransportPingMessage) + hsize], ve->address->transport_name, slen); memcpy (&message_buf[sizeof (struct TransportPingMessage) + slen + hsize], ve->address, ve->address->address_length); papi = GST_plugins_find (ve->address->transport_name); if (papi == NULL) ret = -1; else { GNUNET_assert (papi->send != NULL); GNUNET_assert (papi->get_session != NULL); struct Session * session = papi->get_session(papi->cls, ve->address); if (session != NULL) { ret = papi->send (papi->cls, session, message_buf, tsize, PING_PRIORITY, ACCEPTABLE_PING_DELAY, NULL, NULL); } else { /* Could not get a valid session */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not get a valid session for `%s' %s\n", GNUNET_i2s (pid), GST_plugins_a2s (ve->address)); ret = -1; } } } if (-1 != ret) { ve->send_time = GNUNET_TIME_absolute_get (); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# PING without HELLO messages sent"), 1, GNUNET_NO); ve->expecting_pong = GNUNET_YES; } }