Jeff Foster's SOCKS dissector, support for associating dissectors
authorguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 12 Apr 2000 22:53:16 +0000 (22:53 +0000)
committerguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Wed, 12 Apr 2000 22:53:16 +0000 (22:53 +0000)
with conversations and having TCP and UDP check whether a packet is part
of a conversation with a dissector and, if so, using that dissector on
the conversation, and "ethertype()"-style support for allowing a
dissector to call a sub-dissector via the same path that the TCP and UDP
dissectors use, based on port numbers supplied by that dissector.

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@1837 f5534014-38df-0310-8fa8-9805f1628bb7

AUTHORS
Makefile.am
conversation.c
conversation.h
packet-socks.c [new file with mode: 0644]
packet-tcp.c
packet-tcp.h
packet-udp.c
packet-udp.h

diff --git a/AUTHORS b/AUTHORS
index 3f38334578ae5c0d62146347319fce56d50e3c85..56c3dc00d611ab9cab293fa3420696dcaa9f3d57 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -146,6 +146,9 @@ Jeff Foster <jfoste@woodward.com> {
        Support for protocols registering themselves with dissectors for
            protocols on top of which they run
        Rlogin support
+       Support for associating a dissector with a conversation, and for
+           use of that dissector by TCP and UDP
+       SOCKS support
 }
 
 Peter Torvals <petertv@xoommail.com> {
index 63e01f476cc286bffab40248235927b4464aa02c..b3dbfa6ab5e3b8daace9abe433ca455604296adf 100644 (file)
@@ -1,7 +1,7 @@
 # Makefile.am
 # Automake file for Ethereal
 #
-# $Id: Makefile.am,v 1.180 2000/04/08 07:07:06 guy Exp $
+# $Id: Makefile.am,v 1.181 2000/04/12 22:53:13 guy Exp $
 #
 # Ethereal - Network traffic analyzer
 # By Gerald Combs <gerald@zing.org>
@@ -186,6 +186,7 @@ DISSECTOR_SOURCES = \
        packet-sna.h   \
        packet-snmp.c   \
        packet-snmp.h   \
+       packet-socks.c \
        packet-srvloc.c \
        packet-sscop.c \
        packet-sscop.h \
index 497e80d40c4b45a3c055bc430a2435c46a30f6cb..60e4f8dd5851782ce117a9a1ce6cc00ee561198e 100644 (file)
@@ -1,7 +1,7 @@
 /* conversation.c
  * Routines for building lists of packets that are part of a "conversation"
  *
- * $Id: conversation.c,v 1.6 2000/01/05 21:48:16 gram Exp $
+ * $Id: conversation.c,v 1.7 2000/04/12 22:53:14 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -243,6 +243,10 @@ conversation_new(address *src, address *dst, port_type ptype,
        conversation = g_mem_chunk_alloc(conversation_chunk);
        conversation->index = new_index;
        conversation->data = data;
+
+/* clear dissector pointer */
+       conversation->dissector = NULL;
+
        new_index++;
 
        g_hash_table_insert(conversation_hashtable, new_key, conversation);
@@ -271,3 +275,19 @@ find_conversation(address *src, address *dst, port_type ptype,
        key.port_dst = dst_port;
        return g_hash_table_lookup(conversation_hashtable, &key);
 }
+
+/*
+ * Given source and destination addresses and ports for a packet,
+ * search for a conversational dissector.
+ * Returns NULL if not found.
+ */
+dissector_t find_conversation_dissector(address *src, address *dst, port_type ptype,
+    guint32 src_port, guint32 dst_port){
+
+       conversation_t *conversation = find_conversation(src, dst, ptype, src_port, dst_port);
+
+       if ( conversation)
+               return conversation->dissector;
+
+       return NULL;
+}
index 602b19687ad641907f602013afaefd26b35fb940..68acad18331111e79ce6b9beefb1b9cbefa05b48 100644 (file)
@@ -1,7 +1,7 @@
 /* conversation.h
  * Routines for building lists of packets that are part of a "conversation"
  *
- * $Id: conversation.h,v 1.4 2000/01/05 21:48:16 gram Exp $
+ * $Id: conversation.h,v 1.5 2000/04/12 22:53:14 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -26,6 +26,7 @@
 #ifndef __CONVERSATION_H__
 #define __CONVERSATION_H__
 
+#include "packet.h"            /* for conversation dissector type */
 /*
  * Data structure representing a conversation.
  */
@@ -33,6 +34,8 @@ typedef struct conversation {
        struct conversation *next;      /* pointer to next conversation on hash chain */
        guint32 index;  /* unique ID for conversation */
        void    *data;  /* data our client can associate with a conversation */
+       dissector_t     dissector;      /* protocol dissector client can associate with conversation */
+
 } conversation_t;
 
 extern void conversation_init(void);
@@ -41,4 +44,7 @@ conversation_t *conversation_new(address *src, address *dst, port_type ptype,
 conversation_t *find_conversation(address *src, address *dst, port_type ptype,
     guint32 src_port, guint32 dst_port);
 
+dissector_t find_conversation_dissector(address *src, address *dst, port_type ptype,
+    guint32 src_port, guint32 dst_port);
+
 #endif /* conversation.h */
diff --git a/packet-socks.c b/packet-socks.c
new file mode 100644 (file)
index 0000000..30e9692
--- /dev/null
@@ -0,0 +1,1161 @@
+/* packet-socks.c
+ * Routines for socks versions 4 &5  packet dissection
+ * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com>
+ *
+ * $Id: packet-socks.c,v 1.1 2000/04/12 22:53:14 guy Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@zing.org>
+ * 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.
+ *
+ *
+ * The Version 4 decode is based on SOCKS4.protocol and SOCKS4A.protocol.
+ * The Version 5 decoder is based upon rfc-1928
+ * The Version 5 User/Password authentication is based on rfc-1929.
+ *
+ * See http://www.socks.nec.com/socksprot.html for these and other documents
+ *
+ */
+
+/* Possible enhancements -
+ *
+ * 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 
+ *     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
+*/
+
+
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#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>
+#include "packet.h"
+#include "resolv.h"
+#include "globals.h"
+#include "alignment.h"
+#include "conversation.h"
+
+#include "packet-tcp.h"
+#include "packet-udp.h"
+
+#ifdef NEED_SNPRINTF_H
+# ifdef HAVE_STDARG_H
+#  include <stdarg.h>
+# else
+#  include <varargs.h>
+# endif
+# include "snprintf.h"
+#endif
+
+
+
+#define CHECK_PACKET_LENGTH(X) if ((offset+X) > fd->cap_len){  \
+        proto_tree_add_text(tree, offset, 0, "*** FRAME TOO SHORT ***"); \
+        return; }
+
+#define compare_packet(X) (X == (fd->num))
+#define get_packet_ptr (fd->num)
+#define row_pointer_type guint32
+
+#define TCP_PORT_SOCKS 1080
+
+
+/**************** Socks commands ******************/
+
+#define CONNECT_COMMAND                1
+#define BIND_COMMAND           2
+#define UDP_ASSOCIATE_COMMAND  3
+#define PING_COMMAND           0x80
+#define TRACERT_COMMAND                0x81
+
+
+/********** V5 Authentication methods *************/
+
+#define NO_AUTHENTICATION      0               
+#define GSS_API_AUTHENTICATION         1
+#define USER_NAME_AUTHENTICATION       2
+#define CHAP_AUTHENTICATION    3
+#define AUTHENTICATION_FAILED  0xff
+
+
+/*********** Header field identifiers *************/
+
+static int proto_socks = -1;
+
+static int ett_socks = -1;
+static int ett_socks_auth = -1;
+static int ett_socks_name = -1;
+
+static int hf_socks_ver = -1;
+static int hf_socks_ip_dst = -1;
+static int hf_socks_ip6_dst = -1;
+static int hf_user_name = -1;
+static int hf_socks_dstport = -1;
+static int hf_socks_command = -1;
+
+
+/************* State Machine names ***********/
+
+enum SockState {
+       None = 0,
+       Connecting,
+       V4UserNameWait,
+       V4NameWait,
+       V5Command,
+       V5Reply,
+       V5BindReply,    
+       UserNameAuth,
+       GssApiAuth,
+       AuthReply,
+       Done
+};
+
+
+
+typedef struct {
+       int     state;
+       int     version;
+       int     command;
+       int     grant;
+       gint32  port;
+       gint32  udp_port;
+       gint32  udp_remote_port;
+       
+       int     connect_offset;
+       row_pointer_type        v4_name_row;
+       row_pointer_type        v4_user_name_row;
+       row_pointer_type        connect_row;
+       row_pointer_type        cmd_reply_row;
+       row_pointer_type        bind_reply_row;
+       row_pointer_type        command_row;
+       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;
+
+
+
+
+static char *address_type_table[] = {
+       "Unknown",
+       "IPv4",
+       "Unknown",
+       "Domain Name",
+       "IPv6",
+       "Unknown"
+};
+
+
+/* String table for the V4 reply status messages */
+
+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"
+};
+
+
+/* String table for the V5 reply status messages */
+
+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"
+};
+
+
+#define socks_hash_init_count 20
+#define socks_hash_val_length (sizeof(socks_hash_entry_t))
+
+static GMemChunk *socks_vals = NULL;
+
+static guint32 last_row= 0;    /* used to see if packet is new */
+
+
+/************************* Support routines ***************************/
+
+
+static int display_string( const u_char *pd, int offset, frame_data *fd,
+       proto_tree *tree, char *label){
+
+/* display a string with a length, characters encoding */
+/* they are displayed under a tree with the name in Label variable */
+/* return the length of the string and the length byte */
+
+
+       proto_tree      *name_tree;
+       proto_item      *ti;
+
+
+       char temp[ 256];
+       int length = GBYTE( pd, offset);
+
+       if ((offset + 8) > fd->cap_len){  
+                       proto_tree_add_text(tree, offset, 0, "*** FRAME TOO SHORT ***");
+               return 0;
+       }
+
+       strncpy( temp, &pd[ offset + 1], length);
+       temp[ length ] = 0;
+  
+       ti = proto_tree_add_text(tree, offset, length + 1,
+               "%s: %s" , label, temp);
+
+
+       name_tree = proto_item_add_subtree(ti, ett_socks_name);
+
+       proto_tree_add_text( name_tree, offset, 1, "Length: %d", length);
+
+       ++offset;
+
+       proto_tree_add_text( name_tree, offset, length, "String: %s", temp);
+
+       return length + 1;
+}      
+
+
+static char *get_auth_method_name( guint Number){
+
+/* return the name of the authenication method */
+
+       if ( Number == 0) return "No authentication";
+       if ( Number == 1) return "GSSAPI";
+       if ( Number == 2) return "Username/Password";
+       if ( Number == 3) return "Chap";
+       if (( Number >= 4) && ( Number <= 0x7f))return "IANA assigned";
+       if (( Number >= 0x80) && ( Number <= 0xfe)) return "private method";
+       if ( Number == 0xff) return "no acceptable method";
+
+       /* shouldn't reach here */
+
+       return "Bad method number (not 0-0xff)";
+}
+
+
+static char *get_command_name( guint Number){
+
+/* return the name of the command as a string */
+
+       if ( Number == 0) return "Unknow";
+       if ( Number == 1) return "Connect";
+       if ( Number == 2) return "Bind";
+       if ( Number == 3) return "UdpAssociate";
+       if ( Number == 0x80) return "Ping";
+       if ( Number == 0x81) return "Traceroute";
+       return "Unknown";
+}
+
+
+static int display_address( const u_char *pd, int offset,
+               frame_data *fd, proto_tree *tree) {
+
+/* decode and display the v5 address, return offset of next byte */
+
+       int a_type = GBYTE( pd, offset);
+
+       proto_tree_add_text( tree, offset, 1,
+                       "Address Type: %d (%s)", a_type, 
+                       address_type_table[ MAX( 0, MIN( a_type,
+                               array_length( address_type_table)-1))]);
+
+       ++offset;
+
+       if ( a_type == 1){              /* IPv4 address */
+               if ( (offset + 4) > fd->cap_len) 
+                               proto_tree_add_text(tree, offset, 0, "*** FRAME TOO SHORT ***");
+
+               proto_tree_add_item( tree, hf_socks_ip_dst, offset,
+                                       4, GWORD( pd, offset));
+               offset += 4;
+       }       
+       else if ( a_type == 3){ /* domain name address */
+
+               offset += display_string( pd, offset, fd, tree,
+                       "Remote name");
+       }
+       else if ( a_type == 4){ /* IPv6 address */
+               if ((offset + 16) > fd->cap_len) 
+                               proto_tree_add_text(tree, offset, 0, "*** FRAME TOO SHORT ***");
+
+               proto_tree_add_item( tree, hf_socks_ip6_dst, offset,
+                               4, GWORD( pd, offset));
+               offset += 16;
+       }
+
+       return offset;
+}
+
+
+static int get_address_v5( const u_char *pd, int offset, 
+       socks_hash_entry_t *hash_info) {
+
+/* decode the v5 address and return offset of next byte */
+/*$$$ this needs to handle IPV6 and domain name addresses */
+
+       int a_type = GBYTE( pd, offset++);
+
+       if ( a_type == 1){              /* IPv4 address */
+          
+               if ( hash_info)
+                       hash_info->dst_addr = GWORD( pd, offset);
+               offset += 4;
+       }
+               
+       else if ( a_type == 4)          /* IPv6 address */
+               offset += 16;
+       
+       else if ( a_type == 3)  /* domain name address */
+               offset += GBYTE( pd, offset) + 1;
+       
+       return offset;
+}      
+
+
+/********************* V5 UDP Associate handlers ***********************/
+
+static void socks_udp_dissector( const u_char *pd, int offset, frame_data *fd,
+               proto_tree *tree) {
+
+/* Conversation dissector called from UDP dissector. Decode and display */
+/* the socks header, the pass the rest of the data to the udp port     */
+/* decode routine to  handle the payload.                              */
+
+       guint32 *ptr;
+       socks_hash_entry_t *hash_info;
+       conversation_t *conversation;
+       proto_tree      *socks_tree;
+       proto_item      *ti;
+       
+       conversation = find_conversation( &pi.src, &pi.dst, pi.ptype,
+               pi.srcport, pi.destport);
+
+       g_assert( conversation);        /* should always find a conversation */
+
+       hash_info = (socks_hash_entry_t*)conversation->data;
+
+       if (check_col(fd, COL_PROTOCOL))
+               col_add_str(fd, COL_PROTOCOL, "Socks");
+
+       if (check_col(fd, COL_INFO))
+               col_add_fstr(fd, COL_INFO, "Version: 5, UDP Associated packet");
+                       
+       if ( tree) {
+               ti = proto_tree_add_item( tree, proto_socks, offset,
+                       END_OF_FRAME, NULL, "Socks:" );
+
+               socks_tree = proto_item_add_subtree(ti, ett_socks);
+
+               CHECK_PACKET_LENGTH( 3);
+
+                       proto_tree_add_text( socks_tree, offset, 2, "Reserved");
+               offset += 2;
+               
+                       proto_tree_add_text( socks_tree, offset, 1, "Fragment Number: %d", GBYTE( pd,offset));
+               ++offset;
+       
+
+               offset = display_address( pd, offset, fd, socks_tree);
+               hash_info->udp_remote_port = pntohs( &pd[ offset]);
+               
+               CHECK_PACKET_LENGTH( 2);
+               proto_tree_add_item( socks_tree, hf_socks_dstport,
+                       offset, 2, hash_info->udp_remote_port);
+                       
+               offset += 2;
+       }
+       else {          /* no tree, skip past the socks header */
+               CHECK_PACKET_LENGTH( 3);
+               offset += 3;
+               offset = get_address_v5( pd,offset, 0) + 2;
+       }       
+
+
+/* set pi src/dst port and call the udp sub-dissector lookup */
+
+       if ( pi.srcport == hash_info->port)             
+                       ptr = &pi.destport;
+       else
+               ptr = &pi.srcport;
+
+        *ptr = hash_info->udp_remote_port;
+       
+       decode_udp_ports( pd, offset, fd, tree, pi.srcport, pi.destport);
+        *ptr = hash_info->udp_port;
+
+}
+
+                       
+void new_udp_conversation( socks_hash_entry_t *hash_info){
+
+       conversation_t *conversation = conversation_new( &pi.src, &pi.dst,  PT_UDP,
+                       hash_info->udp_port, hash_info->port, hash_info);
+                       
+       g_assert( conversation);
+       
+       conversation->dissector = socks_udp_dissector;
+}
+
+
+
+
+/**************** Protocol Tree Display routines  ******************/
+
+
+void display_socks_v4( const u_char *pd, int offset, frame_data *fd,
+       proto_tree *parent, proto_tree *tree, socks_hash_entry_t *hash_info) {
+
+
+/* Display the protocol tree for the V5 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    */
+/* didn't have that when I wrote this. And I didn't expect this to get */
+/* so messy.                                                           */
+
+
+       int command;
+
+                                       /* Display command from client */
+       if (compare_packet( hash_info->connect_row)){
+
+               CHECK_PACKET_LENGTH( 8);
+               proto_tree_add_text( tree, offset, 1,
+                               "Version: %u ", hash_info->version);
+               ++offset;
+               command = GBYTE( pd, offset);
+
+               proto_tree_add_text( tree, offset, 1,
+                       "Command: %u (%s)", command, 
+                               get_command_name( command));
+               ++offset;
+
+                                               /* Do remote port       */
+               proto_tree_add_item( tree, hf_socks_dstport, offset, 2,
+                               pntohs( &pd[ offset]));
+               offset += 2;
+
+                                               /* Do destination address */
+               proto_tree_add_item( tree, hf_socks_ip_dst, offset,
+                               4, GWORD( pd, offset));
+
+               offset += 4;
+
+/*$$ check this, needs to do length checking    */             
+                                               /* display user name    */
+                       proto_tree_add_item( tree, hf_user_name, offset, 
+                               strlen( &pd[offset]) + 1,
+                               &pd[offset]);
+
+       }
+                               /*Display command response from server*/
+       
+       else if ( compare_packet( hash_info->cmd_reply_row)){
+                                
+               CHECK_PACKET_LENGTH( 8);
+               proto_tree_add_text( tree, offset, 1,
+                       "Version: %u (should be 0) ", GBYTE( pd, offset));
+               ++offset;
+                                               /* Do results code      */
+               proto_tree_add_text( tree, offset, 1,
+                       "Result Code: %u (%s)", GBYTE( pd, offset) ,
+                       reply_table_v4[ MAX(0, MIN( GBYTE( pd, offset) - 90, 4))]);
+               ++offset;
+
+                                               /* Do remote port       */
+               proto_tree_add_item( tree, hf_socks_dstport, offset, 2,
+                               pntohs( &pd[ offset]));
+               offset += 2;;
+                                               /* Do remote address    */
+               proto_tree_add_item( tree, hf_socks_ip_dst, offset, 4,
+                       GWORD( pd, offset));
+       }
+       
+       else if ( compare_packet( hash_info->v4_user_name_row)){
+                        
+/*$$ check this, needs to do length checking    */             
+               proto_tree_add_text( tree, offset, strlen( &pd[offset]),
+                               "User Name: %s", &pd[offset]);
+       }
+}                      
+
+
+
+void display_socks_v5( const u_char *pd, int offset, frame_data *fd,
+       proto_tree *parent, 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    */
+/* didn't have that when I wrote this. And I didn't expect this to get */
+/* so messy.                                                           */
+
+       int i, command;
+       guint temp;
+       char *AuthMethodStr;
+
+
+       if (compare_packet( hash_info->connect_row)){
+
+               proto_tree      *AuthTree;
+               proto_item      *ti;
+
+               CHECK_PACKET_LENGTH( 2);
+                                               /* Do version   */
+               proto_tree_add_item( tree, hf_socks_ver, offset, 1,
+                               hash_info->version);
+               ++offset;
+
+               temp = GBYTE( pd, offset);      /* Get Auth method count */
+                                                       /* build auth tree */
+               ti = proto_tree_add_text( tree, offset, 1,
+                               "Client Authentication Methods");
+                               
+               AuthTree = proto_item_add_subtree(ti, ett_socks_auth);
+
+               proto_tree_add_text( AuthTree, offset, 1,
+                               "Count: %u ", temp);
+               ++offset;
+
+               CHECK_PACKET_LENGTH( temp);
+
+               for( i = 0; i  < temp; ++i) {
+
+                       AuthMethodStr = get_auth_method_name(
+                               GBYTE( pd, offset + i));
+                       proto_tree_add_text( AuthTree, offset + i, 1,
+                               "Method[%d]: %u (%s)", i,
+                               GBYTE( pd, offset + i), AuthMethodStr); 
+               }
+               return;
+       }                                       /* Get accepted auth method */
+       else if (compare_packet( hash_info->auth_method_row)) {
+
+               ++offset;
+               CHECK_PACKET_LENGTH( 1);
+
+               proto_tree_add_text( tree, offset, 1,
+                       "Accepted Auth Method: 0x%0x (%s)", GBYTE( pd, offset),
+                               get_auth_method_name( GBYTE( pd, offset)));
+
+               return;
+       }                                       /* handle user/password auth */
+       else if (compare_packet( hash_info->user_name_auth_row)) {
+
+               proto_tree_add_text( tree, offset, 1,
+                               "Version: %u ", hash_info->version);
+               ++offset;
+                                               /* process user name    */
+               offset += display_string( pd, offset, fd, tree,
+                               "User name");
+                                               /* process password     */
+               offset += display_string( pd, offset, fd, tree,
+                               "Password");
+       }                                       
+                                       /* command to the server */     
+                                       /* command response from server */
+       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_text( tree, offset, 1,
+                       "Version: %u ", hash_info->version);
+
+               CHECK_PACKET_LENGTH( 1);
+
+               ++offset;
+
+               command = GBYTE( pd, offset);
+               
+               if (compare_packet( hash_info->command_row))
+                       proto_tree_add_text( tree, offset, 1, "Command: %u (%s)",
+                               command,  get_command_name( command));
+               else
+                       proto_tree_add_text( tree, offset, 1, "Status: %d (%s)",
+                               GBYTE( pd, offset), reply_table_v5[ MAX( 0,
+                               MIN(GBYTE( pd, offset) - 90, 9))]);
+               ++offset;
+
+               proto_tree_add_text( tree, offset, 1,
+                       "Reserved: 0x%0x (should = 0x00)", GBYTE( pd, offset)); 
+               ++offset;
+
+               offset = display_address( pd, offset, fd, tree);
+
+               CHECK_PACKET_LENGTH( 2);
+                                               /* Do remote port       */
+               proto_tree_add_text( tree, offset, 2,
+                               "%s Port: %d",
+                               (compare_packet( hash_info->bind_reply_row) ?
+                                       "Remote Host " : ""),
+                                pntohs( &pd[ offset]));
+       }
+}
+
+
+       
+/**************** Decoder State Machines ******************/
+
+
+static guint state_machine_v4( socks_hash_entry_t *hash_info, const u_char *pd,
+       int offset, frame_data *fd) {
+
+/* Decode V4 protocol.  This is done on the first pass through the     */
+/* list.  Based upon the current state, decode the packet and determine        */
+/* what the next state should be.  If we had per packet information,   */
+/* this would be the place to load them up.                            */
+
+       if ( hash_info->state == None) {                /* new connection */
+
+               if (check_col(fd, COL_INFO))
+                       col_append_str(fd, COL_INFO, " Connect to server request");
+
+               hash_info->state = Connecting;  /* change state         */
+
+               hash_info->command = GBYTE( pd, offset + 1);
+                                               /* get remote port      */
+               if ( hash_info->command == CONNECT_COMMAND)                                             
+                       hash_info->port =  pntohs( &pd[ offset + 2]);
+                                               /* get remote address   */
+               hash_info->dst_addr = GWORD( pd, offset + 4);
+               
+                                               /* save the packet pointer */
+               hash_info->connect_row = get_packet_ptr;
+
+                                               /* skip past this stuff */
+               hash_info->connect_offset = offset + 8;
+
+               offset += 8;
+               
+               if ( offset == pi.len)          /* if no user name      */
+                                               /* change state         */
+                       hash_info->state = V4UserNameWait;
+               
+                       
+               hash_info->connect_offset += strlen( &pd[ offset]) + 1;
+               
+               if ( !hash_info->dst_addr){             /* if no dest address */
+                                                       /* if more data */
+                       if ( hash_info->connect_offset < pi.len ) {
+/*$$$ copy remote name here ??? */
+                               hash_info->state = Connecting;
+                       }
+                       else
+                               hash_info->state = V4NameWait;  
+                                               }
+                                               /* waiting for V4 user name */
+       }else if ( hash_info->state == V4UserNameWait){ 
+
+               if (check_col(fd, COL_INFO))
+                       col_append_str(fd, COL_INFO, " Connect Request (User name)");
+
+               hash_info->v4_user_name_row = get_packet_ptr;
+/*$$$ may need to check for domain name here */
+               hash_info->state = Connecting;
+       }
+                                       /* waiting for V4 domain name   */
+       else if ( hash_info->state == V4NameWait){
+
+               hash_info->v4_name_row = get_packet_ptr;
+               hash_info->state = Connecting;
+
+       }
+       else if ( hash_info->state == Connecting){
+
+               if (check_col(fd, COL_INFO))
+                       col_append_str(fd, COL_INFO, " Connect Response");
+
+                                               /* save packet pointer  */
+               hash_info->cmd_reply_row = get_packet_ptr;
+               hash_info->state = Done;                /* change state         */
+               offset = offset + 8;
+       }
+
+       return offset;
+}
+
+
+
+static void state_machine_v5( socks_hash_entry_t *hash_info, const u_char *pd, 
+       int offset, frame_data *fd) {
+
+/* Decode V5 protocol.  This is done on the first pass through the     */
+/* list.  Based upon the current state, decode the packet and determine        */
+/* what the next state should be.  If we had per packet information,   */
+/* this would be the place to load them up.                            */
+
+
+       int temp;
+
+       if ( hash_info->state == None) {
+
+               if (check_col(fd, COL_INFO))
+                       col_append_str(fd, COL_INFO, " Connect to server request");
+
+               hash_info->state = Connecting;  /* change state         */
+               hash_info->connect_row = get_packet_ptr;        
+
+               if (( offset+ 1) > fd->cap_len){ 
+                       hash_info->state = Done;        /* change state         */
+                       return; 
+               }
+
+               temp = GBYTE( pd, offset + 1);
+                                               /* skip past auth methods */
+               offset = hash_info->connect_offset = offset + 1 + temp;
+       }
+       else if ( hash_info->state == Connecting){
+
+               guint AuthMethod = GBYTE( pd, offset + 1);
+
+               if (check_col(fd, COL_INFO))
+                       col_append_str(fd, COL_INFO, " Connect to server response");
+
+               hash_info->auth_method_row = get_packet_ptr;
+
+               if ( AuthMethod == NO_AUTHENTICATION)
+                       hash_info->state = V5Command;
+                       
+               else if ( AuthMethod == USER_NAME_AUTHENTICATION)
+                       hash_info->state = UserNameAuth;
+                       
+               else if ( AuthMethod == GSS_API_AUTHENTICATION)
+/*$$$ should be this           hash_info->state = GssApiAuth; */
+                       hash_info->state = Done;        
+                       
+               else    hash_info->state = Done;        /*Auth failed or error*/
+
+       }
+       
+       else if ( hash_info->state == V5Command) {      /* Handle V5 Command */
+
+               guint temp;
+
+               if (( offset+ 1) > fd->cap_len){ 
+                       hash_info->state = Done;        /* change state         */
+                       return; 
+               }
+
+               hash_info->command = GBYTE( pd, offset + 1); /* get command */
+
+               if (check_col(fd, COL_INFO))
+                       col_append_fstr(fd, COL_INFO, " Command Request - %s",
+                               get_command_name(hash_info->command));
+
+               hash_info->state = V5Reply;
+               hash_info->command_row = get_packet_ptr;
+
+               offset += 3;                    /* skip to address type */
+
+               offset = get_address_v5( pd, offset, hash_info);
+
+               if (( offset+ 1) > fd->cap_len){ 
+                       hash_info->state = Done;
+                       return; 
+               }
+               temp = GBYTE( pd, offset);
+
+               if (( hash_info->command == CONNECT_COMMAND) || 
+                   ( hash_info->command == UDP_ASSOCIATE_COMMAND))
+                                               /* get remote port      */
+                       hash_info->port =  pntohs( &pd[ offset]);
+       }
+
+       else if ( hash_info->state == V5Reply) {        /* V5 Command Reply */
+
+
+               if (check_col(fd, COL_INFO))
+                       col_append_fstr(fd, COL_INFO, " Command Response - %s",
+                               get_command_name(hash_info->command));
+
+               hash_info->cmd_reply_row = get_packet_ptr;
+
+               if (( hash_info->command == CONNECT_COMMAND) ||
+                   (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( pd, offset, hash_info);
+
+       /* save server udp port and create upd conversation */
+                       if (( offset+ 2) > fd->cap_len){ 
+                               hash_info->state = Done;
+                               return; 
+                       }
+                       hash_info->udp_port =  pntohs( &pd[ offset]);
+                       
+                       new_udp_conversation( hash_info);
+
+/*$$ may need else statement to handle unknows and generate error message */
+                       
+               }               
+       }
+       else if ( hash_info->state == V5BindReply) {    /* V5 Bind Second Reply */
+
+               if (check_col(fd, COL_INFO))
+                       col_append_str(fd, COL_INFO, " Command Response: Bind remote host info");
+
+               hash_info->bind_reply_row = get_packet_ptr;
+               hash_info->state = Done;
+       }
+       else if ( hash_info->state == UserNameAuth) {   /* Handle V5 User Auth*/
+               if (check_col(fd, COL_INFO))
+                       col_append_str(fd, COL_INFO,
+                               " User authentication response");
+
+               hash_info->user_name_auth_row = get_packet_ptr;
+               hash_info->state = AuthReply;
+
+       }
+       else if ( hash_info->state == AuthReply){       /* V5 User Auth reply */
+               hash_info->cmd_reply_row = get_packet_ptr;
+               if (check_col(fd, COL_INFO))
+                       col_append_str(fd, COL_INFO, " User authentication reply");
+               hash_info->state = V5Command;
+       }
+}
+
+
+
+static void display_ping_and_tracert( const u_char *pd, int offset,
+       frame_data *fd, 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;
+               int             linelen;
+
+                                       /* handle the end command */
+               if ( pi.destport == TCP_PORT_SOCKS){
+               if (check_col(fd, COL_INFO))
+                       col_append_str(fd, COL_INFO, ", Terminate Request");
+               
+               if ( tree)
+                       proto_tree_add_text(tree, offset, 1,
+                               (hash_info->command  == PING_COMMAND) ?
+                               "Ping: End command" :
+                               "Traceroute: End command");
+       }
+               else{           /* display the PING or Traceroute results */
+               if (check_col(fd, COL_INFO))
+                       col_append_str(fd, COL_INFO, ", Results");
+
+               if ( tree){
+                       proto_tree_add_text(tree, offset, END_OF_FRAME,
+                               (hash_info->command  == PING_COMMAND) ?
+                               "Ping Results:" :
+                               "Traceroute Results");
+
+                       data = &pd[offset];
+                       dataend = data + END_OF_FRAME;
+               
+                               while (data < dataend) {
+       
+                               lineend = find_line_end(data, dataend, &eol);
+                               linelen = lineend - data;
+
+                                       proto_tree_add_text( tree, offset, linelen,
+                                               format_text(data, linelen));
+                                       offset += linelen;
+                                       data = lineend;
+                               }
+               }
+       }
+}
+
+
+
+static void call_next_dissector( const u_char *pd, int offset, frame_data *fd,
+       proto_tree *tree, socks_hash_entry_t *hash_info) {
+
+/* Display the results for PING and TRACERT extensions or              */
+/* Call TCP  dissector for the port that was passed during the         */
+/* connect process                                                     */
+/* Load pointer to pi.XXXport depending upon the direction, change     */
+/* pi port to the remote port, call next dissecotr to decode the       */
+/* payload, and restore the pi port after that is done.                        */
+
+       guint32 *ptr;
+       if (( hash_info->command  == PING_COMMAND) ||
+           ( hash_info->command  == TRACERT_COMMAND))
+                
+               display_ping_and_tracert( pd, offset, fd, tree, hash_info);
+
+       else {          /* call the tcp port decoder to handle the payload */
+       
+/*$$$ may want to load dest address here */
+
+               if ( pi.destport  == TCP_PORT_SOCKS)
+                       ptr = &pi.destport;
+               else
+                       ptr = &pi.srcport;
+
+               *ptr = hash_info->port;
+               decode_tcp_ports( pd, offset, fd, tree, pi.srcport, pi.destport);
+               *ptr = TCP_PORT_SOCKS;
+       }
+}                
+
+
+
+static void
+dissect_socks(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
+
+       proto_tree      *socks_tree;
+       proto_item      *ti;
+       socks_hash_entry_t *hash_info;
+       conversation_t *conversation;
+       
+
+       conversation = find_conversation( &pi.src, &pi.dst, pi.ptype,
+               pi.srcport, pi.destport);
+
+       if ( conversation)                      /* conversation found */
+               hash_info = conversation->data;
+
+                       /* new conversation create local data structure */
+       else {                          
+               hash_info = g_mem_chunk_alloc(socks_vals);
+               hash_info->start_done_row = G_MAXINT;
+               hash_info->state = None;
+               hash_info->port = -1;
+               hash_info->version = GBYTE( pd, offset); /* get version*/
+
+               if (( hash_info->version != 4) &&       /* error test version */
+                  ( hash_info->version != 5))
+                       hash_info->state = Done;
+
+               conversation_new( &pi.src, &pi.dst, pi.ptype,
+                       pi.srcport, pi.destport, hash_info);
+       }
+
+/* display summary window information  */
+
+       if (check_col(fd, COL_PROTOCOL))
+               col_add_str(fd, COL_PROTOCOL, "Socks");
+
+       if (check_col(fd, COL_INFO)){
+               if (( hash_info->version == 4) || ( hash_info->version == 5)){
+                       col_add_fstr(fd, COL_INFO, "Version: %d",
+                               hash_info->version);
+               }               
+               else                    /* unknown version display error */
+                       col_add_str(fd, COL_INFO, "Unknown");
+               
+
+               if ( hash_info->command == PING_COMMAND)
+                       col_append_str(fd, COL_INFO, ", Ping Req");
+               if ( hash_info->command == TRACERT_COMMAND)
+                       col_append_str(fd, COL_INFO, ", Traceroute Req");
+               
+               if ( hash_info->port != -1)
+                       col_append_fstr(fd, COL_INFO, ", Remote Port: %d",
+                               hash_info->port);
+       }
+
+
+/* run state machine if needed */
+
+       if ((hash_info->state != Done) && ( fd->num > last_row)){
+               last_row = fd->num;
+
+               if ( hash_info->version == 4)
+                       state_machine_v4( hash_info, pd, offset, fd);
+
+               else if ( hash_info->version == 5)
+                       state_machine_v5( hash_info, pd, offset, fd);
+
+               if (hash_info->state == Done) {         /* if done now  */
+                       hash_info->start_done_row = fd->num;
+               }
+       }
+       
+/* if proto tree, decode and display */
+
+       if (tree) {                     
+               ti = proto_tree_add_item( tree, proto_socks, offset,
+                       END_OF_FRAME, NULL, "Socks:" );
+
+               socks_tree = proto_item_add_subtree(ti, ett_socks);
+
+               if ( hash_info->version == 4)
+                       display_socks_v4( pd, offset, fd, tree, socks_tree,
+                               hash_info);
+                       
+               else if ( hash_info->version == 5)
+                       display_socks_v5( pd, offset, fd, tree, socks_tree,
+                               hash_info);
+
+                               /* if past startup, add the faked stuff */
+               if ( fd->num >  hash_info->start_done_row){
+                                               /*  add info to tree */
+                       proto_tree_add_text( socks_tree, offset, 0,
+                               "Command: %d (%s)", hash_info->command,
+                               get_command_name(hash_info->command));
+
+                       proto_tree_add_item( socks_tree, hf_socks_ip_dst,
+                                       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_item( socks_tree, hf_socks_dstport,
+                                       offset, 0, hash_info->port);
+                       }
+               }
+
+       }
+
+
+/* call next dissector if ready */
+
+       if ( fd->num > hash_info->start_done_row){
+               call_next_dissector( pd, offset, fd, tree, hash_info);
+       }
+}
+
+
+
+static void socks_reinit( void){
+
+/* Do the cleanup work when a new pass through the packet list is      */
+/* performed. Reset the highest row seen counter and re-initialize the */
+/* conversation memory chunks.                                         */
+
+       last_row = 0;                   
+       
+       if (socks_vals)
+               g_mem_chunk_destroy(socks_vals);
+
+       socks_vals = g_mem_chunk_new("socks_vals", socks_hash_val_length,
+               socks_hash_init_count * socks_hash_val_length,
+               G_ALLOC_AND_FREE);
+}
+
+
+void
+proto_register_socks( void){
+
+/*** Prep the socks protocol, register it and a initialization routine  */
+/*     to clear the hash stuff.                                        */
+
+
+       static gint *ett[] = {
+               &ett_socks,
+               &ett_socks_auth,
+               &ett_socks_name
+               
+       };
+
+       static hf_register_info hf[] = {
+    
+
+               { &hf_socks_ver,
+                       { "Version", "socks.ver", FT_UINT8, BASE_NONE, NULL,
+                               0x0, ""
+                       }
+               },
+               { &hf_socks_ip_dst,
+                       { "Remote Address", "socks.dst", FT_IPv4, BASE_NONE, NULL,
+                               0x0, ""
+                       }
+               },
+               { &hf_socks_ip6_dst,
+                       { "Remote Address", "socks.dstV6", FT_IPv6, BASE_NONE, NULL,
+                               0x0, ""
+                       }
+               },
+
+                { &hf_user_name,
+                       { "User Name", "socks.username", FT_STRING, BASE_NONE,
+                                NULL, 0x0, ""
+                       }
+                },
+               { &hf_socks_dstport,
+                       { "Remote Port", "socks.dstport", FT_UINT16,
+                               BASE_DEC, NULL, 0x0, ""
+                       }
+               },
+               { &hf_socks_command,
+                       { "Command", "socks.command", FT_UINT16,
+                               BASE_DEC, NULL, 0x0, ""
+                       }
+               }
+
+       };
+
+
+       proto_socks = proto_register_protocol (
+               "Socks Protocol", "socks");           
+
+       proto_register_field_array(proto_socks, hf, array_length(hf));
+       proto_register_subtree_array(ett, array_length(ett));  
+
+       register_init_routine( &socks_reinit);  /* register re-init routine */
+}
+
+
+void
+proto_reg_handoff_socks(void) {
+
+       /* dissector install routine */ 
+       dissector_add("tcp.port", TCP_PORT_SOCKS, dissect_socks);
+}
+
+
index b144c3575a752e4e7ee635e2152b59ced384a289..b06a58092c5b9675af1a7bbaf0cfa8c1de474e90 100644 (file)
@@ -1,7 +1,7 @@
 /* packet-tcp.c
  * Routines for TCP packet disassembly
  *
- * $Id: packet-tcp.c,v 1.66 2000/04/08 07:07:39 guy Exp $
+ * $Id: packet-tcp.c,v 1.67 2000/04/12 22:53:15 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -353,6 +353,76 @@ static const true_false_string flags_set_truth = {
   "Not set"
 };
 
+
+void
+decode_tcp_ports( const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
+       int src_port, int dst_port) {
+
+/* Determine if there is a sub-dissector and call it.  This has been */
+/* separated into a stand alone routine to other protocol dissectors */
+/* can call to it, ie. socks   */
+
+
+  dissector_t sub_dissector;
+
+  sub_dissector = find_conversation_dissector( &pi.src, &pi.dst, PT_TCP,
+               src_port, dst_port);
+  if (sub_dissector){
+       (sub_dissector)(pd, offset, fd, tree);
+       return;
+  }
+
+    /* ONC RPC.  We can't base this on anything in the TCP header; we have
+       to look at the payload.  If "dissect_rpc()" returns TRUE, it was
+       an RPC packet, otherwise it's some other type of packet. */
+    if (dissect_rpc(pd, offset, fd, tree))
+      return;
+
+    /* try to apply the plugins */
+#ifdef HAVE_PLUGINS
+    {
+      plugin *pt_plug = plugin_list;
+
+      if (enabled_plugins_number > 0) {
+       while (pt_plug) {
+         if (pt_plug->enabled && !strcmp(pt_plug->protocol, "tcp") &&
+             tree && dfilter_apply(pt_plug->filter, tree, pd)) {
+           pt_plug->dissector(pd, offset, fd, tree);
+           return;
+         }
+         pt_plug = pt_plug->next;
+       }
+      }
+    }
+#endif
+
+    /* do lookup with the subdissector table */
+    if (dissector_try_port(subdissector_table, src_port, pd, offset,
+                               fd, tree) ||
+        dissector_try_port(subdissector_table, dst_port, pd, offset,
+                               fd, tree))
+       return;
+
+    /* check existence of high level protocols */
+
+#define PORT_IS(port)   ( src_port == port || dst_port == port)    
+
+    if (memcmp(&pd[offset], "GIOP",  4) == 0) {
+       dissect_giop(pd, offset, fd, tree);
+       return;
+    }
+
+    if ( PORT_IS(TCP_PORT_YHOO) && 
+               (memcmp(&pd[offset], "YPNS",  4) == 0 ||
+               memcmp(&pd[offset], "YHOO",  4) == 0 )) {
+       dissect_yhoo(pd, offset, fd, tree);
+       return;
+    }
+
+    dissect_data(pd, offset, fd, tree);
+}
+
+
 void
 dissect_tcp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
   e_tcphdr   th;
