In SOCKS5 dynamic forwarding, we were echoing back DST.{ADDR,PORT} as
authorjacob <jacob@cda61777-01e9-0310-a592-d414129be87e>
Fri, 10 Oct 2003 21:20:01 +0000 (21:20 +0000)
committerjacob <jacob@cda61777-01e9-0310-a592-d414129be87e>
Fri, 10 Oct 2003 21:20:01 +0000 (21:20 +0000)
BND.{ADDR,PORT}. Besides being clearly wrong, correspondence with
Sascha Schwarz suggests that this can confuse some SOCKS5 clients
(Aventail and sockscap32) which seem to assume that the reply must
have ATYP=1 (IPv4 literal) and so get the length wrong.

Now all replies have ATYP=1 with BND.{ADDR,PORT} = 0.0.0.0:0 -- this
apparently follows practice in OpenSSH. (We don't have enough info to
fill these fields in correctly.)

git-svn-id: svn://svn.tartarus.org/sgt/putty@3496 cda61777-01e9-0310-a592-d414129be87e

portfwd.c

index e61c05b..a8c8b04 100644 (file)
--- a/portfwd.c
+++ b/portfwd.c
@@ -108,6 +108,7 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
     if (pr->dynamic) {
        while (len--) {
            if (pr->port >= lenof(pr->hostname)) {
+               /* Request too long. */
                if ((pr->dynamic >> 12) == 4) {
                    /* Send back a SOCKS 4 error before closing. */
                    char data[8];
@@ -220,7 +221,23 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
                }
 
                if (pr->dynamic == 0x5001) {
+                   /*
+                    * We're receiving a SOCKS request.
+                    */
+                   unsigned char reply[10]; /* SOCKS5 atyp=1 reply */
                    int atype, alen = 0;
+
+                   /*
+                    * Pre-fill reply packet.
+                    * In all cases, we set BND.{HOST,ADDR} to 0.0.0.0:0
+                    * (atyp=1) in the reply; if we succeed, we don't know
+                    * the right answers, and if we fail, they should be
+                    * ignored.
+                    */
+                   memset(reply, 0, lenof(reply));
+                   reply[0] = 5; /* VER */
+                   reply[3] = 1; /* ATYP = 1 (IPv4, 0.0.0.0:0) */
+
                    if (pr->port < 6) continue;
                    atype = (unsigned char)pr->hostname[3];
                    if (atype == 1)    /* IPv4 address */
@@ -231,9 +248,9 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
                        alen = 1 + (unsigned char)pr->hostname[4];
                    if (pr->port < 6 + alen) continue;
                    if (pr->hostname[1] != 1 || pr->hostname[2] != 0) {
-                       pr->hostname[1] = 1;   /* generic failure */
-                       pr->hostname[2] = 0;   /* reserved */
-                       sk_write(pr->s, pr->hostname, pr->port);
+                       /* Not CONNECT or reserved field nonzero - error */
+                       reply[1] = 1;   /* generic failure */
+                       sk_write(pr->s, reply, lenof(reply));
                        pfd_close(pr->s);
                        return 1;
                    }
@@ -243,8 +260,8 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
                     */
                    pr->port = GET_16BIT_MSB_FIRST(pr->hostname+4+alen);
                    if (atype == 1) {
-                       pr->hostname[1] = 0;   /* succeeded */
-                       sk_write(pr->s, pr->hostname, alen + 6);
+                       /* REP=0 (success) already */
+                       sk_write(pr->s, reply, lenof(reply));
                        sprintf(pr->hostname, "%d.%d.%d.%d",
                                (unsigned char)pr->hostname[4],
                                (unsigned char)pr->hostname[5],
@@ -252,8 +269,8 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
                                (unsigned char)pr->hostname[7]);
                        goto connect;
                    } else if (atype == 3) {
-                       pr->hostname[1] = 0;   /* succeeded */
-                       sk_write(pr->s, pr->hostname, alen + 6);
+                       /* REP=0 (success) already */
+                       sk_write(pr->s, reply, lenof(reply));
                        memmove(pr->hostname, pr->hostname + 5, alen-1);
                        pr->hostname[alen-1] = '\0';
                        goto connect;
@@ -261,8 +278,8 @@ static int pfd_receive(Plug plug, int urgent, char *data, int len)
                        /*
                         * Unknown address type. (FIXME: support IPv6!)
                         */
-                       pr->hostname[1] = 8;   /* atype not supported */
-                       sk_write(pr->s, pr->hostname, pr->port);
+                       reply[1] = 8;   /* atype not supported */
+                       sk_write(pr->s, reply, lenof(reply));
                        pfd_close(pr->s);
                        return 1;                       
                    }