tolerate additional IPv4 address now available for gnunet.org
[oweals/gnunet.git] / src / util / socks.c
index 3fa18cca9c09ae816ac7fc5232fe2957633ac017..7eca0487825e6a2ee28972202fc9f036bffe0923 100644 (file)
@@ -2,20 +2,20 @@
      This file is part of GNUnet.
      Copyright (C) 2009-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 Affero General Public License
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-     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.
+     SPDX-License-Identifier: AGPL3.0-or-later
 */
 
 /**
@@ -29,9 +29,9 @@
 #include "gnunet_util_lib.h"
 
 
-#define LOG(kind,...) GNUNET_log_from (kind, "socks", __VA_ARGS__)
+#define LOG(kind,...) GNUNET_log_from (kind, "util-socks", __VA_ARGS__)
 
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "socks", syscall)
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-socks", syscall)
 
 
 /* SOCKS5 authentication methods */
@@ -83,16 +83,20 @@ const char * SOCKS5_REP_names(int rep)
  * @param s string to encode
  * @return pointer to the end of the encoded string in the buffer
  */
-unsigned char * SOCK5_proto_string(unsigned char * b, const char * s)
+unsigned char *
+SOCK5_proto_string(unsigned char * b,
+                   const char * s)
 {
   size_t l = strlen(s);
-  if (l>255) {
+
+  if (l > 255)
+  {
     LOG (GNUNET_ERROR_TYPE_WARNING,
          "SOCKS5 cannot handle hostnames, usernames, or passwords over 255 bytes, truncating.\n");
     l=255;
   }
-  *(b++) = (unsigned char)l;
-  strncpy((char *)b,s,l);
+  *(b++) = (unsigned char) l;
+  strncpy ((char *)b, s, l);
   return b+l;
 }
 
@@ -105,7 +109,7 @@ unsigned char * SOCK5_proto_string(unsigned char * b, const char * s)
 /**
  * State of the SOCKS5 handshake.
  */
-struct GNUNET_SOCKS_Handshake 
+struct GNUNET_SOCKS_Handshake
 {
 
   /**
@@ -124,7 +128,7 @@ struct GNUNET_SOCKS_Handshake
   struct GNUNET_CONNECTION_TransmitHandle *th;
 
   /**
-   * Our stage in the SOCKS5 handshake 
+   * Our stage in the SOCKS5 handshake
    */
   int step;
 
@@ -199,7 +203,7 @@ SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih)
   GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
   switch (ih->step) {
     case SOCKS5_step_greet:  /* SOCKS5 server's greeting */
-      if (b[0] != 5) 
+      if (b[0] != 5)
       {
         LOG (GNUNET_ERROR_TYPE_ERROR,
              "Not a SOCKS5 server\n");
@@ -234,7 +238,7 @@ SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih)
       b += 2;
       break;
     case SOCKS5_step_cmd:  /* SOCKS5 server's responce to command */
-      if (b[0] != 5) 
+      if (b[0] != 5)
       {
         LOG (GNUNET_ERROR_TYPE_ERROR,
              "SOCKS5 protocol error\n");
@@ -271,11 +275,11 @@ SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih)
       ih->instart = b;
       SOCKS5_handshake_done (ih);
       return;
-    case SOCKS5_step_done: 
+    case SOCKS5_step_done:
       GNUNET_assert (0);
   }
   ih->instart = b;
-  /* Do not reschedule the sender unless we're done reading. 
+  /* Do not reschedule the sender unless we're done reading.
    * I imagine this lets us avoid ever cancelling the transmit handle. */
   register_sender (ih);
 }
@@ -289,14 +293,14 @@ SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih)
  * @param handler_cls closure for @a handler
  */
 void
