-ensure external symbols have proper prefix for conversation service
[oweals/gnunet.git] / src / gns / gnunet-service-gns_resolver.c
index dd893c6b31d5c37a45998d15e444d109734f2726..110263eeefb9b3be47972da345fba6d8efeb0484 100644 (file)
@@ -112,7 +112,7 @@ struct AuthorityChain
     /**
      * The zone of the GNS authority 
      */
-    struct GNUNET_CRYPTO_EccPublicKey gns_authority;
+    struct GNUNET_CRYPTO_EccPublicSignKey gns_authority;
 
     struct
     {
@@ -230,7 +230,7 @@ struct GNS_ResolverHandle
   /**
    * The top-level GNS authoritative zone to query 
    */
-  struct GNUNET_CRYPTO_EccPublicKey authority_zone;
+  struct GNUNET_CRYPTO_EccPublicSignKey authority_zone;
 
   /**
    * called when resolution phase finishes 
@@ -263,7 +263,7 @@ struct GNS_ResolverHandle
   struct GNUNET_RESOLVER_RequestHandle *std_resolve;
 
   /**
-   * Pending Namestore task
+   * Pending Namestore lookup task
    */
   struct GNUNET_NAMESTORE_QueueEntry *namestore_qe;
 
@@ -333,6 +333,30 @@ struct GNS_ResolverHandle
 };
 
 
+/**
+ * Active namestore caching operations.
+ */
+struct CacheOps
+{
+
+  /**
+   * Organized in a DLL.
+   */
+  struct CacheOps *next;
+
+  /**
+   * Organized in a DLL.
+   */
+  struct CacheOps *prev;
+
+  /**
+   * Pending Namestore caching task.
+   */
+  struct GNUNET_NAMESTORE_QueueEntry *namestore_qe_cache;
+
+};
+
+
 /**
  * Our handle to the namestore service
  */
@@ -373,6 +397,17 @@ static struct GNS_ResolverHandle *rlh_head;
  */
 static struct GNS_ResolverHandle *rlh_tail;
 
+/**
+ * Organized in a DLL.
+ */
+static struct CacheOps *co_head;
+
+/**
+ * Organized in a DLL.
+ */
+static struct CacheOps *co_tail;
+
+
 /**
  * Global configuration.
  */
@@ -495,13 +530,15 @@ fail_resolution (void *cls,
 /* Don't have this on W32, here's a naive implementation
  * Was somehow removed on OS X ...  */
 void *
-memrchr (const void *s, int c, size_t n)
+memrchr (const void *s, 
+        int c, 
+        size_t n)
 {
-  size_t i;
-  unsigned char *ucs = (unsigned char *) s;
+  const unsigned char *ucs = s;
+  ssize_t i;
 
   for (i = n - 1; i >= 0; i--)
-    if (ucs[i] == c)
+    if (c == (int) ucs[i])
       return (void *) &ucs[i];
   return NULL;
 }
@@ -577,7 +614,12 @@ transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
        rd[i].flags = GNUNET_NAMESTORE_RF_NONE;
        rd[i].expiration_time = pos->expiration_time;
       }
-    }      
+      i++;
+    }
+    GNUNET_assert (i == n);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
+               "Transmitting standard DNS result with %u records\n",
+               n);
     rh->proc (rh->proc_cls,
              n,
              rd);
@@ -633,9 +675,12 @@ handle_dns_result (void *cls,
   const struct sockaddr_in *sa4;
   const struct sockaddr_in6 *sa6;
 
-  rh->std_resolve = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Received %u bytes of DNS IP data\n",
+             addrlen);
   if (NULL == addr)
   {
+    rh->std_resolve = NULL;
     transmit_lookup_dns_result (rh);
     return;
   }
@@ -719,7 +764,10 @@ dns_result_parser (void *cls,
     GNS_resolver_lookup_cancel (rh);
     return;
   }
