REST: nothing triggers rest
[oweals/gnunet.git] / src / gns / gnunet-service-gns_resolver.c
index 745a2f3bd45bb2ea631cbe09526772d95b5c3324..703a0f6522a3b2ead18df499d8d5fa1c2b128bf6 100644 (file)
@@ -2,20 +2,20 @@
      This file is part of GNUnet.
      Copyright (C) 2011-2013 GNUnet e.V.
 
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
+     GNUnet is free software: you can redistribute it and/or modify it
+     under the terms of the GNU Affero General Public License as published
+     by the Free Software Foundation, either version 3 of the License,
+     or (at your option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
+     Affero General Public License for more details.
 
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
+     You should have received a copy of the GNU Affero General Public License
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
 */
 
 /**
@@ -60,7 +60,7 @@
 /**
  * DHT replication level
  */
-#define DHT_GNS_REPLICATION_LEVEL 5
+#define DHT_GNS_REPLICATION_LEVEL 10
 
 /**
  * How deep do we allow recursions to go before we abort?
@@ -109,6 +109,11 @@ struct Gns2DnsPending
    * Handle for DNS resolution of the DNS nameserver.
    */
   struct GNUNET_RESOLVER_RequestHandle *dns_rh;
+
+  /**
+   * How many results did we get?
+   */
+  unsigned int num_results;
 };
 
 
@@ -145,16 +150,6 @@ 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.
@@ -285,7 +280,7 @@ struct VpnContext
   /**
    * Number of bytes in @e rd_data.
    */
-  size_t rd_data_size;
+  ssize_t rd_data_size;
 };
 
 
@@ -377,6 +372,12 @@ struct GNS_ResolverHandle
    */
   char *name;
 
+  /**
+   * Legacy Hostname to use if we encountered GNS2DNS record
+   * and thus can deduct the LEHO from that transition.
+   */
+  char *leho;
+
   /**
    * DLL of results we got from DNS.
    */
@@ -501,7 +502,7 @@ static struct CacheOps *co_tail;
 /**
  * Use namecache
  */
