add logic to handle SRV/DANE names (#3003 and 2526) in GNS resolver
[oweals/gnunet.git] / src / gns / gnunet-service-gns_resolver.c
index e0d395a5502d0bb84e04285a5f33e21dad4ad028..67f1902cd05c15290b1813b60aaefdbea5d192f8 100644 (file)
  * @brief GNU Name System resolver logic
  * @author Martin Schanzenbach
  * @author Christian Grothoff
- *
- * TODO:
- * - GNS: handle special SRV names --- no delegation, direct lookup;
- *        can likely be done in 'resolver_lookup_get_next_label'. (#3003)
- * - revocation checks (use REVOCATION service!), (#3004)
- * - DNAME support (#3005)
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_dnsstub_lib.h"
 #include "gnunet_dht_service.h"
 #include "gnunet_gnsrecord_lib.h"
+#include "gnunet_namecache_service.h"
 #include "gnunet_namestore_service.h"
 #include "gnunet_dns_service.h"
 #include "gnunet_resolver_service.h"
+#include "gnunet_revocation_service.h"
 #include "gnunet_dnsparser_lib.h"
+#include "gnunet_tun_lib.h"
 #include "gnunet_gns_service.h"
 #include "gns.h"
 #include "gnunet-service-gns_resolver.h"
@@ -98,6 +95,16 @@ struct AuthorityChain
    */
   char *label;
 
+  /**
+   * label/name suggested for shortening to the authority
+   */
+  char *suggested_shortening_label;
+
+  /**
+   * Do we already try to shorten this authority?
+   */
+  int shortening_started;
+
   /**
    * #GNUNET_YES if the authority was a GNS authority,
    * #GNUNET_NO if the authority was a DNS authority.
@@ -166,7 +173,7 @@ struct DnsResult
   uint64_t expiration_time;
 
   /**
-   * Number of bytes in 'data'.
+   * Number of bytes in @e data.
    */
   size_t data_size;
 
@@ -211,6 +218,30 @@ struct VpnContext
 };
 
 
+/**
+ * Information we keep during the resolution of an
+ * IP address for a DNS server while handling a
+ * GNS2DNS record.
+ */
+struct Gns2DnsContext
+{
+
+  /**
+   * DNS domain in which the resolution will continue
+   * (first part of the GNS2DNS record).
+   */
+  char *ns;
+
+  /**
+   * Handle for the resolution of the IP part of the
+   * GNS2DNS record.  Will return to us the addresses
+   * of the DNS resolver to use.
+   */
+  struct GNS_ResolverHandle *rh;
+
+};
+
+
 /**
  * Handle to a currenty pending resolution.  On result (positive or
  * negative) the #GNS_ResultProcessor is called.
@@ -239,10 +270,16 @@ struct GNS_ResolverHandle
   GNS_ResultProcessor proc;
 
   /**
-   * closure passed to proc
+   * closure passed to @e proc
    */
   void* proc_cls;
 
+  /**
+   * Handle used during GNS2DNS resolution for looking up the
+   * IP address of the DNS server.
+   */
+  struct Gns2DnsContext *g2dc;
+
   /**
    * Handle for DHT lookups. should be NULL if no lookups are in progress
    */
@@ -264,9 +301,14 @@ struct GNS_ResolverHandle
   struct GNUNET_RESOLVER_RequestHandle *std_resolve;
 
   /**
-   * Pending Namestore lookup task
+   * Pending Namecache lookup task
    */
-  struct GNUNET_NAMESTORE_QueueEntry *namestore_qe;
+  struct GNUNET_NAMECACHE_QueueEntry *namecache_qe;
+
+  /**
+   * Pending revocation check.
+   */
+  struct GNUNET_REVOCATION_Query *rev_check;
 
   /**
    * Heap node associated with this lookup.  Used to limit number of
@@ -317,7 +359,7 @@ struct GNS_ResolverHandle
   /**
    * Use only cache
    */
-  int only_cached;
+  enum GNUNET_GNS_LocalOptions options;
 
   /**
    * Desired type for the resolution.
@@ -353,15 +395,15 @@ struct CacheOps
   /**
    * Pending Namestore caching task.
    */
-  struct GNUNET_NAMESTORE_QueueEntry *namestore_qe_cache;
+  struct GNUNET_NAMECACHE_QueueEntry *namecache_qe_cache;
 
 };
 
 
 /**
- * Our handle to the namestore service
+ * Our handle to the namecache service
  */
-static struct GNUNET_NAMESTORE_Handle *namestore_handle;
+static struct GNUNET_NAMECACHE_Handle *namecache_handle;
 
 /**
  * Our handle to the vpn service
@@ -408,6 +450,10 @@ static struct CacheOps *co_head;
  */
 static struct CacheOps *co_tail;
 
+/**
+ * Use namecache
+ */
+static int use_cache;
 
 /**
  * Global configuration.
@@ -549,7 +595,17 @@ memrchr (const void *s,
 
 /**
  * Get the next, rightmost label from the name that we are trying to resolve,
- * and update the resolution position accordingly.
+ * and update the resolution position accordingly.  Labels usually consist
+ * of up to 63 characters without a period ("."); however, we use a special
+ * convention to support SRV and TLSA records where the domain name
+ * includes an encoding for a service and protocol in the name.  The
+ * syntax (see RFC 2782) here is "_Service._Proto.Name" and in this
+ * special case we include the "_Service._Proto" in the rightmost label.
+ * Thus, for "_443._tcp.foo.bar" we first return the label "bar" and then
+ * the label "_443._tcp.foo".  The special case is detected by the
+ * presence of labels beginning with an underscore.  Whenever a label
+ * begins with an underscore, it is combined with the label to its right
+ * (and the "." is preserved).
  *
  * @param rh handle to the resolution operation to get the next label from
  * @return NULL if there are no more labels
@@ -563,7 +619,9 @@ resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
 
   if (0 == rh->name_resolution_pos)
     return NULL;
-  dot = memrchr (rh->name, (int) '.', rh->name_resolution_pos);
+  dot = memrchr (rh->name,
+                 (int) '.',
+                 rh->name_resolution_pos);
   if (NULL == dot)
   {
     /* done, this was the last one */
@@ -578,6 +636,16 @@ resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
     rp = dot + 1;
     rh->name_resolution_pos = dot - rh->name;
   }
+  /* merge labels starting with underscore with label on the right (SRV/DANE case) */
+  while ( (NULL != (dot = memrchr (rh->name,
+                                   (int) '.',
+                                   rh->name_resolution_pos))) &&
+          ('_' == dot[1]) )
+  {
+    len += rh->name_resolution_pos - (dot - rh->name) - 1;
+    rp = dot + 1;
+    rh->name_resolution_pos = dot - rh->name;
+  }
   return GNUNET_strndup (rp, len);
 }
 