@@ -469,59 +539,8 @@ dissect_tcp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
   
   /* Check the packet length to see if there's more data
      (it could be an ACK-only packet) */
-  if (packet_max > offset) {
-
-    /* ONC RPC.  We can't base this on anything in the TCP header; we have
-       to look at the payload.  If "dissect_rpc()" returns TRUE, it was
-       an RPC packet, otherwise it's some other type of packet. */
-    if (dissect_rpc(pd, offset, fd, tree))
-      goto reas;
-
-    /* try to apply the plugins */
-#ifdef HAVE_PLUGINS
-    {
-      plugin *pt_plug = plugin_list;
-
-      if (enabled_plugins_number > 0) {
-       while (pt_plug) {
-         if (pt_plug->enabled && !strcmp(pt_plug->protocol, "tcp") &&
-             tree && dfilter_apply(pt_plug->filter, tree, pd)) {
-           pt_plug->dissector(pd, offset, fd, tree);
-           goto reas;
-         }
-         pt_plug = pt_plug->next;
-       }
-      }
-    }
-#endif
-
-    /* do lookup with the subdissector table */
-    if (dissector_try_port(subdissector_table, th.th_sport, pd, offset,
-                               fd, tree) ||
-        dissector_try_port(subdissector_table, th.th_dport, pd, offset,
-                               fd, tree))
-       goto reas;
-
-    /* check existence of high level protocols */
-
-#define PORT_IS(port)   (th.th_sport == port || th.th_dport == port)    
-
-    if (memcmp(&pd[offset], "GIOP",  4) == 0) {
-       dissect_giop(pd, offset, fd, tree);
-       goto reas;
-    }
-
-    if ( PORT_IS(TCP_PORT_YHOO) && 
-               (memcmp(&pd[offset], "YPNS",  4) == 0 ||
-               memcmp(&pd[offset], "YHOO",  4) == 0 )) {
-       dissect_yhoo(pd, offset, fd, tree);
-       goto reas;
-    }
-
-    dissect_data(pd, offset, fd, tree);
-  }
-
-reas:
+  if (packet_max > offset) 
+    decode_tcp_ports( pd, offset, fd, tree, th.th_sport, th.th_dport);
  
   if( data_out_file ) {
     reassemble_tcp( th.th_seq,         /* sequence number */
index ee77c532480546caf1f11e1b9c336abffaa6bea8..d57793e0ec3b34f7643a815dded7fd5995e699ef 100644 (file)
@@ -1,6 +1,6 @@
 /* packet-tcp.h
  *
- * $Id: packet-tcp.h,v 1.2 2000/04/08 03:32:10 guy Exp $
+ * $Id: packet-tcp.h,v 1.3 2000/04/12 22:53:15 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -25,4 +25,7 @@
 /* Urgent pointer value for the current packet. */
 extern guint16   tcp_urgent_pointer;
 
+extern void decode_tcp_ports(const u_char *, int, frame_data *,
+       proto_tree *, int, int);
+
 void dissect_tcp(const u_char *, int, frame_data *, proto_tree *);
index c805250c84c71b23e570e6c14c1a47adf4739d75..ca22c9f972c79db1a6e31912317671ce3df3ac25 100644 (file)
@@ -1,7 +1,7 @@
 /* packet-udp.c
  * Routines for UDP packet disassembly
  *
- * $Id: packet-udp.c,v 1.59 2000/04/08 07:07:41 guy Exp $
+ * $Id: packet-udp.c,v 1.60 2000/04/12 22:53:16 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -83,55 +83,28 @@ typedef struct _e_udphdr {
 
 static dissector_table_t udp_dissector_table;
 
+
 void
-dissect_udp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
-  e_udphdr  uh;
-  guint16    uh_sport, uh_dport, uh_ulen, uh_sum;
-  proto_tree *udp_tree;
-  proto_item *ti;
+decode_udp_ports( const u_char *pd, int offset, frame_data *fd,
+       proto_tree *tree, int uh_sport, int uh_dport){
 
-  if (!BYTES_ARE_IN_FRAME(offset, sizeof(e_udphdr))) {
-    dissect_data(pd, offset, fd, tree);
-    return;
-  }
+/* Determine if there is a sub-dissector and call it.  This has been */
+/* separated into a stand alone routine to other protocol dissectors */
+/* can call to it, ie. socks   */
 
-  /* Avoids alignment problems on many architectures. */
-  memcpy(&uh, &pd[offset], sizeof(e_udphdr));
-  uh_sport = ntohs(uh.uh_sport);
-  uh_dport = ntohs(uh.uh_dport);
-  uh_ulen  = ntohs(uh.uh_ulen);
-  uh_sum   = ntohs(uh.uh_sum);
-  
-  if (check_col(fd, COL_PROTOCOL))
-    col_add_str(fd, COL_PROTOCOL, "UDP");
-  if (check_col(fd, COL_INFO))
-    col_add_fstr(fd, COL_INFO, "Source port: %s  Destination port: %s",
-           get_udp_port(uh_sport), get_udp_port(uh_dport));
-    
-  if (tree) {
-    ti = proto_tree_add_item(tree, proto_udp, offset, 8);
-    udp_tree = proto_item_add_subtree(ti, ett_udp);
+  dissector_t sub_dissector;
 
-    proto_tree_add_uint_format(udp_tree, hf_udp_srcport, offset, 2, uh_sport,
-       "Source port: %s (%u)", get_udp_port(uh_sport), uh_sport);
-    proto_tree_add_uint_format(udp_tree, hf_udp_dstport, offset + 2, 2, uh_dport,
-       "Destination port: %s (%u)", get_udp_port(uh_dport), uh_dport);
 
-    proto_tree_add_item_hidden(udp_tree, hf_udp_port, offset, 2, uh_sport);
-    proto_tree_add_item_hidden(udp_tree, hf_udp_port, offset+2, 2, uh_dport);
+/* determine if this packet is part of a conversation and call dissector */
+/* for the conversation if available */
 
-    proto_tree_add_item(udp_tree, hf_udp_length, offset + 4, 2,  uh_ulen);
-    proto_tree_add_uint_format(udp_tree, hf_udp_checksum, offset + 6, 2, uh_sum,
-       "Checksum: 0x%04x", uh_sum);
+  sub_dissector = find_conversation_dissector( &pi.src, &pi.dst, PT_UDP,
+               uh_sport, uh_dport);
+  if (sub_dissector){
+       (sub_dissector)(pd, offset, fd, tree);
+       return;
   }
 
-  /* Skip over header */
-  offset += 8;
-
-  pi.ptype = PT_UDP;
-  pi.srcport = uh_sport;
-  pi.destport = uh_dport;
-
   /* ONC RPC.  We can't base this on anything in the UDP header; we have
      to look at the payload.  If "dissect_rpc()" returns TRUE, it was
      an RPC packet, otherwise it's some other type of packet. */
@@ -185,6 +158,61 @@ dissect_udp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
   }
 }
 
+
+void
+dissect_udp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
+  e_udphdr  uh;
+  guint16    uh_sport, uh_dport, uh_ulen, uh_sum;
+  proto_tree *udp_tree;
+  proto_item *ti;
+
+  if (!BYTES_ARE_IN_FRAME(offset, sizeof(e_udphdr))) {
+    dissect_data(pd, offset, fd, tree);
+    return;
+  }
+
+  /* Avoids alignment problems on many architectures. */
+  memcpy(&uh, &pd[offset], sizeof(e_udphdr));
+  uh_sport = ntohs(uh.uh_sport);
+  uh_dport = ntohs(uh.uh_dport);
+  uh_ulen  = ntohs(uh.uh_ulen);
+  uh_sum   = ntohs(uh.uh_sum);
+  
+  if (check_col(fd, COL_PROTOCOL))
+    col_add_str(fd, COL_PROTOCOL, "UDP");
+  if (check_col(fd, COL_INFO))
+    col_add_fstr(fd, COL_INFO, "Source port: %s  Destination port: %s",
+           get_udp_port(uh_sport), get_udp_port(uh_dport));
+    
+  if (tree) {
+    ti = proto_tree_add_item(tree, proto_udp, offset, 8);
+    udp_tree = proto_item_add_subtree(ti, ett_udp);
+
+    proto_tree_add_uint_format(udp_tree, hf_udp_srcport, offset, 2, uh_sport,
+       "Source port: %s (%u)", get_udp_port(uh_sport), uh_sport);
+    proto_tree_add_uint_format(udp_tree, hf_udp_dstport, offset + 2, 2, uh_dport,
+       "Destination port: %s (%u)", get_udp_port(uh_dport), uh_dport);
+
+    proto_tree_add_item_hidden(udp_tree, hf_udp_port, offset, 2, uh_sport);
+    proto_tree_add_item_hidden(udp_tree, hf_udp_port, offset+2, 2, uh_dport);
+
+    proto_tree_add_item(udp_tree, hf_udp_length, offset + 4, 2,  uh_ulen);
+    proto_tree_add_uint_format(udp_tree, hf_udp_checksum, offset + 6, 2, uh_sum,
+       "Checksum: 0x%04x", uh_sum);
+  }
+
+  /* Skip over header */
+  offset += 8;
+
+  pi.ptype = PT_UDP;
+  pi.srcport = uh_sport;
+  pi.destport = uh_dport;
+
+/* call sub-dissectors */
+  decode_udp_ports( pd, offset, fd, tree, uh_sport, uh_dport);
+
+}
+
 void
 proto_register_udp(void)
 {
index 3bf5b1de96ed8336f13911915141484ee56890f2..1187497e1708a8a9622905012e1654b438d1926e 100644 (file)
@@ -1,6 +1,6 @@
 /* packet-udp.h
  *
- * $Id: packet-udp.h,v 1.1 2000/02/15 21:03:24 gram Exp $
+ * $Id: packet-udp.h,v 1.2 2000/04/12 22:53:16 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -22,5 +22,7 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
+extern void decode_udp_ports(const u_char *, int, frame_data *,
+       proto_tree *, int, int);
 
 void dissect_udp(const u_char *, int, frame_data *, proto_tree *);