fix compiler warning for format string
[oweals/gnunet.git] / src / gns / gnunet-service-gns_resolver.c
index e6b231459618be8d48ca4cdf472e27bd4b27427a..5e957871e9342a5fed073b6f469bc90fab88040a 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2011-2013 Christian Grothoff (and other contributing authors)
+     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
@@ -14,8 +14,8 @@
 
      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., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
@@ -51,7 +51,7 @@
 /**
  * Default timeout for DNS lookups.
  */
-#define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+#define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
 
 /**
  * Default timeout for VPN redirections.
@@ -168,7 +168,7 @@ struct DnsResult
 
   /**
    * Expiration time for the DNS record, 0 if we didn't
-   * get anything useful (i.e. 'gethostbyname' was used).
+   * get anything useful (i.e. 'gethostbyname()' was used).
    */
   uint64_t expiration_time;
 
@@ -334,7 +334,7 @@ struct GNS_ResolverHandle
   /**
    * ID of a task associated with the resolution process.
    */
-  GNUNET_SCHEDULER_TaskIdentifier task_id;
+  struct GNUNET_SCHEDULER_Task * task_id;
 
   /**
    * The name to resolve
@@ -361,6 +361,18 @@ struct GNS_ResolverHandle
    */
   enum GNUNET_GNS_LocalOptions options;
 
+  /**
+   * For SRV and TLSA records, the number of the
+   * protocol specified in the name.  0 if no protocol was given.
+   */
+  int protocol;
+
+  /**
+   * For SRV and TLSA records, the number of the
+   * service specified in the name.  0 if no service was given.
+   */
+  int service;
+
   /**
    * Desired type for the resolution.
    */
@@ -460,37 +472,6 @@ static int use_cache;
  */
 static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
-#if 0
-/**
- * Check if name is in srv format (_x._y.xxx)
- *
- * @param name
- * @return #GNUNET_YES if true
- */
-static int
-is_srv (const char *name)
-{
-  char *ndup;
-  int ret;
-
-  if (*name != '_')
-    return GNUNET_NO;
-  if (NULL == strstr (name, "._"))
-    return GNUNET_NO;
-  ret = GNUNET_YES;
-  ndup = GNUNET_strdup (name);
-  strtok (ndup, ".");
-  if (NULL == strtok (NULL, "."))
-    ret = GNUNET_NO;
-  if (NULL == strtok (NULL, "."))
-    ret = GNUNET_NO;
-  if (NULL != strtok (NULL, "."))
-    ret = GNUNET_NO;
-  GNUNET_free (ndup);
-  return ret;
-}
-#endif
-
 
 /**
  * Determine if this name is canonical (is a legal name in a zone, without delegation);
@@ -560,15 +541,13 @@ translate_dot_plus (struct GNS_ResolverHandle *rh,
  * Task scheduled to asynchronously fail a resolution.
  *
  * @param cls the 'struct GNS_ResolverHandle' of the resolution to fail
- * @param tc task context
  */
 static void
-fail_resolution (void *cls,
-                const struct GNUNET_SCHEDULER_TaskContext *tc)
+fail_resolution (void *cls)
 {
   struct GNS_ResolverHandle *rh = cls;
 
-  rh->task_id = GNUNET_SCHEDULER_NO_TASK;
+  rh->task_id = NULL;
   rh->proc (rh->proc_cls, 0, NULL);
   GNS_resolver_lookup_cancel (rh);
 }
@@ -577,7 +556,7 @@ fail_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 ...  */
-void *
+static void *
 memrchr (const void *s,
         int c,
         size_t n)
@@ -616,6 +595,11 @@ resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
   const char *rp;
   const char *dot;
   size_t len;
+  char *ret;
+  char *srv_name;
+  char *proto_name;
+  struct protoent *pe;
+  struct servent *se;
 
   if (0 == rh->name_resolution_pos)
     return NULL;
@@ -636,17 +620,53 @@ 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]) )
+  rh->protocol = 0;
+  rh->service = 0;
+  ret = GNUNET_strndup (rp, len);
+  /* If we have labels starting with underscore with label on
+   * the right (SRV/DANE/BOX case), determine port/protocol;
+   * The format of `rh->name` must be "_PORT._PROTOCOL".
+   */
+  if ( ('_' == rh->name[0]) &&
+       (NULL != (dot = memrchr (rh->name,
+                                (int) '.',
+                                rh->name_resolution_pos))) &&
+       ('_' == dot[1]) &&
+       (NULL == memrchr (rh->name,
+                         (int) '.',
+                         dot - rh->name)) )
   {
-    len += rh->name_resolution_pos - (dot - rh->name) - 1;
-    rp = dot + 1;
-    rh->name_resolution_pos = dot - rh->name;
+    srv_name = GNUNET_strndup (&rh->name[1],
+                               (dot - rh->name) - 1);
+    proto_name = GNUNET_strndup (&dot[2],
+                                 rh->name_resolution_pos - (dot - rh->name) - 1);
+    rh->name_resolution_pos = 0;
+    pe = getprotobyname (proto_name);
+    if (NULL == pe)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  _("Protocol `%s' unknown, skipping labels.\n"),
+                  proto_name);
+      GNUNET_free (proto_name);
+      GNUNET_free (srv_name);
+      return ret;
+    }
+    se = getservbyname (srv_name,
+                        proto_name);
+    if (NULL == se)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  _("Service `%s' unknown for protocol `%s', skipping labels.\n"),
+                  srv_name,
+                  proto_name);
+      GNUNET_free (proto_name);
+      GNUNET_free (srv_name);
+      return ret;
+    }
+    rh->protocol = pe->p_proto;
+    rh->service = se->s_port;
   }