-reciever (void *cls, 
+reciever (void *cls,
           const void *buf, size_t available,
           const struct sockaddr * addr,
           socklen_t addrlen, int errCode)
 {
   struct GNUNET_SOCKS_Handshake * ih = cls;
   GNUNET_assert (&ih->inend[available] < &ih->inbuf[1024]);
-  memcpy(ih->inend, buf, available);
+  GNUNET_memcpy(ih->inend, buf, available);
   ih->inend += available;
   SOCKS5_handshake_step (ih);
 }
@@ -328,9 +332,8 @@ register_reciever (struct GNUNET_SOCKS_Handshake *ih, int want)
  * @param buf where the callee should write the message
  * @return number of bytes written to @a buf
  */
-
 size_t
-transmit_ready (void *cls, 
+transmit_ready (void *cls,
                 size_t size,
                 void *buf)
 {
@@ -345,44 +348,42 @@ transmit_ready (void *cls,
    * GNUNET_CONNECTION_notify_transmit_ready() can schedule :
    *   transmit_timeout() - DNS still working
    *   connect_error() - DNS done but no socket?
-   * transmit_ready() - scheduler shutdown or timeout, or signal_transmit_error() 
+   * transmit_ready() - scheduler shutdown or timeout, or signal_transmit_error()
    * We'd need to dig into the scheduler to guess at the reason, as
    * connection.c tells us nothing itself, but mostly its timouts.
    * Initially, we'll simply ignore this and leave massive timeouts, but
    * maybe that should change for error handling pruposes.  It appears that
    * successful operations, including DNS resolution, do not use this.  */
-  if (NULL==buf)
+  if (NULL == buf)
   {
-    enum GNUNET_SCHEDULER_Reason reason = GNUNET_SCHEDULER_get_reason ();
-    if (0 != (reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-      return 0;
-    if (0 != (reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) {
-      if (0==ih->step) {
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-             "Timeout contacting SOCKS server, retrying indefinitely, but probably hopeless.\n");
-        register_sender (ih);
-      } else {
-        LOG (GNUNET_ERROR_TYPE_ERROR,
-             "Timeout during mid SOCKS handshake (step %u), probably not a SOCKS server.\n",
-             ih->step);
-        GNUNET_break (0);
-      }
-      return 0;
+    if (0 == ih->step)
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING,
+          "Timeout contacting SOCKS server, retrying indefinitely, but probably hopeless.\n");
+      register_sender (ih);
+    }
+    else
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+          "Timeout during mid SOCKS handshake (step %u), probably not a SOCKS server.\n",
+          ih->step);
+      GNUNET_break (0);
     }
-    /* if (reason == 48) register_sender (ih); */
-    /* GNUNET_break(0); */
     return 0;
   }
 
-  GNUNET_assert (1024 >= size && size > 0);
-  GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
+  GNUNET_assert ( (1024 >= size) && (size > 0) );
+  GNUNET_assert ( (SOCKS5_step_done > ih->step) && (ih->step >= 0) );
   unsigned char * b = ih->outstep[ih->step];
   unsigned char * e = ih->outstep[ih->step+1];
   GNUNET_assert (e <= &ih->outbuf[1024]);
-  unsigned l = e - b;
-  GNUNET_assert (size >= l && l >= 0);
-  memcpy(buf, b, l);
-  register_reciever (ih, register_reciever_wants(ih));
+  unsigned int l = e - b;
+  GNUNET_assert (size >= l);
+  GNUNET_memcpy (buf,
+                 b,
+                 l);
+  register_reciever (ih,
+                     register_reciever_wants (ih));
   return l;
 }
 
@@ -418,7 +419,7 @@ register_sender (struct GNUNET_SOCKS_Handshake *ih)
 /**
  * Initialize a SOCKS5 handshake for authentication via username and
  * password.  Tor uses SOCKS username and password authentication to assign
- * programs unique circuits. 
+ * programs unique circuits.
  *
  * @param user username for the proxy
  * @param pass password for the proxy
@@ -435,7 +436,7 @@ GNUNET_SOCKS_init_handshake (const char *user, const char *pass)
   unsigned char * n = b++;
   *n = 1; /* Number of authentication methods */
   /* We support no authentication even when requesting authentication,
-   * but this appears harmless, given the way that Tor uses authentication. 
+   * but this appears harmless, given the way that Tor uses authentication.
    * And some SOCKS5 servers might require this.  */
   *(b++) = SOCKS5_AUTH_NOAUTH;
   if (NULL != user) {
@@ -445,7 +446,7 @@ GNUNET_SOCKS_init_handshake (const char *user, const char *pass)
   /* There is no apperent reason to support authentication methods beyond
    * username and password since afaik Tor does not support them. */
 
-  /* We authenticate with an empty username and password if the server demands 
+  /* We authenticate with an empty username and password if the server demands
    * them but we do not have any. */
   if (user == NULL)
     user = "";
@@ -466,7 +467,7 @@ GNUNET_SOCKS_init_handshake (const char *user, const char *pass)
 
 
 /**
- * Initialize a SOCKS5 handshake without authentication, thereby possibly 
+ * Initialize a SOCKS5 handshake without authentication, thereby possibly
  * sharing a Tor circuit with another process.
  *
  * @return Valid SOCKS5 hanbdshake handle
@@ -480,11 +481,11 @@ GNUNET_SOCKS_init_handshake_noauth ()
 
 /**
  * Build request that the SOCKS5 proxy open a TCP/IP stream to the given host
- * and port.  
+ * and port.
  *
  * @param ih SOCKS5 handshake
- * @param hostname 
- * @param port 
+ * @param hostname
+ * @param port
  */
 void
 GNUNET_SOCKS_set_handshake_destination (struct GNUNET_SOCKS_Handshake *ih,
@@ -503,11 +504,11 @@ GNUNET_SOCKS_set_handshake_destination (struct GNUNET_SOCKS_Handshake *ih,
   /* Specify destination */
   if (1 == inet_pton(AF_INET,host,&ia.in4)) {
     *(b++)= 1;  /* IPv4 */
-    memcpy (b, &ia.in4, sizeof(struct in_addr));
+    GNUNET_memcpy (b, &ia.in4, sizeof(struct in_addr));
     b += sizeof(struct in_addr);  /* 4 */
   } else if (1 == inet_pton(AF_INET6,host,&ia.in6)) {
     *(b++)= 4;  /* IPv6 */
-    memcpy (b, &ia.in6, sizeof(struct in6_addr));
+    GNUNET_memcpy (b, &ia.in6, sizeof(struct in6_addr));
     b += sizeof(struct in6_addr);  /* 16 */
   } else {
     *(b++)= 3;  /* hostname */
@@ -529,7 +530,7 @@ GNUNET_SOCKS_set_handshake_destination (struct GNUNET_SOCKS_Handshake *ih,
  * @param c open unused connection, consumed here.
  * @return Connection handle that becomes usable when the SOCKS5 handshake completes.
  */
-struct GNUNET_CONNECTION_Handle * 
+struct GNUNET_CONNECTION_Handle *
 GNUNET_SOCKS_run_handshake(struct GNUNET_SOCKS_Handshake *ih,
                             struct GNUNET_CONNECTION_Handle *c)
 {
@@ -568,59 +569,86 @@ GNUNET_SOCKS_check_service (const char *service_name,
  */
 struct GNUNET_CONNECTION_Handle *
 GNUNET_SOCKS_do_connect (const char *service_name,
-                          const struct GNUNET_CONFIGURATION_Handle *cfg)
+                         const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   struct GNUNET_SOCKS_Handshake *ih;
   struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
-  char *host0,*host1,*user,*pass;
-  unsigned long long port0,port1;
-
-  if (GNUNET_YES != GNUNET_SOCKS_check_service (service_name, cfg))
+  char *host0;
+  char *host1;
+  char *user;
+  char *pass;
+  unsigned long long port0;
+  unsigned long long port1;
+
+  if (GNUNET_YES !=
+      GNUNET_SOCKS_check_service (service_name, cfg))
     return NULL;
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "SOCKSPORT", &port0))
+      GNUNET_CONFIGURATION_get_value_number (cfg,
+                                             service_name,
+                                             "SOCKSPORT",
+                                             &port0))
     port0 = 9050;
-  /* A typical Tor client should usually try port 9150 for the TBB too, but 
-   * GUNNet can probably assume a system Tor instalation. */
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0))
-    host0 = "127.0.0.1";
+  /* A typical Tor client should usually try port 9150 for the TBB too, but
+   * GNUnet can probably assume a system Tor installation. */
   if (port0 > 65535 || port0 <= 0)
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
-        _
-        ("Attempting to use invalid port %d as SOCKS proxy for service `%s'.\n"),
-        port0,service_name);
+        _("Attempting to use invalid port %d as SOCKS proxy for service `%s'.\n"),
+        port0,
+         service_name);
     return NULL;
   }
-
-  if ((GNUNET_OK !=
-       GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port1))
-      || (port1 > 65535) || (port1 <= 0) ||
+  if ( (GNUNET_OK !=
+        GNUNET_CONFIGURATION_get_value_number (cfg,
+                                               service_name,
+                                               "PORT",
+                                               &port1)) ||
+       (port1 > 65535) ||
+       (port1 <= 0) ||
        (GNUNET_OK !=
-        GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME", &host1)))
+        GNUNET_CONFIGURATION_get_value_string (cfg,
+                                               service_name,
+                                               "HOSTNAME",
+                                               &host1)))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
-        _
-        ("Attempting to proxy service `%s' to invalid port %d or hostname `%s'.\n"),
-        service_name,port1,host1);
+        _("Attempting to proxy service `%s' to invalid port %d or hostname.\n"),
+        service_name,
+         port1);
     return NULL;
   }
