From ca1cd117f6a59c0d19f841f72ac37340284ada57 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 6 Oct 2011 21:32:05 +0000 Subject: [PATCH] towards KX --- src/core/gnunet-service-core-new.c | 31 - src/core/gnunet-service-core_kx.c | 1307 ++++++++------------- src/core/gnunet-service-core_kx.h | 112 +- src/core/gnunet-service-core_neighbours.c | 6 +- src/core/gnunet-service-core_neighbours.h | 2 +- src/core/gnunet-service-core_sessions.c | 117 +- src/core/gnunet-service-core_sessions.h | 22 + 7 files changed, 699 insertions(+), 898 deletions(-) diff --git a/src/core/gnunet-service-core-new.c b/src/core/gnunet-service-core-new.c index d67ae47b5..afdc22d9d 100644 --- a/src/core/gnunet-service-core-new.c +++ b/src/core/gnunet-service-core-new.c @@ -145,37 +145,6 @@ #define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS -/** - * State machine for our P2P encryption handshake. Everyone starts in - * "DOWN", if we receive the other peer's key (other peer initiated) - * we start in state RECEIVED (since we will immediately send our - * own); otherwise we start in SENT. If we get back a PONG from - * within either state, we move up to CONFIRMED (the PONG will always - * be sent back encrypted with the key we sent to the other peer). - */ -enum PeerStateMachine -{ - /** - * No handshake yet. - */ - PEER_STATE_DOWN, - - /** - * We've sent our session key. - */ - PEER_STATE_KEY_SENT, - - /** - * We've received the other peers session key. - */ - PEER_STATE_KEY_RECEIVED, - - /** - * The other peer has confirmed our session key with a message - * encrypted with his session key (which we got). Session is now fully up. - */ - PEER_STATE_KEY_CONFIRMED -}; /** * Number of bytes (at the beginning) of "struct EncryptedMessage" diff --git a/src/core/gnunet-service-core_kx.c b/src/core/gnunet-service-core_kx.c index 1ab31cb2b..efc6ca1c2 100644 --- a/src/core/gnunet-service-core_kx.c +++ b/src/core/gnunet-service-core_kx.c @@ -199,6 +199,10 @@ static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; */ static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; +/** + * Our message stream tokenizer (for encrypted payload). + */ +static struct GNUNET_SERVER_MessageStreamTokenizer *mst; @@ -258,7 +262,7 @@ derive_pong_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, * Encrypt size bytes from in and write the result to out. Use the * key for outbound traffic of the given neighbour. * - * @param n neighbour we are sending to + * @param kx key information context * @param iv initialization vector to use * @param in ciphertext * @param out plaintext @@ -266,7 +270,7 @@ derive_pong_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv, * @return GNUNET_OK on success */ static int -do_encrypt (struct Neighbour *n, +do_encrypt (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_CRYPTO_AesInitializationVector *iv, const void *in, void *out, size_t size) { @@ -277,14 +281,14 @@ do_encrypt (struct Neighbour *n, } GNUNET_assert (size == GNUNET_CRYPTO_aes_encrypt (in, (uint16_t) size, - &n->encrypt_key, iv, out)); + &kx->encrypt_key, iv, out)); GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes encrypted"), size, GNUNET_NO); #if DEBUG_CORE > 2 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted %u bytes for `%4s' using key %u, IV %u\n", - (unsigned int) size, GNUNET_i2s (&n->peer), - (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv, + (unsigned int) size, GNUNET_i2s (&kx->peer), + (unsigned int) kx->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv, sizeof (iv))); #endif @@ -299,7 +303,7 @@ do_encrypt (struct Neighbour *n, * key for inbound traffic of the given neighbour. This function does * NOT do any integrity-checks on the result. * - * @param n neighbour we are receiving from + * @param kx key information context * @param iv initialization vector to use * @param in ciphertext * @param out plaintext @@ -307,7 +311,7 @@ do_encrypt (struct Neighbour *n, * @return GNUNET_OK on success */ static int -do_decrypt (struct Neighbour *n, +do_decrypt (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_CRYPTO_AesInitializationVector *iv, const void *in, void *out, size_t size) { @@ -316,14 +320,14 @@ do_decrypt (struct Neighbour *n, GNUNET_break (0); return GNUNET_NO; } - if ((n->status != PEER_STATE_KEY_RECEIVED) && - (n->status != PEER_STATE_KEY_CONFIRMED)) + if ((kx->status != KX_STATE_KEY_RECEIVED) && + (kx->status != KX_STATE_UP)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if (size != - GNUNET_CRYPTO_aes_decrypt (in, (uint16_t) size, &n->decrypt_key, iv, out)) + GNUNET_CRYPTO_aes_decrypt (in, (uint16_t) size, &kx->decrypt_key, iv, out)) { GNUNET_break (0); return GNUNET_SYSERR; @@ -333,8 +337,8 @@ do_decrypt (struct Neighbour *n, #if DEBUG_CORE > 1 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decrypted %u bytes from `%4s' using key %u, IV %u\n", - (unsigned int) size, GNUNET_i2s (&n->peer), - (unsigned int) n->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv, + (unsigned int) size, GNUNET_i2s (&kx->peer), + (unsigned int) kx->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv, sizeof (*iv))); #endif @@ -342,6 +346,104 @@ do_decrypt (struct Neighbour *n, } + +/** + * Task that will retry "send_key" if our previous attempt failed. + * + * @param cls our 'struct GSC_KeyExchangeInfo' + * @param tc scheduler context + */ +static void +set_key_retry_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GSC_KeyExchangeInfo *kx = cls; + + kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; + kx->set_key_retry_frequency = GNUNET_TIME_relative_multiply (kx->set_key_retry_frequency, 2); + send_key (kx); +} + + +/** + * PEERINFO is giving us a HELLO for a peer. Add the public key to + * the neighbour's struct and continue with the key exchange. Or, if + * we did not get a HELLO, just do nothing. + * + * @param cls the 'struct GSC_KeyExchangeInfo' to retry sending the key for + * @param peer the peer for which this is the HELLO + * @param hello HELLO message of that peer + * @param err_msg NULL if successful, otherwise contains error message + */ +static void +process_hello (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Message *hello, + const char *err_msg) +{ + struct GSC_KeyExchangeInfo *kx = cls; + struct SetKeyMessage *skm; + + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->retry_set_key_task); + if (err_msg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Error in communication with PEERINFO service\n")); + kx->pitr = NULL; + return; + } + if (peer == NULL) + { + kx->pitr = NULL; + if (kx->public_key != NULL) + return; /* done here */ +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to obtain public key for peer `%4s', delaying processing of SET_KEY\n", + GNUNET_i2s (&kx->peer)); +#endif + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# Delayed connecting due to lack of public key"), + 1, GNUNET_NO); + kx->retry_set_key_task = + GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency, + &set_key_retry_task, kx); + return; + } + if (kx->public_key != NULL) + { + /* already have public key, why are we here? */ + GNUNET_break (0); + return; + } + kx->public_key = + GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + if (GNUNET_OK != GNUNET_HELLO_get_key (hello, n->public_key)) + { + GNUNET_break (0); + GNUNET_free (kx->public_key); + kx->public_key = NULL; + return; + } + send_key (kx); + if (NULL != kx->skm_received) + { + skm = kx->skm_received; + kx->skm_received = NULL; + GSC_KX_handle_set_key (kx, &skm->header); + GNUNET_free (skm); + } +} + + +/** + * Send our key (and encrypted PING) to the other peer. + * + * @param kx key exchange context + */ +static void +send_key (struct GSC_KeyExchangeInfo *kx); + + /** * Start the key exchange with the given peer. * @@ -353,7 +455,14 @@ GSC_KX_start (const struct GNUNET_PeerIdentity *pid) { struct GSC_KeyExchangeInfo *kx; - kx = NULL; + kx = GNUNET_malloc (sizeof (struct GSC_KeyExchangeInfo)); + kx->peer = *pid; + n->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY; + kx->pitr = GNUNET_PEERINFO_iterate (peerinfo, + pid, + GNUNET_TIME_UNIT_FOREVER_REL /* timeout? */, + &process_hello, + kx); return kx; } @@ -371,11 +480,19 @@ GSC_KX_stop (struct GSC_KeyExchangeInfo *kx) GNUNET_PEERINFO_iterate_cancel (kx->pitr); kx->pitr = NULL; } - - GNUNET_SCHEDULER_cancel (n->dead_clean_task); - if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) if (kx->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK) + { GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); + kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; + } + if (kx->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (n->keep_alive_task); + kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free_non_null (kx->skm_received); + GNUNET_free_non_null (kx->ping_received); + GNUNET_free_non_null (kx->pong_received); GNUNET_free_non_null (kx->public_key); GNUNET_free (kx); } @@ -385,15 +502,12 @@ GSC_KX_stop (struct GSC_KeyExchangeInfo *kx) * We received a SET_KEY message. Validate and update * our key material and status. * - * @param n the neighbour from which we received message m - * @param m the set key message we received - * @param ats performance data - * @param ats_count number of entries in ats (excluding 0-termination) + * @param kx key exchange status for the corresponding peer + * @param msg the set key message we received */ void -GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *n, const struct GNUNET_MessageHandler *msg, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count) +GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_MessageHandler *msg) { const struct SetKeyMessage *m; struct SetKeyMessage *m_cpy; @@ -417,43 +531,19 @@ GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *n, const struct GNUNET_Messag #if DEBUG_CORE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' request from `%4s'.\n", "SET_KEY", - GNUNET_i2s (&n->peer)); + GNUNET_i2s (&kx->peer)); #endif - if (n->public_key == NULL) + if (kx->public_key == NULL) { - if (n->pitr != NULL) - { -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Ignoring `%s' message due to lack of public key for peer (still trying to obtain one).\n", - "SET_KEY"); -#endif - return; - } -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Lacking public key for peer, trying to obtain one (handle_set_key).\n"); -#endif - m_cpy = GNUNET_malloc (sizeof (struct SetKeyMessage)); - memcpy (m_cpy, m, sizeof (struct SetKeyMessage)); - /* lookup n's public key, then try again */ - GNUNET_assert (n->skm == NULL); - n->skm = m_cpy; - n->pitr = - GNUNET_PEERINFO_iterate (peerinfo, &n->peer, GNUNET_TIME_UNIT_MINUTES, - &process_hello_retry_handle_set_key, n); - GNUNET_STATISTICS_update (stats, - gettext_noop - ("# SET_KEY messages deferred (need public key)"), - 1, GNUNET_NO); + GNUNET_free_non_null (kx->skm_received); + kx->skm_received = GNUNET_copy_message (msg); return; } if (0 != - memcmp (&m->target, &my_identity, sizeof (struct GNUNET_PeerIdentity))) + memcmp (&m->target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _ - ("Received `%s' message that was for `%s', not for me. Ignoring.\n"), + _("`%s' is for `%s', not for me. Ignoring.\n"), "SET_KEY", GNUNET_i2s (&m->target)); return; } @@ -464,16 +554,16 @@ GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *n, const struct GNUNET_Messag sizeof (struct GNUNET_PeerIdentity)) || (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_SET_KEY, &m->purpose, - &m->signature, n->public_key))) + &m->signature, kx->public_key))) { /* invalid signature */ GNUNET_break_op (0); return; } t = GNUNET_TIME_absolute_ntoh (m->creation_time); - if (((n->status == PEER_STATE_KEY_RECEIVED) || - (n->status == PEER_STATE_KEY_CONFIRMED)) && - (t.abs_value < n->decrypt_key_created.abs_value)) + if (((kx->status == KX_STATE_KEY_RECEIVED) || + (kx->status == KX_STATE_UP)) && + (t.abs_value < kx->decrypt_key_created.abs_value)) { /* this could rarely happen due to massive re-ordering of * messages on the network level, but is most likely either @@ -481,9 +571,6 @@ GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *n, const struct GNUNET_Messag GNUNET_break_op (0); return; } -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decrypting key material.\n"); -#endif if ((GNUNET_CRYPTO_rsa_decrypt (my_private_key, &m->encrypted_key, &k, sizeof (struct GNUNET_CRYPTO_AesSessionKey)) != @@ -497,68 +584,50 @@ GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *n, const struct GNUNET_Messag GNUNET_STATISTICS_update (stats, gettext_noop ("# SET_KEY messages decrypted"), 1, GNUNET_NO); - n->decrypt_key = k; - if (n->decrypt_key_created.abs_value != t.abs_value) + kx->decrypt_key = k; + if (kx->decrypt_key_created.abs_value != t.abs_value) { /* fresh key, reset sequence numbers */ - n->last_sequence_number_received = 0; - n->last_packets_bitmap = 0; - n->decrypt_key_created = t; + kx->last_sequence_number_received = 0; + kx->last_packets_bitmap = 0; + kx->decrypt_key_created = t; } - update_neighbour_performance (n, ats, ats_count); sender_status = (enum PeerStateMachine) ntohl (m->sender_status); - switch (n->status) + + switch (kx->status) { - case PEER_STATE_DOWN: - n->status = PEER_STATE_KEY_RECEIVED; -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Responding to `%s' with my own key.\n", "SET_KEY"); -#endif - send_key (n); + case KX_STATE_DOWN: + kx->status = PEER_STATE_KEY_RECEIVED; + /* we're not up, so we are already doing 'send_key' */ break; - case PEER_STATE_KEY_SENT: - case PEER_STATE_KEY_RECEIVED: + case KX_STATE_KEY_SENT: n->status = PEER_STATE_KEY_RECEIVED; - if ((sender_status != PEER_STATE_KEY_RECEIVED) && - (sender_status != PEER_STATE_KEY_CONFIRMED)) - { -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Responding to `%s' with my own key (other peer has status %u).\n", - "SET_KEY", (unsigned int) sender_status); -#endif - send_key (n); - } + /* we're not up, so we are already doing 'send_key' */ break; - case PEER_STATE_KEY_CONFIRMED: - if ((sender_status != PEER_STATE_KEY_RECEIVED) && - (sender_status != PEER_STATE_KEY_CONFIRMED)) - { -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Responding to `%s' with my own key (other peer has status %u), I was already fully up.\n", - "SET_KEY", (unsigned int) sender_status); -#endif - send_key (n); - } + case KX_STATE_KEY_RECEIVED: + /* we're not up, so we are already doing 'send_key' */ + break; + case KX_STATE_UP: + if ( (sender_status == KX_STATE_DOWN) || + (sender_status == KX_PEER_STATE_KEY_SENT) ) + send_key (kx); /* we are up, but other peer is not! */ break; default: GNUNET_break (0); break; } - if (n->pending_ping != NULL) + if (kx->ping_received != NULL) { - ping = n->pending_ping; - n->pending_ping = NULL; - handle_ping (n, ping, NULL, 0); + ping = kx->ping_received; + kx->ping_received = NULL; + GSC_KX_handle_ping (kx, &ping->header); GNUNET_free (ping); } - if (n->pending_pong != NULL) + if (kx->pong_received != NULL) { - pong = n->pending_pong; - n->pending_pong = NULL; - handle_pong (n, pong, NULL, 0); + pong = kx->pong_received; + kx->pong_received = NULL; + GSC_KX_handle_pong (kx, &pong->header); GNUNET_free (pong); } } @@ -566,25 +635,20 @@ GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *n, const struct GNUNET_Messag /** * We received a PING message. Validate and transmit - * PONG. + * a PONG message. * - * @param n sender of the PING - * @param m the encrypted PING message itself - * @param ats performance data - * @param ats_count number of entries in ats (excluding 0-termination) + * @param kx key exchange status for the corresponding peer + * @param msg the encrypted PING message itself */ void -GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *n, const struct GNUNET_MessageHeader *msg, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count) +GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *n, const struct GNUNET_MessageHeader *msg) { const struct PingMessage *m; struct PingMessage t; struct PongMessage tx; - struct PongMessage *tp; - struct MessageEntry *me; + struct PongMessage tp; struct GNUNET_CRYPTO_AesInitializationVector iv; - size_t size; + uint16_t msize; msize = ntohs (msg->size); if (msize != sizeof (struct PingMessage)) @@ -592,49 +656,34 @@ GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *n, const struct GNUNET_MessageHe GNUNET_break_op (0); return; } - GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages received"), + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# PING messages received"), 1, GNUNET_NO); - -#if FIXME - if ((n->status != PEER_STATE_KEY_RECEIVED) && - (n->status != PEER_STATE_KEY_CONFIRMED)) + if ( (kx->status != KX_STATE_KEY_RECEIVED) && + (kx->status != KX_STATE_UP) ) { -#if DEBUG_CORE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Core service receives `%s' request from `%4s' but have not processed key; marking as pending.\n", - "PING", GNUNET_i2s (&n->peer)); -#endif + /* defer */ GNUNET_free_non_null (n->pending_ping); - n->pending_ping = GNUNET_malloc (sizeof (struct PingMessage)); - memcpy (n->pending_ping, message, sizeof (struct PingMessage)); + n->pending_ping = GNUNET_copy_message (msg); return; } -#endif - m = (const struct PingMessage*) msg; + m = (const struct PingMessage*) msg; #if DEBUG_CORE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' request from `%4s'.\n", "PING", GNUNET_i2s (&n->peer)); #endif - derive_iv (&iv, &n->decrypt_key, m->iv_seed, &my_identity); + derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity); if (GNUNET_OK != - do_decrypt (n, &iv, &m->target, &t.target, + do_decrypt (kx, &iv, &m->target, &t.target, sizeof (struct PingMessage) - ((void *) &m->target - (void *) m))) + { + GNUNET_break_op (0); return; -#if DEBUG_HANDSHAKE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Decrypted `%s' to `%4s' with challenge %u decrypted using key %u, IV %u (salt %u)\n", - "PING", GNUNET_i2s (&t.target), (unsigned int) t.challenge, - (unsigned int) n->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv, - sizeof - (iv)), - m->iv_seed); -#endif - GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages decrypted"), - 1, GNUNET_NO); + } if (0 != - memcmp (&t.target, &my_identity, sizeof (struct GNUNET_PeerIdentity))) + memcmp (&t.target, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) { char sender[9]; char peer[9]; @@ -642,60 +691,135 @@ GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *n, const struct GNUNET_MessageHe GNUNET_snprintf (sender, sizeof (sender), "%8s", GNUNET_i2s (&n->peer)); GNUNET_snprintf (peer, sizeof (peer), "%8s", GNUNET_i2s (&t.target)); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _ - ("Received PING from `%s' for different identity: I am `%s', PONG identity: `%s'\n"), + _("Received PING from `%s' for different identity: I am `%s', PONG identity: `%s'\n"), sender, GNUNET_i2s (&my_identity), peer); GNUNET_break_op (0); return; } - update_neighbour_performance (n, ats, ats_count); - me = GNUNET_malloc (sizeof (struct MessageEntry) + - sizeof (struct PongMessage)); - GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail, - n->encrypted_tail, me); - me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PONG_DELAY); - me->priority = PONG_PRIORITY; - me->size = sizeof (struct PongMessage); + /* construct PONG */ tx.inbound_bw_limit = n->bw_in; tx.challenge = t.challenge; tx.target = t.target; - tp = (struct PongMessage *) &me[1]; - tp->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PONG); - tp->header.size = htons (sizeof (struct PongMessage)); - tp->iv_seed = + tp.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PONG); + tp.header.size = htons (sizeof (struct PongMessage)); + tp.iv_seed = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); - derive_pong_iv (&iv, &n->encrypt_key, tp->iv_seed, t.challenge, &n->peer); - do_encrypt (n, &iv, &tx.challenge, &tp->challenge, - sizeof (struct PongMessage) - ((void *) &tp->challenge - + derive_pong_iv (&iv, &n->encrypt_key, tp.iv_seed, t.challenge, &kx->peer); + do_encrypt (n, &iv, &tx.challenge, &tp.challenge, + sizeof (struct PongMessage) - ((void *) &tp.challenge - (void *) tp)); - GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages created"), 1, + GNUNET_STATISTICS_update (GSC_stats, + gettext_noop ("# PONG messages created"), 1, GNUNET_NO); -#if DEBUG_HANDSHAKE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Encrypting `%s' with challenge %u using key %u, IV %u (salt %u)\n", - "PONG", (unsigned int) t.challenge, - (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv, - sizeof - (iv)), - tp->iv_seed); -#endif - /* trigger queue processing */ - process_encrypted_neighbour_queue (n); + GSC_NEIGHBOURS_transmit (&kx->peer, + &tp.header, + GNUNET_TIME_UNIT_FOREVER_REL /* FIXME: timeout */); +} + + +/** + * Create a fresh SET KEY message for transmission to the other peer. + * Also creates a new key. + * + * @param kx key exchange context to create SET KEY message for + */ +static void +setup_fresh_setkey (struct GSC_KeyExchangeInfo *kx) +{ + struct SetKeyMessage *skm; + + GNUNET_CRYPTO_aes_create_session_key (&kx->encrypt_key); + kx->encrypt_key_created = GNUNET_TIME_absolute_get (); + skm = &kx->skm; + skm->header.size = htons (sizeof (struct SetKeyMessage)); + skm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SET_KEY); + skm->purpose.size = + htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + + sizeof (struct GNUNET_TIME_AbsoluteNBO) + + sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) + + sizeof (struct GNUNET_PeerIdentity)); + skm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_KEY); + skm->creation_time = GNUNET_TIME_absolute_hton (kx->encrypt_key_created); + skm->target = kx->peer; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_encrypt (&kx->encrypt_key, + sizeof (struct + GNUNET_CRYPTO_AesSessionKey), + kx->public_key, &skm->encrypted_key)); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (my_private_key, &skm->purpose, + &skm->signature)); +} + + +/** + * Create a fresh PING message for transmission to the other peer. + * + * @param kx key exchange context to create PING for + */ +static void +setup_fresh_ping (struct GSC_KeyExchangeInfo *kx) +{ + struct PingMessage pp; + struct PingMessage *pm; + + pm = &kx->ping; + pm->header.size = htons (sizeof (struct PingMessage)); + pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING); + pm->iv_seed = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); + derive_iv (&iv, &kx->encrypt_key, pm->iv_seed, &kx->peer); + pp.challenge = kx->ping_challenge; + pp.target = kx->peer; + do_encrypt (kx, &iv, &pp.target, &pm->target, + sizeof (struct PingMessage) - ((void *) &pm->target - + (void *) pm)); +} + + +/** + * Task triggered when a neighbour entry is about to time out + * (and we should prevent this by sending a PING). + * + * @param cls the 'struct GSC_KeyExchangeInfo' + * @param tc scheduler context (not used) + */ +static void +send_keep_alive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GSC_KeyExchangeInfo *kx = cls; + struct GNUNET_TIME_Relative retry; + struct GNUNET_TIME_Relative left; + + kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK; + left = GNUNET_TIME_absolute_get_remaining (kx->timeout); + if (left.rel_value == 0) + { + GSC_SESSIONS_end (&kx->peer); + kx->status = KX_STATE_DOWN; + return; + } + setup_fresh_ping (kx); + GDS_NEIGHBOURS_transmit (&kx->peer, + &kx->ping.header, + kx->set_key_retry_frequency); + retry = + GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2), + MIN_PING_FREQUENCY); + kx->keep_alive_task = + GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, kx); + } /** * We received a PONG message. Validate and update our status. * - * @param n sender of the PONG + * @param kx key exchange context for the the PONG * @param m the encrypted PONG message itself - * @param ats performance data - * @param ats_count number of entries in ats (excluding 0-termination) */ void -GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *n, const struct GNUNET_MessageHeader *msg, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count) +GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_MessageHeader *msg) { const struct PongMessage *m; struct PongMessage t; @@ -708,41 +832,35 @@ GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *n, const struct GNUNET_MessageHe msize = ntohs (msg->size); if (msize != sizeof (struct PongMessage)) - { - GNUNET_break_op (0); - return; - } - GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages received"), + { + GNUNET_break_op (0); + return; + } + GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# PONG messages received"), 1, GNUNET_NO); -#if FIXME - if ((n->status != PEER_STATE_KEY_RECEIVED) && - (n->status != PEER_STATE_KEY_CONFIRMED)) + if ( (kx->status != KX_STATE_KEY_RECEIVED) && + (kx->status != KX_STATE_UP) ) + { + if (kx->status == KX_STATE_KEY_SENT) { -#if DEBUG_CORE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Core service receives `%s' request from `%4s' but have not processed key; marking as pending.\n", - "PONG", GNUNET_i2s (&n->peer)); -#endif GNUNET_free_non_null (n->pending_pong); - n->pending_pong = GNUNET_malloc (sizeof (struct PongMessage)); - memcpy (n->pending_pong, message, sizeof (struct PongMessage)); - return; + n->pending_pong = GNUNET_copy_message (msg); } -#endif - + return; + } m = (const struct PongMessage*) msg; #if DEBUG_HANDSHAKE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' response from `%4s'.\n", "PONG", - GNUNET_i2s (&n->peer)); + GNUNET_i2s (&kx->peer)); #endif /* mark as garbage, just to be sure */ memset (&t, 255, sizeof (t)); - derive_pong_iv (&iv, &n->decrypt_key, m->iv_seed, n->ping_challenge, + derive_pong_iv (&iv, &kx->decrypt_key, m->iv_seed, kx->ping_challenge, &my_identity); if (GNUNET_OK != - do_decrypt (n, &iv, &m->challenge, &t.challenge, + do_decrypt (kx, &iv, &m->challenge, &t.challenge, sizeof (struct PongMessage) - ((void *) &m->challenge - (void *) m))) { @@ -751,17 +869,8 @@ GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *n, const struct GNUNET_MessageHe } GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages decrypted"), 1, GNUNET_NO); -#if DEBUG_HANDSHAKE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Decrypted `%s' from `%4s' with challenge %u using key %u, IV %u (salt %u)\n", - "PONG", GNUNET_i2s (&t.target), (unsigned int) t.challenge, - (unsigned int) n->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv, - sizeof - (iv)), - m->iv_seed); -#endif - if ((0 != memcmp (&t.target, &n->peer, sizeof (struct GNUNET_PeerIdentity))) - || (n->ping_challenge != t.challenge)) + if ((0 != memcmp (&t.target, &kx->peer, sizeof (struct GNUNET_PeerIdentity))) + || (kx->ping_challenge != t.challenge)) { /* PONG malformed */ #if DEBUG_CORE @@ -773,490 +882,99 @@ GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *n, const struct GNUNET_MessageHe "Received malformed `%s' received from `%4s' with challenge %u\n", "PONG", GNUNET_i2s (&t.target), (unsigned int) t.challenge); #endif - GNUNET_break_op (n->ping_challenge != t.challenge); return; } - switch (n->status) + switch (kx->status) { - case PEER_STATE_DOWN: + case KX_STATE_DOWN: GNUNET_break (0); /* should be impossible */ return; - case PEER_STATE_KEY_SENT: - GNUNET_break (0); /* should be impossible, how did we decrypt? */ + case KX_STATE_KEY_SENT: + GNUNET_break (0); /* should be impossible */ return; - case PEER_STATE_KEY_RECEIVED: + case KX_STATE_KEY_RECEIVED: GNUNET_STATISTICS_update (stats, gettext_noop ("# Session keys confirmed via PONG"), 1, GNUNET_NO); - n->status = PEER_STATE_KEY_CONFIRMED; - { - struct GNUNET_MessageHeader *hdr; - - hdr = compute_type_map_message (); - send_type_map_to_neighbour (hdr, &n->peer.hashPubKey, n); - GNUNET_free (hdr); - } - if (n->bw_out_external_limit.value__ != t.inbound_bw_limit.value__) - { - n->bw_out_external_limit = t.inbound_bw_limit; - n->bw_out = - GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit, - n->bw_out_internal_limit); - GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window, - n->bw_out); - GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out); - } -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Confirmed key via `%s' message for peer `%4s'\n", "PONG", - GNUNET_i2s (&n->peer)); -#endif - if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (n->retry_set_key_task); - n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; - } - update_neighbour_performance (n, ats, ats_count); - size = - sizeof (struct ConnectNotifyMessage) + - (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information); - if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) - { - GNUNET_break (0); - /* recovery strategy: throw away performance data */ - GNUNET_array_grow (n->ats, n->ats_count, 0); - size = - sizeof (struct PeerStatusNotifyMessage) + - n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information); - } - cnm = (struct ConnectNotifyMessage *) buf; - cnm->header.size = htons (size); - cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); - cnm->ats_count = htonl (n->ats_count); - cnm->peer = n->peer; - mats = &cnm->ats; - memcpy (mats, n->ats, - n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)); - mats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR); - mats[n->ats_count].value = htonl (0); - send_to_all_clients (&cnm->header, GNUNET_NO, - GNUNET_CORE_OPTION_SEND_CONNECT); - process_encrypted_neighbour_queue (n); - /* fall-through! */ + kx->status = KX_STATE_UP; + GSC_SESSIONS_create (&kx->peer); + GNUNET_assert (kx->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK); + GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); + kx->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_assert (kx->keep_alive_task == GNUNET_SCHEDULER_NO_TASK); + update_timeout (kx); + break; case PEER_STATE_KEY_CONFIRMED: - n->last_activity = GNUNET_TIME_absolute_get (); - if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->keep_alive_task); - n->keep_alive_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide - (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, - 2), &send_keep_alive, n); - handle_peer_status_change (n); + update_timeout (kx); break; default: GNUNET_break (0); break; } - -#if FIXME - if (n->status == PEER_STATE_KEY_CONFIRMED) - { - now = GNUNET_TIME_absolute_get (); - n->last_activity = now; - changed = GNUNET_YES; - if (!up) - { - GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"), - 1, GNUNET_NO); - n->time_established = now; - } - if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->keep_alive_task); - n->keep_alive_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide - (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, - 2), &send_keep_alive, n); - } - if (changed) - handle_peer_status_change (n); -#endif -} - - - -/** - * PEERINFO is giving us a HELLO for a peer. Add the public key to - * the neighbour's struct and retry send_key. Or, if we did not get a - * HELLO, just do nothing. - * - * @param cls the 'struct Neighbour' to retry sending the key for - * @param peer the peer for which this is the HELLO - * @param hello HELLO message of that peer - * @param err_msg NULL if successful, otherwise contains error message - */ -static void -process_hello_retry_send_key (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Message *hello, - const char *err_msg) -{ - struct Neighbour *n = cls; - - if (err_msg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Error in communication with PEERINFO service\n")); - /* return; */ - } - - if (peer == NULL) - { -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Entered `%s' and `%s' is NULL!\n", - "process_hello_retry_send_key", "peer"); -#endif - n->pitr = NULL; - if (n->public_key != NULL) - { - if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (n->retry_set_key_task); - n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; - } - GNUNET_STATISTICS_update (stats, - gettext_noop - ("# SET_KEY messages deferred (need public key)"), - -1, GNUNET_NO); - send_key (n); - } - else - { -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to obtain public key for peer `%4s', delaying processing of SET_KEY\n", - GNUNET_i2s (&n->peer)); -#endif - GNUNET_STATISTICS_update (stats, - gettext_noop - ("# Delayed connecting due to lack of public key"), - 1, GNUNET_NO); - if (GNUNET_SCHEDULER_NO_TASK == n->retry_set_key_task) - n->retry_set_key_task = - GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency, - &set_key_retry_task, n); - } - return; - } - -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Entered `%s' for peer `%4s'\n", - "process_hello_retry_send_key", GNUNET_i2s (peer)); -#endif - if (n->public_key != NULL) - { - /* already have public key, why are we here? */ - GNUNET_break (0); - return; - } - -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received new `%s' message for `%4s', initiating key exchange.\n", - "HELLO", GNUNET_i2s (peer)); -#endif - n->public_key = - GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); - if (GNUNET_OK != GNUNET_HELLO_get_key (hello, n->public_key)) - { - GNUNET_STATISTICS_update (stats, - gettext_noop - ("# Error extracting public key from HELLO"), 1, - GNUNET_NO); - GNUNET_free (n->public_key); - n->public_key = NULL; -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "GNUNET_HELLO_get_key returned awfully\n"); -#endif - return; - } } /** * Send our key (and encrypted PING) to the other peer. * - * @param n the other peer + * @param kx key exchange context */ static void -send_key (struct Neighbour *n) +send_key (struct GSC_KeyExchangeInfo *kx) { - struct MessageEntry *pos; - struct SetKeyMessage *sm; - struct MessageEntry *me; - struct PingMessage pp; - struct PingMessage *pm; struct GNUNET_CRYPTO_AesInitializationVector iv; - if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (n->retry_set_key_task); - n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; - } - if (n->pitr != NULL) - { -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Key exchange in progress with `%4s'.\n", - GNUNET_i2s (&n->peer)); -#endif - return; /* already in progress */ - } - if (GNUNET_YES != n->is_connected) + GNUNET_assert (kx->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK); + if (KX_STATE_UP == kx->status) + return; /* nothing to do */ + if (kx->public_key == NULL) { - GNUNET_STATISTICS_update (stats, - gettext_noop - ("# Asking transport to connect (for SET_KEY)"), - 1, GNUNET_NO); - GNUNET_TRANSPORT_try_connect (transport, &n->peer); + /* lookup public key, then try again */ + kx->pitr = + GNUNET_PEERINFO_iterate (peerinfo, &kx->peer, + GNUNET_TIME_UNIT_FOREVER_REL /* timeout? */, + &process_hello, kx); return; } -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Asked to perform key exchange with `%4s'.\n", - GNUNET_i2s (&n->peer)); -#endif - if (n->public_key == NULL) - { - /* lookup n's public key, then try again */ -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Lacking public key for `%4s', trying to obtain one (send_key).\n", - GNUNET_i2s (&n->peer)); -#endif - GNUNET_assert (n->pitr == NULL); - n->pitr = - GNUNET_PEERINFO_iterate (peerinfo, &n->peer, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 20), - &process_hello_retry_send_key, n); - return; - } - pos = n->encrypted_head; - while (pos != NULL) - { - if (GNUNET_YES == pos->is_setkey) - { - if (pos->sender_status == n->status) - { -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "`%s' message for `%4s' queued already\n", "SET_KEY", - GNUNET_i2s (&n->peer)); -#endif - goto trigger_processing; - } - GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, pos); - GNUNET_free (pos); -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Removing queued `%s' message for `%4s', will create a new one\n", - "SET_KEY", GNUNET_i2s (&n->peer)); -#endif - break; - } - pos = pos->next; - } /* update status */ switch (n->status) { - case PEER_STATE_DOWN: - n->status = PEER_STATE_KEY_SENT; - break; - case PEER_STATE_KEY_SENT: + case KX_STATE_DOWN: + n->status = PEER_STATE_KEY_SENT; + /* setup SET KEY message */ + setup_fresh_set_key (kx); + setup_fresh_ping (kx); + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# SET_KEY and PING messages created"), 1, + GNUNET_NO); break; - case PEER_STATE_KEY_RECEIVED: + case KX_STATE_KEY_SENT: break; - case PEER_STATE_KEY_CONFIRMED: + case KX_STATE_KEY_RECEIVED: break; + case KX_STATE_KEY_CONFIRMED: + GNUNET_break (0); + return; default: GNUNET_break (0); - break; - } - - - /* first, set key message */ - me = GNUNET_malloc (sizeof (struct MessageEntry) + - sizeof (struct SetKeyMessage) + - sizeof (struct PingMessage)); - me->deadline = GNUNET_TIME_relative_to_absolute (MAX_SET_KEY_DELAY); - me->priority = SET_KEY_PRIORITY; - me->size = sizeof (struct SetKeyMessage) + sizeof (struct PingMessage); - me->is_setkey = GNUNET_YES; - me->got_slack = GNUNET_YES; /* do not defer this one! */ - me->sender_status = n->status; - GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail, - n->encrypted_tail, me); - sm = (struct SetKeyMessage *) &me[1]; - sm->header.size = htons (sizeof (struct SetKeyMessage)); - sm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SET_KEY); - sm->sender_status = - htonl ((int32_t) - ((n->status == - PEER_STATE_DOWN) ? PEER_STATE_KEY_SENT : n->status)); - sm->purpose.size = - htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + - sizeof (struct GNUNET_TIME_AbsoluteNBO) + - sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) + - sizeof (struct GNUNET_PeerIdentity)); - sm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_KEY); - sm->creation_time = GNUNET_TIME_absolute_hton (n->encrypt_key_created); - sm->target = n->peer; - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_rsa_encrypt (&n->encrypt_key, - sizeof (struct - GNUNET_CRYPTO_AesSessionKey), - n->public_key, &sm->encrypted_key)); - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (my_private_key, &sm->purpose, - &sm->signature)); - pm = (struct PingMessage *) &sm[1]; - pm->header.size = htons (sizeof (struct PingMessage)); - pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING); - pm->iv_seed = - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); - derive_iv (&iv, &n->encrypt_key, pm->iv_seed, &n->peer); - pp.challenge = n->ping_challenge; - pp.target = n->peer; -#if DEBUG_HANDSHAKE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Encrypting `%s' and `%s' messages with challenge %u for `%4s' using key %u, IV %u (salt %u).\n", - "SET_KEY", "PING", (unsigned int) n->ping_challenge, - GNUNET_i2s (&n->peer), (unsigned int) n->encrypt_key.crc32, - GNUNET_CRYPTO_crc32_n (&iv, sizeof (iv)), pm->iv_seed); -#endif - do_encrypt (n, &iv, &pp.target, &pm->target, - sizeof (struct PingMessage) - ((void *) &pm->target - - (void *) pm)); - GNUNET_STATISTICS_update (stats, - gettext_noop - ("# SET_KEY and PING messages created"), 1, - GNUNET_NO); -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Have %llu ms left for `%s' transmission.\n", - (unsigned long long) - GNUNET_TIME_absolute_get_remaining (me->deadline).rel_value, - "SET_KEY"); -#endif -trigger_processing: - /* trigger queue processing */ - process_encrypted_neighbour_queue (n); - if ((n->status != PEER_STATE_KEY_CONFIRMED) && - (GNUNET_SCHEDULER_NO_TASK == n->retry_set_key_task)) - n->retry_set_key_task = - GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency, - &set_key_retry_task, n); -} - - -/** - * We received a SET_KEY message. Validate and update - * our key material and status. - * - * @param n the neighbour from which we received message m - * @param m the set key message we received - * @param ats performance data - * @param ats_count number of entries in ats (excluding 0-termination) - */ -static void -handle_set_key (struct Neighbour *n, const struct SetKeyMessage *m, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count); - - - -/** - * PEERINFO is giving us a HELLO for a peer. Add the public key to - * the neighbour's struct and retry handling the set_key message. Or, - * if we did not get a HELLO, just free the set key message. - * - * @param cls pointer to the set key message - * @param peer the peer for which this is the HELLO - * @param hello HELLO message of that peer - * @param err_msg NULL if successful, otherwise contains error message - */ -static void -process_hello_retry_handle_set_key (void *cls, - const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_HELLO_Message *hello, - const char *err_msg) -{ - struct Neighbour *n = cls; - struct SetKeyMessage *sm = n->skm; - - if (err_msg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Error in communication with PEERINFO service\n")); - /* return; */ - } - - if (peer == NULL) - { - n->skm = NULL; - n->pitr = NULL; - if (n->public_key != NULL) - { -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s' for `%4s', continuing processing of `%s' message.\n", - "HELLO", GNUNET_i2s (&n->peer), "SET_KEY"); -#endif - handle_set_key (n, sm, NULL, 0); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _ - ("Ignoring `%s' message due to lack of public key for peer `%4s' (failed to obtain one).\n"), - "SET_KEY", GNUNET_i2s (&n->peer)); - } - GNUNET_free (sm); return; } - if (n->public_key != NULL) - return; /* multiple HELLOs match!? */ - n->public_key = - GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); - if (GNUNET_OK != GNUNET_HELLO_get_key (hello, n->public_key)) - { - GNUNET_break_op (0); - GNUNET_free (n->public_key); - n->public_key = NULL; - } -} - - -/** - * Task that will retry "send_key" if our previous attempt failed - * to yield a PONG. - */ -static void -set_key_retry_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct Neighbour *n = cls; + /* always update sender status in SET KEY message */ + kx->skm.sender_status = htonl ((int32_t) kx->status); -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Retrying key transmission to `%4s'\n", - GNUNET_i2s (&n->peer)); -#endif - n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK; - n->set_key_retry_frequency = - GNUNET_TIME_relative_multiply (n->set_key_retry_frequency, 2); - send_key (n); + GDS_NEIGHBOURS_transmit (&kx->peer, + &kx->skm.header, + kx->set_key_retry_frequency); + GDS_NEIGHBOURS_transmit (&kx->peer, + &kx->ping.header, + kx->set_key_retry_frequency); + kx->retry_set_key_task = + GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency, + &set_key_retry_task, kx); } @@ -1264,91 +982,93 @@ set_key_retry_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * Encrypt and transmit a message with the given payload. * * @param kx key exchange context + * @param bw_in bandwidth limit to transmit to the other peer; + * the other peer shall not send us more than the + * given rate * @param payload payload of the message * @param payload_size number of bytes in 'payload' */ void GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx, + struct GNUNET_BANDWIDTH_Value32NBO bw_in, const void *payload, size_t payload_size) { - char pbuf[GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE + sizeof (struct EncryptedMessage)]; /* plaintext */ - size_t used; + size_t used = payload_size + sizeof (struct EncryptedMessage); + char pbuf[used]; /* plaintext */ + char cbuf[used]; /* ciphertext */ struct EncryptedMessage *em; /* encrypted message */ struct EncryptedMessage *ph; /* plaintext header */ - struct MessageEntry *me; - unsigned int priority; - struct GNUNET_TIME_Absolute deadline; - struct GNUNET_TIME_Relative retry_time; struct GNUNET_CRYPTO_AesInitializationVector iv; struct GNUNET_CRYPTO_AuthKey auth_key; #if DEBUG_CORE_QUOTA GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending %u b/s as new limit to peer `%4s'\n", - (unsigned int) ntohl (n->bw_in.value__), GNUNET_i2s (&n->peer)); + (unsigned int) ntohl (bw_in.value__), + GNUNET_i2s (&kx->peer)); #endif + ph = (struct EncryptedMessage*) pbuf; ph->iv_seed = htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX)); - ph->sequence_number = htonl (++n->last_sequence_number_sent); - ph->inbound_bw_limit = n->bw_in; + ph->sequence_number = htonl (++kx->last_sequence_number_sent); + ph->inbound_bw_limit = bw_in; ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); + memcpy (&ph[1], payload, payload_size); - /* setup encryption message header */ - me = GNUNET_malloc (sizeof (struct MessageEntry) + used); - me->deadline = deadline; - me->priority = priority; - me->size = used; - em = (struct EncryptedMessage *) &me[1]; + em = (struct EncryptedMessage *) cbuf; em->header.size = htons (used); em->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE); em->iv_seed = ph->iv_seed; - derive_iv (&iv, &n->encrypt_key, ph->iv_seed, &n->peer); - /* encrypt */ -#if DEBUG_HANDSHAKE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Encrypting %u bytes of plaintext messages for `%4s' for transmission in %llums.\n", - (unsigned int) used - ENCRYPTED_HEADER_SIZE, - GNUNET_i2s (&n->peer), - (unsigned long long) - GNUNET_TIME_absolute_get_remaining (deadline).rel_value); -#endif + derive_iv (&iv, &kx->encrypt_key, ph->iv_seed, &kx->peer); GNUNET_assert (GNUNET_OK == - do_encrypt (n, &iv, &ph->sequence_number, &em->sequence_number, + do_encrypt (kx, &iv, &ph->sequence_number, &em->sequence_number, used - ENCRYPTED_HEADER_SIZE)); - derive_auth_key (&auth_key, &n->encrypt_key, ph->iv_seed, - n->encrypt_key_created); + derive_auth_key (&auth_key, &kx->encrypt_key, ph->iv_seed, + kx->encrypt_key_created); GNUNET_CRYPTO_hmac (&auth_key, &em->sequence_number, used - ENCRYPTED_HEADER_SIZE, &em->hmac); -#if DEBUG_HANDSHAKE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Authenticated %u bytes of ciphertext %u: `%s'\n", - used - ENCRYPTED_HEADER_SIZE, - GNUNET_CRYPTO_crc32_n (&em->sequence_number, - used - ENCRYPTED_HEADER_SIZE), - GNUNET_h2s (&em->hmac)); -#endif GDS_NEIGHBOURS_transmit (&kx->peer, &em->header, GNUNET_TIME_UNIT_FOREVER_REL); } +/** + * We've seen a valid message from the other peer. + * Update the time when the session would time out + * and delay sending our keep alive message further. + * + * @param kx key exchange where we saw activity + */ +static void +update_timeout (struct GSC_KeyExchangeInfo *kx) +{ + kx->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); + if (kx->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (n->keep_alive_task); + kx->keep_alive_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide + (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + 2), &send_keep_alive, kx); +} + + /** * We received an encrypted message. Decrypt, validate and * pass on to the appropriate clients. * * @param n target of the message * @param m encrypted message - * @param ats performance data - * @param ats_count number of entries in ats (excluding 0-termination) + * @param atsi performance data + * @param atsi_count number of entries in ats (excluding 0-termination) */ void GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *n, const struct GNUNET_MessageHeader *msg, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count) + const struct GNUNET_TRANSPORT_ATS_Information *atsi, + uint32_t atsi_count) { const struct EncryptedMessage *m; char buf[size]; @@ -1362,86 +1082,68 @@ GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *n, if (size < sizeof (struct EncryptedMessage) + sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break_op (0); - return; - } + { + GNUNET_break_op (0); + return; + } m = (const struct EncryptedMessage*) msg; -#if FIXME - if ((n->status != PEER_STATE_KEY_RECEIVED) && - (n->status != PEER_STATE_KEY_CONFIRMED)) - { - GNUNET_STATISTICS_update (stats, - gettext_noop - ("# failed to decrypt message (no session key)"), - 1, GNUNET_NO); - send_key (n); - return; - } -#endif - -#if DEBUG_CORE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Core service receives `%s' request from `%4s'.\n", - "ENCRYPTED_MESSAGE", GNUNET_i2s (&n->peer)); -#endif + if ( (kx->status != KX_STATE_KEY_RECEIVED) && + (kx->status != KX_STATE_UP) ) + { + GNUNET_STATISTICS_update (stats, + gettext_noop + ("# failed to decrypt message (no session key)"), + 1, GNUNET_NO); + return; + } /* validate hash */ - derive_auth_key (&auth_key, &n->decrypt_key, m->iv_seed, - n->decrypt_key_created); + derive_auth_key (&auth_key, &kx->decrypt_key, m->iv_seed, + kx->decrypt_key_created); GNUNET_CRYPTO_hmac (&auth_key, &m->sequence_number, size - ENCRYPTED_HEADER_SIZE, &ph); -#if DEBUG_HANDSHAKE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Re-Authenticated %u bytes of ciphertext (`%u'): `%s'\n", - (unsigned int) size - ENCRYPTED_HEADER_SIZE, - GNUNET_CRYPTO_crc32_n (&m->sequence_number, - size - ENCRYPTED_HEADER_SIZE), - GNUNET_h2s (&ph)); -#endif - if (0 != memcmp (&ph, &m->hmac, sizeof (GNUNET_HashCode))) { /* checksum failed */ GNUNET_break_op (0); return; } - derive_iv (&iv, &n->decrypt_key, m->iv_seed, &my_identity); + derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity); /* decrypt */ if (GNUNET_OK != - do_decrypt (n, &iv, &m->sequence_number, &buf[ENCRYPTED_HEADER_SIZE], + do_decrypt (kx, &iv, &m->sequence_number, &buf[ENCRYPTED_HEADER_SIZE], size - ENCRYPTED_HEADER_SIZE)) return; pt = (struct EncryptedMessage *) buf; /* validate sequence number */ snum = ntohl (pt->sequence_number); - if (n->last_sequence_number_received == snum) + if (kx->last_sequence_number_received == snum) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received duplicate message, ignoring.\n"); /* duplicate, ignore */ - GNUNET_STATISTICS_update (stats, + GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes dropped (duplicates)"), size, GNUNET_NO); return; } - if ((n->last_sequence_number_received > snum) && - (n->last_sequence_number_received - snum > 32)) + if ((kx->last_sequence_number_received > snum) && + (kx->last_sequence_number_received - snum > 32)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received ancient out of sequence message, ignoring.\n"); /* ancient out of sequence, ignore */ - GNUNET_STATISTICS_update (stats, + GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes dropped (out of sequence)"), size, GNUNET_NO); return; } - if (n->last_sequence_number_received > snum) + if (kx->last_sequence_number_received > snum) { - unsigned int rotbit = 1 << (n->last_sequence_number_received - snum - 1); + unsigned int rotbit = 1 << (kx->last_sequence_number_received - snum - 1); - if ((n->last_packets_bitmap & rotbit) != 0) + if ((kx->last_packets_bitmap & rotbit) != 0) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received duplicate message, ignoring.\n"); @@ -1451,17 +1153,17 @@ GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *n, /* duplicate, ignore */ return; } - n->last_packets_bitmap |= rotbit; + kx->last_packets_bitmap |= rotbit; } - if (n->last_sequence_number_received < snum) + if (kx->last_sequence_number_received < snum) { - int shift = (snum - n->last_sequence_number_received); + unsigned int shift = (snum - kx->last_sequence_number_received); - if (shift >= 8 * sizeof (n->last_packets_bitmap)) - n->last_packets_bitmap = 0; + if (shift >= 8 * sizeof (kx->last_packets_bitmap)) + kx->last_packets_bitmap = 0; else - n->last_packets_bitmap <<= shift; - n->last_sequence_number_received = snum; + kx->last_packets_bitmap <<= shift; + kx->last_sequence_number_received = snum; } /* check timestamp */ @@ -1480,104 +1182,49 @@ GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *n, } /* process decrypted message(s) */ - if (n->bw_out_external_limit.value__ != pt->inbound_bw_limit.value__) - { -#if DEBUG_CORE_SET_QUOTA - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received %u b/s as new inbound limit for peer `%4s'\n", - (unsigned int) ntohl (pt->inbound_bw_limit.value__), - GNUNET_i2s (&n->peer)); -#endif - n->bw_out_external_limit = pt->inbound_bw_limit; - n->bw_out = - GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit, - n->bw_out_internal_limit); - GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window, - n->bw_out); - GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out); - } - n->last_activity = GNUNET_TIME_absolute_get (); - if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (n->keep_alive_task); - n->keep_alive_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide - (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, - 2), &send_keep_alive, n); + update_timeout (kx); + GSC_SESSIONS_update (&kx->peer, + pt->inbound_bw_limit, + atsi, atsi_count); // FIXME: does 'SESSIONS' need atsi!? GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes of payload decrypted"), size - sizeof (struct EncryptedMessage), GNUNET_NO); - handle_peer_status_change (n); - update_neighbour_performance (n, ats, ats_count); if (GNUNET_OK != - GNUNET_SERVER_mst_receive (mst, n, &buf[sizeof (struct EncryptedMessage)], + GNUNET_SERVER_mst_receive (mst, kx, &buf[sizeof (struct EncryptedMessage)], size - sizeof (struct EncryptedMessage), GNUNET_YES, GNUNET_NO)) GNUNET_break_op (0); } + + /** - * Task triggered when a neighbour entry is about to time out - * (and we should prevent this by sending a PING). + * Deliver P2P message to interested clients. * - * @param cls the 'struct Neighbour' - * @param tc scheduler context (not used) + * @param cls always NULL + * @param client who sent us the message (struct GSC_KeyExchangeInfo) + * @param m the message */ static void -send_keep_alive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +deliver_message (void *cls, void *client, const struct GNUNET_MessageHeader *m) { - struct Neighbour *n = cls; - struct GNUNET_TIME_Relative retry; - struct GNUNET_TIME_Relative left; - struct MessageEntry *me; - struct PingMessage pp; - struct PingMessage *pm; - struct GNUNET_CRYPTO_AesInitializationVector iv; - - n->keep_alive_task = GNUNET_SCHEDULER_NO_TASK; - /* send PING */ - me = GNUNET_malloc (sizeof (struct MessageEntry) + - sizeof (struct PingMessage)); - me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PING_DELAY); - me->priority = PING_PRIORITY; - me->size = sizeof (struct PingMessage); - GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail, - n->encrypted_tail, me); - pm = (struct PingMessage *) &me[1]; - pm->header.size = htons (sizeof (struct PingMessage)); - pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING); - pm->iv_seed = - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX); - derive_iv (&iv, &n->encrypt_key, pm->iv_seed, &n->peer); - pp.challenge = n->ping_challenge; - pp.target = n->peer; -#if DEBUG_HANDSHAKE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Encrypting `%s' message with challenge %u for `%4s' using key %u, IV %u (salt %u).\n", - "PING", (unsigned int) n->ping_challenge, GNUNET_i2s (&n->peer), - (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv, - sizeof - (iv)), - pm->iv_seed); -#endif - do_encrypt (n, &iv, &pp.target, &pm->target, - sizeof (struct PingMessage) - ((void *) &pm->target - - (void *) pm)); - process_encrypted_neighbour_queue (n); - /* reschedule PING job */ - left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n)); - retry = - GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2), - MIN_PING_FREQUENCY); - n->keep_alive_task = - GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, n); - + struct GSC_KeyExchangeInfo *kx = client; + + // FIXME (need to check stuff, need ATSI, etc.) + // FIXME: does clients work properly if never called with option 'NOTHING'!? + GSC_CLIENTS_deliver_message (&kx->peer, + NULL, 0, // kx->atsi... + m, + ntohs (m->size), + GNUNET_CORE_OPTION_SEND_FULL_INBOUND); + GSC_CLIENTS_deliver_message (&kx->peer, + NULL, 0, // kx->atsi... + m, + sizeof (struct GNUNET_MessageHeader), + GNUNET_CORE_OPTION_SEND_HDR_INBOUND); } - - - - /** * Initialize KX subsystem. * @@ -1616,6 +1263,7 @@ GSC_KX_init () my_private_key = NULL; return GNUNET_SYSERR; } + mst = GNUNET_SERVER_mst_create (&deliver_message, NULL); return GNUNET_OK; } @@ -1632,10 +1280,15 @@ GSC_KX_done () my_private_key = NULL; } if (peerinfo != NULL) - { - GNUNET_PEERINFO_disconnect (peerinfo); - peerinfo = NULL; - } + { + GNUNET_PEERINFO_disconnect (peerinfo); + peerinfo = NULL; + } + if (mst != NULL) + { + GNUNET_SERVER_mst_destroy (mst); + mst = NULL; + } } /* end of gnunet-service-core_kx.c */ diff --git a/src/core/gnunet-service-core_kx.h b/src/core/gnunet-service-core_kx.h index 104aed5e4..071665a19 100644 --- a/src/core/gnunet-service-core_kx.h +++ b/src/core/gnunet-service-core_kx.h @@ -29,17 +29,77 @@ #include "gnunet_util_lib.h" +/** + * State machine for our P2P encryption handshake. Everyone starts in + * "DOWN", if we receive the other peer's key (other peer initiated) + * we start in state RECEIVED (since we will immediately send our + * own); otherwise we start in SENT. If we get back a PONG from + * within either state, we move up to CONFIRMED (the PONG will always + * be sent back encrypted with the key we sent to the other peer). + */ +enum KxStateMachine +{ + /** + * No handshake yet. + */ + KX_STATE_DOWN, + + /** + * We've sent our session key. + */ + KX_STATE_KEY_SENT, + + /** + * We've received the other peers session key. + */ + KX_STATE_KEY_RECEIVED, + + /** + * The other peer has confirmed our session key with a message + * encrypted with his session key (which we got). Key exchange + * is done. + */ + KX_STATE_UP +}; + + /** * Information about the status of a key exchange with another peer. */ struct GSC_KeyExchangeInfo { + /** + * Identity of the peer. + */ + struct GNUNET_PeerIdentity peer; /** - * SetKeyMessage to transmit, NULL if we are not currently trying - * to send one. + * SetKeyMessage to transmit (initialized the first + * time our status goes past 'KX_STATE_KEY_SENT'). */ - struct SetKeyMessage *skm; + struct SetKeyMessage skm; + + /** + * PING message we transmit to the other peer. + */ + struct PingMessage ping; + + /** + * SetKeyMessage we received and did not process yet. + */ + struct SetKeyMessage *skm_received; + + /** + * PING message we received from the other peer and + * did not process yet (or NULL). + */ + struct PingMessage *ping_received; + + /** + * PONG message we received from the other peer and + * did not process yet (or NULL). + */ + struct PongMessage *pong_received; /** * Non-NULL if we are currently looking up HELLOs for this peer. @@ -52,13 +112,6 @@ struct GSC_KeyExchangeInfo */ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key; - /** - * We received a PING message before we got the "public_key" - * (or the SET_KEY). We keep it here until we have a key - * to decrypt it. NULL if no PING is pending. - */ - struct PingMessage *pending_ping; - /** * We received a PONG message before we got the "public_key" * (or the SET_KEY). We keep it here until we have a key @@ -88,6 +141,11 @@ struct GSC_KeyExchangeInfo */ struct GNUNET_TIME_Absolute decrypt_key_created; + /** + * When should the session time out (if there are no PONGs)? + */ + struct GNUNET_TIME_Absolute timeout; + /** * At what frequency are we currently re-trying SET_KEY messages? */ @@ -111,7 +169,7 @@ struct GSC_KeyExchangeInfo /** * What is our connection status? */ - enum PeerStateMachine status; + enum KxStateMachine status; }; @@ -122,14 +180,10 @@ struct GSC_KeyExchangeInfo * * @param kx key exchange status for the corresponding peer * @param msg the set key message we received - * @param ats performance data - * @param ats_count number of entries in ats (excluding 0-termination) */ void -GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *n, - const struct GNUNET_MessageHandler *msg, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count); +GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *kx, + const struct GNUNET_MessageHandler *msg); /** @@ -138,14 +192,10 @@ GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *n, * * @param kx key exchange status for the corresponding peer * @param msg the encrypted PING message itself - * @param ats performance data - * @param ats_count number of entries in ats (excluding 0-termination) */ void GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *kx, - const struct GNUNET_MessageHeader *msg, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count); + const struct GNUNET_MessageHeader *msg); /** @@ -153,25 +203,25 @@ GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *kx, * * @param kx key exchange status for the corresponding peer * @param msg the encrypted PONG message itself - * @param ats performance data - * @param ats_count number of entries in ats (excluding 0-termination) */ void GSC_KX_handle_pong (struct GSC_KeyExchangeInfo *kx, - const struct GNUNET_MessageHeader *msg, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count); + const struct GNUNET_MessageHeader *msg); /** * Encrypt and transmit a message with the given payload. * * @param kx key exchange context + * @param bw_in bandwidth limit to transmit to the other peer; + * the other peer shall not send us more than the + * given rate * @param payload payload of the message * @param payload_size number of bytes in 'payload' */ void GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx, + struct GNUNET_BANDWIDTH_Value32NBO bw_in, const void *payload, size_t payload_size); @@ -182,14 +232,14 @@ GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx, * * @param kx key exchange information context * @param msg encrypted message - * @param ats performance data - * @param ats_count number of entries in ats (excluding 0-termination) + * @param atsi performance data + * @param atsi_count number of entries in ats (excluding 0-termination) */ void GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *kx, const struct GNUNET_MessageHeader *msg, - const struct GNUNET_TRANSPORT_ATS_Information *ats, - uint32_t ats_count); + const struct GNUNET_TRANSPORT_ATS_Information *atsi, + uint32_t atsi_count); /** diff --git a/src/core/gnunet-service-core_neighbours.c b/src/core/gnunet-service-core_neighbours.c index 8a0677c88..d78f696e6 100644 --- a/src/core/gnunet-service-core_neighbours.c +++ b/src/core/gnunet-service-core_neighbours.c @@ -428,13 +428,13 @@ handle_transport_receive (void *cls, const struct GNUNET_PeerIdentity *peer, switch (type) { case GNUNET_MESSAGE_TYPE_CORE_SET_KEY: - GSC_KX_handle_set_key (n->kxinfo, message, ats, ats_count); + GSC_KX_handle_set_key (n->kxinfo, message); break; case GNUNET_MESSAGE_TYPE_CORE_PING: - GSC_KX_handle_ping (n->kxinfo, message, ats, ats_count); + GSC_KX_handle_ping (n->kxinfo, message); break; case GNUNET_MESSAGE_TYPE_CORE_PONG: - GSC_KX_handle_pong (n->kxinfo, message, ats, ats_count); + GSC_KX_handle_pong (n->kxinfo, message); break; case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE: GSC_KX_handle_encrypted_message (peer, diff --git a/src/core/gnunet-service-core_neighbours.h b/src/core/gnunet-service-core_neighbours.h index 8dad1aafe..36682770e 100644 --- a/src/core/gnunet-service-core_neighbours.h +++ b/src/core/gnunet-service-core_neighbours.h @@ -41,7 +41,7 @@ * @param timeout by when should the transmission be done? */ void -GDS_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target, +GSC_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target, const struct GNUNET_MessageHeader *msg, struct GNUNET_TIME_Relative timeout); diff --git a/src/core/gnunet-service-core_sessions.c b/src/core/gnunet-service-core_sessions.c index b72a0e0b3..a2b662252 100644 --- a/src/core/gnunet-service-core_sessions.c +++ b/src/core/gnunet-service-core_sessions.c @@ -1123,11 +1123,7 @@ create_neighbour (const struct GNUNET_PeerIdentity *pid) #endif n = GNUNET_malloc (sizeof (struct Neighbour)); n->peer = *pid; - GNUNET_CRYPTO_aes_create_session_key (&n->encrypt_key); - now = GNUNET_TIME_absolute_get (); - n->encrypt_key_created = now; - n->last_activity = now; - n->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY; + n->last_activity = GNUNET_TIME_absolute_get (); n->bw_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT; n->bw_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT; n->bw_out_internal_limit = GNUNET_BANDWIDTH_value_init (UINT32_MAX); @@ -1673,7 +1669,118 @@ GSC_SESSIONS_handle_client_request_info (void *cls, struct GNUNET_SERVER_Client } +/** + * Create a session, a key exchange was just completed. + */ +void +GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer) +{ + { + struct GNUNET_MessageHeader *hdr; + + hdr = compute_type_map_message (); + send_type_map_to_neighbour (hdr, &n->peer.hashPubKey, n); + GNUNET_free (hdr); + } + if (n->bw_out_external_limit.value__ != t.inbound_bw_limit.value__) + { + n->bw_out_external_limit = t.inbound_bw_limit; + n->bw_out = + GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit, + n->bw_out_internal_limit); + GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window, + n->bw_out); + GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out); + } +#if DEBUG_CORE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Confirmed key via `%s' message for peer `%4s'\n", "PONG", + GNUNET_i2s (&n->peer)); +#endif + + + size = + sizeof (struct ConnectNotifyMessage) + + (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information); + if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + /* recovery strategy: throw away performance data */ + GNUNET_array_grow (n->ats, n->ats_count, 0); + size = + sizeof (struct PeerStatusNotifyMessage) + + n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information); + } + cnm = (struct ConnectNotifyMessage *) buf; + cnm->header.size = htons (size); + cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); + cnm->ats_count = htonl (n->ats_count); + cnm->peer = n->peer; + mats = &cnm->ats; + memcpy (mats, n->ats, + n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information)); + mats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR); + mats[n->ats_count].value = htonl (0); + send_to_all_clients (&cnm->header, GNUNET_NO, + GNUNET_CORE_OPTION_SEND_CONNECT); + process_encrypted_neighbour_queue (n); + n->last_activity = GNUNET_TIME_absolute_get (); + + if (n->status == PEER_STATE_KEY_CONFIRMED) + { + now = GNUNET_TIME_absolute_get (); + n->last_activity = now; + changed = GNUNET_YES; + if (!up) + { + GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"), + 1, GNUNET_NO); + n->time_established = now; + } + if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (n->keep_alive_task); + n->keep_alive_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide + (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, + 2), &send_keep_alive, n); + } + + +} + + +/** + * Update information about a session. + * + * @param peer peer who's session should be updated + * @param bw_out new outbound bandwidth limit for the peer + * @param atsi performance information + * @param atsi_count number of performance records supplied + */ +void +GSC_SESSIONS_update (const struct GNUNET_PeerIdentity *peer, + struct GNUNET_BANDWIDTH_Value32NBO bw_out, + const struct GNUNET_TRANSPORT_ATS_Information *atsi, + uint32_t atsi_count) +{ + if (bw_out_external_limit.value__ != pt->inbound_bw_limit.value__) + { +#if DEBUG_CORE_SET_QUOTA + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received %u b/s as new inbound limit for peer `%4s'\n", + (unsigned int) ntohl (pt->inbound_bw_limit.value__), + GNUNET_i2s (&n->peer)); +#endif + n->bw_out_external_limit = pt->inbound_bw_limit; + n->bw_out = + GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit, + n->bw_out_internal_limit); + GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window, + n->bw_out); + GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out); + } +} /** diff --git a/src/core/gnunet-service-core_sessions.h b/src/core/gnunet-service-core_sessions.h index fc5944cda..781398d44 100644 --- a/src/core/gnunet-service-core_sessions.h +++ b/src/core/gnunet-service-core_sessions.h @@ -146,6 +146,28 @@ GSC_SESSIONS_handle_client_request_info (void *cls, struct GNUNET_SERVER_Client const struct GNUNET_MessageHeader *message); +/** + * Create a session, a key exchange was just completed. + */ +void +GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer); + +/** + * Update information about a session. + * + * @param peer peer who's session should be updated + * @param bw_out new outbound bandwidth limit for the peer + * @param atsi performance information + * @param atsi_count number of performance records supplied + */ +void +GSC_SESSIONS_update (const struct GNUNET_PeerIdentity *peer, + struct GNUNET_BANDWIDTH_Value32NBO bw_out, + const struct GNUNET_TRANSPORT_ATS_Information *atsi, + uint32_t atsi_count); + + + /** * Initialize sessions subsystem. */ -- 2.25.1