@@ -909,6 +977,10 @@ dns_result_parser (void *cls,
        continue;
       }
     }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Returning DNS response for `%s' with %u answers\n",
+                rh->ac_tail->label,
+                (unsigned int) p->num_answers);
     rh->proc (rh->proc_cls, rd_count - skip, rd);
     GNS_resolver_lookup_cancel (rh);
   }
@@ -1034,11 +1106,8 @@ handle_gns_cname_result (struct GNS_ResolverHandle *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);
+    ac->suggested_shortening_label = NULL;
+    ac->shortening_started = GNUNET_NO;
     /* add AC to tail */
     GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
                                      rh->ac_tail,
@@ -1133,6 +1202,146 @@ vpn_allocation_cb (void *cls,
 }
 
 
+/**
+ * We've resolved the IP address for the DNS resolver to use
+ * after encountering a GNS2DNS record.
+ *
+ * TODO: Right now we only foward the request to ONE DNS resolver,
+ * even if we get multiple IP addresses back; a correct implementation
+ * should try all DNS resolvers.
+ *
+ * @param cls the `struct GNS_ResolverHandle` where we encountered
+ *            the GNS2DNS record
+ * @param rd_count number of records in @a rd
+ * @param rd addresses for the DNS resolver  (presumably)
+ */
+static void
+handle_gns2dns_result (void *cls,
+                       unsigned int rd_count,
+                       const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct GNS_ResolverHandle *rh = cls;
+  struct AuthorityChain *ac;
+  unsigned int j;
+  struct sockaddr *sa;
+  struct sockaddr_in v4;
+  struct sockaddr_in6 v6;
+  size_t sa_len;
+
+  /* find suitable A/AAAA record */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received %u results for IP address of DNS server for GNS2DNS transition\n",
+              rd_count);
+  /* enable cleanup of 'rh' handle that comes next... */
+  GNUNET_CONTAINER_DLL_insert (rlh_head,
+                              rlh_tail,
+                              rh->g2dc->rh);
+  rh->g2dc->rh = NULL;
+  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;
+#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[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;
+#endif
+      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)
+  {
+    /* 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;
+  strcpy (ac->authority_info.dns_authority.name,
+          rh->g2dc->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) ? "." : "",
+                   rh->g2dc->ns);
+  GNUNET_free (rh->g2dc->ns);
+  GNUNET_free (rh->g2dc);
+  rh->g2dc = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Will continue resolution using DNS server `%s' to resolve `%s'\n",
+              GNUNET_a2s (sa, sa_len),
+              ac->label);
+  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);
+}
+
+
 /**
  * Process a records that were decrypted from a block.
  *
@@ -1147,12 +1356,8 @@ handle_gns_resolution_result (void *cls,
 {
   struct GNS_ResolverHandle *rh = cls;
   struct AuthorityChain *ac;
+  struct AuthorityChain *shorten_ac;
   unsigned int i;
-  unsigned int j;
-  struct sockaddr *sa;
-  struct sockaddr_in v4;
-  struct sockaddr_in6 v6;
-  size_t sa_len;
   char *cname;
   struct VpnContext *vpn_ctx;
   const struct GNUNET_TUN_GnsVpnRecord *vpn;
@@ -1166,7 +1371,7 @@ handle_gns_resolution_result (void *cls,
   struct GNUNET_GNSRECORD_Data rd_new[rd_count];
   unsigned int rd_off;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
              "Resolution succeeded for `%s' in zone %s, got %u records\n",
              rh->ac_tail->label,
              GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
@@ -1188,6 +1393,7 @@ handle_gns_resolution_result (void *cls,
        GNUNET_break_op (0);
        rh->proc (rh->proc_cls, 0, NULL);
        GNS_resolver_lookup_cancel (rh);
+        GNUNET_free_non_null (cname);
        return;
       }
       handle_gns_cname_result (rh,
@@ -1207,7 +1413,7 @@ handle_gns_resolution_result (void *cls,
        case GNUNET_GNSRECORD_TYPE_VPN:
          {
            af = (GNUNET_DNSPARSER_TYPE_A == rh->record_type) ? AF_INET : AF_INET6;
-           if (sizeof (struct GNUNET_TUN_GnsVpnRecord) <
+           if (sizeof (struct GNUNET_TUN_GnsVpnRecord) >
                rd[i].data_size)
            {
              GNUNET_break_op (0);
@@ -1224,19 +1430,26 @@ handle_gns_resolution_result (void *cls,
              GNS_resolver_lookup_cancel (rh);
              return;
            }
-           GNUNET_CRYPTO_hash (vname,
-                               strlen (vname), // FIXME: +1?
-                               &vhash);
+           GNUNET_TUN_service_name_to_hash (vname,
+                                             &vhash);
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                        "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
+                        GNUNET_i2s (&vpn->peer),
+                        vname,
+                        (int) af,
+                        (int) ntohs (vpn->proto));
            vpn_ctx = GNUNET_new (struct VpnContext);
            rh->vpn_ctx = vpn_ctx;
            vpn_ctx->rh = rh;
            vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
                                                                       rd);
            vpn_ctx->rd_data = GNUNET_malloc (vpn_ctx->rd_data_size);
-           (void) GNUNET_GNSRECORD_records_serialize (rd_count,
-                                                      rd,
-                                                      vpn_ctx->rd_data_size,
-                                                      vpn_ctx->rd_data);
+            vpn_ctx->rd_count = rd_count;
+           GNUNET_assert (vpn_ctx->rd_data_size ==
+                           GNUNET_GNSRECORD_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),
@@ -1244,23 +1457,26 @@ handle_gns_resolution_result (void *cls,
                                                                &vhash,
                                                                GNUNET_TIME_relative_to_absolute (VPN_TIMEOUT),
                                                                &vpn_allocation_cb,
-                                                               rh);
+                                                               vpn_ctx);
            return;
          }
        case GNUNET_GNSRECORD_TYPE_GNS2DNS:
          {
            /* delegation to DNS */
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                        "Found GNS2DNS record, delegating to DNS!\n");
            goto do_recurse;
          }
        default:
          break;
