Merge branch 'master' into getopt
[oweals/gnunet.git] / src / dns / dnsstub.c
index 0c3bf0ef3099616a6dcd56efd6c9a4a54860ffd6..68cd55275085ed85a70f8824e7f88b4d6af79798 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2012 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2012 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.
 */
 /**
  * @file dns/dnsstub.c
@@ -24,6 +24,7 @@
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
+#include "gnunet_tun_lib.h"
 #include "gnunet_dnsstub_lib.h"
 
 /**
@@ -43,7 +44,7 @@
  */
 struct GNUNET_DNSSTUB_RequestSocket
 {
-  
+
   /**
    * UDP socket we use for this request for IPv4
    */
@@ -60,14 +61,14 @@ struct GNUNET_DNSSTUB_RequestSocket
   GNUNET_DNSSTUB_ResultCallback rc;
 
   /**
-   * Closure for 'rc'.
+   * Closure for @e rc.
    */
   void *rc_cls;
 
   /**
    * Task for reading from dnsout4 and dnsout6.
    */
-  GNUNET_SCHEDULER_TaskIdentifier read_task;
+  struct GNUNET_SCHEDULER_Task * read_task;
 
   /**
    * When should this request time out?
@@ -80,24 +81,27 @@ struct GNUNET_DNSSTUB_RequestSocket
   struct sockaddr_storage addr;
 
   /**
-   * Number of bytes in 'addr'.
+   * Number of bytes in @e addr.
    */
   socklen_t addrlen;
 
 };
 
 
+/**
+ * Handle to the stub resolver.
+ */
 struct GNUNET_DNSSTUB_Context
 {
 
   /**
-   * Array of all open sockets for DNS requests. 
+   * Array of all open sockets for DNS requests.
    */
   struct GNUNET_DNSSTUB_RequestSocket sockets[DNS_SOCKET_MAX];
 
   /**
    * IP address to use for the DNS server if we are a DNS exit service
-   * (for VPN via mesh); otherwise NULL.
+   * (for VPN via cadet); otherwise NULL.
    */
   char *dns_exit;
 };
@@ -105,7 +109,7 @@ struct GNUNET_DNSSTUB_Context
 
 
 /**
- * We're done with a GNUNET_DNSSTUB_RequestSocket, close it for now.
+ * We're done with a `struct GNUNET_DNSSTUB_RequestSocket`, close it for now.
  *
  * @param rs request socket to clean up
  */
@@ -122,10 +126,10 @@ cleanup_rs (struct GNUNET_DNSSTUB_RequestSocket *rs)
     GNUNET_NETWORK_socket_close (rs->dnsout6);
     rs->dnsout6 = NULL;
   }
-  if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
+  if (NULL != rs->read_task)
   {
     GNUNET_SCHEDULER_cancel (rs->read_task);
-    rs->read_task = GNUNET_SCHEDULER_NO_TASK;
+    rs->read_task = NULL;
   }
 }
 
@@ -134,8 +138,8 @@ cleanup_rs (struct GNUNET_DNSSTUB_RequestSocket *rs)
  * Open source port for sending DNS requests
  *
  * @param af AF_INET or AF_INET6
- * @return GNUNET_OK on success
- */ 
+ * @return #GNUNET_OK on success
+ */
 static struct GNUNET_NETWORK_Handle *
 open_socket (int af)
 {
@@ -165,10 +169,10 @@ open_socket (int af)
   }
   sa->sa_family = af;
   if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret,
-                                              sa, 
+                                              sa,
                                               alen))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Could not bind to any port: %s\n"),
                STRERROR (errno));
     GNUNET_NETWORK_socket_close (ret);
@@ -182,16 +186,14 @@ open_socket (int af)
  * Read a DNS response from the (unhindered) UDP-Socket
  *
  * @param cls socket to read from
- * @param tc scheduler context (must be shutdown or read ready)
  */
 static void
