socks5_connect(): Properly deal with socks replies that contain IPv6 addresses
authorFabian Keil <fk@fabiankeil.de>
Tue, 25 Oct 2016 10:43:00 +0000 (10:43 +0000)
committerFabian Keil <fk@fabiankeil.de>
Tue, 25 Oct 2016 10:43:00 +0000 (10:43 +0000)
Previously parts of the reply were left unread and
later on treated as invalid HTTP response data.

Fixes #904 reported by Danny Goossen who also provided
the initial version of this patch.

gateway.c

index 22efba5..304ecd4 100644 (file)
--- a/gateway.c
+++ b/gateway.c
@@ -1,4 +1,4 @@
-const char gateway_rcs[] = "$Id: gateway.c,v 1.95 2015/08/12 10:37:11 fabiankeil Exp $";
+const char gateway_rcs[] = "$Id: gateway.c,v 1.96 2016/01/16 12:30:43 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/gateway.c,v $
@@ -935,9 +935,12 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
                                 int target_port,
                                 struct client_state *csp)
 {
+#define SIZE_SOCKS5_REPLY_IPV4 10
+#define SIZE_SOCKS5_REPLY_IPV6 22
+#define SOCKS5_REPLY_DIFFERENCE (SIZE_SOCKS5_REPLY_IPV6 - SIZE_SOCKS5_REPLY_IPV4)
    int err = 0;
    char cbuf[300];
-   char sbuf[10];
+   char sbuf[SIZE_SOCKS5_REPLY_IPV6];
    size_t client_pos = 0;
    int server_size = 0;
    size_t hostlen = 0;
@@ -1134,8 +1137,8 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
       }
    }
 
-   server_size = read_socket(sfd, sbuf, sizeof(sbuf));
-   if (server_size != sizeof(sbuf))
+   server_size = read_socket(sfd, sbuf, SIZE_SOCKS5_REPLY_IPV4);
+   if (server_size != SIZE_SOCKS5_REPLY_IPV4)
    {
       errstr = "SOCKS5 negotiation read failed";
    }
@@ -1155,7 +1158,24 @@ static jb_socket socks5_connect(const struct forward_spec *fwd,
       }
       else
       {
-         return(sfd);
+         if (sbuf[3] == '\x04')
+         {
+            /*
+             * The address field contains an IPv6 address
+             * which means we didn't get the whole reply
+             * yet. Read and discard the rest of it to make
+             * sure it isn't treated as HTTP data later on.
+             */
+            server_size = read_socket(sfd, sbuf, SOCKS5_REPLY_DIFFERENCE);
+            if (server_size != SOCKS5_REPLY_DIFFERENCE)
+            {
+               errstr = "SOCKS5 negotiation read failed (IPv6 address)";
+            }
+         }
+         if (errstr == NULL)
+         {
+            return(sfd);
+         }
       }
    }