Ethereal-dev: [Ethereal-dev] a few things for dcerpc

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Todd Sabin <tas@xxxxxxxxxxx>
Date: 18 Nov 2001 19:44:51 -0500
Here's a patch (and a new file) for some dcerpc stuff.  It does the
following:

o Modifies the dcerpc handoff to subdissectors slightly.  It also
needs to pass the data representation to the subdissector.  Also, if
no subdissector is found, it puts a "Stub data" entry in the tree.

o Adds optional TCP desegmentation to the dcerpc layer.  Note that
dcerpc has it's own ability to fragment PDUs.  This isn't for dealing
with that, but with the case of a single PDU being broken over more
than one TCP segment.

o Adds a little bit of dissection to packet-dcerpc-epm.c.  Mainly just
proof of concept for the dcerpc handoff stuff.  (Writing this is how I
realized the need for the drep.)

o Adds packet-dcerpc-ndr.c, which will contain NDR dissection routines
for use by subdissectors.


Todd

? packet-dcerpc-ndr.c
Index: Makefile.am
===================================================================
RCS file: /cvsroot/ethereal/Makefile.am,v
retrieving revision 1.381
diff -u -r1.381 Makefile.am
--- Makefile.am	2001/11/15 21:11:01	1.381
+++ Makefile.am	2001/11/19 00:17:40
@@ -100,6 +100,7 @@
 	packet-dcerpc-conv.c  \
 	packet-dcerpc-epm.c  \
 	packet-dcerpc-mgmt.c  \
+	packet-dcerpc-ndr.c  \
 	packet-dcerpc-remact.c  \
 	packet-dcerpc-oxid.c  \
 	packet-ddtp.c  \
Index: packet-dcerpc-epm.c
===================================================================
RCS file: /cvsroot/ethereal/packet-dcerpc-epm.c,v
retrieving revision 1.1
diff -u -r1.1 packet-dcerpc-epm.c
--- packet-dcerpc-epm.c	2001/07/11 01:25:44	1.1
+++ packet-dcerpc-epm.c	2001/11/19 00:17:40
@@ -41,6 +41,18 @@
 
 static int proto_epm = -1;
 
+static int hf_epm_inquiry_type = -1;
+static int hf_epm_object_p = -1;
+static int hf_epm_object = -1;
+static int hf_epm_if_id_p = -1;
+static int hf_epm_if_id = -1;
+static int hf_epm_ver_maj = -1;
+static int hf_epm_ver_min = -1;
+static int hf_epm_ver_opt = -1;
+static int hf_epm_lookup_hnd = -1;
+static int hf_epm_max_ents = -1;
+static int hf_epm_num_ents = -1;
+
 static gint ett_epm = -1;
 
 
@@ -48,10 +60,69 @@
 static guint16  ver_epm = 3;
 
 
