*/
#include "platform.h"
#include "gnunet-service-core_kx.h"
+#include "gnunet-service-core.h"
+#include "gnunet-service-core_clients.h"
#include "gnunet-service-core_neighbours.h"
+#include "gnunet-service-core_sessions.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_peerinfo_service.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_constants.h"
+#include "gnunet_signatures.h"
+#include "gnunet_protocols.h"
+#include "core.h"
+
+/**
+ * How long do we wait for SET_KEY confirmation initially?
+ */
+#define INITIAL_SET_KEY_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (MAX_SET_KEY_DELAY, 1)
+
+/**
+ * What is the minimum frequency for a PING message?
+ */
+#define MIN_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+/**
+ * What is the maximum age of a message for us to consider processing
+ * it? Note that this looks at the timestamp used by the other peer,
+ * so clock skew between machines does come into play here. So this
+ * should be picked high enough so that a little bit of clock skew
+ * does not prevent peers from connecting to us.
+ */
+#define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS
+
+/**
+ * What is the maximum delay for a SET_KEY message?
+ */
+#define MAX_SET_KEY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
/**
};
+/**
+ * Number of bytes (at the beginning) of "struct EncryptedMessage"
+ * that are NOT encrypted.
+ */
+#define ENCRYPTED_HEADER_SIZE (offsetof(struct EncryptedMessage, sequence_number))
+
/**
* State machine for our P2P encryption handshake. Everyone starts in
*/
GNUNET_SCHEDULER_TaskIdentifier keep_alive_task;
+ /**
+ * Bit map indicating which of the 32 sequence numbers before the last
+ * were received (good for accepting out-of-order packets and
+ * estimating reliability of the connection)
+ */
+ unsigned int last_packets_bitmap;
+
+ /**
+ * last sequence number received on this connection (highest)
+ */
+ uint32_t last_sequence_number_received;
+
+ /**
+ * last sequence number transmitted
+ */
+ uint32_t last_sequence_number_sent;
+
/**
* What was our PING challenge number (for this peer)?
*/
GNUNET_assert (size ==
GNUNET_CRYPTO_aes_encrypt (in, (uint16_t) size,
&kx->encrypt_key, iv, out));
- GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes encrypted"), size,
+ GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes encrypted"), size,
GNUNET_NO);
#if DEBUG_CORE > 2
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
GNUNET_break (0);
return GNUNET_SYSERR;
}
- GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes decrypted"), size,
+ GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# bytes decrypted"), size,
GNUNET_NO);
#if DEBUG_CORE > 1
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
}
+/**
+ * Send our key (and encrypted PING) to the other peer.
+ *
+ * @param kx key exchange context
+ */
+static void
+send_key (struct GSC_KeyExchangeInfo *kx);
+
/**
* Task that will retry "send_key" if our previous attempt failed.
struct GSC_KeyExchangeInfo *kx = cls;
struct SetKeyMessage *skm;
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->retry_set_key_task);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == kx->retry_set_key_task);
if (err_msg != NULL)
{
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,
+ GNUNET_STATISTICS_update (GSC_stats,
gettext_noop
("# Delayed connecting due to lack of public key"),
1, GNUNET_NO);
}
kx->public_key =
GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
- if (GNUNET_OK != GNUNET_HELLO_get_key (hello, n->public_key))
+ if (GNUNET_OK != GNUNET_HELLO_get_key (hello, kx->public_key))
{
GNUNET_break (0);
GNUNET_free (kx->public_key);
}
-/**
- * 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.
*
kx = GNUNET_malloc (sizeof (struct GSC_KeyExchangeInfo));
kx->peer = *pid;
- n->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
+ kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
kx->pitr = GNUNET_PEERINFO_iterate (peerinfo,
pid,
GNUNET_TIME_UNIT_FOREVER_REL /* timeout? */,
}
if (kx->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (n->keep_alive_task);
+ GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
kx->keep_alive_task = GNUNET_SCHEDULER_NO_TASK;
}
GNUNET_free_non_null (kx->skm_received);
*/
void
GSC_KX_handle_set_key (struct GSC_KeyExchangeInfo *kx,
- const struct GNUNET_MessageHandler *msg)
+ const struct GNUNET_MessageHeader *msg)
{
const struct SetKeyMessage *m;
- struct SetKeyMessage *m_cpy;
struct GNUNET_TIME_Absolute t;
struct GNUNET_CRYPTO_AesSessionKey k;
struct PingMessage *ping;
struct PongMessage *pong;
- enum PeerStateMachine sender_status;
+ enum KxStateMachine sender_status;
uint16_t size;
- size = ntohs (msg->header);
+ size = ntohs (msg->size);
if (size != sizeof (struct SetKeyMessage))
{
GNUNET_break_op (0);
return;
}
m = (const struct SetKeyMessage*) msg;
- GNUNET_STATISTICS_update (stats, gettext_noop ("# session keys received"),
+ GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# session keys received"),
1, GNUNET_NO);
#if DEBUG_CORE
GNUNET_break_op (0);
return;
}
- GNUNET_STATISTICS_update (stats,
+ GNUNET_STATISTICS_update (GSC_stats,
gettext_noop ("# SET_KEY messages decrypted"), 1,
GNUNET_NO);
kx->decrypt_key = k;
kx->last_packets_bitmap = 0;
kx->decrypt_key_created = t;
}
- sender_status = (enum PeerStateMachine) ntohl (m->sender_status);
+ sender_status = (enum KxStateMachine) ntohl (m->sender_status);
switch (kx->status)
{
case KX_STATE_DOWN:
- kx->status = PEER_STATE_KEY_RECEIVED;
+ kx->status = KX_STATE_KEY_RECEIVED;
/* we're not up, so we are already doing 'send_key' */
break;
case KX_STATE_KEY_SENT:
- n->status = PEER_STATE_KEY_RECEIVED;
+ kx->status = KX_STATE_KEY_RECEIVED;
/* we're not up, so we are already doing 'send_key' */
break;
case KX_STATE_KEY_RECEIVED:
break;
case KX_STATE_UP:
if ( (sender_status == KX_STATE_DOWN) ||
- (sender_status == KX_PEER_STATE_KEY_SENT) )
+ (sender_status == KX_STATE_KEY_SENT) )
send_key (kx); /* we are up, but other peer is not! */
break;
default:
* @param msg the encrypted PING message itself
*/
void
-GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *n, const struct GNUNET_MessageHeader *msg)
+GSC_KX_handle_ping (struct GSC_KeyExchangeInfo *kx,
+ const struct GNUNET_MessageHeader *msg)
{
const struct PingMessage *m;
struct PingMessage t;
(kx->status != KX_STATE_UP) )
{
/* defer */
- GNUNET_free_non_null (n->pending_ping);
- n->pending_ping = GNUNET_copy_message (msg);
+ GNUNET_free_non_null (kx->ping_received);
+ kx->ping_received = GNUNET_copy_message (msg);
return;
}
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));
+ GNUNET_i2s (&kx->peer));
#endif
derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity);
if (GNUNET_OK !=
char sender[9];
char peer[9];
- GNUNET_snprintf (sender, sizeof (sender), "%8s", GNUNET_i2s (&n->peer));
+ GNUNET_snprintf (sender, sizeof (sender), "%8s", GNUNET_i2s (&kx->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"),
- sender, GNUNET_i2s (&my_identity), peer);
+ sender, GNUNET_i2s (&GSC_my_identity), peer);
GNUNET_break_op (0);
return;
}
/* construct PONG */
- tx.inbound_bw_limit = n->bw_in;
+ tx.inbound_bw_limit = kx->bw_in; // FIXME!
tx.challenge = t.challenge;
tx.target = t.target;
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, &kx->peer);
- do_encrypt (n, &iv, &tx.challenge, &tp.challenge,
+ derive_pong_iv (&iv, &kx->encrypt_key, tp.iv_seed, t.challenge, &kx->peer);
+ do_encrypt (kx, &iv, &tx.challenge, &tp.challenge,
sizeof (struct PongMessage) - ((void *) &tp.challenge -
(void *) tp));
GNUNET_STATISTICS_update (GSC_stats,
{
struct PingMessage pp;
struct PingMessage *pm;
+ struct GNUNET_CRYPTO_AesInitializationVector iv;
pm = &kx->ping;
pm->header.size = htons (sizeof (struct PingMessage));
return;
}
setup_fresh_ping (kx);
- GDS_NEIGHBOURS_transmit (&kx->peer,
+ GSC_NEIGHBOURS_transmit (&kx->peer,
&kx->ping.header,
kx->set_key_retry_frequency);
retry =
MIN_PING_FREQUENCY);
kx->keep_alive_task =
GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, kx);
+}
+
+/**
+ * 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 (kx->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);
}
{
const struct PongMessage *m;
struct PongMessage t;
- struct ConnectNotifyMessage *cnm;
struct GNUNET_CRYPTO_AesInitializationVector iv;
- char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
- struct GNUNET_TRANSPORT_ATS_Information *mats;
uint16_t msize;
- size_t size;
msize = ntohs (msg->size);
if (msize != sizeof (struct PongMessage))
{
if (kx->status == KX_STATE_KEY_SENT)
{
- GNUNET_free_non_null (n->pending_pong);
- n->pending_pong = GNUNET_copy_message (msg);
+ GNUNET_free_non_null (kx->pong_received);
+ kx->pong_received = GNUNET_copy_message (msg);
}
return;
}
/* mark as garbage, just to be sure */
memset (&t, 255, sizeof (t));
derive_pong_iv (&iv, &kx->decrypt_key, m->iv_seed, kx->ping_challenge,
- &my_identity);
+ &GSC_my_identity);
if (GNUNET_OK !=
do_decrypt (kx, &iv, &m->challenge, &t.challenge,
sizeof (struct PongMessage) - ((void *) &m->challenge -
GNUNET_break_op (0);
return;
}
- GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages decrypted"),
+ GNUNET_STATISTICS_update (GSC_stats, gettext_noop ("# PONG messages decrypted"),
1, GNUNET_NO);
if ((0 != memcmp (&t.target, &kx->peer, sizeof (struct GNUNET_PeerIdentity)))
|| (kx->ping_challenge != t.challenge))
#if DEBUG_CORE
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received malformed `%s' wanted sender `%4s' with challenge %u\n",
- "PONG", GNUNET_i2s (&n->peer),
- (unsigned int) n->ping_challenge);
+ "PONG", GNUNET_i2s (&kx->peer),
+ (unsigned int) kx->ping_challenge);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received malformed `%s' received from `%4s' with challenge %u\n",
"PONG", GNUNET_i2s (&t.target), (unsigned int) t.challenge);
GNUNET_break (0); /* should be impossible */
return;
case KX_STATE_KEY_RECEIVED:
- GNUNET_STATISTICS_update (stats,
+ GNUNET_STATISTICS_update (GSC_stats,
gettext_noop
("# Session keys confirmed via PONG"), 1,
GNUNET_NO);
kx->status = KX_STATE_UP;
- GSC_SESSIONS_create (&kx->peer);
+ GSC_SESSIONS_create (&kx->peer, kx);
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:
+ case KX_STATE_UP:
update_timeout (kx);
break;
default:
static void
send_key (struct GSC_KeyExchangeInfo *kx)
{
- struct GNUNET_CRYPTO_AesInitializationVector iv;
-
GNUNET_assert (kx->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK);
if (KX_STATE_UP == kx->status)
return; /* nothing to do */
}
/* update status */
- switch (n->status)
+ switch (kx->status)
{
case KX_STATE_DOWN:
- n->status = PEER_STATE_KEY_SENT;
+ kx->status = KX_STATE_KEY_SENT;
/* setup SET KEY message */
- setup_fresh_set_key (kx);
+ setup_fresh_setkey (kx);
setup_fresh_ping (kx);
- GNUNET_STATISTICS_update (stats,
+ GNUNET_STATISTICS_update (GSC_stats,
gettext_noop
("# SET_KEY and PING messages created"), 1,
GNUNET_NO);
break;
case KX_STATE_KEY_RECEIVED:
break;
- case KX_STATE_KEY_CONFIRMED:
+ case KX_STATE_UP:
GNUNET_break (0);
return;
default:
/* always update sender status in SET KEY message */
kx->skm.sender_status = htonl ((int32_t) kx->status);
- GDS_NEIGHBOURS_transmit (&kx->peer,
+ GSC_NEIGHBOURS_transmit (&kx->peer,
&kx->skm.header,
kx->set_key_retry_frequency);
- GDS_NEIGHBOURS_transmit (&kx->peer,
+ GSC_NEIGHBOURS_transmit (&kx->peer,
&kx->ping.header,
kx->set_key_retry_frequency);
kx->retry_set_key_task =
kx->encrypt_key_created);
GNUNET_CRYPTO_hmac (&auth_key, &em->sequence_number,
used - ENCRYPTED_HEADER_SIZE, &em->hmac);
- GDS_NEIGHBOURS_transmit (&kx->peer,
+ GSC_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);
-}
-
-
/**
* Closure for 'deliver_message'
*/
* Number of entries in 'atsi' array.
*/
uint32_t atsi_count;
-}
-
+};
+
/**
* We received an encrypted message. Decrypt, validate and
* pass on to the appropriate clients.
*
- * @param n target of the message
+ * @param kx key exchange context for encrypting the message
* @param m encrypted message
* @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,
+GSC_KX_handle_encrypted_message (struct GSC_KeyExchangeInfo *kx,
const struct GNUNET_MessageHeader *msg,
const struct GNUNET_TRANSPORT_ATS_Information *atsi,
uint32_t atsi_count)
if ( (kx->status != KX_STATE_KEY_RECEIVED) &&
(kx->status != KX_STATE_UP) )
{
- GNUNET_STATISTICS_update (stats,
+ GNUNET_STATISTICS_update (GSC_stats,
gettext_noop
("# failed to decrypt message (no session key)"),
1, GNUNET_NO);
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received duplicate message, ignoring.\n");
- GNUNET_STATISTICS_update (stats,
+ GNUNET_STATISTICS_update (GSC_stats,
gettext_noop ("# bytes dropped (duplicates)"),
size, GNUNET_NO);
/* duplicate, ignore */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Message received far too old (%llu ms). Content ignored.\n"),
GNUNET_TIME_absolute_get_duration (t).rel_value);
- GNUNET_STATISTICS_update (stats,
+ GNUNET_STATISTICS_update (GSC_stats,
gettext_noop
("# bytes dropped (ancient message)"), size,
GNUNET_NO);
update_timeout (kx);
GSC_SESSIONS_update (&kx->peer,
pt->inbound_bw_limit);
- GNUNET_STATISTICS_update (stats,
+ GNUNET_STATISTICS_update (GSC_stats,
gettext_noop ("# bytes of payload decrypted"),
size - sizeof (struct EncryptedMessage), GNUNET_NO);
dmc.atsi = atsi;
}
GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
- &my_identity.hashPubKey);
- peerinfo = GNUNET_PEERINFO_connect (cfg);
+ &GSC_my_identity.hashPubKey);
+ peerinfo = GNUNET_PEERINFO_connect (GSC_cfg);
if (NULL == peerinfo)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,