-static int use_cache;
+static int disable_cache;
 
 /**
  * Global configuration.
@@ -623,25 +624,6 @@ timeout_resolution (void *cls)
 }
 
 
-#if (defined WINDOWS) || (defined DARWIN)
-/* Don't have this on W32, here's a naive implementation
- * Was somehow removed on OS X ...  */
-static void *
-memrchr (const void *s,
-        int c,
-        size_t n)
-{
-  const unsigned char *ucs = s;
-  ssize_t i;
-
-  for (i = n - 1; i >= 0; i--)
-    if (c == (int) ucs[i])
-      return (void *) &ucs[i];
-  return NULL;
-}
-#endif
-
-
 /**
  * Get the next, rightmost label from the name that we are trying to resolve,
  * and update the resolution position accordingly.  Labels usually consist
@@ -813,7 +795,9 @@ add_dns_result (struct GNS_ResolverHandle *rh,
   res->data_size = data_size;
   res->record_type = record_type;
   res->data = &res[1];
-  GNUNET_memcpy (&res[1], data, data_size);
+  GNUNET_memcpy (&res[1],
+                 data,
+                 data_size);
   GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
                               rh->dns_result_tail,
                               res);
@@ -939,41 +923,57 @@ dns_result_parser (void *cls,
   if ( (p->num_answers > 0) &&
        (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
        (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type) )
-    {
-      int af;
+  {
+    int af;
 
-      GNUNET_free (rh->name);
-      rh->name = GNUNET_strdup (p->answers[0].data.hostname);
-      rh->name_resolution_pos = strlen (rh->name);
-      switch (rh->record_type)
-      {
-      case GNUNET_DNSPARSER_TYPE_A:
-        af = AF_INET;
-        break;
-      case GNUNET_DNSPARSER_TYPE_AAAA:
-        af = AF_INET6;
-        break;
-      default:
-        af = AF_UNSPEC;
-        break;
-      }
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Doing standard DNS lookup for `%s'\n",
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Got CNAME `%s' from DNS for `%s'\n",
+                p->answers[0].data.hostname,
+                rh->name);
+    if (NULL != rh->std_resolve)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Multiple CNAME results from DNS resolving `%s'! Not really allowed...\n",
                   rh->name);
-      rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
-                                                af,
-                                                DNS_LOOKUP_TIMEOUT,
-                                                &handle_dns_result,
-                                                rh);
-      GNUNET_DNSPARSER_free_packet (p);
-      return;
+      GNUNET_RESOLVER_request_cancel (rh->std_resolve);
+    }
+    GNUNET_free (rh->name);
+    rh->name = GNUNET_strdup (p->answers[0].data.hostname);
+    rh->name_resolution_pos = strlen (rh->name);
+    switch (rh->record_type)
+    {
+    case GNUNET_DNSPARSER_TYPE_A:
+      af = AF_INET;
+      break;
+    case GNUNET_DNSPARSER_TYPE_AAAA:
+      af = AF_INET6;
+      break;
+    default:
+      af = AF_UNSPEC;
+      break;
     }
+    if (NULL != rh->leho)
+      add_dns_result (rh,
+                     GNUNET_TIME_UNIT_HOURS.rel_value_us,
+                     GNUNET_GNSRECORD_TYPE_LEHO,
+                     strlen (rh->leho),
+                     rh->leho);
+    rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
+                                              af,
+                                              DNS_LOOKUP_TIMEOUT,
+                                              &handle_dns_result,
+                                              rh);
+    GNUNET_DNSPARSER_free_packet (p);
+    GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
+    rh->dns_request = NULL;
+    return;
+  }
 
   /* convert from (parsed) DNS to (binary) GNS format! */
   rd_count = p->num_answers + p->num_authority_records + p->num_additional_records;
   {
-    struct GNUNET_GNSRECORD_Data rd[rd_count];
-    unsigned int skip;
+    struct GNUNET_GNSRECORD_Data rd[rd_count + 1]; /* +1 for LEHO */
+    int skip;
     char buf[UINT16_MAX];
     size_t buf_off;
     size_t buf_start;
@@ -1097,14 +1097,28 @@ dns_result_parser (void *cls,
        skip++;
        continue;
       }
+    } /* end of for all records in answer */
+    if (NULL != rh->leho)
+    {
+      rd[rd_count - skip].record_type = GNUNET_GNSRECORD_TYPE_LEHO;
+      rd[rd_count - skip].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
+      rd[rd_count - skip].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us;
+      rd[rd_count - skip].data = rh->leho;
+      rd[rd_count - skip].data_size = strlen (rh->leho);
+      skip--; /* skip one LESS */
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Adding LEHO %s\n",
+                 rh->leho);
     }
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Returning DNS response for `%s' with %u answers\n",
                 rh->ac_tail->label,
-                (unsigned int) p->num_answers);
+                (unsigned int) (rd_count - skip));
     rh->proc (rh->proc_cls,
               rd_count - skip,
               rd);
+    GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
+    rh->dns_request = NULL;
   }
   GNUNET_DNSPARSER_free_packet (p);
   if (NULL != rh->task_id)
@@ -1168,6 +1182,7 @@ recursive_dns_resolution (struct GNS_ResolverHandle *rh)
     rh->original_dns_id = p->id;
     GNUNET_assert (NULL != ac->authority_info.dns_authority.dns_handle);
     GNUNET_assert (NULL == rh->dns_request);
+    rh->leho = GNUNET_strdup (ac->label);
     rh->dns_request = GNUNET_DNSSTUB_resolve (ac->authority_info.dns_authority.dns_handle,
                                              dns_request,
                                              dns_request_length,
@@ -1228,8 +1243,6 @@ 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);
-    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,
@@ -1238,6 +1251,17 @@ handle_gns_cname_result (struct GNS_ResolverHandle *rh,
                                            rh);
     return;
   }
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Got CNAME `%s' from GNS for `%s'\n",
+              cname,
+              rh->name);
+  if (NULL != rh->std_resolve)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               "Multiple CNAME results from GNS resolving `%s'! Not really allowed...\n",
+                rh->name);
+    GNUNET_RESOLVER_request_cancel (rh->std_resolve);
+  }
   /* name is absolute, go to DNS */
   GNUNET_free (rh->name);
   rh->name = GNUNET_strdup (cname);
@@ -1305,7 +1329,7 @@ vpn_allocation_cb (void *cls,
   vpn_ctx->vpn_request = NULL;
   rh->vpn_ctx = NULL;
   GNUNET_assert (GNUNET_OK ==
-                GNUNET_GNSRECORD_records_deserialize (vpn_ctx->rd_data_size,
+                GNUNET_GNSRECORD_records_deserialize ((size_t) vpn_ctx->rd_data_size,
                                                       vpn_ctx->rd_data,
                                                       vpn_ctx->rd_count,
                                                       rd));
@@ -1336,6 +1360,10 @@ vpn_allocation_cb (void *cls,
     }
   }
   GNUNET_assert (i < vpn_ctx->rd_count);
+  if (0 == vpn_ctx->rd_count)
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               _("VPN returned empty result for `%s'\n"),
+               rh->name);
   handle_gns_resolution_result (rh,
                                vpn_ctx->rd_count,
                                rd);