+static int
+epm_dissect_ept_lookup_rqst (tvbuff_t *tvb, int offset, 
+                             packet_info *pinfo, proto_tree *tree, 
+                             char *drep)
+{
+    guint32 dummy;
+    offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
+                                 hf_epm_inquiry_type, NULL);
+    offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
+                                 hf_epm_object_p, &dummy);
+    if (dummy) {
+        offset = dissect_ndr_uuid_t (tvb, offset, pinfo, tree, drep,
+                                     hf_epm_object, NULL);
+    }
+    offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
+                                 hf_epm_if_id_p, &dummy);
+    if (dummy) {
+        offset = dissect_ndr_uuid_t (tvb, offset, pinfo, tree, drep,
+                                     hf_epm_if_id, NULL);
+        offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
+                                     hf_epm_ver_maj, NULL);
+        offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
+                                     hf_epm_ver_min, NULL);
+    }
+    offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
+                                 hf_epm_ver_opt, NULL);
+    if (tree) {
+        proto_tree_add_bytes (tree, hf_epm_lookup_hnd, tvb, offset, 20,
+                              tvb_get_ptr (tvb, offset, 20));
+    }
+    offset += 20;
+
+    offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
+                                 hf_epm_max_ents, NULL);
+    return offset;
+}
+
+
+static int
+epm_dissect_ept_lookup_resp (tvbuff_t *tvb, int offset, 
+                             packet_info *pinfo, proto_tree *tree, 
+                             char *drep)
+{
+    guint32 dummy;
+
+    /* need a dissect_ndr_ctx_handle */
+    if (tree) {
+        proto_tree_add_bytes (tree, hf_epm_lookup_hnd, tvb, offset, 20,
+                              tvb_get_ptr (tvb, offset, 20));
+    }
+    offset += 20;
+
+    offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
+                                 hf_epm_num_ents, NULL);
+    /* FIXME: more to do here */
+    return offset;
+}
+
+
 static dcerpc_sub_dissector epm_dissectors[] = {
     { 0, "ept_insert", NULL, NULL },
     { 1, "ept_delete", NULL, NULL },
-    { 2, "ept_lookup", NULL, NULL },
+    { 2, "ept_lookup", epm_dissect_ept_lookup_rqst, epm_dissect_ept_lookup_resp },
     { 3, "ept_map", NULL, NULL },
     { 4, "ept_lookup_handle_free", NULL, NULL },
     { 5, "ept_inq_object", NULL, NULL },
@@ -63,18 +134,36 @@
 void
 proto_register_epm (void)
 {
-#if 0
 	static hf_register_info hf[] = {
-	};
-#endif
+        { &hf_epm_inquiry_type,
+          { "Inquiry type", "epm.inq_type", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+        { &hf_epm_object_p,
+          { "Object pointer", "epm.object_p", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+        { &hf_epm_object,
+          { "Object", "epm.object", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+        { &hf_epm_if_id_p,
+          { "Interface pointer", "epm.if_id_p", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+        { &hf_epm_if_id,
+          { "Interface", "epm.if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+        { &hf_epm_ver_maj,
+          { "Version Major", "epm.ver_maj", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+        { &hf_epm_ver_min,
+          { "Version Minor", "epm.ver_min", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+        { &hf_epm_ver_opt,
+          { "Version Option", "epm.ver_opt", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},	
+        { &hf_epm_lookup_hnd,
+          { "Lookup Handle", "epm.lookup_hnd", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},	
+        { &hf_epm_max_ents,
+          { "Max entries", "epm.max_ents", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+        { &hf_epm_num_ents,
+          { "Num entries", "epm.num_ents", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+    };
 
 	static gint *ett[] = {
 		&ett_epm,
 	};
 	proto_epm = proto_register_protocol ("DCE/RPC Endpoint Mapper", "EPM", "epm");
-#if 0
 	proto_register_field_array (proto_epm, hf, array_length (hf));
-#endif
 	proto_register_subtree_array (ett, array_length (ett));
 }
 
Index: packet-dcerpc.c
===================================================================
RCS file: /cvsroot/ethereal/packet-dcerpc.c,v
retrieving revision 1.14
diff -u -r1.14 packet-dcerpc.c
--- packet-dcerpc.c	2001/11/12 09:04:11	1.14
+++ packet-dcerpc.c	2001/11/19 00:17:40
@@ -38,6 +38,7 @@
 #include "packet.h"
 #include "packet-dcerpc.h"
 #include "conversation.h"
+#include "prefs.h"
 
 static const value_string pckt_vals[] = {
     { 0, "Request"},
@@ -169,6 +170,9 @@
 static gint ett_dcerpc_dg_flags1 = -1;
 static gint ett_dcerpc_dg_flags2 = -1;
 
+/* try to desegment big DCE/RPC packets over TCP? */
+static gboolean dcerpc_cn_desegment = TRUE;
+
 /*
  * Subdissectors
  */
@@ -425,15 +429,16 @@
                     proto_tree *dcerpc_tree,
                     tvbuff_t *tvb, gint offset,
                     e_uuid_t *uuid, guint16 ver, 
-                    guint16 opnum, gboolean is_rqst)
+                    guint16 opnum, gboolean is_rqst,
+                    char *drep)
 {
     dcerpc_uuid_key key;
     dcerpc_uuid_value *sub_proto;
     int length;
-    proto_item *sub_item;
     proto_tree *sub_tree = NULL;
     dcerpc_sub_dissector *proc;
     gchar *name = NULL;
+    dcerpc_dissect_fnct_t *sub_dissect;
 
     key.uuid = *uuid;
     key.ver = ver;
@@ -450,6 +455,7 @@
     }
 
     if (tree) {
+        proto_item *sub_item;
         sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset, 
                                         tvb_length (tvb) - offset, FALSE);
         if (sub_item) {
@@ -476,14 +482,17 @@
         col_set_str (pinfo->fd, COL_PROTOCOL, sub_proto->name);
     }
 
-    if (is_rqst) {
-            if (proc->dissect_rqst)
-                    return proc->dissect_rqst(tvb, offset, pinfo, sub_tree);
+    sub_dissect = is_rqst ? proc->dissect_rqst : proc->dissect_resp;
+    if (sub_dissect) {
+        sub_dissect (tvb, offset, pinfo, sub_tree, drep);
     } else {
-            if (proc->dissect_resp)
-                    return proc->dissect_resp(tvb, offset, pinfo, sub_tree);
+        length = tvb_length_remaining (tvb, offset);
+        if (length > 0) {
+            proto_tree_add_text (sub_tree, tvb, offset, length,
+                                 "Stub data (%d byte%s)", length,
+                                 plurality(length, "", "s"));
+        }
     }
-
     return 0;
 }
 
@@ -817,7 +826,7 @@
                                 tvb_new_subset (tvb, offset, length,
                                                 reported_length),
                                 0, &value->uuid, value->ver,
-                                opnum, TRUE);
+                                opnum, TRUE, hdr->drep);
         }
     }
 }
@@ -870,7 +879,7 @@
                                 tvb_new_subset (tvb, offset, length,
                                                 reported_length),
                                 0, &value->uuid, value->ver,
-                                value->opnum, FALSE);
+                                value->opnum, FALSE, hdr->drep);
         }
     }
 }
@@ -929,6 +938,13 @@
     hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
     offset += 4;
 
+    if (dcerpc_cn_desegment && pinfo->can_desegment
+        && hdr.frag_len > tvb_length_remaining (tvb, 0)) {
+        pinfo->desegment_offset = 0;
+        pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, 0);
+        return TRUE;
+    }
+
     if (tree) {
         ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, tvb_length(tvb), FALSE);
         if (ti) {
@@ -1213,17 +1229,17 @@
         dcerpc_call_add_map (hdr.seqnum, conv, hdr.opnum,
                              hdr.if_ver, &hdr.if_id);
         dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
-                            &hdr.if_id, hdr.if_ver, hdr.opnum, TRUE);
+                            &hdr.if_id, hdr.if_ver, hdr.opnum, TRUE, hdr.drep);
         break;
     case PDU_RESP:
         {
             dcerpc_call_value *v = dcerpc_call_lookup (hdr.seqnum, conv);
             if (v) {
                 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
-                                    &v->uuid, v->ver, v->opnum, FALSE);
+                                    &v->uuid, v->ver, v->opnum, FALSE, hdr.drep);
             } else {
                 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, tvb, offset,
-                                    &hdr.if_id, hdr.if_ver, hdr.opnum, FALSE);
+                                    &hdr.if_id, hdr.if_ver, hdr.opnum, FALSE, hdr.drep);
             }
         }
         break;
@@ -1438,6 +1454,12 @@
     proto_register_subtree_array (ett, array_length (ett));
     register_init_routine (dcerpc_init_protocol);
 
+    prefs_register_bool_preference (prefs_register_protocol (proto_dcerpc, 
+                                                             NULL),
+                                    "desegment_dcerpc",
+                                    "Desegment all DCE/RPC over TCP",
+                                    "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
+                                    &dcerpc_cn_desegment);
     dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
 }
 
Index: packet-dcerpc.h
===================================================================
RCS file: /cvsroot/ethereal/packet-dcerpc.h,v
retrieving revision 1.2
diff -u -r1.2 packet-dcerpc.h
--- packet-dcerpc.h	2001/07/11 01:25:45	1.2
+++ packet-dcerpc.h	2001/11/19 00:17:40
@@ -83,12 +83,43 @@
 #define PDU_ALTER_ACK 15
 #define PDU_AUTH3     16
 
-
+/*
+ * helpers for packet-dcerpc.c and packet-dcerpc-ndr.c
+ * If you're writing a subdissector, you almost certainly want the
+ * NDR functions below.
+ */
 guint16 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep);
 guint32 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep);
 void dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid);