-       }
-      }
-    }
+       } /* end: switch */
+      } /* end: for rd */
+    } /* end: name_resolution_pos */
     /* convert relative names in record values to absolute names,
        using 'scratch' array for memory allocations */
     scratch_off = 0;
     rd_off = 0;
+    shorten_ac = rh->ac_tail;
     for (i=0;i<rd_count;i++)
     {
       rd_new[rd_off] = rd[i];
@@ -1286,6 +1502,7 @@ handle_gns_resolution_result (void *cls,
          else
          {
            cname = translate_dot_plus (rh, cname);
+            GNUNET_break (NULL != cname);
            scratch_start = scratch_off;
            if (GNUNET_OK !=
                GNUNET_DNSPARSER_builder_add_name (scratch,
@@ -1383,8 +1600,6 @@ handle_gns_resolution_result (void *cls,
          struct GNUNET_DNSPARSER_SrvRecord *srv;
 
          off = 0;
-         /* FIXME: passing rh->name here is is not necessarily what we want
-            (SRV support not finished) */
          srv = GNUNET_DNSPARSER_parse_srv (rh->name,
                                            rd[i].data,
                                            rd[i].data_size,
@@ -1418,6 +1633,21 @@ handle_gns_resolution_result (void *cls,
            GNUNET_DNSPARSER_free_srv (srv);
        }
        break;
+
+      case GNUNET_GNSRECORD_TYPE_NICK:
+        {
+          const char *nick;
+          nick = rd[i].data;
+          if ((rd[i].data_size > 0) &&
+              (nick[rd[i].data_size -1] != '\0'))
+          {
+            GNUNET_break_op (0);
+            break;
+          }
+          if (NULL == shorten_ac->suggested_shortening_label)
+            shorten_ac->suggested_shortening_label = GNUNET_strdup (nick);
+          break;
+        }
       case GNUNET_GNSRECORD_TYPE_PKEY:
         {
          struct GNUNET_CRYPTO_EcdsaPublicKey pub;
@@ -1428,14 +1658,6 @@ handle_gns_resolution_result (void *cls,
            break;
          }
          memcpy (&pub, rd[i].data, rd[i].data_size);
-
-          /* tigger shortening */
-          if (NULL != rh->shorten_key)
-          {
-            GNS_shorten_start (rh->ac_tail->label,
-                               &pub,
-                               rh->shorten_key);
-          }
           rd_off++;
           if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type)
           {
@@ -1447,6 +1669,8 @@ handle_gns_resolution_result (void *cls,
             ac->gns_authority = GNUNET_YES;
             ac->authority_info.gns_authority = pub;
             ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
+            ac->suggested_shortening_label = NULL;
+            ac->shortening_started = GNUNET_NO;
             GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
                                               rh->ac_tail,
                                               ac);
@@ -1456,13 +1680,41 @@ handle_gns_resolution_result (void *cls,
           }
         }
        break;
+      case GNUNET_GNSRECORD_TYPE_GNS2DNS:
+        {
+          /* delegation to DNS */
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Found GNS2DNS record, delegating to DNS!\n");
+          goto do_recurse;
+        }
       default:
        rd_off++;
        break;
-      }
+      } /* end: switch */
+    } /* end: for rd_count */
+
+    /* trigger shortening */
+    if ((NULL != rh->shorten_key) &&
+        (NULL != shorten_ac) &&
+        (GNUNET_NO == shorten_ac->shortening_started) &&
+        (NULL != shorten_ac->suggested_shortening_label))
+    {
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Start shortening for label `%s' based on nick `%s'\n",
+                    shorten_ac->label,
+                    shorten_ac->suggested_shortening_label);
+        shorten_ac->shortening_started = GNUNET_YES;
+        GNS_shorten_start (shorten_ac->label,
+                         shorten_ac->suggested_shortening_label,
+                         &shorten_ac->authority_info.gns_authority,
+                         rh->shorten_key);
     }
 
     /* yes, we are done, return result */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Returning GNS response for `%s' with %u answers\n",
+                rh->ac_tail->label,
+                rd_off);
     rh->proc (rh->proc_cls, rd_off, rd_new);
     GNS_resolver_lookup_cancel (rh);
     return;
@@ -1487,15 +1739,12 @@ handle_gns_resolution_result (void *cls,
       ac = GNUNET_new (struct AuthorityChain);
       ac->rh = rh;
       ac->gns_authority = GNUNET_YES;
+      ac->suggested_shortening_label = NULL;
+      ac->shortening_started = GNUNET_NO;
       memcpy (&ac->authority_info.gns_authority,
              rd[i].data,
              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
       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,
@@ -1506,126 +1755,48 @@ handle_gns_resolution_result (void *cls,
       return;
     case GNUNET_GNSRECORD_TYPE_GNS2DNS:
       {
-       char *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++)
-       {
-         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;
-#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[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;
-#endif
-             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)
-       {
-         /* 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);
-         GNUNET_free_non_null (ns);
-         GNUNET_free (ac);
-         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);
+        struct Gns2DnsContext *g2dc;
+        char *ip;
+        char *ns;
+
+        off = 0;
+        ns = GNUNET_DNSPARSER_parse_name (rd[i].data,
+                                          rd[i].data_size,
+                                          &off);
+        ip = GNUNET_DNSPARSER_parse_name (rd[i].data,
+                                          rd[i].data_size,
+                                          &off);
+        if ( (NULL == ns) ||
+             (NULL == ip) ||
+             (off != rd[i].data_size) )
+        {
+          GNUNET_break_op (0);
+          GNUNET_free_non_null (ns);
+          GNUNET_free_non_null (ip);
          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;
+        }
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition\n",
+                    ip);
+        /* resolve 'ip' to determine the IP(s) of the DNS
+           resolver to use */
+        g2dc = GNUNET_new (struct Gns2DnsContext);
+        g2dc->ns = ns;
+        g2dc->rh = GNUNET_new (struct GNS_ResolverHandle);
+        g2dc->rh->authority_zone = rh->ac_tail->authority_info.gns_authority;
+        ip = translate_dot_plus (rh, ip);
+        g2dc->rh->name = ip;
+        g2dc->rh->name_resolution_pos = strlen (ip);
+        g2dc->rh->proc = &handle_gns2dns_result;
+        g2dc->rh->proc_cls = rh;
+        g2dc->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
+        g2dc->rh->options = GNUNET_GNS_LO_DEFAULT;
+        g2dc->rh->loop_limiter = rh->loop_limiter + 1;
+        rh->g2dc = g2dc;
+        start_resolver_lookup (g2dc->rh);
        return;
       }
     case GNUNET_DNSPARSER_TYPE_CNAME:
@@ -1672,13 +1843,13 @@ handle_gns_resolution_result (void *cls,
  * @param emsg error message
  */
 static void
-namestore_cache_continuation (void *cls,
+namecache_cache_continuation (void *cls,
                              int32_t success,
                              const char *emsg)
 {
   struct CacheOps *co = cls;
 
-  co->namestore_qe_cache = NULL;
+  co->namecache_qe_cache = NULL;
   if (NULL != emsg)
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _("Failed to cache GNS resolution: %s\n"),
@@ -1761,13 +1932,19 @@ handle_dht_response (void *cls,
     GNS_resolver_lookup_cancel (rh);
     return;
   }
+  if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Received expired block from the DHT, will not cache it.\n");
+    return;
+  }
   /* Cache well-formed blocks */
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Caching response from the DHT in namestore\n");
+             "Caching response from the DHT in namecache\n");
   co = GNUNET_new (struct CacheOps);
-  co->namestore_qe_cache = GNUNET_NAMESTORE_block_cache (namestore_handle,
+  co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
                                                         block,
-                                                        &namestore_cache_continuation,
+                                                        &namecache_cache_continuation,
                                                         co);
   GNUNET_CONTAINER_DLL_insert (co_head,
                               co_tail,
@@ -1776,57 +1953,101 @@ handle_dht_response (void *cls,
 
 
 /**
- * Process a record that was stored in the namestore.
+ * Initiate a DHT query for a set of GNS records.
+ *
+ * @param rh resolution handle
+ * @param query key to use in the DHT lookup
+ */
+static void
+start_dht_request (struct GNS_ResolverHandle *rh,
+                   const struct GNUNET_HashCode *query)
+{
+  struct GNS_ResolverHandle *rx;
+
+  GNUNET_assert (NULL == rh->get_handle);
+  rh->get_handle = GNUNET_DHT_get_start (dht_handle,
+                                         GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
+                                         query,
+                                         DHT_GNS_REPLICATION_LEVEL,
+                                         GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
+                                         NULL, 0,
+                                         &handle_dht_response, rh);
+  rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
+                                                    rh,
+                                                    GNUNET_TIME_absolute_get ().abs_value_us);
+  if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
+  {
+    /* 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);
+  }
+}
+
+
+/**
+ * Process a records that were decrypted from a block that we got from
+ * the namecache.  Simply calls #handle_gns_resolution_result().
+ *
+ * @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
+ */
+static void
+handle_gns_namecache_resolution_result (void *cls,
+                                        unsigned int rd_count,
+                                        const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct GNS_ResolverHandle *rh = cls;
+
+  handle_gns_resolution_result (rh,
+                                rd_count,
+                                rd);
+}
+
+
+/**
+ * Process a record that was stored in the namecache.
  *
  * @param cls closure with the `struct GNS_ResolverHandle`
- * @param block block that was stored in the namestore
+ * @param block block that was stored in the namecache
  */
 static void
-handle_namestore_block_response (void *cls,
+handle_namecache_block_response (void *cls,
                                 const struct GNUNET_GNSRECORD_Block *block)
 {
   struct GNS_ResolverHandle *rh = cls;
-  struct GNS_ResolverHandle *rx;
   struct AuthorityChain *ac = rh->ac_tail;
   const char *label = ac->label;
   const struct GNUNET_CRYPTO_EcdsaPublicKey *auth = &ac->authority_info.gns_authority;
   struct GNUNET_HashCode query;
 
-  GNUNET_GNSRECORD_query_from_public_key (auth,
-                                         label,
-                                         &query);
-  GNUNET_assert (NULL != rh->namestore_qe);
-  rh->namestore_qe = NULL;
-  if ( (GNUNET_NO == rh->only_cached) &&
+  GNUNET_assert (NULL != rh->namecache_qe);
+  rh->namecache_qe = NULL;
+  if ( ( (GNUNET_GNS_LO_DEFAULT == rh->options) ||
+        ( (GNUNET_GNS_LO_LOCAL_MASTER == rh->options) &&
+          (ac != rh->ac_head) ) ) &&
        ( (NULL == block) ||
         (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) ) )
   {
-    /* Namestore knows nothing; try DHT lookup */
+    /* namecache knows nothing; try DHT lookup */
+    GNUNET_GNSRECORD_query_from_public_key (auth,
+                                            label,
+                                            &query);
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-               "Starting DHT lookup for `%s' in zone %s\n",
-               ac->label,
-               GNUNET_GNSRECORD_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,
-                                          DHT_GNS_REPLICATION_LEVEL,
-                                          GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
-                                          NULL, 0,
-                                          &handle_dht_response, rh);
-    rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
-                                                     rh,
-                                                     GNUNET_TIME_absolute_get ().abs_value_us);
-    if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) > max_allowed_background_queries)
-    {
-      /* 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);
-    }
+                "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
+                ac->label,
+                GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
+                GNUNET_h2s (&query));
+    start_dht_request (rh, &query);
     return;
   }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received result from namecache for label `%s'\n",
+              ac->label);
+
   if ( (NULL == block) ||
        (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (block->expiration_time)).rel_value_us) )
   {
@@ -1839,30 +2060,36 @@ handle_namestore_block_response (void *cls,
     GNS_resolver_lookup_cancel (rh);
     return;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Decrypting block from the namestore\n");
   if (GNUNET_OK !=
       GNUNET_GNSRECORD_block_decrypt (block,
                                      auth,
                                      label,
-                                     &handle_gns_resolution_result,
+                                     &handle_gns_namecache_resolution_result,
                                      rh))
   {
     GNUNET_break_op (0); /* block was ill-formed */
-    rh->proc (rh->proc_cls, 0, NULL);
-    GNS_resolver_lookup_cancel (rh);
+    /* try DHT instead */
+    GNUNET_GNSRECORD_query_from_public_key (auth,
+                                            label,
+                                            &query);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
+                ac->label,
+                GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
+                GNUNET_h2s (&query));
+    start_dht_request (rh, &query);
     return;
   }
 }
 
 
 /**
- * Lookup tail of our authority chain in the namestore.
+ * Lookup tail of our authority chain in the namecache.
  *
  * @param rh query we are processing
  */
 static void
-recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
+recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
 {
   struct AuthorityChain *ac = rh->ac_tail;
   struct GNUNET_HashCode query;
@@ -1874,11 +2101,67 @@ recursive_gns_resolution_namestore (struct GNS_ResolverHandle *rh)
   GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
                                          ac->label,
                                          &query);
-  rh->namestore_qe = GNUNET_NAMESTORE_lookup_block (namestore_handle,
-                                                   &query,
-                                                   &handle_namestore_block_response,
-                                                   rh);
-  GNUNET_assert (NULL != rh->namestore_qe);
+  if (GNUNET_YES == use_cache)
+  {
+    rh->namecache_qe
+      = GNUNET_NAMECACHE_lookup_block (namecache_handle,
+                                       &query,
+                                       &handle_namecache_block_response,
+                                       rh);
+    GNUNET_assert (NULL != rh->namecache_qe);
+  }
+  else
+  {
+    start_dht_request (rh, &query);
+  }
+}
+
+
+/**
+ * Function called with the result from a revocation check.
+ *
+ * @param cls the `struct GNS_ResovlerHandle`
+ * @param is_valid #GNUNET_YES if the zone was not yet revoked
+ */
+static void
+handle_revocation_result (void *cls,
+                          int is_valid)
+{
+  struct GNS_ResolverHandle *rh = cls;
+  struct AuthorityChain *ac = rh->ac_tail;
+
+  rh->rev_check = NULL;
+  if (GNUNET_YES != is_valid)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                _("Zone %s was revoked, resolution fails\n"),
+                GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
+    rh->proc (rh->proc_cls, 0, NULL);
+    GNS_resolver_lookup_cancel (rh);
+    return;
+  }
+  recursive_gns_resolution_namecache (rh);
+}
+
+
+/**
+ * Perform revocation check on tail of our authority chain.
+ *
+ * @param rh query we are processing
+ */
+static void
+recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
+{
+  struct AuthorityChain *ac = rh->ac_tail;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Starting revocation check for zone %s\n",
+             GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
+  rh->rev_check = GNUNET_REVOCATION_query (cfg,
+                                           &ac->authority_info.gns_authority,
+                                           &handle_revocation_result,
+                                           rh);
+  GNUNET_assert (NULL != rh->rev_check);
 }
 
 
