[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r8672 - gnunet/src/transport
From: |
gnunet |
Subject: |
[GNUnet-SVN] r8672 - gnunet/src/transport |
Date: |
Sun, 12 Jul 2009 09:31:11 -0600 |
Author: grothoff
Date: 2009-07-12 09:31:11 -0600 (Sun, 12 Jul 2009)
New Revision: 8672
Modified:
gnunet/src/transport/gnunet-service-transport.c
gnunet/src/transport/plugin_transport.h
gnunet/src/transport/plugin_transport_tcp.c
gnunet/src/transport/plugin_transport_template.c
Log:
improving HELLO validation by transports
Modified: gnunet/src/transport/gnunet-service-transport.c
===================================================================
--- gnunet/src/transport/gnunet-service-transport.c 2009-07-12 13:27:48 UTC
(rev 8671)
+++ gnunet/src/transport/gnunet-service-transport.c 2009-07-12 15:31:11 UTC
(rev 8672)
@@ -437,70 +437,6 @@
/**
- * Message used to ask a peer to validate receipt (to check an address
- * from a HELLO). Followed by the address used. Note that the
- * recipients response does not affirm that he has this address,
- * only that he got the challenge message.
- */
-struct ValidationChallengeMessage
-{
-
- /**
- * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * What are we signing and why?
- */
- struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
-
- /**
- * Random challenge number (in network byte order).
- */
- uint32_t challenge GNUNET_PACKED;
-
- /**
- * Who is the intended recipient?
- */
- struct GNUNET_PeerIdentity target;
-};
-
-
-/**
- * Message used to validate a HELLO. If this was
- * the right recipient, the response is a signature
- * of the original validation request. The
- * challenge is included in the confirmation to make
- * matching of replies to requests possible.
- */
-struct ValidationChallengeResponse
-{
-
- /**
- * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * Random challenge number (in network byte order).
- */
- uint32_t challenge GNUNET_PACKED;
-
- /**
- * Who signed this message?
- */
- struct GNUNET_PeerIdentity sender;
-
- /**
- * Signature.
- */
- struct GNUNET_CRYPTO_RsaSignature signature;
-
-};
-
-
-/**
* For each HELLO, we may have to validate multiple addresses;
* each address gets its own request entry.
*/
@@ -512,12 +448,6 @@
struct ValidationAddress *next;
/**
- * Our challenge message. Points to after this
- * struct, so this field should not be freed.
- */
- struct ValidationChallengeMessage *msg;
-
- /**
* Name of the transport.
*/
char *transport_name;
@@ -533,6 +463,11 @@
size_t addr_len;
/**
+ * Challenge number we used.
+ */
+ uint32_t challenge;
+
+ /**
* Set to GNUNET_YES if the challenge was met,
* GNUNET_SYSERR if we know it failed, GNUNET_NO
* if we are waiting on a response.
@@ -940,116 +875,7 @@
}
-
-
/**
- * We could not use an existing (or validated) connection to
- * talk to a peer. Try addresses that have not yet been
- * validated.
- *
- * @param n neighbour we want to communicate with
- * @return plugin ready to talk, or NULL if none is available
- */
-static struct ReadyList *
-try_unvalidated_addresses (struct NeighbourList *n)
-{
- struct ValidationList *vl;
- struct ValidationAddress *va;
- struct GNUNET_PeerIdentity id;
- struct GNUNET_TIME_Absolute now;
- unsigned int total;
- unsigned int cnt;
- struct ReadyList *rl;
- struct TransportPlugin *plugin;
-
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Trying to connect to `%4s' using unvalidated addresses\n",
- GNUNET_i2s (&n->id));
-#endif
- /* NOTE: this function needs to not only identify the
- plugin but also setup "plugin_handle", binding it to the
- right address using the plugin's "send_to" API */
- now = GNUNET_TIME_absolute_get ();
- vl = pending_validations;
- while (vl != NULL)
- {
- GNUNET_CRYPTO_hash (&vl->publicKey,
- sizeof (struct
- GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
- &id.hashPubKey);
- if (0 == memcmp (&id, &n->id, sizeof (struct GNUNET_PeerIdentity)))
- break;
- vl = vl->next;
- }
- if (vl == NULL)
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "No unvalidated address found for peer `%4s'\n",
- GNUNET_i2s (&n->id));
-#endif
- return NULL;
- }
- total = 0;
- cnt = 0;
- va = vl->addresses;
- while (va != NULL)
- {
- cnt++;
- if (va->expiration.value > now.value)
- total++;
- va = va->next;
- }
- if (total == 0)
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "All %u unvalidated addresses for peer have expired\n",
- cnt);
-#endif
- return NULL;
- }
- total = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
- for (va = vl->addresses; va != NULL; va = va->next)
- {
- if (va->expiration.value <= now.value)
- continue;
- if (total > 0)
- {
- total--;
- continue;
- }
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Trying unvalidated address of `%s' transport\n",
- va->transport_name);
-#endif
- plugin = find_transport (va->transport_name);
- if (plugin == NULL)
- {
- GNUNET_break (0);
- break;
- }
- rl = GNUNET_malloc (sizeof (struct ReadyList));
- rl->next = n->plugins;
- n->plugins = rl;
- rl->plugin = plugin;
- rl->plugin_handle = plugin->api->send_to (plugin->api->cls,
- &n->id,
- 0,
- NULL,
- NULL,
- GNUNET_TIME_UNIT_ZERO,
- &va->msg[1], va->addr_len);
- rl->transmit_ready = GNUNET_YES;
- return rl;
- }
- return NULL;
-}
-
-
-/**
* Check the ready list for the given neighbour and
* if a plugin is ready for transmission (and if we
* have a message), do so!
@@ -1094,8 +920,6 @@
pos = pos->next;
}
if (rl == NULL)
- rl = try_unvalidated_addresses (neighbour);
- if (rl == NULL)
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1568,7 +1392,7 @@
return 0;
ret = GNUNET_HELLO_add_address ((*va)->transport_name,
(*va)->expiration,
- &(*va)->msg[1], (*va)->addr_len, buf, max);
+ &(*va)[1], (*va)->addr_len, buf, max);
*va = (*va)->next;
return ret;
}
@@ -1648,6 +1472,101 @@
}
+
+
+/**
+ * Function that will be called if we receive a validation
+ * of an address challenge that we transmitted to another
+ * peer. Note that the validation should only be considered
+ * acceptable if the challenge matches AND if the sender
+ * address is at least a plausible address for this peer
+ * (otherwise we may be seeing a MiM attack).
+ *
+ * @param cls closure
+ * @param name name of the transport that generated the address
+ * @param peer who responded to our challenge
+ * @param challenge the challenge number we presumably used
+ * @param sender_addr string describing our sender address (as observed
+ * by the other peer in human-readable format)
+ */
+static void
+plugin_env_notify_validation (void *cls,
+ const char *name,
+ const struct GNUNET_PeerIdentity *peer,
+ uint32_t challenge,
+ const char *sender_addr)
+{
+ int all_done;
+ int matched;
+ struct ValidationList *pos;
+ struct ValidationAddress *va;
+ struct GNUNET_PeerIdentity id;
+
+ pos = pending_validations;
+ while (pos != NULL)
+ {
+ GNUNET_CRYPTO_hash (&pos->publicKey,
+ sizeof (struct
+ GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+ &id.hashPubKey);
+ if (0 ==
+ memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
+ break;
+ pos = pos->next;
+ }
+ if (pos == NULL)
+ {
+ /* TODO: call statistics (unmatched PONG) */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _
+ ("Received validation response but have no record of a
matching validation request. Ignoring.\n"));
+ return;
+ }
+ all_done = GNUNET_YES;
+ matched = GNUNET_NO;
+ va = pos->addresses;
+ while (va != NULL)
+ {
+ if (va->challenge == challenge)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Confirmed validity of peer address.\n");
+#endif
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
+ _("Another peer saw us using the address `%s' via `%s'.
If this is not plausible, this address should be listed in the configuration as
implausible to avoid MiM attacks.\n"),
+ sender_addr,
+ name);
+ va->ok = GNUNET_YES;
+ va->expiration =
+ GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
+ matched = GNUNET_YES;
+ }
+ if (va->ok != GNUNET_YES)
+ all_done = GNUNET_NO;
+ va = va->next;
+ }
+ if (GNUNET_NO == matched)
+ {
+ /* TODO: call statistics (unmatched PONG) */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _
+ ("Received `%s' message but have no record of a matching
`%s' message. Ignoring.\n"),
+ "PONG", "PING");
+ }
+ if (GNUNET_YES == all_done)
+ {
+ pos->timeout.value = 0;
+ GNUNET_SCHEDULER_add_delayed (sched,
+ GNUNET_NO,
+ GNUNET_SCHEDULER_PRIORITY_IDLE,
+ GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
+ GNUNET_TIME_UNIT_ZERO,
+ &cleanup_validation, NULL);
+ }
+}
+
+
struct CheckHelloValidatedContext
{
/**
@@ -1681,7 +1600,6 @@
struct ValidationList *e = cls;
struct TransportPlugin *tp;
struct ValidationAddress *va;
- struct ValidationChallengeMessage *vcm;
struct GNUNET_PeerIdentity id;
tp = find_transport (tname);
@@ -1704,25 +1622,14 @@
tname,
GNUNET_i2s(&id));
- va = GNUNET_malloc (sizeof (struct ValidationAddress) +
- sizeof (struct ValidationChallengeMessage) + addrlen);
+ va = GNUNET_malloc (sizeof (struct ValidationAddress) + addrlen);
va->next = e->addresses;
e->addresses = va;
- vcm = (struct ValidationChallengeMessage *) &va[1];
- va->msg = vcm;
va->transport_name = GNUNET_strdup (tname);
va->addr_len = addrlen;
- vcm->header.size =
- htons (sizeof (struct ValidationChallengeMessage) + addrlen);
- vcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
- vcm->purpose.size =
- htonl (sizeof (struct ValidationChallengeMessage) + addrlen -
- sizeof (struct GNUNET_MessageHeader));
- vcm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO);
- vcm->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- (unsigned int) -1);
- vcm->target = id;
- memcpy (&vcm[1], addr, addrlen);
+ va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ (unsigned int) -1);
+ memcpy (&va[1], addr, addrlen);
return GNUNET_OK;
}
@@ -1735,7 +1642,8 @@
static void
check_hello_validated (void *cls,
const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_HELLO_Message *h, uint32_t trust)
+ const struct GNUNET_HELLO_Message *h,
+ uint32_t trust)
{
struct CheckHelloValidatedContext *chvc = cls;
struct ValidationAddress *va;
@@ -1776,20 +1684,19 @@
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Establishing `%s' connection to validate `%s' of `%4s'
(sending our `%s')\n",
+ "Establishing `%s' connection to validate `%s' of `%4s'\n",
va->transport_name,
- "HELLO", GNUNET_i2s (&va->msg->target), "HELLO");
+ "HELLO", GNUNET_i2s (peer));
#endif
tp = find_transport (va->transport_name);
GNUNET_assert (tp != NULL);
- if (NULL ==
- tp->api->send_to (tp->api->cls,
- &va->msg->target,
- 0,
- (const struct GNUNET_MessageHeader *) our_hello,
- &va->msg->header,
- HELLO_VERIFICATION_TIMEOUT,
- &va->msg[1], va->addr_len))
+ if (GNUNET_OK !=
+ tp->api->validate (tp->api->cls,
+ peer,
+ va->challenge,
+ HELLO_VERIFICATION_TIMEOUT,
+ &va[1],
+ va->addr_len))
va->ok = GNUNET_SYSERR;
va = va->next;
}
@@ -1885,188 +1792,8 @@
}
-/**
- * Handle PING-message. If the plugin that gave us the message is
- * able to queue the PONG immediately, we only queue one PONG.
- * Otherwise we send at most TWO PONG messages, one via an unconfirmed
- * transport and one via a confirmed transport. Both addresses are
- * selected randomly among those available.
- *
- * @param plugin plugin that gave us the message
- * @param sender claimed sender of the PING
- * @param plugin_context context that might be used to send response
- * @param message the actual message
- */
-static void
-process_ping (struct TransportPlugin *plugin,
- const struct GNUNET_PeerIdentity *sender,
- void *plugin_context,
- const struct GNUNET_MessageHeader *message)
-{
- const struct ValidationChallengeMessage *vcm;
- struct ValidationChallengeResponse vcr;
- uint16_t msize;
- struct NeighbourList *n;
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Processing PING\n");
-#endif
- msize = ntohs (message->size);
- if (msize < sizeof (struct ValidationChallengeMessage))
- {
- GNUNET_break_op (0);
- return;
- }
- vcm = (const struct ValidationChallengeMessage *) message;
- if (0 != memcmp (&vcm->target,
- &my_identity, sizeof (struct GNUNET_PeerIdentity)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Received `%s' message not destined for me!\n"), "PING");
- /* TODO: call statistics */
- return;
- }
- if ((ntohl (vcm->purpose.size) !=
- msize - sizeof (struct GNUNET_MessageHeader))
- || (ntohl (vcm->purpose.purpose) !=
- GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO))
- {
- GNUNET_break_op (0);
- return;
- }
- msize -= sizeof (struct ValidationChallengeMessage);
- if (GNUNET_OK !=
- plugin->api->address_suggested (plugin->api->cls, &vcm[1], msize))
- {
- GNUNET_break_op (0);
- return;
- }
- vcr.header.size = htons (sizeof (struct ValidationChallengeResponse));
- vcr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
- vcr.challenge = vcm->challenge;
- vcr.sender = my_identity;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_rsa_sign (my_private_key,
- &vcm->purpose, &vcr.signature));
-#if EXTRA_CHECKS
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_rsa_verify
- (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &vcm->purpose,
- &vcr.signature, &my_public_key));
-#endif
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Trying to transmit PONG using inbound connection\n");
-#endif
- n = find_neighbour (sender);
- if (n == NULL)
- {
- GNUNET_break (0);
- return;
- }
- transmit_to_peer (NULL, 0, &vcr.header, GNUNET_YES, n);
-}
-
-
/**
- * Handle PONG-message.
- *
- * @param message the actual message
- */
-static void
-process_pong (struct TransportPlugin *plugin,
- const struct GNUNET_MessageHeader *message)
-{
- const struct ValidationChallengeResponse *vcr;
- struct ValidationList *pos;
- struct GNUNET_PeerIdentity peer;
- struct ValidationAddress *va;
- int all_done;
- int matched;
-
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
- "Processing PONG\n");
-#endif
- vcr = (const struct ValidationChallengeResponse *) message;
- pos = pending_validations;
- while (pos != NULL)
- {
- GNUNET_CRYPTO_hash (&pos->publicKey,
- sizeof (struct
- GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
- &peer.hashPubKey);
- if (0 ==
- memcmp (&peer, &vcr->sender, sizeof (struct GNUNET_PeerIdentity)))
- break;
- pos = pos->next;
- }
- if (pos == NULL)
- {
- /* TODO: call statistics (unmatched PONG) */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _
- ("Received `%s' message but have no record of a matching
`%s' message. Ignoring.\n"),
- "PONG", "PING");
- return;
- }
- all_done = GNUNET_YES;
- matched = GNUNET_NO;
- va = pos->addresses;
- while (va != NULL)
- {
- if (va->msg->challenge == vcr->challenge)
- {
- if (GNUNET_OK !=
- GNUNET_CRYPTO_rsa_verify
- (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &va->msg->purpose,
- &vcr->signature, &pos->publicKey))
- {
- /* this could rarely happen if we used the same
- challenge number for the peer for two different
- transports / addresses, but the likelihood is
- very small... */
- GNUNET_break_op (0);
- }
- else
- {
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Confirmed validity of peer address.\n");
-#endif
- va->ok = GNUNET_YES;
- va->expiration =
- GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
- matched = GNUNET_YES;
- }
- }
- if (va->ok != GNUNET_YES)
- all_done = GNUNET_NO;
- va = va->next;
- }
- if (GNUNET_NO == matched)
- {
- /* TODO: call statistics (unmatched PONG) */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _
- ("Received `%s' message but have no record of a matching
`%s' message. Ignoring.\n"),
- "PONG", "PING");
- }
- if (GNUNET_YES == all_done)
- {
- pos->timeout.value = 0;
- GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_NO,
- GNUNET_SCHEDULER_PRIORITY_IDLE,
- GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
- GNUNET_TIME_UNIT_ZERO,
- &cleanup_validation, NULL);
- }
-}
-
-
-/**
* The peer specified by the given neighbour has timed-out. Update
* our state and do the necessary notifications. Also notifies
* our clients that the neighbour is now officially gone.
@@ -2342,12 +2069,6 @@
#endif
transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
break;
- case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
- process_ping (plugin, peer, plugin_context, message);
- break;
- case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
- process_pong (plugin, message);
- break;
case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
n->saw_ack = GNUNET_YES;
/* intentional fall-through! */
@@ -2639,10 +2360,13 @@
plug->env.cfg = cfg;
plug->env.sched = sched;
plug->env.my_public_key = &my_public_key;
+ plug->env.my_private_key = my_private_key;
+ plug->env.my_identity = &my_identity;
plug->env.cls = plug;
plug->env.receive = &plugin_env_receive;
plug->env.lookup = &plugin_env_lookup_address;
plug->env.notify_address = &plugin_env_notify_address;
+ plug->env.notify_validation = &plugin_env_notify_validation;
plug->env.default_quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) /
(60 * 1000);
plug->env.max_connections = max_connect_per_transport;
}
Modified: gnunet/src/transport/plugin_transport.h
===================================================================
--- gnunet/src/transport/plugin_transport.h 2009-07-12 13:27:48 UTC (rev
8671)
+++ gnunet/src/transport/plugin_transport.h 2009-07-12 15:31:11 UTC (rev
8672)
@@ -91,6 +91,29 @@
/**
+ * Function that will be called if we receive a validation
+ * of an address challenge that we transmitted to another
+ * peer. Note that the validation should only be considered
+ * acceptable if the challenge matches AND if the sender
+ * address is at least a plausible address for this peer
+ * (otherwise we may be seeing a MiM attack).
+ *
+ * @param cls closure
+ * @param name name of the transport that generated the address
+ * @param peer who responded to our challenge
+ * @param challenge the challenge number we presumably used
+ * @param sender_addr string describing our sender address (as observed
+ * by the other peer in human-readable format)
+ */
+typedef void (*GNUNET_TRANSPORT_ValidationNotification) (void *cls,
+ const char *name,
+ const struct
GNUNET_PeerIdentity *peer,
+ uint32_t challenge,
+ const char
*sender_addr);
+
+
+
+/**
* Function that will be called for each address the transport
* is aware that it might be reachable under.
*
@@ -167,6 +190,16 @@
struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *my_public_key;
/**
+ * Our private key.
+ */
+ struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
+
+ /**
+ * Identity of this peer.
+ */
+ const struct GNUNET_PeerIdentity *my_identity;
+
+ /**
* Closure for the various callbacks.
*/
void *cls;
@@ -190,6 +223,14 @@
GNUNET_TRANSPORT_AddressNotification notify_address;
/**
+ * Function that must be called by each plugin to notify the
+ * transport service about a successful validation of an
+ * address of another peer (or at least likely successful
+ * validation).
+ */
+ GNUNET_TRANSPORT_ValidationNotification notify_validation;
+
+ /**
* What is the default quota (in terms of incoming bytes per
* ms) for new connections?
*/
@@ -206,34 +247,28 @@
/**
- * Function that can be used by the transport service to transmit
- * a message using the plugin using a fresh connection (even if
+ * Function that can be used by the transport service to validate
+ * the address of another peer. Even if
* we already have a connection to this peer, this function is
- * required to establish a new one).
+ * required to establish a new one.
*
* @param cls closure
* @param target who should receive this message
- * @param priority how important is the message
- * @param msg1 first message to transmit
- * @param msg2 second message to transmit (can be NULL)
+ * @param challenge challenge code to use
* @param timeout how long should we try to transmit these?
* @param addrlen length of the address
* @param addr the address
- * @return session instance if the transmission has been scheduled
- * NULL if the address format is invalid
+ * @return GNUNET_OK on success, GNUNET_SYSERR if the address
+ * format is invalid
*/
-typedef void *
- (*GNUNET_TRANSPORT_TransmitToAddressFunction) (void *cls,
- const struct
- GNUNET_PeerIdentity * target,
- unsigned int priority,
- const struct
- GNUNET_MessageHeader * msg1,
- const struct
- GNUNET_MessageHeader * msg2,
- struct GNUNET_TIME_Relative
- timeout, const void *addr,
- size_t addrlen);
+typedef int
+ (*GNUNET_TRANSPORT_ValidationFunction) (void *cls,
+ const struct
+ GNUNET_PeerIdentity * target,
+ uint32_t challenge,
+ struct GNUNET_TIME_Relative
+ timeout, const void *addr,
+ size_t addrlen);
/**
* Function called by the GNUNET_TRANSPORT_TransmitFunction
@@ -415,7 +450,7 @@
* peer using the specified address. Used to validate
* HELLOs.
*/
- GNUNET_TRANSPORT_TransmitToAddressFunction send_to;
+ GNUNET_TRANSPORT_ValidationFunction validate;
/**
* Function that the transport service will use to transmit data to
Modified: gnunet/src/transport/plugin_transport_tcp.c
===================================================================
--- gnunet/src/transport/plugin_transport_tcp.c 2009-07-12 13:27:48 UTC (rev
8671)
+++ gnunet/src/transport/plugin_transport_tcp.c 2009-07-12 15:31:11 UTC (rev
8672)
@@ -33,6 +33,7 @@
#include "gnunet_resolver_service.h"
#include "gnunet_server_lib.h"
#include "gnunet_service_lib.h"
+#include "gnunet_signatures.h"
#include "gnunet_statistics_service.h"
#include "gnunet_transport_service.h"
#include "plugin_transport.h"
@@ -62,7 +63,85 @@
*/
#define ACK_LOG_SIZE 32
+
+
/**
+ * Message used to ask a peer to validate receipt (to check an address
+ * from a HELLO). Followed by the address used. Note that the
+ * recipients response does not affirm that he has this address,
+ * only that he got the challenge message.
+ */
+struct ValidationChallengeMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PING
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Random challenge number (in network byte order).
+ */
+ uint32_t challenge GNUNET_PACKED;
+
+ /**
+ * Who is the intended recipient?
+ */
+ struct GNUNET_PeerIdentity target;
+
+};
+
+
+/**
+ * Message used to validate a HELLO. The challenge is included in the
+ * confirmation to make matching of replies to requests possible. The
+ * signature signs the original challenge number, our public key, the
+ * sender's address (so that the sender can check that the address we
+ * saw is plausible for him and possibly detect a MiM attack) and a
+ * timestamp (to limit replay).<p>
+ *
+ * This message is followed by the address of the
+ * client that we are observing (which is part of what
+ * is being signed).
+ */
+struct ValidationChallengeResponse
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PONG
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * For padding, always zero.
+ */
+ uint32_t reserved GNUNET_PACKED;
+
+ /**
+ * Signature.
+ */
+ struct GNUNET_CRYPTO_RsaSignature signature;
+
+ /**
+ * What are we signing and why?
+ */
+ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
+
+ /**
+ * Random challenge number (in network byte order).
+ */
+ uint32_t challenge GNUNET_PACKED;
+
+ /**
+ * Who signed this message?
+ */
+ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
+
+};
+
+
+
+/**
* Initial handshake message for a session. This header
* is followed by the address that the other peer used to
* connect to us (so that we may learn it) or the address
@@ -625,35 +704,30 @@
/**
- * Function that can be used by the transport service to transmit
- * a message using the plugin using a fresh connection (even if
- * we already have a connection to this peer, this function is
- * required to establish a new one).
+ * Function that can be used by the transport service to validate that
+ * another peer is reachable at a particular address (even if we
+ * already have a connection to this peer, this function is required
+ * to establish a new one).
*
* @param cls closure
* @param target who should receive this message
- * @param priority how important is the message
- * @param msg1 first message to transmit
- * @param msg2 second message to transmit (can be NULL)
- * @param timeout how long should we try to transmit these?
+ * @param challenge challenge code to use
* @param addrlen length of the address
* @param addr the address
- * @return session if the transmission has been scheduled
- * NULL if the address format is invalid
+ * @param timeout how long should we try to transmit these?
+ * @return GNUNET_OK if the transmission has been scheduled
*/
-static void *
-tcp_plugin_send_to (void *cls,
- const struct GNUNET_PeerIdentity *target,
- unsigned int priority,
- const struct GNUNET_MessageHeader *msg1,
- const struct GNUNET_MessageHeader *msg2,
- struct GNUNET_TIME_Relative timeout,
- const void *addr, size_t addrlen)
+static int
+tcp_plugin_validate (void *cls,
+ const struct GNUNET_PeerIdentity *target,
+ uint32_t challenge,
+ struct GNUNET_TIME_Relative timeout,
+ const void *addr, size_t addrlen)
{
struct Plugin *plugin = cls;
struct Session *session;
- struct PendingMessage *pl;
struct PendingMessage *pm;
+ struct ValidationChallengeMessage *vcm;
session = connect_and_create_session (plugin, target, addr, addrlen);
if (session == NULL)
@@ -662,44 +736,24 @@
GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
"tcp", "Failed to create fresh session.\n");
#endif
- return NULL;
+ return GNUNET_SYSERR;
}
- pl = NULL;
- if (msg2 != NULL)
- {
- pm = GNUNET_malloc (sizeof (struct PendingMessage) +
- ntohs (msg2->size));
- pm->msg = (struct GNUNET_MessageHeader *) &pm[1];
- memcpy (pm->msg, msg2, ntohs (msg2->size));
- pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
- pm->is_welcome = GNUNET_NO;
- pl = pm;
- }
- if (msg1 != NULL)
- {
- pm = GNUNET_malloc (sizeof (struct PendingMessage) +
- ntohs (msg1->size));
- pm->msg = (struct GNUNET_MessageHeader *) &pm[1];
- memcpy (pm->msg, msg1, ntohs (msg1->size));
- pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
- pm->is_welcome = GNUNET_NO;
- pm->next = pl;
- pl = pm;
- }
- /* append */
- if (session->pending_messages != NULL)
- {
- pm = session->pending_messages;
- while (pm->next != NULL)
- pm = pm->next;
- pm->next = pl;
- }
- else
- {
- session->pending_messages = pl;
- }
+ pm = GNUNET_malloc (sizeof (struct PendingMessage) +
+ sizeof (struct ValidationChallengeMessage) + addrlen);
+ pm->msg = (struct GNUNET_MessageHeader *) &pm[1];
+ pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ pm->is_welcome = GNUNET_YES;
+ vcm = (struct ValidationChallengeMessage*) &pm[1];
+ vcm->header.size =
+ htons (sizeof (struct ValidationChallengeMessage) + addrlen);
+ vcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PING);
+ vcm->challenge = htonl(challenge);
+ vcm->target = *target;
+ memcpy (&vcm[1], addr, addrlen);
+ GNUNET_assert (session->pending_messages == NULL);
+ session->pending_messages = pm;
process_pending_messages (session);
- return session;
+ return GNUNET_OK;
}
@@ -1346,6 +1400,210 @@
/**
+ * Send a validation challenge response.
+ */
+static size_t
+send_vcr (void *cls,
+ size_t size,
+ void *buf)
+{
+ struct ValidationChallengeResponse *vcr = cls;
+ uint16_t msize;
+
+ if (NULL == buf)
+ {
+ GNUNET_free (vcr);
+ return 0;
+ }
+ msize = ntohs(vcr->header.size);
+ GNUNET_assert (size >= msize);
+ memcpy (buf, vcr, msize);
+ GNUNET_free (vcr);
+ return msize;
+}
+
+
+/**
+ * We've received a PING from this peer via TCP.
+ * Send back our PONG.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_tcp_ping (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct Plugin *plugin = cls;
+ const struct ValidationChallengeMessage *vcm;
+ struct ValidationChallengeResponse *vcr;
+ uint16_t msize;
+ size_t addrlen;
+ void *addr;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Processing PING\n");
+#endif
+ msize = ntohs (message->size);
+ if (msize < sizeof (struct ValidationChallengeMessage))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ vcm = (const struct ValidationChallengeMessage *) message;
+ if (0 != memcmp (&vcm->target,
+ plugin->env->my_identity, sizeof (struct
GNUNET_PeerIdentity)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Received `%s' message not destined for me!\n"), "PING");
+ /* TODO: call statistics */
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ msize -= sizeof (struct ValidationChallengeMessage);
+ if (GNUNET_OK !=
+ tcp_plugin_address_suggested (plugin, &vcm[1], msize))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_SERVER_client_get_address (client,
+ &addr,
+ &addrlen))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ vcr = GNUNET_malloc (sizeof (struct ValidationChallengeResponse) + addrlen);
+ vcr->header.size = htons (sizeof (struct ValidationChallengeResponse) +
addrlen);
+ vcr->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PONG);
+ vcr->purpose.size =
+ htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+ sizeof (uint32_t) +
+ sizeof ( struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
+ addrlen);
+ vcr->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
+ vcr->challenge = vcm->challenge;
+ vcr->signer = *plugin->env->my_public_key;
+ memcpy (&vcr[1],
+ addr,
+ addrlen);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_rsa_sign (plugin->env->my_private_key,
+ &vcr->purpose,
+ &vcr->signature));
+#if EXTRA_CHECKS
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_rsa_verify
+ (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING,
+ &vcr->purpose,
+ &vcr->signature,
+ plugin->env->my_public_key));
+#endif
+ GNUNET_free (addr);
+ if (NULL ==
+ GNUNET_SERVER_notify_transmit_ready (client,
+ sizeof (struct
ValidationChallengeResponse) + addrlen,
+ GNUNET_TIME_UNIT_SECONDS,
+ &send_vcr,
+ vcr))
+ {
+ GNUNET_break (0);
+ GNUNET_free (vcr);
+ }
+ /* after a PING, we always close the connection */
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+}
+
+
+/**
+ * Handle PING-message. If the plugin that gave us the message is
+ * able to queue the PONG immediately, we only queue one PONG.
+ * Otherwise we send at most TWO PONG messages, one via an unconfirmed
+ * transport and one via a confirmed transport. Both addresses are
+ * selected randomly among those available.
+ *
+ * @param plugin plugin that gave us the message
+ * @param sender claimed sender of the PING
+ * @param plugin_context context that might be used to send response
+ * @param message the actual message
+ */
+/**
+ * We've received a PING from this peer via TCP.
+ * Send back our PONG.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_tcp_pong (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct Plugin *plugin = cls;
+ const struct ValidationChallengeResponse *vcr;
+ struct GNUNET_PeerIdentity peer;
+ char *sender_addr;
+ size_t addrlen;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Processing PONG\n");
+#endif
+ if (ntohs(message->size) < sizeof(struct ValidationChallengeResponse))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ addrlen = ntohs(message->size) - sizeof(struct ValidationChallengeResponse);
+ vcr = (const struct ValidationChallengeResponse *) message;
+ if ( (ntohs(vcr->purpose.size) !=
+ sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+ sizeof (uint32_t) +
+ sizeof ( struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
+ addrlen))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify
+ (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING,
+ &vcr->purpose,
+ &vcr->signature,
+ &vcr->signer))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_CRYPTO_hash (&vcr->signer,
+ sizeof( struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+ &peer.hashPubKey);
+ sender_addr = GNUNET_strdup (GNUNET_a2s((const struct sockaddr*) &vcr[1],
+ addrlen));
+ plugin->env->notify_validation (plugin->env->cls,
+ "tcp",
+ &peer,
+ ntohs(vcr->challenge),
+ sender_addr);
+ GNUNET_free (sender_addr);
+ /* after a PONG, we always close the connection */
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+}
+
+
+/**
* We've received a welcome from this peer via TCP.
* Possibly create a fresh client record and send back
* our welcome.
@@ -1562,6 +1820,8 @@
* Handlers for the various TCP messages.
*/
static struct GNUNET_SERVER_MessageHandler my_handlers[] = {
+ {&handle_tcp_ping, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PING, 0},
+ {&handle_tcp_pong, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_PONG, 0},
{&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME, 0},
{&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_DATA, 0},
{NULL, NULL, 0, 0}
@@ -1728,7 +1988,7 @@
plugin->statistics = NULL;
api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
api->cls = plugin;
- api->send_to = &tcp_plugin_send_to;
+ api->validate = &tcp_plugin_validate;
api->send = &tcp_plugin_send;
api->cancel = &tcp_plugin_cancel;
api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
Modified: gnunet/src/transport/plugin_transport_template.c
===================================================================
--- gnunet/src/transport/plugin_transport_template.c 2009-07-12 13:27:48 UTC
(rev 8671)
+++ gnunet/src/transport/plugin_transport_template.c 2009-07-12 15:31:11 UTC
(rev 8672)
@@ -132,33 +132,29 @@
/**
- * Function that can be used by the transport service to transmit
- * a message using the plugin using a fresh connection (even if
- * we already have a connection to this peer, this function is
- * required to establish a new one).
+ * Function that can be used by the transport service to validate that
+ * another peer is reachable at a particular address (even if we
+ * already have a connection to this peer, this function is required
+ * to establish a new one).
*
* @param cls closure
* @param target who should receive this message
- * @param priority how important is the message
- * @param msg1 first message to transmit
- * @param msg2 second message to transmit (can be NULL)
- * @param timeout how long until we give up?
- * @param addr the address
+ * @param challenge challenge code to use
* @param addrlen length of the address
- * @return non-null session if the transmission has been scheduled
- * NULL if the address format is invalid
+ * @param addr the address
+ * @param timeout how long should we try to transmit these?
+ * @return GNUNET_OK if the transmission has been scheduled
*/
-static void *
-template_plugin_send_to (void *cls,
- const struct GNUNET_PeerIdentity *target,
- unsigned int priority,
- const struct GNUNET_MessageHeader *msg1,
- const struct GNUNET_MessageHeader *msg2,
- struct GNUNET_TIME_Relative timeout,
- const void *addr, size_t addrlen)
+static int
+template_plugin_validate (void *cls,
+ const struct GNUNET_PeerIdentity *target,
+ uint32_t challenge,
+ struct GNUNET_TIME_Relative timeout,
+ const void *addr,
+ size_t addrlen)
{
// FIXME
- return NULL;
+ return GNUNET_SYSERR;
}
@@ -311,7 +307,7 @@
plugin->statistics = NULL;
api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
api->cls = plugin;
- api->send_to = &template_plugin_send_to;
+ api->validate = &template_plugin_validate;
api->send = &template_plugin_send;
api->cancel = &template_plugin_cancel;
api->address_pretty_printer = &template_plugin_address_pretty_printer;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r8672 - gnunet/src/transport,
gnunet <=