+int dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
+                          proto_tree *tree, char *drep, 
+                          int hfindex, guint8 *pdata);
+int dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
+                           proto_tree *tree, char *drep, 
+                           int hfindex, guint16 *pdata);
+int dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
+                           proto_tree *tree, char *drep, 
+                           int hfindex, guint32 *pdata);
+
+
+/*
+ * NDR routines for subdissectors.
+ */
+int dissect_ndr_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
+                       proto_tree *tree, char *drep, 
+                       int hfindex, guint8 *pdata);
+int dissect_ndr_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
+                        proto_tree *tree, char *drep, 
+                        int hfindex, guint16 *pdata);
+int dissect_ndr_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
+                        proto_tree *tree, char *drep, 
+                        int hfindex, guint32 *pdata);
+int dissect_ndr_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo,
+                        proto_tree *tree, char *drep, 
+                        int hfindex, e_uuid_t *pdata);
+
 
-typedef int (dcerpc_dissect_fnct_t)(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree);
+typedef int (dcerpc_dissect_fnct_t)(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, char *drep);
 
 typedef struct _dcerpc_sub_dissector {
     guint16 num;
/* packet-dcerpc-ndr.c
 * Routines for DCERPC NDR dissection
 * Copyright 2001, Todd Sabin <tas@xxxxxxxxxxx>
 *
 * $Id: $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * 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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif

#include <string.h>
#include <ctype.h>

#include <glib.h>
#include "packet.h"
#include "packet-dcerpc.h"


/*
 * The NDR routines are for use by dcerpc subdissetors.  They're
 * primarily for making sure things are aligned properly according
 * to the rules of NDR.
 */

int
dissect_ndr_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                   proto_tree *tree, char *drep, 
                   int hfindex, guint8 *pdata)
{
    /* no alignment needed */
    return dissect_dcerpc_uint8 (tvb, offset, pinfo, 
                                 tree, drep, hfindex, pdata);
}

