stuff
[oweals/gnunet.git] / src / transport / gnunet-service-transport_validation.c
index 4f0848c8775624c8ea659d0107a196c98228ff74..c77fe7a44788f5a229868fda4e76bd22213a264f 100644 (file)
@@ -26,6 +26,7 @@
 #include "platform.h"
 #include "gnunet-service-transport_validation.h"
 #include "gnunet-service-transport_plugins.h"
+#include "gnunet-service-transport_hello.h"
 #include "gnunet-service-transport.h"
 #include "gnunet_hello_lib.h"
 #include "gnunet_peerinfo_service.h"
@@ -243,11 +244,6 @@ struct CheckHelloValidatedContext
    */
   const struct GNUNET_HELLO_Message *hello;
 
-  /**
-   * Context for peerinfo iteration.
-   */
-  struct GNUNET_PEERINFO_IteratorContext *piter;
-
 };
 
 
@@ -273,95 +269,10 @@ static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
  */
 static struct GNUNET_CONTAINER_MultiHashMap *notify_map;
 
-
 /**
- * Start the validation subsystem.
+ * Context for peerinfo iteration.
  */
-void 
-GST_validation_start ()
-{
-  validation_map = GNUNET_CONTAINER_multihashmap_create (VALIDATION_MAP_SIZE);
-  notify_map = GNUNET_CONTAINER_multihashmap_create (VALIDATION_MAP_SIZE);
-}
-
-
-/**
- * Iterate over validation entries and free them.
- *
- * @param cls (unused)
- * @param key peer identity (unused)
- * @param value a 'struct ValidationEntry' to clean up
- * @return GNUNET_YES (continue to iterate)
- */
-static int
-cleanup_validation_entry (void *cls,
-                         const GNUNET_HashCode *key,
-                         void *value)
-{
-  struct ValidationEntry *ve = value;
-    
-  GNUNET_free (ve->transport_name);
-  if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task)
-    {
-      GNUNET_SCHEDULER_cancel (ve->timeout_task);
-      ve->timeout_task = GNUNET_SCHEDULER_NO_TASK;
-    }
-  GNUNET_free (ve);
-  return GNUNET_OK;
-}
-
-
-/**
- * Stop the validation subsystem.
- */
-void
-GST_validation_stop ()
-{
-  struct CheckHelloValidatedContext *chvc;
-
-  GNUNET_CONTAINER_multihashmap_iterate (validation_map,
-                                        &cleanup_validation_entry,
-                                        NULL);
-  GNUNET_CONTAINER_multihashmap_destroy (validation_map);
-  validation_map = NULL;
-  GNUNET_assert (GNUNET_CONTAINER_multihashmap_size (notify_map) == 0);
-  GNUNET_CONTAINER_multihashmap_destroy (notify_map);
-  notify_map = NULL;
-  while (NULL != (chvc = chvc_head))
-    {
-      GNUNET_CONTAINER_DLL_remove (chvc_head,
-                                  chvc_tail,
-                                  chvc);
-      GNUNET_PEERINFO_iterate_cancel (chvc->piter);      
-      GNUNET_free (chvc);
-    }
-}
-
-
-/**
- * Address validation cleanup task (record no longer needed).
- *
- * @param cls the 'struct ValidationEntry'
- * @param tc scheduler context (unused)
- */
-static void
-timeout_hello_validation (void *cls, 
-                         const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  struct ValidationEntry *va = cls;
-
-  va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
-  GNUNET_STATISTICS_update (GST_stats,
-                           gettext_noop ("# address records discarded"),
-                           1,
-                           GNUNET_NO);
-  GNUNET_break (GNUNET_OK ==
-                GNUNET_CONTAINER_multihashmap_remove (validation_map,
-                                                     &va->pid.hashPubKey,
-                                                     va));
-  GNUNET_free (va->transport_name);
-  GNUNET_free (va);
-}
+static struct GNUNET_PEERINFO_NotifyContext *pnc;
 
 
 /**
@@ -474,10 +385,170 @@ find_validation_entry (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub
 }
 
 
+/**
+ * Iterator which adds the given address to the set of validated
+ * addresses.
+ *
+ * @param cls original HELLO message
+ * @param tname name of the transport
+ * @param expiration expiration time
+ * @param addr the address
+ * @param addrlen length of the address
+ * @return GNUNET_OK (keep the address)
+ */
+static int
+add_valid_address (void *cls,
+                  const char *tname,
+                  struct GNUNET_TIME_Absolute expiration,
+                  const void *addr, 
+                  uint16_t addrlen)
+{
+  const struct GNUNET_HELLO_Message *hello = cls;
+  struct ValidationEntry *ve;
+  struct GNUNET_PeerIdentity pid;
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
+
+  if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0)
+    return GNUNET_OK; /* expired */
+  if ( (GNUNET_OK !=
+       GNUNET_HELLO_get_id (hello, &pid)) ||
+       (GNUNET_OK !=
+       GNUNET_HELLO_get_key (hello, &public_key)) )
+    {
+      GNUNET_break (0);
+      return GNUNET_OK; /* invalid HELLO !? */
+    }
+    
+  ve = find_validation_entry (&public_key, &pid, tname, addr, addrlen);
+  ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until,
+                                             expiration);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Function called for any HELLO known to PEERINFO. 
+ *
+ * @param cls unused
+ * @param peer id of the peer, NULL for last call
+ * @param hello hello message for the peer (can be NULL)
+ * @param error message
+ */
+static void
+process_peerinfo_hello (void *cls,
+                       const struct GNUNET_PeerIdentity *peer,
+                       const struct GNUNET_HELLO_Message *hello,
+                       const char *err_msg)
+{
+  GNUNET_assert (NULL != peer);
+  if (NULL == hello)
+    return;
+  GNUNET_assert (NULL ==
+                GNUNET_HELLO_iterate_addresses (hello,
+                                                GNUNET_NO,
+                                                &add_valid_address,
+                                                (void*) hello));  
+}
+
+
+/**
+ * Start the validation subsystem.
+ */
+void 
+GST_validation_start ()
+{
+  validation_map = GNUNET_CONTAINER_multihashmap_create (VALIDATION_MAP_SIZE);
+  notify_map = GNUNET_CONTAINER_multihashmap_create (VALIDATION_MAP_SIZE);
+  pnc = GNUNET_PEERINFO_notify (GST_cfg,
+                               &process_peerinfo_hello,
+                               NULL);
+}
+
+
+/**
+ * Iterate over validation entries and free them.
+ *
+ * @param cls (unused)
+ * @param key peer identity (unused)
+ * @param value a 'struct ValidationEntry' to clean up
+ * @return GNUNET_YES (continue to iterate)
+ */
+static int
+cleanup_validation_entry (void *cls,
+                         const GNUNET_HashCode *key,
+                         void *value)
+{
+  struct ValidationEntry *ve = value;
+    
+  GNUNET_free (ve->transport_name);
+  if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task)
+    {
+      GNUNET_SCHEDULER_cancel (ve->timeout_task);
+      ve->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+    }
+  GNUNET_free (ve);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Stop the validation subsystem.
+ */
+void
+GST_validation_stop ()
+{
+  struct CheckHelloValidatedContext *chvc;
+
+  GNUNET_CONTAINER_multihashmap_iterate (validation_map,
+                                        &cleanup_validation_entry,
+                                        NULL);
+  GNUNET_CONTAINER_multihashmap_destroy (validation_map);
+  validation_map = NULL;
+  GNUNET_assert (GNUNET_CONTAINER_multihashmap_size (notify_map) == 0);
+  GNUNET_CONTAINER_multihashmap_destroy (notify_map);
+  notify_map = NULL;
+  while (NULL != (chvc = chvc_head))
+    {
+      GNUNET_CONTAINER_DLL_remove (chvc_head,
+                                  chvc_tail,
+                                  chvc);
+      GNUNET_free (chvc);
+    }
+  GNUNET_PEERINFO_notify_cancel (pnc);
+}
+
+
+/**
+ * Address validation cleanup task (record no longer needed).
+ *
+ * @param cls the 'struct ValidationEntry'
+ * @param tc scheduler context (unused)
+ */
+static void
+timeout_hello_validation (void *cls, 
+                         const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct ValidationEntry *va = cls;
+
+  va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+  GNUNET_STATISTICS_update (GST_stats,
+                           gettext_noop ("# address records discarded"),
+                           1,
+                           GNUNET_NO);
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_CONTAINER_multihashmap_remove (validation_map,
+                                                     &va->pid.hashPubKey,
+                                                     va));
+  GNUNET_free (va->transport_name);
+  GNUNET_free (va);
+}
+
+
 /**
  * Send the given PONG to the given address.
  *
  * @param cls the PONG message
+ * @param public_key public key for the peer, never NULL
  * @param target peer this change is about, never NULL
  * @param valid_until is ZERO if we never validated the address,
  *                    otherwise a time up to when we consider it (or was) valid
@@ -490,6 +561,7 @@ find_validation_entry (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pub
  */
 static void
 multicast_pong (void *cls,
+               const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key,
                const struct GNUNET_PeerIdentity *target,
                struct GNUNET_TIME_Absolute valid_until,
                struct GNUNET_TIME_Absolute validation_block,
@@ -540,6 +612,7 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
   const struct TransportPingMessage *ping;
   struct TransportPongMessage *pong;
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
+  struct SessionHeader *session_header;
   const char *addr;
   const char *addrend;
   size_t alen;
@@ -590,13 +663,14 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
       /* peer wants to confirm that we have an outbound connection to him; 
         we handle this case here even though it has nothing to do with
         address validation (!) */
-      if (sender_address == NULL)
+      if ( (sender_address == NULL) || (session == NULL) )
        {
          GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                      _("Refusing to create PONG since I do initiate the session with `%s'.\n"),
                      GNUNET_i2s (sender));
          return;
        }