-
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Received DNS response for `%s' with %u answers\n",
+             rh->ac_tail->label,
+             (unsigned int) p->num_answers);
   if ( (p->num_answers > 0) &&
        (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
        (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
@@ -727,6 +775,7 @@ dns_result_parser (void *cls,
       GNUNET_free (rh->name);
       rh->name = GNUNET_strdup (p->answers[0].data.hostname);
       start_resolver_lookup (rh);
+      GNUNET_DNSPARSER_free_packet (p);
       return;     
     }
   /* FIXME: add DNAME support */
@@ -738,6 +787,7 @@ dns_result_parser (void *cls,
     unsigned int skip;
     char buf[UINT16_MAX];
     size_t buf_off;
+    size_t buf_start;
 
     buf_off = 0;
     skip = 0;
@@ -790,6 +840,7 @@ dns_result_parser (void *cls,
       case GNUNET_DNSPARSER_TYPE_CNAME:
       case GNUNET_DNSPARSER_TYPE_PTR:
       case GNUNET_DNSPARSER_TYPE_NS:
+       buf_start = buf_off;
        if (GNUNET_OK !=
            GNUNET_DNSPARSER_builder_add_name (buf,
                                               sizeof (buf),
@@ -800,8 +851,11 @@ dns_result_parser (void *cls,
          skip++;
          continue;
        }
+       rd[i - skip].data_size = buf_off - buf_start;
+       rd[i - skip].data = &buf[buf_start];    
        break;
       case GNUNET_DNSPARSER_TYPE_SOA:
+       buf_start = buf_off;
        if (GNUNET_OK !=
            GNUNET_DNSPARSER_builder_add_soa (buf,
                                               sizeof (buf),
@@ -812,8 +866,11 @@ dns_result_parser (void *cls,
          skip++;
          continue;
        }
+       rd[i - skip].data_size = buf_off - buf_start;
+       rd[i - skip].data = &buf[buf_start];    
        break;
       case GNUNET_DNSPARSER_TYPE_MX:
+       buf_start = buf_off;
        if (GNUNET_OK !=
            GNUNET_DNSPARSER_builder_add_mx (buf,
                                             sizeof (buf),
@@ -824,8 +881,11 @@ dns_result_parser (void *cls,
          skip++;
          continue;
        }
+       rd[i - skip].data_size = buf_off - buf_start;
+       rd[i - skip].data = &buf[buf_start];    
        break;
       case GNUNET_DNSPARSER_TYPE_SRV:
+       buf_start = buf_off;
        if (GNUNET_OK !=
            GNUNET_DNSPARSER_builder_add_srv (buf,
                                              sizeof (buf),
@@ -836,6 +896,8 @@ dns_result_parser (void *cls,
          skip++;
          continue;
        }
+       rd[i - skip].data_size = buf_off - buf_start;
+       rd[i - skip].data = &buf[buf_start];    
        break;
       default:
        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -872,6 +934,9 @@ recursive_dns_resolution (struct GNS_ResolverHandle *rh)
 
   ac = rh->ac_tail;
   GNUNET_assert (NULL != ac);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Starting DNS lookup for `%s'\n",
