As per a suggestion by Olivier Biot, note that objects pointed to by
[obnox/wireshark/wip.git] / packet-socks.c
index 124fe94b83ad6c509694b011185fb03a774ecbec..f03e3e424df36aa7f64b4d8d9f54ce668a44e53e 100644 (file)
@@ -2,22 +2,22 @@
  * Routines for socks versions 4 &5  packet dissection
  * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com>
  *
- * $Id: packet-socks.c,v 1.37 2002/04/11 09:38:03 guy Exp $
+ * $Id: packet-socks.c,v 1.48 2003/10/15 20:07:51 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
- * 
+ *
  * This program 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 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program 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.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
  * Revisions:
  *
+ * 2003-09-18 JCFoster Fixed problem with socks tunnel in socks tunnel
+ *                     causing heap overflow because of an infinite loop
+ *                     where the socks dissect was call over and over.
+ *
+ *                     Also remove some old code marked with __JUNK__
+ *
  * 2001-01-08 JCFoster Fixed problem with NULL pointer for hash data.
  *                     Now test and exit if hash_info is null.
  */
@@ -40,8 +46,8 @@
  * Add GSS-API authentication per rfc-1961
  * Add CHAP authentication
  * Decode FLAG bits per
- *      http://www.socks.nec.com/draft/draft-ietf-aft-socks-pro-v-04.txt 
- * In call_next_dissector, could load the destination address into the 
+ *      http://www.socks.nec.com/draft/draft-ietf-aft-socks-pro-v-04.txt
+ * In call_next_dissector, could load the destination address into the
  *     pi structure before calling next dissector.
  * remove display_string or at least make it use protocol identifiers
  * socks_hash_entry_t needs to handle V5 address type and domain names
 #endif
 
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
 #include <stdio.h>
 #include <string.h>
 #include <glib.h>
 
-#ifdef NEED_SNPRINTF_H
-# include "snprintf.h"
-#endif
-
 #include <epan/packet.h>
 #include <epan/resolv.h>
 #include "alignment.h"
 
 /********** V5 Authentication methods *************/
 
-#define NO_AUTHENTICATION      0               
+#define NO_AUTHENTICATION      0
 #define GSS_API_AUTHENTICATION         1
 #define USER_NAME_AUTHENTICATION       2
 #define CHAP_AUTHENTICATION    3
 #define AUTHENTICATION_FAILED  0xff
 
+/* 2003-09-18 JCFoster Fixed problem with socks tunnel in socks tunnel */
+
+static int in_socks_dissector_flag = 0;                /* set to 1 to avoid recursive overflow */
 
 /*********** Header field identifiers *************/
 