+      session_header = (struct SessionHeader *)session;
 #if DEBUG_TRANSPORT
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Creating PONG indicating that we initiated a connection to peer `%s' using address `%s' \n",
@@ -624,8 +698,6 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
       memcpy (&((char*)&pong[1])[slen],
              sender_address,
              sender_address_len);
-#if 0
-      /* FIXME: lookup signature! */
       if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < 
          PONG_SIGNATURE_LIFETIME.rel_value / 4)
        {
@@ -637,7 +709,7 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
          session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
          pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
          GNUNET_assert (GNUNET_OK ==
-                        GNUNET_CRYPTO_rsa_sign (my_private_key,
+                        GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
                                                 &pong->purpose,
                                                 &session_header->pong_signature));
        }
@@ -645,21 +717,15 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
        {
          pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
        }
-      memcpy (&pong->signature,
-             &session_header->pong_signature,
-             sizeof (struct GNUNET_CRYPTO_RsaSignature));
-#else
-      pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
-      GNUNET_assert (GNUNET_OK ==
-                    GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
-                                            &pong->purpose,
-                                            &pong->signature));
-#endif
+      pong->signature = session_header->pong_signature;
     }
   else
     {
       /* peer wants to confirm that this is one of our addresses, this is what is
         used for address validation */
+      struct GNUNET_CRYPTO_RsaSignature *sig_cache;
+      struct GNUNET_TIME_Absolute *sig_cache_exp;
+
       addrend = memchr (addr, '\0', alen);
       if (NULL == addrend)
        {
@@ -669,13 +735,13 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
       addrend++;
       slen = strlen(addr);
       alen -= slen;
-      papi = GST_plugins_find (addr);
-      
-      if ( (NULL == papi) ||
-          (GNUNET_OK !=
-           papi->check_address (papi->cls,
-                                addrend,
-                                alen)) )
+
+      if (GNUNET_YES !=
+         GST_hello_test_address (addr,
+                                 addrend,
+                                 alen,
+                                 &sig_cache,
+                                 &sig_cache_exp))
        {
          GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                      _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
@@ -699,46 +765,25 @@ GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
       pong->pid = GST_my_identity;
       memcpy (&pong[1], addr, slen);
       memcpy (&((char*)&pong[1])[slen], addrend, alen);
-#if 0
-      if ( (oal != NULL) &&
-          (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
+      if (GNUNET_TIME_absolute_get_remaining (*sig_cache_exp).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
        {
          /* create / update cached sig */
 #if DEBUG_TRANSPORT
          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                      "Creating PONG signature to indicate ownership.\n");
 #endif
-         oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
-         pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
-         GNUNET_assert (GNUNET_OK ==
-                        GNUNET_CRYPTO_rsa_sign (my_private_key,
-                                                &pong->purpose,
-                                                &oal->pong_signature));
-         memcpy (&pong->signature,
-                 &oal->pong_signature,
-                 sizeof (struct GNUNET_CRYPTO_RsaSignature));
-       }
-      else if (oal == NULL)
-       {
-#else
-         /* not using cache (typically DV-only) */
-         pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
+         *sig_cache_exp = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
+         pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp);
          GNUNET_assert (GNUNET_OK ==
                         GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
                                                 &pong->purpose,
-                                                &pong->signature));
-#endif
-#if 0
+                                                sig_cache));
        }
       else
        {
-         /* can used cached version */
-         pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
-         memcpy (&pong->signature,
-                 &oal->pong_signature,
-                 sizeof (struct GNUNET_CRYPTO_RsaSignature));
+         pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp);
        }
-#endif
+      pong->signature = *sig_cache;
     }
 
   /* first see if the session we got this PING from can be used to transmit
@@ -1145,6 +1190,7 @@ iterate_addresses (void *cls,
   struct ValidationEntry *ve = value;
 
   vic->cb (vic->cb_cls,
+          &ve->public_key,
           &ve->pid,
           ve->valid_until,
           ve->validation_block,