@@ -1494,26 +1522,48 @@ handle_gns2dns_ip (void *cls,
 {
   struct Gns2DnsPending *gp = cls;
   struct AuthorityChain *ac = gp->ac;
+  struct sockaddr_storage ss;
+  struct sockaddr_in *v4;
+  struct sockaddr_in6 *v6;
 
-  GNUNET_RESOLVER_request_cancel (gp->dns_rh);
-  GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
-                               ac->authority_info.dns_authority.gp_tail,
-                               gp);
-  GNUNET_free (gp);
   if (NULL == addr)
   {
-    /* DNS resolution failed */
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Failed to use DNS to resolve name of DNS resolver\n");
+    /* DNS resolution finished */
+    if (0 == gp->num_results)
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Failed to use DNS to resolve name of DNS resolver\n");
+    GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
+                                 ac->authority_info.dns_authority.gp_tail,
+                                 gp);
+    GNUNET_free (gp);
+    continue_with_gns2dns (ac);
+    return;
   }
-  else
+  GNUNET_memcpy (&ss,
+                 addr,
+                 addrlen);
+  switch (ss.ss_family)
   {
-    if (GNUNET_OK ==
-        GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
-                                   addr))
-      ac->authority_info.dns_authority.found = GNUNET_YES;
+  case AF_INET:
+    v4 = (struct sockaddr_in *) &ss;
+    v4->sin_port = htons (53);
+    gp->num_results++;
+    break;
+  case AF_INET6:
+    v6 = (struct sockaddr_in6 *) &ss;
+    v6->sin6_port = htons (53);
+    gp->num_results++;
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unsupported AF %d\n",
+                ss.ss_family);
+    return;
   }
-  continue_with_gns2dns (ac);
+  if (GNUNET_OK ==
+      GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
+                                 (struct sockaddr *) &ss))
+    ac->authority_info.dns_authority.found = GNUNET_YES;
 }
 
 
@@ -1572,8 +1622,6 @@ recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
   ac = GNUNET_new (struct AuthorityChain);
   ac->rh = rh;
   ac->gns_authority = GNUNET_YES;
-  ac->suggested_shortening_label = NULL;
-  ac->shortening_started = GNUNET_NO;
   GNUNET_memcpy (&ac->authority_info.gns_authority,
                  rd->data,
                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
@@ -1620,6 +1668,8 @@ recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
     size_t off;
     struct Gns2DnsPending *gp;
     struct GNUNET_CRYPTO_EcdsaPublicKey zone;
+    struct sockaddr_in v4;
+    struct sockaddr_in6 v6;
 
     if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
       continue;
@@ -1661,10 +1711,16 @@ recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
     }
 
     /* check if 'ip' is already an IPv4/IPv6 address */
-    if (GNUNET_OK ==
-        GNUNET_DNSSTUB_add_dns_ip (ac->authority_info.dns_authority.dns_handle,
-                                   ip))
+    if ( (1 == inet_pton (AF_INET,
+                          ip,
+                          &v4)) ||
+         (1 == inet_pton (AF_INET6,
+                          ip,
+                          &v6)) )
     {
+      GNUNET_break (GNUNET_OK ==
+                    GNUNET_DNSSTUB_add_dns_ip (ac->authority_info.dns_authority.dns_handle,
+                                               ip));
       ac->authority_info.dns_authority.found = GNUNET_YES;
       GNUNET_free (ip);
       continue;
@@ -1769,7 +1825,6 @@ handle_gns_resolution_result (void *cls,
                              const struct GNUNET_GNSRECORD_Data *rd)
 {
   struct GNS_ResolverHandle *rh = cls;
-  struct AuthorityChain *shorten_ac;
   char *cname;
   struct VpnContext *vpn_ctx;
   const struct GNUNET_TUN_GnsVpnRecord *vpn;
@@ -1791,7 +1846,8 @@ handle_gns_resolution_result (void *cls,
   if (0 == rd_count)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                _("GNS lookup failed (zero records found)\n"));
+                _("GNS lookup failed (zero records found for `%s')\n"),
+               rh->name);
     fail_resolution (rh);
     return;
   }
@@ -1860,13 +1916,20 @@ handle_gns_resolution_result (void *cls,
            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);