+             ac->label);
   GNUNET_assert (GNUNET_NO == ac->gns_authority);
   switch (((const struct sockaddr *) &ac->authority_info.dns_authority.dns_ip)->sa_family)
   {
@@ -890,7 +955,7 @@ recursive_dns_resolution (struct GNS_ResolverHandle *rh)
   query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
   query->name = GNUNET_strdup (ac->label);
   query->type = rh->record_type;
-  query->class = GNUNET_TUN_DNS_CLASS_INTERNET;
+  query->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
   p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
   p->queries = query;
   p->num_queries = 1;
@@ -937,6 +1002,7 @@ handle_gns_cname_result (struct GNS_ResolverHandle *rh,
 {
   size_t nlen;
   char *res;
+  struct AuthorityChain *ac;
 
   nlen = strlen (cname);
   if ( (nlen > 2) &&
@@ -961,6 +1027,20 @@ handle_gns_cname_result (struct GNS_ResolverHandle *rh,
     }
     GNUNET_free (rh->name);
     rh->name = res;
+    ac = GNUNET_new (struct AuthorityChain);
+    ac->rh = rh;
+    ac->gns_authority = GNUNET_YES;
+    ac->authority_info.gns_authority = rh->ac_tail->authority_info.gns_authority;    
+    ac->label = resolver_lookup_get_next_label (rh);
+    /* tigger shortening */
+    if (NULL != rh->shorten_key)      
+      GNS_shorten_start (rh->ac_tail->label,
+                        &ac->authority_info.gns_authority,
+                        rh->shorten_key);      
+    /* add AC to tail */
+    GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
+                                     rh->ac_tail,
+                                     ac);
     rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
                                            rh);
     return;
@@ -1054,7 +1134,7 @@ vpn_allocation_cb (void *cls,
 /**
  * Process a records that were decrypted from a block.
  *
- * @param cls closure with the 'struct GNS_ResolverHandle'
+ * @param cls closure with the `struct GNS_ResolverHandle`
  * @param rd_count number of entries in @a rd array
  * @param rd array of records with data to store
  */
@@ -1083,7 +1163,12 @@ handle_gns_resolution_result (void *cls,
   size_t off;
   struct GNUNET_NAMESTORE_RecordData rd_new[rd_count];
   unsigned int rd_off;
-  
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Resolution succeeded for `%s' in zone %s, got %u records\n",
+             rh->ac_tail->label,
+             GNUNET_NAMESTORE_z2s (&rh->ac_tail->authority_info.gns_authority),
+             rd_count);  
   if (0 == rh->name_resolution_pos)
   {
     /* top-level match, are we done yet? */
@@ -1091,8 +1176,18 @@ handle_gns_resolution_result (void *cls,
         (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
         (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
     {
-      cname = GNUNET_strndup (rd[0].data,
-                             rd[0].data_size);
+      off = 0;
+      cname = GNUNET_DNSPARSER_parse_name (rd[0].data,
+                                          rd[0].data_size,
+                                          &off);
+      if ( (NULL == cname) ||
+          (off != rd[0].data_size) )
+      {
+       GNUNET_break_op (0);
+       rh->proc (rh->proc_cls, 0, NULL);
+       GNS_resolver_lookup_cancel (rh);
+       return;                 
+      }
       handle_gns_cname_result (rh, 
                               cname);
       GNUNET_free (cname);
@@ -1105,49 +1200,58 @@ handle_gns_resolution_result (void *cls,
     {
       for (i=0;i<rd_count;i++)
       {
-       if (GNUNET_NAMESTORE_TYPE_VPN == rd[i].record_type)
+       switch (rd[i].record_type)
        {
-         af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
-         if (sizeof (struct GNUNET_TUN_GnsVpnRecord) <
-             rd[i].data_size)
+       case GNUNET_NAMESTORE_TYPE_VPN:
          {
-           GNUNET_break_op (0);
-           rh->proc (rh->proc_cls, 0, NULL);
-           GNS_resolver_lookup_cancel (rh);
-           return;         
+           af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
+           if (sizeof (struct GNUNET_TUN_GnsVpnRecord) <
+               rd[i].data_size)
+           {
+             GNUNET_break_op (0);
+             rh->proc (rh->proc_cls, 0, NULL);
+             GNS_resolver_lookup_cancel (rh);
+             return;         
+           }
+           vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
+           vname = (const char *) &vpn[1];
+           if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)])
+           {
+             GNUNET_break_op (0);
+             rh->proc (rh->proc_cls, 0, NULL);
+             GNS_resolver_lookup_cancel (rh);
+             return;
+           }
+           GNUNET_CRYPTO_hash (vname,
+                               strlen (vname), // FIXME: +1?
+                               &vhash);
+           vpn_ctx = GNUNET_new (struct VpnContext);
+           rh->vpn_ctx = vpn_ctx;
+           vpn_ctx->rh = rh;
+           vpn_ctx->rd_data_size = GNUNET_NAMESTORE_records_get_size (rd_count,
+                                                                      rd);
+           vpn_ctx->rd_data = GNUNET_malloc (vpn_ctx->rd_data_size);
+           (void) GNUNET_NAMESTORE_records_serialize (rd_count,
+                                                      rd,
+                                                      vpn_ctx->rd_data_size,
+                                                      vpn_ctx->rd_data);
+           vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
+                                                               af,
+                                                               ntohs (vpn->proto),
+                                                               &vpn->peer,
+                                                               &vhash,
+                                                               GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
+                                                               &vpn_allocation_cb,
+                                                               rh);
+           return;
          }
-         vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
-         vname = (const char *) &vpn[1];
-         if ('\0' != vname[rd[i].data_size - 1 - sizeof (struct GNUNET_TUN_GnsVpnRecord)])
+       case GNUNET_NAMESTORE_TYPE_GNS2DNS:
          {
-           GNUNET_break_op (0);
-           rh->proc (rh->proc_cls, 0, NULL);
-           GNS_resolver_lookup_cancel (rh);
-           return;
+           /* delegation to DNS */
+           goto do_recurse;
          }
-         GNUNET_CRYPTO_hash (vname,
-                             strlen (vname), // FIXME: +1?
-                             &vhash);
-         vpn_ctx = GNUNET_new (struct VpnContext);
-         rh->vpn_ctx = vpn_ctx;
-         vpn_ctx->rh = rh;
-         vpn_ctx->rd_data_size = GNUNET_NAMESTORE_records_get_size (rd_count,
-                                                                    rd);
-         vpn_ctx->rd_data = GNUNET_malloc (vpn_ctx->rd_data_size);
-         (void) GNUNET_NAMESTORE_records_serialize (rd_count,
-                                                    rd,
-                                                    vpn_ctx->rd_data_size,
-                                                    vpn_ctx->rd_data);
-         vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
-                                                             af,
-                                                             ntohs (vpn->proto),
-                                                             &vpn->peer,
-                                                             &vhash,
-                                                             GNUNET_NO,
-                                                             GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
-                                                             &vpn_allocation_cb,
-                                                             rh);
-         return;
+       default:
+         break;
        }
       }
     }
@@ -1195,8 +1299,8 @@ handle_gns_resolution_result (void *cls,
              rd_new[rd_off].data_size = scratch_off - scratch_start;
              rd_off++;
            }
-           GNUNET_free (cname);
          }
+         GNUNET_free_non_null (cname);   
        }
        break;
       case GNUNET_DNSPARSER_TYPE_SOA:
@@ -1231,8 +1335,9 @@ handle_gns_resolution_result (void *cls,
              rd_new[rd_off].data_size = scratch_off - scratch_start;
              rd_off++;
            }
-           GNUNET_DNSPARSER_free_soa (soa);
          }
+         if (NULL != soa)
+           GNUNET_DNSPARSER_free_soa (soa);      
        }
        break;
       case GNUNET_DNSPARSER_TYPE_MX:
@@ -1266,8 +1371,9 @@ handle_gns_resolution_result (void *cls,
              rd_new[rd_off].data_size = scratch_off - scratch_start;
              rd_off++;
            }
-           GNUNET_DNSPARSER_free_mx (mx);
          }
+         if (NULL != mx)
+           GNUNET_DNSPARSER_free_mx (mx);        
        }       
        break;
       case GNUNET_DNSPARSER_TYPE_SRV:
@@ -1305,17 +1411,18 @@ handle_gns_resolution_result (void *cls,
              rd_new[rd_off].data_size = scratch_off - scratch_start;
              rd_off++;
            }
-           GNUNET_DNSPARSER_free_srv (srv);
          }
+         if (NULL != srv)
+           GNUNET_DNSPARSER_free_srv (srv);      
        }
        break;
       case GNUNET_NAMESTORE_TYPE_PKEY:
        /* tigger shortening */
        if (NULL != rh->shorten_key)
        {
-         struct GNUNET_CRYPTO_EccPublicKey pub;
+         struct GNUNET_CRYPTO_EccPublicSignKey pub;
          
-         if (rd[i].data_size != sizeof (struct GNUNET_CRYPTO_EccPublicKey))
+         if (rd[i].data_size != sizeof (struct GNUNET_CRYPTO_EccPublicSignKey))
          {
            GNUNET_break_op (0);
            break;
@@ -1325,7 +1432,10 @@ handle_gns_resolution_result (void *cls,
                             &pub,
                             rh->shorten_key);
        }
+       rd_off++;
+       break;
       default:
+       rd_off++;
        break;
       }
     }
@@ -1335,6 +1445,7 @@ handle_gns_resolution_result (void *cls,
     GNS_resolver_lookup_cancel (rh);
     return;         
   }
+ do_recurse:
   /* need to recurse, check if we can */
   for (i=0;i<rd_count;i++)
   {
@@ -1342,7 +1453,7 @@ handle_gns_resolution_result (void *cls,
     {
     case GNUNET_NAMESTORE_TYPE_PKEY:
       /* delegation to another zone */
-      if (sizeof (struct GNUNET_CRYPTO_EccPublicKey) !=
+      if (sizeof (struct GNUNET_CRYPTO_EccPublicSignKey) !=
          rd[i].data_size)
       {
        GNUNET_break_op (0);
@@ -1356,7 +1467,7 @@ handle_gns_resolution_result (void *cls,
       ac->gns_authority = GNUNET_YES;
       memcpy (&ac->authority_info.gns_authority,
              rd[i].data,
-             sizeof (struct GNUNET_CRYPTO_EccPublicKey));
+             sizeof (struct GNUNET_CRYPTO_EccPublicSignKey));
       ac->label = resolver_lookup_get_next_label (rh);
       /* tigger shortening */
       if (NULL != rh->shorten_key)      
@@ -1370,121 +1481,150 @@ handle_gns_resolution_result (void *cls,
       /* recurse */
       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
                                              rh);
-      break;
-    case GNUNET_DNSPARSER_TYPE_NS:
-      /* resolution continues within DNS */
-      if (GNUNET_DNSPARSER_MAX_NAME_LENGTH < rd[i].data_size)
-      {
-       GNUNET_break_op (0);
-       rh->proc (rh->proc_cls, 0, NULL);
-       GNS_resolver_lookup_cancel (rh);
-       return;     
-      }
-      /* find associated A/AAAA record */
-      sa = NULL;
-      sa_len = 0;
-      for (j=0;j<rd_count;j++)
+      return;
+    case GNUNET_NAMESTORE_TYPE_GNS2DNS:
       {
-       switch (rd[j].record_type)
+       char *ns;
+       /* resolution continues within DNS */
+       if (GNUNET_DNSPARSER_MAX_NAME_LENGTH < rd[i].data_size)
        {
-       case GNUNET_DNSPARSER_TYPE_A:
-         if (sizeof (struct in_addr) != rd[i].data_size)
-         {
-           GNUNET_break_op (0);
-           rh->proc (rh->proc_cls, 0, NULL);
-           GNS_resolver_lookup_cancel (rh);
-           return;     
-         }
-         /* FIXME: might want to check if we support IPv4 here,
-            and otherwise skip this one and hope we find another */
-         memset (&v4, 0, sizeof (v4));
-         sa_len = sizeof (v4);
-         v4.sin_family = AF_INET;
-         v4.sin_port = htons (53);
+         GNUNET_break_op (0);
+         rh->proc (rh->proc_cls, 0, NULL);
+         GNS_resolver_lookup_cancel (rh);
+         return;     
+       }
+       /* find associated A/AAAA record */
+       sa = NULL;
+       sa_len = 0;
+       for (j=0;j<rd_count;j++)
+       {
+         switch (rd[j].record_type)
+           {
+           case GNUNET_DNSPARSER_TYPE_A:
+             if (sizeof (struct in_addr) != rd[j].data_size)
+             {
+               GNUNET_break_op (0);
+               rh->proc (rh->proc_cls, 0, NULL);
+               GNS_resolver_lookup_cancel (rh);
+               return;     
+             }
+             /* FIXME: might want to check if we support IPv4 here,
+                and otherwise skip this one and hope we find another */
+             memset (&v4, 0, sizeof (v4));
+             sa_len = sizeof (v4);
+             v4.sin_family = AF_INET;
+             v4.sin_port = htons (53);
 #if HAVE_SOCKADDR_IN_SIN_LEN
-         v4.sin_len = (u_char) sa_len;
+             v4.sin_len = (u_char) sa_len;
 #endif
-         memcpy (&v4.sin_addr,
-                 rd[j].data,
-                 sizeof (struct in_addr));
-         sa = (struct sockaddr *) &v4;
-         break;
-       case GNUNET_DNSPARSER_TYPE_AAAA:
-         if (sizeof (struct in6_addr) != rd[i].data_size)
-         {
-           GNUNET_break_op (0);
-           rh->proc (rh->proc_cls, 0, NULL);
-           GNS_resolver_lookup_cancel (rh);
-           return;     
-         }
-         /* FIXME: might want to check if we support IPv6 here,
-            and otherwise skip this one and hope we find another */
-         memset (&v6, 0, sizeof (v6));
-         sa_len = sizeof (v6);
-         v6.sin6_family = AF_INET6;
-         v6.sin6_port = htons (53);
+             memcpy (&v4.sin_addr,
+                     rd[j].data,
+                     sizeof (struct in_addr));
+             sa = (struct sockaddr *) &v4;
+             break;
+           case GNUNET_DNSPARSER_TYPE_AAAA:
+             if (sizeof (struct in6_addr) != rd[j].data_size)
+             {
+               GNUNET_break_op (0);
+               rh->proc (rh->proc_cls, 0, NULL);
+               GNS_resolver_lookup_cancel (rh);
+               return;     
+             }
+             /* FIXME: might want to check if we support IPv6 here,
+                and otherwise skip this one and hope we find another */
+             memset (&v6, 0, sizeof (v6));
+             sa_len = sizeof (v6);
+             v6.sin6_family = AF_INET6;
+             v6.sin6_port = htons (53);
 #if HAVE_SOCKADDR_IN_SIN_LEN
-         v6.sin6_len = (u_char) sa_len;
+             v6.sin6_len = (u_char) sa_len;
 #endif
-         memcpy (&v6.sin6_addr,
-                 rd[j].data,
-                 sizeof (struct in6_addr));
-         sa = (struct sockaddr *) &v6;
-         break;
-       default:
-         break;
+             memcpy (&v6.sin6_addr,
+                     rd[j].data,
+                     sizeof (struct in6_addr));
+             sa = (struct sockaddr *) &v6;
+             break;
+           default:
+             break;
+           }
+         if (NULL != sa)
+           break;
        }
-       if (NULL != sa)
-         break;
-      }
-      if (NULL == sa)
-      {
-       /* we cannot continue; NS without A/AAAA */
-       rh->proc (rh->proc_cls, 0, NULL);
-       GNS_resolver_lookup_cancel (rh);
+       if (NULL == sa)
+       {
+         /* we cannot continue; NS without A/AAAA */
+         rh->proc (rh->proc_cls, 0, NULL);
+         GNS_resolver_lookup_cancel (rh);
+         return;
+       }
+       /* expand authority chain */
+       ac = GNUNET_new (struct AuthorityChain);
+       ac->rh = rh;
+       off = 0;
+       ns = GNUNET_DNSPARSER_parse_name (rd[i].data,
+                                         rd[i].data_size,
+                                         &off);
+       if ( (NULL == ns) ||
+            (off != rd[i].data_size) )
+       {
+         GNUNET_break_op (0); /* record not well-formed */
+         rh->proc (rh->proc_cls, 0, NULL);
+         GNS_resolver_lookup_cancel (rh);
+         return;
+       }
+       strcpy (ac->authority_info.dns_authority.name,
+               ns);
+       memcpy (&ac->authority_info.dns_authority.dns_ip,
+               sa,
+               sa_len);
+       /* for DNS recursion, the label is the full DNS name,
+          created from the remainder of the GNS name and the
+          name in the NS record */
+       GNUNET_asprintf (&ac->label,
+                        "%.*s%s%s",
+                        (int) rh->name_resolution_pos,
+                        rh->name,
+                        (0 != rh->name_resolution_pos) ? "." : "",
+                        ns);
+       GNUNET_free (ns);
+       GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
+                                         rh->ac_tail,
+                                         ac);
+       if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                     _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
+                     ac->label);
+         rh->proc (rh->proc_cls, 0, NULL);
+         GNS_resolver_lookup_cancel (rh);
+         return;
+       }
+       /* recurse */
+       rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
+                                               rh);
        return;
       }
-      /* expand authority chain */
-      ac = GNUNET_new (struct AuthorityChain);
-      ac->rh = rh;
-      strncpy (ac->authority_info.dns_authority.name,
-              rd[i].data,
-              rd[i].data_size);
-      ac->authority_info.dns_authority.name[rd[i].data_size] = '\0';
-      memcpy (&ac->authority_info.dns_authority.dns_ip,
-             sa,
-             sa_len);
-      /* for DNS recursion, the label is the full DNS name,
-        created from the remainder of the GNS name and the
-        name in the NS record */
-      GNUNET_asprintf (&ac->label,
-                      "%.*s%s",
-                      (int) rh->name_resolution_pos,
-                      rh->name,
-                      ac->authority_info.dns_authority.name);
-      GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
-                                       rh->ac_tail,
-                                       ac);
-      if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
+    case GNUNET_DNSPARSER_TYPE_CNAME:
       {
-       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                   _("GNS lookup resulted in DNS name that is too long (`%s')\n"),
-                   ac->label);
-       rh->proc (rh->proc_cls, 0, NULL);
-       GNS_resolver_lookup_cancel (rh);
+       char *cname;
+       
+       off = 0;
+       cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
+                                            rd[i].data_size,
+                                            &off);
+       if ( (NULL == cname) ||
+            (off != rd[i].data_size) )
+       {
+         GNUNET_break_op (0); /* record not well-formed */
+         rh->proc (rh->proc_cls, 0, NULL);
+         GNS_resolver_lookup_cancel (rh);
+         return;
+       }
+       handle_gns_cname_result (rh, 
+                                cname);
+       GNUNET_free (cname);
        return;
       }
-      /* recurse */
-      rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
-                                             rh);
-      return;
-    case GNUNET_DNSPARSER_TYPE_CNAME:
-      cname = GNUNET_strndup (rd[i].data,
-                             rd[i].data_size);
-      handle_gns_cname_result (rh, 
-                              cname);
-      GNUNET_free (cname);
-      return;
       /* FIXME: handle DNAME */
     default:
       /* skip */