@@ -1905,7 +2188,7 @@ recursive_resolution (void *cls,
     return;
   }
   if (GNUNET_YES == rh->ac_tail->gns_authority)
-    recursive_gns_resolution_namestore (rh);
+    recursive_gns_resolution_revocation (rh);
   else
     recursive_dns_resolution (rh);
 }
@@ -1921,10 +2204,42 @@ static void
 start_resolver_lookup (struct GNS_ResolverHandle *rh)
 {
   struct AuthorityChain *ac;
-  char *x;
   char *y;
-  char *pkey;
+  struct in_addr v4;
+  struct in6_addr v6;
 
+  if (1 == inet_pton (AF_INET,
+                      rh->name,
+                      &v4))
+  {
+    /* name is IPv4 address, pretend it's an A record */
+    struct GNUNET_GNSRECORD_Data rd;
+
+    rd.data = &v4;
+    rd.data_size = sizeof (v4);
+    rd.expiration_time = UINT64_MAX;
+    rd.record_type = GNUNET_DNSPARSER_TYPE_A;
+    rd.flags = 0;
+    rh->proc (rh->proc_cls, 1, &rd);
+    GNS_resolver_lookup_cancel (rh);
+    return;
+  }
+  if (1 == inet_pton (AF_INET6,
+                      rh->name,
+                      &v6))
+  {
+    /* name is IPv6 address, pretend it's an AAAA record */
+    struct GNUNET_GNSRECORD_Data rd;
+
+    rd.data = &v6;
+    rd.data_size = sizeof (v6);
+    rd.expiration_time = UINT64_MAX;
+    rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
+    rd.flags = 0;
+    rh->proc (rh->proc_cls, 1, &rd);
+    GNS_resolver_lookup_cancel (rh);
+    return;
+  }
   if ( ( (GNUNET_YES == is_canonical (rh->name)) &&
         (0 != strcmp (GNUNET_GNS_TLD, rh->name)) ) ||
        ( (GNUNET_YES != is_gnu_tld (rh->name)) &&
@@ -1960,26 +2275,19 @@ start_resolver_lookup (struct GNS_ResolverHandle *rh)
     /* Name ends with ".zkey", try to replace authority zone with zkey
        authority */
     GNUNET_free (resolver_lookup_get_next_label (rh)); /* will return "zkey" */
-    x = resolver_lookup_get_next_label (rh); /* will return 'x' coordinate */
     y = resolver_lookup_get_next_label (rh); /* will return 'y' coordinate */
-    GNUNET_asprintf (&pkey,
-                    "%s%s",
-                    x, y);
-    if ( (NULL == x) ||
-        (NULL == y) ||
+    if ( (NULL == y) ||
         (GNUNET_OK !=
-         GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey,
-                                                   strlen (pkey),
-                                                   &rh->authority_zone)) )
+         GNUNET_CRYPTO_ecdsa_public_key_from_string (y,
+                                                      strlen (y),
+                                                      &rh->authority_zone)) )
     {
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                  _("Hostname `%s' is not well-formed, resolution fails\n"),
                  rh->name);
       rh->task_id = GNUNET_SCHEDULER_add_now (&fail_resolution, rh);
     }
