gnunet-svn
[Top][All Lists]
Advanced

[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;





reply via email to

[Prev in Thread] Current Thread [Next in Thread]