-read_response (void *cls,
-              const struct GNUNET_SCHEDULER_TaskContext *tc);
+read_response (void *cls);
 
 
 /**
  * Get a socket of the specified address family to send out a
- * UDP DNS request to the Internet.  
+ * UDP DNS request to the Internet.
  *
  * @param ctx the DNSSTUB context
  * @param af desired address family
@@ -204,7 +206,7 @@ get_request_socket (struct GNUNET_DNSSTUB_Context *ctx,
   struct GNUNET_DNSSTUB_RequestSocket *rs;
   struct GNUNET_NETWORK_FDSet *rset;
 
-  rs = &ctx->sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 
+  rs = &ctx->sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
                                               DNS_SOCKET_MAX)];
   rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
   switch (af)
@@ -219,11 +221,11 @@ get_request_socket (struct GNUNET_DNSSTUB_Context *ctx,
     break;
   default:
     return NULL;
-  }  
-  if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
+  }
+  if (NULL != rs->read_task)
   {
     GNUNET_SCHEDULER_cancel (rs->read_task);
-    rs->read_task = GNUNET_SCHEDULER_NO_TASK;
+    rs->read_task = NULL;
   }
   if ( (NULL == rs->dnsout4) &&
        (NULL == rs->dnsout6) )
@@ -247,7 +249,8 @@ get_request_socket (struct GNUNET_DNSSTUB_Context *ctx,
  * Perform DNS resolution.
  *
  * @param ctx stub resolver to use
- * @param af address family to use
+ * @param sa the socket address
+ * @param sa_len the socket length
  * @param request DNS request to transmit
  * @param request_len number of bytes in msg
  * @param rc function to call with result
@@ -275,13 +278,25 @@ GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
   else
     ret = rs->dnsout6;
   GNUNET_assert (NULL != ret);
+  GNUNET_memcpy (&rs->addr,
+         sa,
+         sa_len);
+  rs->addrlen = sa_len;
   rs->rc = rc;
   rs->rc_cls = rc_cls;
-  GNUNET_NETWORK_socket_sendto (ret,
-                               request,
-                               request_len,
-                               sa,
-                               sa_len);
+  if (GNUNET_SYSERR ==
+      GNUNET_NETWORK_socket_sendto (ret,
+                                   request,
+                                   request_len,
+                                   sa,
+                                   sa_len))
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               _("Failed to send DNS request to %s\n"),
+               GNUNET_a2s (sa, sa_len));
+  else
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               _("Sent DNS request to %s\n"),
+               GNUNET_a2s (sa, sa_len));
   return rs;
 }
 
@@ -306,7 +321,7 @@ GNUNET_DNSSTUB_resolve2 (struct GNUNET_DNSSTUB_Context *ctx,
   int af;
   struct sockaddr_in v4;
   struct sockaddr_in6 v6;
-  struct sockaddr *so;
+  struct sockaddr *sa;
   socklen_t salen;
   struct GNUNET_NETWORK_Handle *dnsout;
   struct GNUNET_DNSSTUB_RequestSocket *rs;
@@ -321,7 +336,7 @@ GNUNET_DNSSTUB_resolve2 (struct GNUNET_DNSSTUB_Context *ctx,
 #if HAVE_SOCKADDR_IN_SIN_LEN
     v4.sin_len = (u_char) salen;
 #endif
-    so = (struct sockaddr *) &v4;
+    sa = (struct sockaddr *) &v4;
     af = AF_INET;
   }
   else if (1 == inet_pton (AF_INET6, ctx->dns_exit, &v6.sin6_addr))
@@ -332,9 +347,9 @@ GNUNET_DNSSTUB_resolve2 (struct GNUNET_DNSSTUB_Context *ctx,
 #if HAVE_SOCKADDR_IN_SIN_LEN
     v6.sin6_len = (u_char) salen;
 #endif
-    so = (struct sockaddr *) &v6;
+    sa = (struct sockaddr *) &v6;
     af = AF_INET6;
-  }  
+  }
   else
   {
     GNUNET_break (0);
@@ -353,19 +368,21 @@ GNUNET_DNSSTUB_resolve2 (struct GNUNET_DNSSTUB_Context *ctx,
                ctx->dns_exit);
     return NULL;
   }
-  memcpy (&rs->addr,
-         so,
+  GNUNET_memcpy (&rs->addr,
+         sa,
          salen);
   rs->addrlen = salen;
   rs->rc = rc;
   rs->rc_cls = rc_cls;
-  GNUNET_NETWORK_socket_sendto (dnsout,
-                               request,
-                               request_len, so, salen); 
+  if (GNUNET_SYSERR ==
+      GNUNET_NETWORK_socket_sendto (dnsout,
+                                   request,
+                                   request_len, sa, salen))
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               _("Failed to send DNS request to %s\n"),
+               GNUNET_a2s (sa, salen));
   rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
-  
   return rs;
-
 }
 
 
@@ -375,7 +392,7 @@ GNUNET_DNSSTUB_resolve2 (struct GNUNET_DNSSTUB_Context *ctx,
  *
  * @param rs request socket with callback details
  * @param dnsout socket to read from
- * @return GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket)
+ * @return #GNUNET_OK on success, #GNUNET_NO on drop, #GNUNET_SYSERR on IO-errors (closed socket)
  */
 static int
 do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