-  return GNUNET_strndup (rp, len);
+  return ret;
 }
 
 
@@ -721,7 +741,7 @@ add_dns_result (struct GNS_ResolverHandle *rh,
   res->data_size = data_size;
   res->record_type = record_type;
   res->data = &res[1];
-  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);
@@ -745,15 +765,15 @@ handle_dns_result (void *cls,
   const struct sockaddr_in *sa4;
   const struct sockaddr_in6 *sa6;
 
-  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;
   }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Received %u bytes of DNS IP data\n",
+             addrlen);
   switch (addr->sa_family)
   {
   case AF_INET:
@@ -786,8 +806,7 @@ handle_dns_result (void *cls,
  * @param tc task context
  */
 static void
-recursive_resolution (void *cls,
-                     const struct GNUNET_SCHEDULER_TaskContext *tc);
+recursive_resolution (void *cls);
 
 
 /**
@@ -823,7 +842,7 @@ dns_result_parser (void *cls,
 
   rh->dns_request = NULL;
   GNUNET_SCHEDULER_cancel (rh->task_id);
-  rh->task_id = GNUNET_SCHEDULER_NO_TASK;
+  rh->task_id = NULL;
   p = GNUNET_DNSPARSER_parse ((const char *) dns,
                              dns_len);
   if (NULL == p)
@@ -849,7 +868,6 @@ dns_result_parser (void *cls,
       GNUNET_DNSPARSER_free_packet (p);
       return;
     }
-  /* FIXME: add DNAME support */
 
   /* convert from (parsed) DNS to (binary) GNS format! */
   rd_count = p->num_answers + p->num_authority_records + p->num_additional_records;
@@ -870,7 +888,7 @@ dns_result_parser (void *cls,
       else if (i < p->num_answers + p->num_authority_records)
        rec = &p->authority_records[i - p->num_answers];
       else
-       rec = &p->authority_records[i - p->num_answers - p->num_authority_records];
+       rec = &p->additional_records[i - p->num_answers - p->num_authority_records];
       /* As we copied the full DNS name to 'rh->ac_tail->label', this
         should be the correct check to see if this record is actually
         a record for our label... */
@@ -1262,7 +1280,7 @@ handle_gns2dns_result (void *cls,
 #if HAVE_SOCKADDR_IN_SIN_LEN
       v4.sin_len = (u_char) sa_len;
 #endif
-      memcpy (&v4.sin_addr,
+      GNUNET_memcpy (&v4.sin_addr,
               rd[j].data,
               sizeof (struct in_addr));
       sa = (struct sockaddr *) &v4;
@@ -1284,7 +1302,7 @@ handle_gns2dns_result (void *cls,
 #if HAVE_SOCKADDR_IN_SIN_LEN
       v6.sin6_len = (u_char) sa_len;
 #endif
-      memcpy (&v6.sin6_addr,
+      GNUNET_memcpy (&v6.sin6_addr,
               rd[j].data,
               sizeof (struct in6_addr));
       sa = (struct sockaddr *) &v6;
@@ -1305,9 +1323,10 @@ handle_gns2dns_result (void *cls,
   /* expand authority chain */
   ac = GNUNET_new (struct AuthorityChain);
   ac->rh = rh;
+  GNUNET_assert (strlen (rh->g2dc->ns) <= GNUNET_DNSPARSER_MAX_NAME_LENGTH);
   strcpy (ac->authority_info.dns_authority.name,
           rh->g2dc->ns);
-  memcpy (&ac->authority_info.dns_authority.dns_ip,
+  GNUNET_memcpy (&ac->authority_info.dns_authority.dns_ip,
           sa,
           sa_len);
   /* for DNS recursion, the label is the full DNS name,
@@ -1481,6 +1500,11 @@ handle_gns_resolution_result (void *cls,
     shorten_ac = rh->ac_tail;
     for (i=0;i<rd_count;i++)
     {
+      if ( (0 != rh->protocol) &&
+           (0 != rh->service) &&
+           (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type) )
+        continue; /* we _only_ care about boxed records */
+
       rd_new[rd_off] = rd[i];
       /* Check if the embedded name(s) end in "+", and if so,
         replace the "+" with the zone at "ac_tail", changing the name
@@ -1602,8 +1626,7 @@ handle_gns_resolution_result (void *cls,
          struct GNUNET_DNSPARSER_SrvRecord *srv;
 
          off = 0;
-         srv = GNUNET_DNSPARSER_parse_srv (rh->name,
-                                           rd[i].data,
+         srv = GNUNET_DNSPARSER_parse_srv (rd[i].data,
                                            rd[i].data_size,
                                            &off);
          if ( (NULL == srv) ||
@@ -1613,7 +1636,6 @@ handle_gns_resolution_result (void *cls,
          }
          else
          {
-           srv->domain_name = translate_dot_plus (rh, srv->domain_name);
            srv->target = translate_dot_plus (rh, srv->target);
            scratch_start = scratch_off;
            if (GNUNET_OK !=
@@ -1639,6 +1661,7 @@ handle_gns_resolution_result (void *cls,
       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'))
@@ -1659,7 +1682,7 @@ handle_gns_resolution_result (void *cls,
            GNUNET_break_op (0);
            break;
          }
-         memcpy (&pub, rd[i].data, rd[i].data_size);
+         GNUNET_memcpy (&pub, rd[i].data, rd[i].data_size);
           rd_off++;
           if (GNUNET_GNSRECORD_TYPE_PKEY != rh->record_type)
           {
@@ -1685,10 +1708,42 @@ handle_gns_resolution_result (void *cls,
       case GNUNET_GNSRECORD_TYPE_GNS2DNS:
         {
           /* delegation to DNS */
+          if (GNUNET_GNSRECORD_TYPE_GNS2DNS == rh->record_type)
+          {
+            rd_off++;
+            break; /* do not follow to DNS, we wanted the GNS2DNS record! */
+          }
           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                       "Found GNS2DNS record, delegating to DNS!\n");
           goto do_recurse;
         }
+      case GNUNET_GNSRECORD_TYPE_BOX:
+        {
+          /* unbox SRV/TLSA records if a specific one was requested */
+          if ( (0 != rh->protocol) &&
+               (0 != rh->service) &&
+               (rd[i].data_size >= sizeof (struct GNUNET_GNSRECORD_BoxRecord)) )
+          {
+            const struct GNUNET_GNSRECORD_BoxRecord *box;
+
+            box = rd[i].data;
+            if ( (ntohs (box->protocol) == rh->protocol) &&
+                 (ntohs (box->service) == rh->service) )
+            {
+              /* Box matches, unbox! */
+              rd_new[rd_off].record_type = ntohl (box->record_type);
+              rd_new[rd_off].data_size -= sizeof (struct GNUNET_GNSRECORD_BoxRecord);
+              rd_new[rd_off].data = &box[1];
+              rd_off++;
+            }
+          }
+          else
+          {
+            /* no specific protocol/service specified, preserve all BOX
+               records (for modern, GNS-enabled applications) */
+            rd_off++;
+          }
+        }
       default:
        rd_off++;
        break;
@@ -1743,7 +1798,7 @@ handle_gns_resolution_result (void *cls,
       ac->gns_authority = GNUNET_YES;
       ac->suggested_shortening_label = NULL;
       ac->shortening_started = GNUNET_NO;
-      memcpy (&ac->authority_info.gns_authority,
+      GNUNET_memcpy (&ac->authority_info.gns_authority,
              rd[i].data,
              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
       ac->label = resolver_lookup_get_next_label (rh);
@@ -1787,6 +1842,7 @@ handle_gns_resolution_result (void *cls,
            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);
@@ -2171,15 +2227,13 @@ recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
  * Task scheduled to continue with the resolution process.
  *
  * @param cls the `struct GNS_ResolverHandle` of the resolution
- * @param tc task context
  */
 static void
-recursive_resolution (void *cls,
-                     const struct GNUNET_SCHEDULER_TaskContext *tc)
+recursive_resolution (void *cls)
 {
   struct GNS_ResolverHandle *rh = cls;
 
-  rh->task_id = GNUNET_SCHEDULER_NO_TASK;
+  rh->task_id = NULL;
   if (MAX_RECURSION < rh->loop_limiter++)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
@@ -2403,10 +2457,10 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
     GNUNET_free (rh->g2dc);
     rh->g2dc = NULL;
   }
-  if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
+  if (NULL != rh->task_id)
   {
     GNUNET_SCHEDULER_cancel (rh->task_id);
-    rh->task_id = GNUNET_SCHEDULER_NO_TASK;
+    rh->task_id = NULL;
   }
   if (NULL != rh->get_handle)
   {
@@ -2484,12 +2538,14 @@ 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")))
+  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");
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Namecache disabled\n");
 
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (c,