-
-  socks5 = GNUNET_CONNECTION_create_from_connect (cfg, host0, port0);
-  GNUNET_free (host0);
+  /* Appeared to still work after host0 corrupted, so either test case is broken, or
+     this whole routine is not being called. */
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0))
+    host0 = NULL;
+  socks5 = GNUNET_CONNECTION_create_from_connect (cfg,
+                                                  (host0 != NULL)
+                                                  ? host0
+                                                  :"127.0.0.1",
+                                                  port0);
+  GNUNET_free_non_null (host0);
 
   /* Sets to NULL if they do not exist */
-  GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSUSER", &user);
-  GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSPASS", &pass);
+  (void) GNUNET_CONFIGURATION_get_value_string (cfg,
+                                                service_name,
+                                                "SOCKSUSER",
+                                                &user);
+  (void) GNUNET_CONFIGURATION_get_value_string (cfg,
+                                                service_name,
+                                                "SOCKSPASS",
+                                                &pass);
   ih = GNUNET_SOCKS_init_handshake(user,pass);
-  if (NULL != user) GNUNET_free (user);
-  if (NULL != pass) GNUNET_free (pass);
+  GNUNET_free_non_null (user);
+  GNUNET_free_non_null (pass);
 
-  GNUNET_SOCKS_set_handshake_destination (ih,host1,port1);
+  GNUNET_SOCKS_set_handshake_destination (ih,
+                                          host1,
+                                          port1);
   GNUNET_free (host1);
-
-  return GNUNET_SOCKS_run_handshake(ih,socks5);
+  return GNUNET_SOCKS_run_handshake (ih,
+                                     socks5);
 }
 
 /* socks.c */