-    GNUNET_free_non_null (x);
     GNUNET_free_non_null (y);
-    GNUNET_free (pkey);
   }
   else
   {
@@ -1989,6 +2297,7 @@ start_resolver_lookup (struct GNS_ResolverHandle *rh)
   ac = GNUNET_new (struct AuthorityChain);
   ac->rh = rh;
   ac->label = resolver_lookup_get_next_label (rh);
+  ac->suggested_shortening_label = NULL;
   if (NULL == ac->label)
     /* name was just "gnu", so we default to label '+' */
     ac->label = GNUNET_strdup (GNUNET_GNS_MASTERZONE_STR);
@@ -2010,7 +2319,7 @@ start_resolver_lookup (struct GNS_ResolverHandle *rh)
  * @param record_type the record type to look up
  * @param name the name to look up
  * @param shorten_key a private key for use with PSEU import (can be NULL)
- * @param only_cached #GNUNET_NO to only check locally not DHT for performance
+ * @param options local options to control local lookup
  * @param proc the processor to call on result
  * @param proc_cls the closure to pass to @a proc
  * @return handle to cancel operation
@@ -2020,7 +2329,7 @@ GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
                     uint32_t record_type,
                     const char *name,
                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_key,
-                    int only_cached,
+                    enum GNUNET_GNS_LocalOptions options,
                     GNS_ResultProcessor proc, void *proc_cls)
 {
   struct GNS_ResolverHandle *rh;
@@ -2037,7 +2346,7 @@ GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
   rh->authority_zone = *zone;
   rh->proc = proc;
   rh->proc_cls = proc_cls;
-  rh->only_cached = only_cached;
+  rh->options = options;
   rh->record_type = record_type;
   rh->name = GNUNET_strdup (name);
   rh->name_resolution_pos = strlen (name);
@@ -2072,8 +2381,26 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
                                 rh->ac_tail,
                                 ac);
     GNUNET_free (ac->label);