int
dissect_ndr_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                    proto_tree *tree, char *drep, 
                    int hfindex, guint16 *pdata)
{
    if (offset % 2) {
        offset++;
    }
    return dissect_dcerpc_uint16 (tvb, offset, pinfo, 
                                  tree, drep, hfindex, pdata);
}

int
dissect_ndr_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                    proto_tree *tree, char *drep, 
                    int hfindex, guint32 *pdata)
{
    if (offset % 4) {
        offset += 4 - (offset % 4);
    }
    return dissect_dcerpc_uint32 (tvb, offset, pinfo, 
                                  tree, drep, hfindex, pdata);
}

int
dissect_ndr_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo,
                    proto_tree *tree, char *drep, 
                    int hfindex, e_uuid_t *pdata)
{
    e_uuid_t uuid;

    /* uuid's are aligned to 4 bytes, due to initial uint32 in struct */
    if (offset % 4) {
        offset += 4 - (offset % 4);
    }
    dcerpc_tvb_get_uuid (tvb, offset, drep, &uuid);
    if (tree) {
        proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
                                      "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
                                      uuid.Data1, uuid.Data2, uuid.Data3,
                                      uuid.Data4[0], uuid.Data4[1],
                                      uuid.Data4[2], uuid.Data4[3],
                                      uuid.Data4[4], uuid.Data4[5],
                                      uuid.Data4[6], uuid.Data4[7]);
    }
    if (pdata) {
        *pdata = uuid;
    }
    return offset + 16;
}