+            if (vpn_ctx->rd_data_size < 0)
+            {
+             GNUNET_break_op (0);
+              GNUNET_free (vpn_ctx);
+              fail_resolution (rh);
+             return;
+            }
+           vpn_ctx->rd_data = GNUNET_malloc ((size_t) vpn_ctx->rd_data_size);
             vpn_ctx->rd_count = rd_count;
            GNUNET_assert (vpn_ctx->rd_data_size ==
-                           (size_t) GNUNET_GNSRECORD_records_serialize (rd_count,
-                                                                       rd,
-                                                                       vpn_ctx->rd_data_size,
-                                                                       vpn_ctx->rd_data));
+                           GNUNET_GNSRECORD_records_serialize (rd_count,
+                                                               rd,
+                                                               (size_t) vpn_ctx->rd_data_size,
+                                                               vpn_ctx->rd_data));
            vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
                                                                af,
                                                                ntohs (vpn->proto),
@@ -1899,7 +1962,6 @@ handle_gns_resolution_result (void *cls,
        using 'scratch' array for memory allocations */
     scratch_off = 0;
     rd_off = 0;
-    shorten_ac = rh->ac_tail;
     for (unsigned int i=0;i<rd_count;i++)
     {
       GNUNET_assert (rd_off <= i);
@@ -2077,8 +2139,6 @@ handle_gns_resolution_result (void *cls,
             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:
@@ -2104,8 +2164,6 @@ handle_gns_resolution_result (void *cls,
             ac->gns_authority = GNUNET_YES;
             ac->authority_info.gns_authority = pub;
             ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
-            ac->suggested_shortening_label = NULL;
-            ac->shortening_started = GNUNET_NO;
             GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
                                               rh->ac_tail,
                                               ac);
@@ -2300,6 +2358,11 @@ handle_dht_response (void *cls,
     fail_resolution (rh);
     return;
   }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Decrypting DHT block of size %u for `%s', expires %s\n",
+             ntohl (block->purpose.size),
+             rh->name,
+             GNUNET_STRINGS_absolute_time_to_string (exp));
   if (GNUNET_OK !=
       GNUNET_GNSRECORD_block_decrypt (block,
                                      &ac->authority_info.gns_authority,
@@ -2317,6 +2380,8 @@ handle_dht_response (void *cls,
                 "Received expired block from the DHT, will not cache it.\n");
     return;
   }
+  if (GNUNET_YES == disable_cache)
+    return;
   /* Cache well-formed blocks */
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Caching response from the DHT in namecache\n");
@@ -2357,7 +2422,8 @@ start_dht_request (struct GNS_ResolverHandle *rh,
   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);
+    rx = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
+    rx->dht_heap_node = NULL;
     GNUNET_assert (NULL != rx);
     fail_resolution (rx);
   }
@@ -2379,6 +2445,10 @@ handle_gns_namecache_resolution_result (void *cls,
 {
   struct GNS_ResolverHandle *rh = cls;
 
+  if (0 == rd_count)
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               _("GNS namecache returned empty result for `%s'\n"),
+               rh->name);
   handle_gns_resolution_result (rh,
                                 rd_count,
                                 rd);
@@ -2478,7 +2548,7 @@ recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
   GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
                                          ac->label,
                                          &query);
-  if (GNUNET_YES == use_cache)
+  if (GNUNET_YES != disable_cache)
   {
     rh->namecache_qe
       = GNUNET_NAMECACHE_lookup_block (namecache_handle,
@@ -2489,7 +2559,8 @@ recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
   }
   else
   {
-    start_dht_request (rh, &query);
+    start_dht_request (rh,
+                      &query);
   }
 }
 
@@ -2626,7 +2697,6 @@ start_resolver_lookup (void *cls)
   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 the "TLD", so we default to label
        #GNUNET_GNS_EMPTY_LABEL_AT */
@@ -2740,7 +2810,6 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
       GNUNET_DNSSTUB_stop (ac->authority_info.dns_authority.dns_handle);
     }
     GNUNET_free (ac->label);
-    GNUNET_free_non_null (ac->suggested_shortening_label);
     GNUNET_free (ac);
   }
   if (NULL != rh->task_id)
@@ -2788,6 +2857,7 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
                                 dr);
     GNUNET_free (dr);
   }
+  GNUNET_free_non_null (rh->leho);
   GNUNET_free (rh->name);
   GNUNET_free (rh);
 }
@@ -2816,13 +2886,11 @@ GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
   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,
+  disable_cache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                                       "namecache",
+                                                       "DISABLE");
+  if (GNUNET_YES == disable_cache)
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 "Namecache disabled\n");
   vpn_handle = GNUNET_VPN_connect (cfg);
 }