+    GNUNET_free_non_null (ac->suggested_shortening_label);
     GNUNET_free (ac);
   }
+  if (NULL != rh->g2dc)
+  {
+    /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
+       using GNS_resolver_lookup_cancel here, we need to
+       add it first... */
+    if (NULL != rh->g2dc->rh)
+    {
+      GNUNET_CONTAINER_DLL_insert (rlh_head,
+                                   rlh_tail,
+                                   rh->g2dc->rh);
+      GNS_resolver_lookup_cancel (rh->g2dc->rh);
+      rh->g2dc->rh = NULL;
+    }
+    GNUNET_free (rh->g2dc->ns);
+    GNUNET_free (rh->g2dc);
+    rh->g2dc = NULL;
+  }
   if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
   {
     GNUNET_SCHEDULER_cancel (rh->task_id);
@@ -2100,10 +2427,15 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
     GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
     rh->dns_request = NULL;
   }
-  if (NULL != rh->namestore_qe)
+  if (NULL != rh->namecache_qe)
   {
-    GNUNET_NAMESTORE_cancel (rh->namestore_qe);
-    rh->namestore_qe = NULL;
+    GNUNET_NAMECACHE_cancel (rh->namecache_qe);
+    rh->namecache_qe = NULL;
+  }
+  if (NULL != rh->rev_check)
+  {
+    GNUNET_REVOCATION_query_cancel (rh->rev_check);
+    rh->rev_check = NULL;
   }
   if (NULL != rh->std_resolve)
   {
@@ -2131,13 +2463,13 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
 /**
  * Initialize the resolver
  *
- * @param nh the namestore handle
+ * @param nc the namecache handle
  * @param dht the dht handle
  * @param c configuration handle
  * @param max_bg_queries maximum number of parallel background queries in dht
  */
 void
-GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
+GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
                   struct GNUNET_DHT_Handle *dht,
                   const struct GNUNET_CONFIGURATION_Handle *c,
                   unsigned long long max_bg_queries)
@@ -2145,11 +2477,18 @@ GNS_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
   char *dns_ip;
 
   cfg = c;
-  namestore_handle = nh;
+  namecache_handle = nc;
   dht_handle = dht;
   dht_lookup_heap =
     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
   max_allowed_background_queries = max_bg_queries;
+  if (GNUNET_SYSERR == (use_cache = GNUNET_CONFIGURATION_get_value_yesno (c,
+                                             "gns",
+                                             "USE_CACHE")))
+    use_cache = GNUNET_YES;
+  if (GNUNET_NO == use_cache)
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Namecache disabled\n");
+
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (c,
                                             "gns",
@@ -2185,7 +2524,7 @@ GNS_resolver_done ()
     GNUNET_CONTAINER_DLL_remove (co_head,
                                 co_tail,
                                 co);
-    GNUNET_NAMESTORE_cancel (co->namestore_qe_cache);
+    GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
     GNUNET_free (co);
   }
   GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
@@ -2195,7 +2534,7 @@ GNS_resolver_done ()
   GNUNET_VPN_disconnect (vpn_handle);
   vpn_handle = NULL;
   dht_handle = NULL;
-  namestore_handle = NULL;
+  namecache_handle = NULL;
 }