@@ -1502,7 +1642,7 @@ handle_gns_resolution_result (void *cls,
  * Function called once the namestore has completed the request for
  * caching a block.
  *
- * @param cls closure with the 'struct GNS_ResolverHandle'
+ * @param cls closure with the `struct CacheOps`
  * @param success #GNUNET_OK on success
  * @param emsg error message
  */
@@ -1511,13 +1651,17 @@ namestore_cache_continuation (void *cls,
                              int32_t success,
                              const char *emsg)
 {
-  struct GNS_ResolverHandle *rh = cls;
+  struct CacheOps *co = cls;
 
-  rh->namestore_qe = NULL;
+  co->namestore_qe_cache = NULL;
   if (NULL != emsg)
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _("Failed to cache GNS resolution: %s\n"),
                emsg);
+  GNUNET_CONTAINER_DLL_remove (co_head,
+                              co_tail,
+                              co);
+  GNUNET_free (co);
 }
 
 
@@ -1525,15 +1669,15 @@ namestore_cache_continuation (void *cls,
  * Iterator called on each result obtained for a DHT
  * operation that expects a reply
  *
- * @param cls closure with the 'struct GNS_ResolverHandle'
+ * @param cls closure with the `struct GNS_ResolverHandle`
  * @param exp when will this value expire
  * @param key key of the result
  * @param get_path peers on reply path (or NULL if not recorded)
  *                 [0] = datastore's first neighbor, [length - 1] = local peer
- * @param get_path_length number of entries in get_path
+ * @param get_path_length number of entries in @a get_path
  * @param put_path peers on the PUT path (or NULL if not recorded)
  *                 [0] = origin, [length - 1] = datastore
- * @param put_path_length number of entries in get_path
+ * @param put_path_length number of entries in @a put_path
  * @param type type of the result
  * @param size number of bytes in data
  * @param data pointer to the result data
@@ -1541,7 +1685,7 @@ namestore_cache_continuation (void *cls,
 static void
 handle_dht_response (void *cls,
                     struct GNUNET_TIME_Absolute exp,
-                    const struct GNUNET_HashCode * key,
+                    const struct GNUNET_HashCode *key,
                     const struct GNUNET_PeerIdentity *get_path,
                     unsigned int get_path_length,
                     const struct GNUNET_PeerIdentity *put_path, 
@@ -1552,11 +1696,14 @@ handle_dht_response (void *cls,
   struct GNS_ResolverHandle *rh = cls;
   struct AuthorityChain *ac = rh->ac_tail;
   const struct GNUNET_NAMESTORE_Block *block;
+  struct CacheOps *co;
   
   GNUNET_DHT_get_stop (rh->get_handle);
   rh->get_handle = NULL;
   GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
   rh->dht_heap_node = NULL;  
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Handling response from the DHT\n");
   if (size < sizeof (struct GNUNET_NAMESTORE_Block))
   {
     /* how did this pass DHT block validation!? */
@@ -1567,8 +1714,8 @@ handle_dht_response (void *cls,
   }
   block = data; 
   if (size !=
-      ntohs (block->purpose.size) + 
-      sizeof (struct GNUNET_CRYPTO_EccPublicKey) +
+      ntohl (block->purpose.size) + 
+      sizeof (struct GNUNET_CRYPTO_EccPublicSignKey) +
       sizeof (struct GNUNET_CRYPTO_EccSignature))
   {
     /* how did this pass DHT block validation!? */
@@ -1590,10 +1737,16 @@ handle_dht_response (void *cls,
     return;
   }
   /* Cache well-formed blocks */
-  rh->namestore_qe = GNUNET_NAMESTORE_block_cache (namestore_handle,
-                                                  block,
-                                                  &namestore_cache_continuation,
-                                                  rh);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Caching response from the DHT in namestore\n");
+  co = GNUNET_new (struct CacheOps);
+  co->namestore_qe_cache = GNUNET_NAMESTORE_block_cache (namestore_handle,
+                                                        block,
+                                                        &namestore_cache_continuation,
+                                                        co);
+  GNUNET_CONTAINER_DLL_insert (co_head,
+                              co_tail,
+                              co);
 }
 
 
@@ -1611,18 +1764,24 @@ handle_namestore_block_response (void *cls,
   struct GNS_ResolverHandle *rx;
   struct AuthorityChain *ac = rh->ac_tail;
   const char *label = ac->label;
-  const struct GNUNET_CRYPTO_EccPublicKey *auth = &ac->authority_info.gns_authority;
+  const struct GNUNET_CRYPTO_EccPublicSignKey *auth = &ac->authority_info.gns_authority;
   struct GNUNET_HashCode query;
 
   GNUNET_NAMESTORE_query_from_public_key (auth,
                                          label,
                                          &query);
+  GNUNET_assert (NULL != rh->namestore_qe);
   rh->namestore_qe = NULL;
   if ( (GNUNET_NO == rh->only_cached) &&
        ( (NULL == block) ||
         (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) ) )
   {
     /* Namestore knows nothing; try DHT lookup */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Starting DHT lookup for `%s' in zone %s\n",
+               ac->label,
+               GNUNET_NAMESTORE_z2s (&ac->authority_info.gns_authority));
+    GNUNET_assert (NULL == rh->get_handle);
     rh->get_handle = GNUNET_DHT_get_start (dht_handle,
                                           GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
                                           &query,
@@ -1637,6 +1796,7 @@ handle_namestore_block_response (void *cls,
     {
       /* fail longest-standing DHT request */
       rx = GNUNET_CONTAINER_heap_peek (dht_lookup_heap);
+      GNUNET_assert (NULL != rx);
       rx->proc (rx->proc_cls, 0, NULL);
       GNS_resolver_lookup_cancel (rx);
     }
@@ -1646,10 +1806,16 @@ handle_namestore_block_response (void *cls,
        (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) )
   {
     /* DHT not permitted and no local result, fail */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
+               ac->label,
+               GNUNET_NAMESTORE_z2s (&ac->authority_info.gns_authority));
     rh->proc (rh->proc_cls, 0, NULL);
     GNS_resolver_lookup_cancel (rh);
     return;
   }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Decrypting block from the namestore\n");
   if (GNUNET_OK !=
       GNUNET_NAMESTORE_block_decrypt (block,
                                      auth,
@@ -1676,6 +1842,10 @@ recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
   struct AuthorityChain *ac = rh->ac_tail;
   struct GNUNET_HashCode query;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Starting GNS resolution for `%s' in zone %s\n",
+             ac->label,
+             GNUNET_NAMESTORE_z2s (&ac->authority_info.gns_authority));
   GNUNET_NAMESTORE_query_from_public_key (&ac->authority_info.gns_authority,
                                          ac->label,
                                          &query);
@@ -1683,6 +1853,7 @@ recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
                                                    &query,
                                                    &handle_namestore_block_response,
                                                    rh);
+  GNUNET_assert (NULL != rh->namestore_qe);
 }
 
 
@@ -1708,10 +1879,10 @@ recursive_resolution (void *cls,
     GNS_resolver_lookup_cancel (rh);
     return;
   }
-  if (GNUNET_YES == rh->ac_tail->gns_authority)
-    recursive_gns_resolution_namestore (rh);
-  else
-    recursive_dns_resolution (rh);
+  if (GNUNET_YES == rh->ac_tail->gns_authority) 
+    recursive_gns_resolution_namestore (rh);  
+  else  
+    recursive_dns_resolution (rh);  
 }
 
 
@@ -1748,7 +1919,10 @@ start_resolver_lookup (struct GNS_ResolverHandle *rh)
     default:
       af = AF_UNSPEC;
       break;
-    }
+    }  
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
+               "Doing standard DNS lookup for `%s'\n",
+               rh->name);
     rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name, 
                                              af,
                                              DNS_LOOKUP_TIMEOUT,