@@ -397,13 +414,15 @@ do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
   /* port the code above? */
   len = UINT16_MAX;
 #endif
-
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Receiving %d byte DNS reply\n",
+             len);
   {
     unsigned char buf[len] GNUNET_ALIGN;
 
     addrlen = sizeof (addr);
-    memset (&addr, 0, sizeof (addr));  
-    r = GNUNET_NETWORK_socket_recvfrom (dnsout, 
+    memset (&addr, 0, sizeof (addr));
+    r = GNUNET_NETWORK_socket_recvfrom (dnsout,
                                        buf, sizeof (buf),
                                        (struct sockaddr*) &addr, &addrlen);
     if (-1 == r)
@@ -414,23 +433,29 @@ do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
     }
     if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Received DNS response that is too small (%u bytes)"),
-                 r);
+                 (unsigned int) r);
       return GNUNET_NO;
     }
     dns = (struct GNUNET_TUN_DnsHeader *) buf;
     if ( (addrlen != rs->addrlen) ||
-        (0 != memcmp (&rs->addr,
-                      &addr,
-                      addrlen)) ||      
-       (0 == GNUNET_TIME_absolute_get_remaining (rs->timeout).rel_value) )
+        (GNUNET_YES !=
+          GNUNET_TUN_sockaddr_cmp ((struct sockaddr *) &rs->addr,
+                                   (struct sockaddr *) &addr,
+                                   GNUNET_YES)) ||
+       (0 == GNUNET_TIME_absolute_get_remaining (rs->timeout).rel_value_us) )
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Request timeout or invalid sender address; ignoring reply\n");
       return GNUNET_NO;
-    rs->rc (rs->rc_cls,
-           rs,
-           dns,
-           r);
-  }  
+    }
+    if (NULL != rs->rc)
+      rs->rc (rs->rc_cls,
+             rs,
+             dns,
+             r);
+  }
   return GNUNET_OK;
 }
 
@@ -439,19 +464,19 @@ do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
  * Read a DNS response from the (unhindered) UDP-Socket
  *
  * @param cls socket to read from
- * @param tc scheduler context (must be shutdown or read ready)
  */
 static void
-read_response (void *cls,
-              const struct GNUNET_SCHEDULER_TaskContext *tc)
+read_response (void *cls)
 {
   struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
   struct GNUNET_NETWORK_FDSet *rset;
+  const struct GNUNET_SCHEDULER_TaskContext *tc;
 
-  rs->read_task = GNUNET_SCHEDULER_NO_TASK;
+  rs->read_task = NULL;
+  tc = GNUNET_SCHEDULER_get_task_context ();
   if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
   {
-    /* timeout or shutdown */
+    /* timeout */
     cleanup_rs (rs);
     return;
   }
@@ -480,6 +505,17 @@ read_response (void *cls,
 }
 
 
+/**
+ * Cancel DNS resolution.
+ *
+ * @param rs resolution to cancel
+ */
+void
+GNUNET_DNSSTUB_resolve_cancel (struct GNUNET_DNSSTUB_RequestSocket *rs)
+{
+  rs->rc = NULL;
+}
+
 
 /**
  * Start a DNS stub resolver.
@@ -491,8 +527,8 @@ struct GNUNET_DNSSTUB_Context *
 GNUNET_DNSSTUB_start (const char *dns_ip)
 {
   struct GNUNET_DNSSTUB_Context *ctx;
-  
-  ctx = GNUNET_malloc (sizeof (struct GNUNET_DNSSTUB_Context));
+
+  ctx = GNUNET_new (struct GNUNET_DNSSTUB_Context);
   if (NULL != dns_ip)
     ctx->dns_exit = GNUNET_strdup (dns_ip);
   return ctx;
@@ -509,7 +545,7 @@ GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx)
 {
   unsigned int i;
 
-  for (i=0;i<=UINT16_MAX;i++)
+  for (i=0;i<DNS_SOCKET_MAX;i++)
     cleanup_rs (&ctx->sockets[i]);
   if (NULL != ctx->dns_exit)
   {