@@ -139,7 +136,7 @@ enum SockState {
        V4NameWait,
        V5Command,
        V5Reply,
-       V5BindReply,    
+       V5BindReply,
        UserNameAuth,
        GssApiAuth,
        AuthReply,
@@ -156,7 +153,7 @@ typedef struct {
        guint32         port;
        guint32         udp_port;
        guint32         udp_remote_port;
-       
+
        int             connect_offset;
        row_pointer_type        v4_name_row;
        row_pointer_type        v4_user_name_row;
@@ -167,7 +164,7 @@ typedef struct {
        row_pointer_type        auth_method_row;
        row_pointer_type        user_name_auth_row;
        guint32 start_done_row;
-       
+
        guint32 dst_addr;       /* this needs to handle IPv6 */
 }socks_hash_entry_t;
 
@@ -186,16 +183,6 @@ static char *address_type_table[] = {
 
 /* String table for the V4 reply status messages */
 
-#ifdef __JUNK__
-static char *reply_table_v4[] = {
-       "Granted",
-       "Rejected or Failed",
-       "Rejected because SOCKS server cannot connect to identd on the client",
-       "Rejected because the client program and identd report different user-ids",
-       "Unknown"
-};
-#endif
-
 static const value_string reply_table_v4[] = {
        {90, "Granted"},
        {91, "Rejected or Failed"},
@@ -206,21 +193,6 @@ static const value_string reply_table_v4[] = {
 
 /* String table for the V5 reply status messages */
 
-#ifdef __JUNK__
-static char *reply_table_v5[] = {
-       "Succeeded",
-       "General SOCKS server failure",
-       "Connection not allowed by ruleset",
-       "Network unreachable",
-       "Host unreachable",
-       "Connection refused",
-       "TTL expired",
-       "Command not supported",
-       "Address type not supported",
-       "Unknown"
-};
-#endif 
-
 static const value_string reply_table_v5[] = {
        {0, "Succeeded"},
        {1, "General SOCKS server failure"},
@@ -236,7 +208,7 @@ static const value_string reply_table_v5[] = {
 static const value_string cmd_strings[] = {
        {0, "Unknow"},
        {1, "Connect"},
-       {2, "Bind"}, 
+       {2, "Bind"},
        {3, "UdpAssociate"},
        {0x80, "Ping"},
        {0x81, "Traceroute"},
@@ -263,28 +235,27 @@ static int display_string(tvbuff_t *tvb, int offset,
        proto_tree      *name_tree;
        proto_item      *ti;
 
-
        char temp[ 256];
        int length = tvb_get_guint8(tvb, offset);
 
-       strncpy( temp, tvb_get_ptr(tvb, offset+1, -1), length);
+       tvb_memcpy(tvb, (guint8 *)temp, offset+1, length);
        temp[ length ] = 0;
-  
+
        ti = proto_tree_add_text(tree, tvb, offset, length + 1,
                "%s: %s" , label, temp);
 
 
        name_tree = proto_item_add_subtree(ti, ett_socks_name);
 
-       proto_tree_add_text( name_tree, tvb, offset, 1, "Length: %d", length);
+       proto_tree_add_text( name_tree, tvb, offset, 1, "Length: %u", length);
 
        ++offset;
 
        proto_tree_add_text( name_tree, tvb, offset, length, "String: %s", temp);
 
        return length + 1;
-}      
+}
+
 
 
 static char *get_auth_method_name( guint Number){
@@ -326,7 +297,7 @@ static int display_address(tvbuff_t *tvb, int offset, proto_tree *tree) {
        int a_type = tvb_get_guint8(tvb, offset);
 
        proto_tree_add_text( tree, tvb, offset, 1,
-                       "Address Type: %d (%s)", a_type, 
+                       "Address Type: %d (%s)", a_type,
                        address_type_table[ MIN( (guint) a_type,
                                array_length( address_type_table)-1) ]);
 
@@ -336,7 +307,7 @@ static int display_address(tvbuff_t *tvb, int offset, proto_tree *tree) {
                proto_tree_add_item( tree, hf_socks_ip_dst, tvb, offset,
                                        4, FALSE);
                offset += 4;
-       }       
+       }
        else if ( a_type == 3){ /* domain name address */
 
                offset += display_string(tvb, offset, tree,
@@ -352,30 +323,30 @@ static int display_address(tvbuff_t *tvb, int offset, proto_tree *tree) {
 }
 
 
-static int get_address_v5(tvbuff_t *tvb, int offset, 
+static int get_address_v5(tvbuff_t *tvb, int offset,
        socks_hash_entry_t *hash_info) {
 
 /* decode the v5 address and return offset of next byte */
 /*XXX this needs to handle IPV6 and domain name addresses */
+
 
        int a_type = tvb_get_guint8(tvb, offset++);
 
        if ( a_type == 1){              /* IPv4 address */
-          
+
                if ( hash_info)
                        tvb_memcpy(tvb, (guint8 *)&hash_info->dst_addr,
                            offset, 4);
                offset += 4;
        }
-               
+
        else if ( a_type == 4)          /* IPv6 address */
                offset += 16;
-       
+
        else if ( a_type == 3)  /* domain name address */
                offset += tvb_get_guint8(tvb, offset) + 1;
        return offset;
-}      
+}
 
 
 /********************* V5 UDP Associate handlers ***********************/
@@ -393,7 +364,7 @@ socks_udp_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
        conversation_t *conversation;
        proto_tree      *socks_tree;
        proto_item      *ti;
-       
+
        conversation = find_conversation( &pinfo->src, &pinfo->dst, pinfo->ptype,
                pinfo->srcport, pinfo->destport, 0);
 
@@ -406,7 +377,7 @@ socks_udp_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
 
        if (check_col(pinfo->cinfo, COL_INFO))
                col_add_fstr(pinfo->cinfo, COL_INFO, "Version: 5, UDP Associated packet");
-                       
+
        if ( tree) {
                ti = proto_tree_add_protocol_format( tree, proto_socks, tvb,
                        offset, -1, "Socks" );
@@ -415,49 +386,49 @@ socks_udp_dissector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
 
                        proto_tree_add_text( socks_tree, tvb, offset, 2, "Reserved");
                offset += 2;
-               
-                       proto_tree_add_text( socks_tree, tvb, offset, 1, "Fragment Number: %d", tvb_get_guint8(tvb, offset));
+
+                       proto_tree_add_text( socks_tree, tvb, offset, 1, "Fragment Number: %u", tvb_get_guint8(tvb, offset));
                ++offset;
-       
+
 
                offset = display_address( tvb, offset, socks_tree);
                hash_info->udp_remote_port = tvb_get_ntohs(tvb, offset);
-               
+
                proto_tree_add_uint( socks_tree, hf_socks_dstport, tvb,
                        offset, 2, hash_info->udp_remote_port);
-                       
+
                offset += 2;
        }
        else {          /* no tree, skip past the socks header */
                offset += 3;
                offset = get_address_v5( tvb, offset, 0) + 2;
-       }       
+       }
 
 
 /* set pi src/dst port and call the udp sub-dissector lookup */
 
-       if ( pinfo->srcport == hash_info->port)                 
+       if ( pinfo->srcport == hash_info->port)
                        ptr = &pinfo->destport;
        else
                ptr = &pinfo->srcport;
 
         *ptr = hash_info->udp_remote_port;
-       
+
        decode_udp_ports( tvb, offset, pinfo, tree, pinfo->srcport, pinfo->destport);
+
         *ptr = hash_info->udp_port;
 
 }
 
-                       
-void 
+
+static void
 new_udp_conversation( socks_hash_entry_t *hash_info, packet_info *pinfo){
 
        conversation_t *conversation = conversation_new( &pinfo->src, &pinfo->dst,  PT_UDP,
                        hash_info->udp_port, hash_info->port, 0);
 
        g_assert( conversation);
-       
+
        conversation_add_proto_data(conversation, proto_socks, hash_info);
        conversation_set_dissector(conversation, socks_udp_handle);
 }
@@ -485,12 +456,12 @@ display_socks_v4(tvbuff_t *tvb, int offset, packet_info *pinfo,
        if (compare_packet( hash_info->connect_row)){
 
                proto_tree_add_text( tree, tvb, offset, 1,
-                               "Version: %u ", hash_info->version);
+                               "Version: %u", hash_info->version);
                ++offset;
                command = tvb_get_guint8(tvb, offset);
 
                proto_tree_add_text( tree, tvb, offset, 1,
-                       "Command: %u (%s)", command, 
+                       "Command: %u (%s)", command,
                                get_command_name( command));
                ++offset;
 
@@ -505,20 +476,20 @@ display_socks_v4(tvbuff_t *tvb, int offset, packet_info *pinfo,
 
                offset += 4;
 
-/*XXX check this, needs to do length checking   */             
+/*XXX check this, needs to do length checking   */
 /* Should perhaps do TCP reassembly as well */
                if ( tvb_offset_exists(tvb, offset)) {
                                                /* display user name    */
-                       proto_tree_add_string( tree, hf_user_name, tvb, offset, 
-                               strlen( tvb_get_ptr(tvb, offset, -1)) + 1,
+                       proto_tree_add_string( tree, hf_user_name, tvb, offset,
+                               tvb_strsize(tvb, offset),
                                tvb_get_ptr(tvb, offset, -1));
                }
 
        }
                                /*Display command response from server*/
-       
+
        else if ( compare_packet( hash_info->cmd_reply_row)){
-                                
+
                proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1,
                                FALSE);
                ++offset;
@@ -536,24 +507,24 @@ display_socks_v4(tvbuff_t *tvb, int offset, packet_info *pinfo,
                proto_tree_add_item( tree, hf_socks_ip_dst, tvb, offset, 4,
                        FALSE);
        }
-       
+
        else if ( compare_packet( hash_info->v4_user_name_row)){
-                        
+
 /*XXX check this, needs to do length checking   */
 /* Should perhaps do TCP reassembly as well */
                if ( tvb_offset_exists(tvb, offset)) {
                        proto_tree_add_text( tree, tvb, offset,
-                               strlen( tvb_get_ptr(tvb, offset, -1)),
+                               tvb_strsize(tvb, offset),
                                "User Name: %s", tvb_get_ptr(tvb, offset, -1));
                }
        }
-}                      
+}
 
 
-static void 
+static void
 display_socks_v5(tvbuff_t *tvb, int offset, packet_info *pinfo,
        proto_tree *tree, socks_hash_entry_t *hash_info) {
-       
+
 /* Display the protocol tree for the version. This routine uses the    */
 /* stored conversation information to decide what to do with the row.  */
 /* Per packet information would have been better to do this, but we    */
@@ -564,42 +535,39 @@ display_socks_v5(tvbuff_t *tvb, int offset, packet_info *pinfo,
        guint temp;
        char *AuthMethodStr;
 
+       proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1, FALSE);
+       ++offset;
 
        if (compare_packet( hash_info->connect_row)){
 
                proto_tree      *AuthTree;
                proto_item      *ti;
 
-                                               /* Do version   */
-               proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1,
-                               hash_info->version);
-               ++offset;
-
                temp = tvb_get_guint8(tvb, offset);     /* Get Auth method count */
                                                        /* build auth tree */
-               ti = proto_tree_add_text( tree, tvb, offset, 1,
+               ti = proto_tree_add_text( tree, tvb, offset, -1,
                                "Client Authentication Methods");
-                               
+
                AuthTree = proto_item_add_subtree(ti, ett_socks_auth);
 
                proto_tree_add_text( AuthTree, tvb, offset, 1,
-                               "Count: %u ", temp);
+                               "Count: %u", temp);
                ++offset;
 
                for( i = 0; i  < temp; ++i) {
 
                        AuthMethodStr = get_auth_method_name(
-                               tvb_get_guint8( tvb, offset + i));
-                       proto_tree_add_text( AuthTree, tvb, offset + i, 1,
-                               "Method[%d]: %u (%s)", i,
-                               tvb_get_guint8( tvb, offset + i), AuthMethodStr); 
+                               tvb_get_guint8( tvb, offset));
+                       proto_tree_add_text( AuthTree, tvb, offset, 1,
+                               "Method[%u]: %u (%s)", i,
+                               tvb_get_guint8( tvb, offset), AuthMethodStr);
+                       ++offset;
                }
+               proto_item_set_end( ti, tvb, offset);
                return;
        }                                       /* Get accepted auth method */
        else if (compare_packet( hash_info->auth_method_row)) {
 
-               ++offset;
-
                proto_tree_add_text( tree, tvb, offset, 1,
                        "Accepted Auth Method: 0x%0x (%s)", tvb_get_guint8( tvb, offset),
                                get_auth_method_name( tvb_get_guint8( tvb, offset)));
@@ -608,27 +576,21 @@ display_socks_v5(tvbuff_t *tvb, int offset, packet_info *pinfo,
        }                                       /* handle user/password auth */
        else if (compare_packet( hash_info->user_name_auth_row)) {
 
-               proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1, FALSE);
-               ++offset;
                                                /* process user name    */
                offset += display_string( tvb, offset, tree,
                                "User name");
                                                /* process password     */
                offset += display_string( tvb, offset, tree,
                                "Password");
-       }                                       
-                                       /* command to the server */     
+       }
+                                       /* command to the server */
                                        /* command response from server */
-       else if ((compare_packet( hash_info->command_row)) || 
+       else if ((compare_packet( hash_info->command_row)) ||
                 (compare_packet( hash_info->cmd_reply_row)) ||
                 (compare_packet( hash_info->bind_reply_row))){
 
-               proto_tree_add_item( tree, hf_socks_ver, tvb, offset, 1, FALSE);
-
-               ++offset;
-
                command = tvb_get_guint8(tvb, offset);
-               
+
                if (compare_packet( hash_info->command_row))
                        proto_tree_add_uint( tree, hf_socks_cmd, tvb, offset, 1,
                            command);
@@ -641,14 +603,14 @@ display_socks_v5(tvbuff_t *tvb, int offset, packet_info *pinfo,
                ++offset;
 
                proto_tree_add_text( tree, tvb, offset, 1,
-                       "Reserved: 0x%0x (should = 0x00)", tvb_get_guint8(tvb, offset)); 
+                       "Reserved: 0x%0x (should = 0x00)", tvb_get_guint8(tvb, offset));
                ++offset;
 
                offset = display_address(tvb, offset, tree);
 /*XXX Add remote port for search somehow */
                                                /* Do remote port       */
                proto_tree_add_text( tree, tvb, offset, 2,
-                               "%sPort: %d",
+                               "%sPort: %u",
                                (compare_packet( hash_info->bind_reply_row) ?
                                        "Remote Host " : ""),
                                 tvb_get_ntohs(tvb, offset));
@@ -656,11 +618,11 @@ display_socks_v5(tvbuff_t *tvb, int offset, packet_info *pinfo,
 }
 
 
-       
+
 /**************** Decoder State Machines ******************/
 
 
-static guint 
+static guint
 state_machine_v4( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
        int offset, packet_info *pinfo) {
 
@@ -678,12 +640,12 @@ state_machine_v4( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
 
                hash_info->command = tvb_get_guint8(tvb, offset + 1);
                                                /* get remote port      */
-               if ( hash_info->command == CONNECT_COMMAND)                                             
+               if ( hash_info->command == CONNECT_COMMAND)
                        hash_info->port =  tvb_get_ntohs(tvb, offset + 2);
                                                /* get remote address   */
 
                tvb_memcpy(tvb, (guint8 *)&hash_info->dst_addr, offset + 4, 4);
-               
+
                                                /* save the packet pointer */
                hash_info->connect_row = get_packet_ptr;
 
@@ -691,14 +653,24 @@ state_machine_v4( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
                hash_info->connect_offset = offset + 8;
 
                offset += 8;
-               
-               if ( !tvb_offset_exists(tvb, offset))   /* if no user name */
+
+               if ( !tvb_offset_exists(tvb, offset)) { /* if no user name */
                                                        /* change state */
                        hash_info->state = V4UserNameWait;
-               
-                       
-               hash_info->connect_offset += strlen( tvb_get_ptr(tvb, offset, -1)) + 1;
-               
+                       /*
+                        * XXX - add 1, or leave it alone?
+                        * We were adding "strlen(...) + 1".
+                        */
+                       hash_info->connect_offset += 1;
+               } else {
+                       /*
+                        * Add in the length of the user name.
+                        * XXX - what if the user name is split between
+                        * TCP segments?
+                        */
+                       hash_info->connect_offset += tvb_strsize(tvb, offset);
+               }
+
                if ( !hash_info->dst_addr){             /* if no dest address */
                                                        /* if more data */
                        if ( tvb_offset_exists(tvb, hash_info->connect_offset)) {
@@ -706,10 +678,10 @@ state_machine_v4( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
                                hash_info->state = Connecting;
                        }
                        else
-                               hash_info->state = V4NameWait;  
+                               hash_info->state = V4NameWait;
                                                }
                                                /* waiting for V4 user name */
-       }else if ( hash_info->state == V4UserNameWait){ 
+       }else if ( hash_info->state == V4UserNameWait){
 
                if (check_col(pinfo->cinfo, COL_INFO))
                        col_append_str(pinfo->cinfo, COL_INFO, " Connect Request (User name)");
@@ -741,7 +713,7 @@ state_machine_v4( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
 
 
 
-static void 
+static void
 state_machine_v5( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
        int offset, packet_info *pinfo) {
 
@@ -759,7 +731,7 @@ state_machine_v5( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
                        col_append_str(pinfo->cinfo, COL_INFO, " Connect to server request");
 
                hash_info->state = Connecting;  /* change state         */
-               hash_info->connect_row = get_packet_ptr;        
+               hash_info->connect_row = get_packet_ptr;
 
                temp = tvb_get_guint8(tvb, offset + 1);
                                                /* skip past auth methods */
@@ -776,18 +748,18 @@ state_machine_v5( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
 
                if ( AuthMethod == NO_AUTHENTICATION)
                        hash_info->state = V5Command;
-                       
+
                else if ( AuthMethod == USER_NAME_AUTHENTICATION)
                        hash_info->state = UserNameAuth;
-                       
+
                else if ( AuthMethod == GSS_API_AUTHENTICATION)
 /*XXX should be this           hash_info->state = GssApiAuth; */
-                       hash_info->state = Done;        
-                       
+                       hash_info->state = Done;
+
                else    hash_info->state = Done;        /*Auth failed or error*/
 
        }
-       
+
        else if ( hash_info->state == V5Command) {      /* Handle V5 Command */
 
                guint temp;
@@ -807,7 +779,7 @@ state_machine_v5( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
 
                temp = tvb_get_guint8(tvb, offset);
 
-               if (( hash_info->command == CONNECT_COMMAND) || 
+               if (( hash_info->command == CONNECT_COMMAND) ||
                    ( hash_info->command == UDP_ASSOCIATE_COMMAND))
                                                /* get remote port      */
                        hash_info->port =  tvb_get_ntohs(tvb, offset);
@@ -826,23 +798,23 @@ state_machine_v5( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
                    (hash_info->command == PING_COMMAND) ||
                    (hash_info->command == TRACERT_COMMAND))
                        hash_info->state = Done;
-                       
+
                else if ( hash_info->command == BIND_COMMAND)
                        hash_info->state = V5BindReply;
-                       
+
                else if ( hash_info->command == UDP_ASSOCIATE_COMMAND){
                        offset += 3;            /* skip to address type */
                        offset = get_address_v5(tvb, offset, hash_info);
 
        /* save server udp port and create udp conversation */
                        hash_info->udp_port =  tvb_get_ntohs(tvb, offset);
-                       
+
                        if (!pinfo->fd->flags.visited)
                                new_udp_conversation( hash_info, pinfo);
 
 /*XXX may need else statement to handle unknows and generate error message */
-                       
-               }               
+
+               }
        }
        else if ( hash_info->state == V5BindReply) {    /* V5 Bind Second Reply */
 
@@ -871,21 +843,21 @@ state_machine_v5( socks_hash_entry_t *hash_info, tvbuff_t *tvb,
 
 
 
-static void 
+static void
 display_ping_and_tracert(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, socks_hash_entry_t *hash_info) {
 
 /* Display the ping/trace_route conversation */
 
 
-               const u_char    *data, *dataend;
-               const u_char   *lineend, *eol;
+               const guchar    *data, *dataend;
+               const guchar   *lineend, *eol;
                int             linelen;
 
                                        /* handle the end command */
                if ( pinfo->destport == TCP_PORT_SOCKS){
                if (check_col(pinfo->cinfo, COL_INFO))
                        col_append_str(pinfo->cinfo, COL_INFO, ", Terminate Request");
-               
+
                if ( tree)
                        proto_tree_add_text(tree, tvb, offset, 1,
                                (hash_info->command  == PING_COMMAND) ?
@@ -904,14 +876,14 @@ display_ping_and_tracert(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tr
 
                        data = tvb_get_ptr(tvb, offset, -1);
                        dataend = data + tvb_length_remaining(tvb, offset);
-               
+
                                while (data < dataend) {
-       
+
                                lineend = find_line_end(data, dataend, &eol);
                                linelen = lineend - data;
 
                                        proto_tree_add_text( tree, tvb, offset, linelen,
-                                               format_text(data, linelen));
+                                               "%s", format_text(data, linelen));
                                        offset += linelen;
                                        data = lineend;
                                }
@@ -932,14 +904,14 @@ static void call_next_dissector(tvbuff_t *tvb, int offset, packet_info *pinfo,
 /* the payload, and restore the pinfo port after that is done.         */
 
        guint32 *ptr;
+
        if (( hash_info->command  == PING_COMMAND) ||
            ( hash_info->command  == TRACERT_COMMAND))
-                
+
                display_ping_and_tracert(tvb, offset, pinfo, tree, hash_info);
 
        else {          /* call the tcp port decoder to handle the payload */
-       
+
 /*XXX may want to load dest address here */
 
                if ( pinfo->destport  == TCP_PORT_SOCKS)
@@ -948,10 +920,18 @@ static void call_next_dissector(tvbuff_t *tvb, int offset, packet_info *pinfo,
                        ptr = &pinfo->srcport;
 
                *ptr = hash_info->port;
-               decode_tcp_ports( tvb, offset, pinfo, tree, pinfo->srcport, pinfo->destport);
+
+/* 2003-09-18 JCFoster Fixed problem with socks tunnel in socks tunnel */
+
+               in_socks_dissector_flag = 1; /* avoid recursive overflow */
+
+               decode_tcp_ports( tvb, offset, pinfo, tree, pinfo->srcport, pinfo->destport, 0);
+
+               in_socks_dissector_flag = 0; /* avoid recursive overflow */
+
                *ptr = TCP_PORT_SOCKS;
        }
-}                
+}
 
 
 
@@ -963,7 +943,15 @@ dissect_socks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
        proto_item      *ti;
        socks_hash_entry_t *hash_info;
        conversation_t *conversation;
-       
+
+/* 2003-09-18 JCFoster Fixed problem with socks tunnel in socks tunnel */
+
+       /* avoid recursive overflow */
+
+       if ( in_socks_dissector_flag) {
+               return;
+       }
+
        conversation = find_conversation( &pinfo->src, &pinfo->dst, pinfo->ptype,
                pinfo->srcport, pinfo->destport, 0);
 
@@ -999,19 +987,19 @@ dissect_socks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                if (( hash_info->version == 4) || ( hash_info->version == 5)){
                        col_add_fstr(pinfo->cinfo, COL_INFO, "Version: %d",
                                hash_info->version);
-               }               
+               }
                else                    /* unknown version display error */
                        col_set_str(pinfo->cinfo, COL_INFO, "Unknown");
-               
+
 
                if ( hash_info->command == PING_COMMAND)
                        col_append_str(pinfo->cinfo, COL_INFO, ", Ping Req");
                if ( hash_info->command == TRACERT_COMMAND)
                        col_append_str(pinfo->cinfo, COL_INFO, ", Traceroute Req");
-               
+
 /*XXX          if ( hash_info->port != -1) */
                if ( hash_info->port != 0)
-                       col_append_fstr(pinfo->cinfo, COL_INFO, ", Remote Port: %d",
+                       col_append_fstr(pinfo->cinfo, COL_INFO, ", Remote Port: %u",
                                hash_info->port);
        }
 
@@ -1030,10 +1018,10 @@ dissect_socks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                        hash_info->start_done_row = pinfo->fd->num;
                }
        }
-       
+
 /* if proto tree, decode and display */
 
-       if (tree) {                     
+       if (tree) {
                ti = proto_tree_add_item( tree, proto_socks, tvb, offset, -1,
                        FALSE );
 
@@ -1042,7 +1030,7 @@ dissect_socks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                if ( hash_info->version == 4)
                        display_socks_v4(tvb, offset, pinfo, socks_tree,
                                hash_info);
-                       
+
                else if ( hash_info->version == 5)
                        display_socks_v5(tvb, offset, pinfo, socks_tree,
                                hash_info);
@@ -1058,7 +1046,7 @@ dissect_socks(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                                        offset, 0, hash_info->dst_addr);
 
                                /* no fake address for ping & traceroute */
-                               
+
                        if (( hash_info->command != PING_COMMAND) &&
                            ( hash_info->command != TRACERT_COMMAND)){
                                proto_tree_add_uint( socks_tree, hf_socks_dstport, tvb,
@@ -1104,11 +1092,11 @@ proto_register_socks( void){
                &ett_socks,
                &ett_socks_auth,
                &ett_socks_name
-               
+
        };
 
        static hf_register_info hf[] = {
-    
+
 
                { &hf_socks_ver,
                        { "Version", "socks.version", FT_UINT8, BASE_DEC, NULL,
@@ -1161,10 +1149,10 @@ proto_register_socks( void){
 
 
        proto_socks = proto_register_protocol (
-               "Socks Protocol", "Socks", "socks");           
+               "Socks Protocol", "Socks", "socks");
 
        proto_register_field_array(proto_socks, hf, array_length(hf));
-       proto_register_subtree_array(ett, array_length(ett));  
+       proto_register_subtree_array(ett, array_length(ett));
 
        register_init_routine( &socks_reinit);  /* register re-init routine */
 
@@ -1177,8 +1165,7 @@ proto_register_socks( void){
 void
 proto_reg_handoff_socks(void) {
 
-       /* dissector install routine */ 
+       /* dissector install routine */
+
        dissector_add("tcp.port", TCP_PORT_SOCKS, socks_handle);
 }
-