@@ -1769,7 +1943,7 @@ start_resolver_lookup (struct GNS_ResolverHandle *rh)
     if ( (NULL == x) ||
         (NULL == y) ||
         (GNUNET_OK !=
-         GNUNET_CRYPTO_ecc_public_key_from_string (pkey,
+         GNUNET_CRYPTO_ecc_public_sign_key_from_string (pkey,
                                                    strlen (pkey),
                                                    &rh->authority_zone)) )
     {
@@ -1817,7 +1991,7 @@ start_resolver_lookup (struct GNS_ResolverHandle *rh)
  * @return handle to cancel operation
  */
 struct GNS_ResolverHandle *
-GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicKey *zone,
+GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicSignKey *zone,
                     uint32_t record_type,
                     const char *name,
                     const struct GNUNET_CRYPTO_EccPrivateKey *shorten_key,
@@ -1826,6 +2000,11 @@ GNS_resolver_lookup (const struct GNUNET_CRYPTO_EccPublicKey *zone,
 {
   struct GNS_ResolverHandle *rh;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             (NULL == shorten_key)
+             ? "Starting lookup for `%s' with shortening disabled\n" 
+             : "Starting lookup for `%s' with shortening enabled\n",
+             name);
   rh = GNUNET_new (struct GNS_ResolverHandle);
   GNUNET_CONTAINER_DLL_insert (rlh_head,
                               rlh_tail,
@@ -1903,6 +2082,8 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
   }
   if (NULL != rh->std_resolve)
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Canceling standard DNS resolution\n");
     GNUNET_RESOLVER_request_cancel (rh->std_resolve);
     rh->std_resolve = NULL;
   }
@@ -1966,6 +2147,7 @@ void
 GNS_resolver_done ()
 {
   struct GNS_ResolverHandle *rh;
+  struct CacheOps *co;
 
   /* abort active resolutions */
   while (NULL != (rh = rlh_head))
@@ -1973,6 +2155,14 @@ GNS_resolver_done ()
     rh->proc (rh->proc_cls, 0, NULL);
     GNS_resolver_lookup_cancel (rh);    
   }
+  while (NULL != (co = co_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (co_head,
+                                co_tail,
+                                co);
+    GNUNET_NAMESTORE_cancel (co->namestore_qe_cache);
+    GNUNET_free (co);
+  }
   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
   dht_lookup_heap = NULL;
   GNUNET_DNSSTUB_stop (dns_handle);