Ethereal-dev: dcerpc patch (was Re: [Ethereal-dev] Is someone working on a DCOM/ORPC dissector
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: 09 Jul 2001 08:03:02 -0400
ulf.lamping@xxxxxx writes: > > Do you know, if the .idl syntax for the DCE-RPC and DCOM are identical? If > not, do you have an example DCE-RPC idl file (just for my information at this > devel stage)? > > Do you have some further information about the DCE-RPC protocol? > The IDL for DCOM is defined by Microsoft. I don't know if there's an official spec for it, other than what their IDL compiler accepts. It is based on the original dce-rpc idl, but has many extensions. The original is documented at http://www.opengroup.org. Search for DCE RPC 1.1. It used to be freely available, but seems you may have to register for it now. That document also describes the basic DCE/RPC wire protocol. > Is the "handoff stage" on your to-do list, or are you already working on it? > Well, I hadn't started, and I was describing what I was going to do, when it suddenly seemed like it wouldn't be all that bad. :-) Naturally, it turned out to be more than expected. Anyway, here's a patch to do almost all of the handoff, and a few subdissectors which use it. None of them dissect any of the actual payload, yet, but they do show the names of the calls. Could someone double-check the conversation/hash stuff for leaks? I used pretty much the same approach used by packet-rpc.c, so assuming it's ok, then I think this is as well, but... Todd p.s. I tend to agree with the other poster about putting the subdissectors for GIOP in a subdirectory or something. The same is true for dcerpc. There are literally hundreds of these things which can be written.
Index: packet-dcerpc.c =================================================================== RCS file: /cvsroot/ethereal/packet-dcerpc.c,v retrieving revision 1.5 diff -u -r1.5 packet-dcerpc.c --- packet-dcerpc.c 2001/06/18 02:17:45 1.5 +++ packet-dcerpc.c 2001/07/09 11:16:58 @@ -37,6 +37,7 @@ #include <glib.h> #include "packet.h" #include "packet-dcerpc.h" +#include "conversation.h" static const value_string pckt_vals[] = { { 0, "Request"}, @@ -92,6 +93,7 @@ static int hf_dcerpc_cn_num_trans_items = -1; static int hf_dcerpc_cn_bind_if_id = -1; static int hf_dcerpc_cn_bind_if_ver = -1; +static int hf_dcerpc_cn_bind_if_ver_minor = -1; static int hf_dcerpc_cn_bind_trans_id = -1; static int hf_dcerpc_cn_bind_trans_ver = -1; static int hf_dcerpc_cn_alloc_hint = -1; @@ -99,6 +101,7 @@ static int hf_dcerpc_cn_num_results = -1; static int hf_dcerpc_cn_ack_result = -1; static int hf_dcerpc_cn_ack_reason = -1; +static int hf_dcerpc_cn_cancel_count = -1; static int hf_dcerpc_dg_flags1 = -1; static int hf_dcerpc_dg_flags1_rsrvd_01 = -1; static int hf_dcerpc_dg_flags1_last_frag = -1; @@ -137,7 +140,216 @@ static gint ett_dcerpc_dg_flags1 = -1; static gint ett_dcerpc_dg_flags2 = -1; +/* + * Subdissectors + */ + +/* the registered subdissectors */ +static GHashTable *dcerpc_uuids; + +typedef struct _dcerpc_uuid_key { + e_uuid_t uuid; + guint16 ver; +} dcerpc_uuid_key; + +typedef struct _dcerpc_uuid_value { + int proto; + int ett; + gchar *name; + dcerpc_sub_dissector *procs; +} dcerpc_uuid_value; + +static gint +dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2) +{ + dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1; + dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2; + return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0) + && (key1->ver == key2->ver)); +} + +static guint +dcerpc_uuid_hash (gconstpointer k) +{ + dcerpc_uuid_key *key = (dcerpc_uuid_key *)k; + /* This isn't perfect, but the Data1 part of these is almost always + unique. */ + return key->uuid.Data1; +} + +void +dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver, + dcerpc_sub_dissector *procs) +{ + dcerpc_uuid_key *key = g_malloc (sizeof (*key)); + dcerpc_uuid_value *value = g_malloc (sizeof (*value)); + + key->uuid = *uuid; + key->ver = ver; + + value->proto = proto; + value->ett = ett; + value->name = proto_get_protocol_short_name (proto); + value->procs = procs; + + g_hash_table_insert (dcerpc_uuids, key, value); +} + + +/* + * To keep track of ctx_id mappings. Should really use some + * generic conversation support instead. + */ +static GHashTable *dcerpc_convs; + +typedef struct _dcerpc_conv_key { + conversation_t *conv; + guint16 ctx_id; +} dcerpc_conv_key; + +typedef struct _dcerpc_conv_value { + e_uuid_t uuid; + guint16 ver; +} dcerpc_conv_value; + +static gint +dcerpc_conv_equal (gconstpointer k1, gconstpointer k2) +{ + dcerpc_conv_key *key1 = (dcerpc_conv_key *)k1; + dcerpc_conv_key *key2 = (dcerpc_conv_key *)k2; + return (key1->conv == key2->conv + && key1->ctx_id == key2->ctx_id); +} + +static guint +dcerpc_conv_hash (gconstpointer k) +{ + dcerpc_conv_key *key = (dcerpc_conv_key *)k; + return ((guint)key->conv) + key->ctx_id; +} + + + +/* + * To keep track of callid mappings. Should really use some generic + * conversation support instead. + */ +static GHashTable *dcerpc_calls; + +typedef struct _dcerpc_call_key { + conversation_t *conv; + guint32 call_id; +} dcerpc_call_key; + +typedef struct _dcerpc_call_value { + e_uuid_t uuid; + guint16 ver; + guint16 opnum; +} dcerpc_call_value; + +static gint +dcerpc_call_equal (gconstpointer k1, gconstpointer k2) +{ + dcerpc_call_key *key1 = (dcerpc_call_key *)k1; + dcerpc_call_key *key2 = (dcerpc_call_key *)k2; + return (key1->conv == key2->conv + && key1->call_id == key2->call_id); +} + +static guint +dcerpc_call_hash (gconstpointer k) +{ + dcerpc_call_key *key = (dcerpc_call_key *)k; + return ((guint32)key->conv) ^ key->call_id; +} + +static void +dcerpc_call_add_map (guint32 call_id, conversation_t *conv, + guint16 opnum, guint16 ver, e_uuid_t *uuid) +{ + dcerpc_call_key *key = g_malloc (sizeof (*key)); + dcerpc_call_value *value = g_malloc (sizeof (*value)); + + key->call_id = call_id; + key->conv = conv; + value->uuid = *uuid; + value->ver = ver; + value->opnum = opnum; + g_hash_table_insert (dcerpc_calls, key, value); +} + +static dcerpc_call_value* +dcerpc_call_lookup (guint32 call_id, conversation_t *conv) +{ + dcerpc_call_key key; + + key.call_id = call_id; + key.conv = conv; + return g_hash_table_lookup (dcerpc_calls, &key); +} + + +/* + * Utility functions. Modeled after packet-rpc.c + */ + +int +dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, char *drep, + int hfindex, guint8 *pdata) +{ + guint8 data; + + data = tvb_get_guint8 (tvb, offset); + if (tree) { + proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10)); + } + if (pdata) + *pdata = data; + return offset + 1; +} + +int +dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, char *drep, + int hfindex, guint16 *pdata) +{ + guint16 data; + + data = ((drep[0] & 0x10) + ? tvb_get_letohs (tvb, offset) + : tvb_get_ntohs (tvb, offset)); + + if (tree) { + proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10)); + } + if (pdata) + *pdata = data; + return offset + 2; +} +int +dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, char *drep, + int hfindex, guint32 *pdata) +{ + guint32 data; + + data = ((drep[0] & 0x10) + ? tvb_get_letohl (tvb, offset) + : tvb_get_ntohl (tvb, offset)); + + if (tree) { + proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10)); + } + if (pdata) + *pdata = data; + return offset+4; +} + +/* + * a couple simpler things + */ guint16 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep) { @@ -171,122 +383,166 @@ } } +static int +dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree, + tvbuff_t *tvb, gint offset, + e_uuid_t *uuid, guint16 ver, + guint16 opnum, gboolean is_rqst) +{ + dcerpc_uuid_key key; + dcerpc_uuid_value *sub_proto; + proto_item *sub_item; + proto_tree *sub_tree; + dcerpc_sub_dissector *proc; + gchar *name = NULL; + + key.uuid = *uuid; + key.ver = ver; + + + if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == 0) + return -1; + if (tree) { + sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset, + tvb_length (tvb) - offset, FALSE); + if (sub_item) { + sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett); + } + + } + for (proc = sub_proto->procs; proc->name; proc++) { + if (proc->num == opnum) { + name = proc->name; + break; + } + } + + if (!name) + name = "Unknown?!"; + + if (check_col (pinfo->fd, COL_INFO)) { + col_add_fstr (pinfo->fd, COL_INFO, "%s %s:%s(...)", + is_rqst ? "rqst" : "rply", + sub_proto->name, name); + } + + if (check_col (pinfo->fd, COL_PROTOCOL)) { + col_set_str (pinfo->fd, COL_PROTOCOL, sub_proto->name); + } + // FIXME: call approp. dissector + return 0; +} + + +/* + * Connection oriented packet types + */ + static void dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr) { - guint16 max_xmit, max_recv; - guint32 assoc_group; + conversation_t *conv = NULL; + dcerpc_conv_key *key; + dcerpc_conv_value *value; guint8 num_ctx_items; guint16 ctx_id; guint16 num_trans_items; e_uuid_t if_id; e_uuid_t trans_id; - guint32 if_ver, trans_ver; + guint32 trans_ver; + guint16 if_ver, if_ver_minor; int offset = 16; - max_xmit = dcerpc_tvb_get_ntohs (tvb, offset, hdr->drep); - offset += 2; + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_max_xmit, NULL); - max_recv = dcerpc_tvb_get_ntohs (tvb, offset, hdr->drep); - offset += 2; + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_max_recv, NULL); - assoc_group = dcerpc_tvb_get_ntohl (tvb, offset, hdr->drep); - offset += 4; + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_assoc_group, NULL); - num_ctx_items = tvb_get_guint8 (tvb, offset); - offset++; + offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_num_ctx_items, &num_ctx_items); /* padding */ offset += 3; - ctx_id = dcerpc_tvb_get_ntohs (tvb, offset, hdr->drep); - offset += 2; + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_ctx_id, &ctx_id); - num_trans_items = dcerpc_tvb_get_ntohs (tvb, offset, hdr->drep); - offset += 2; + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_num_trans_items, &num_trans_items); dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id); - offset += 16; - - if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr->drep); - offset += 4; - - dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id); - offset += 16; - - trans_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr->drep); - offset += 4; - - if (check_col (pinfo->fd, COL_INFO)) { - col_add_fstr (pinfo->fd, COL_INFO, "Bind: UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %d", - if_id.Data1, if_id.Data2, if_id.Data3, - if_id.Data4[0], if_id.Data4[1], - if_id.Data4[2], if_id.Data4[3], - if_id.Data4[4], if_id.Data4[5], - if_id.Data4[6], if_id.Data4[7], - if_ver); - } - if (dcerpc_tree) { - offset = 16; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_max_xmit, tvb, offset, 2, max_xmit); - offset += 2; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_max_recv, tvb, offset, 2, max_recv); - offset += 2; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_assoc_group, tvb, offset, 4, assoc_group); - offset += 4; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_num_ctx_items, tvb, offset, 1, num_ctx_items); - offset++; - - /* padding */ - offset += 3; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_ctx_id, tvb, offset, 2, ctx_id); - offset += 2; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_num_trans_items, tvb, offset, 2, num_trans_items); - offset += 2; - proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb, offset, 16, "HMMM", "Interface UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", if_id.Data1, if_id.Data2, if_id.Data3, - if_id.Data4[0], - if_id.Data4[1], - if_id.Data4[2], - if_id.Data4[3], - if_id.Data4[4], - if_id.Data4[5], - if_id.Data4[6], - if_id.Data4[7]); - offset += 16; + if_id.Data4[0], if_id.Data4[1], + if_id.Data4[2], if_id.Data4[3], + if_id.Data4[4], if_id.Data4[5], + if_id.Data4[6], if_id.Data4[7]); + } + offset += 16; - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_bind_if_ver, tvb, offset, 4, if_ver); - offset += 4; + if (hdr->drep[0] & 0x10) { + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_bind_if_ver, &if_ver); + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor); + } else { + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor); + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_bind_if_ver, &if_ver); + } + dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id); + if (dcerpc_tree) { proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb, offset, 16, "HMMM", "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", trans_id.Data1, trans_id.Data2, trans_id.Data3, - trans_id.Data4[0], - trans_id.Data4[1], - trans_id.Data4[2], - trans_id.Data4[3], - trans_id.Data4[4], - trans_id.Data4[5], - trans_id.Data4[6], - trans_id.Data4[7]); - offset += 16; + trans_id.Data4[0], trans_id.Data4[1], + trans_id.Data4[2], trans_id.Data4[3], + trans_id.Data4[4], trans_id.Data4[5], + trans_id.Data4[6], trans_id.Data4[7]); + } + offset += 16; - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_bind_trans_ver, tvb, offset, 4, trans_ver); - offset += 4; + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_bind_trans_ver, &trans_ver); + + if (check_col (pinfo->fd, COL_INFO)) { + col_add_fstr (pinfo->fd, COL_INFO, "%s: UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %d.%d", + hdr->ptype == PDU_BIND ? "Bind" : "Alter Ctx", + if_id.Data1, if_id.Data2, if_id.Data3, + if_id.Data4[0], if_id.Data4[1], + if_id.Data4[2], if_id.Data4[3], + if_id.Data4[4], if_id.Data4[5], + if_id.Data4[6], if_id.Data4[7], + if_ver, if_ver_minor); + } + conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, 0); + if (conv == NULL) { + conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, NULL, 0); } + + key = g_malloc (sizeof (*key)); + key->conv = conv; + key->ctx_id = ctx_id; + + value = g_malloc (sizeof (*value)); + value->uuid = if_id; + value->ver = if_ver; + + g_hash_table_insert (dcerpc_convs, key, value); } static void @@ -294,7 +550,6 @@ e_dce_cn_common_hdr_t *hdr) { guint16 max_xmit, max_recv; - guint32 assoc_group; guint16 sec_addr_len; guint8 num_results; guint16 result = 0; @@ -302,128 +557,77 @@ int offset = 16; - max_xmit = dcerpc_tvb_get_ntohs (tvb, offset, hdr->drep); - offset += 2; + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_max_xmit, &max_xmit); - max_recv = dcerpc_tvb_get_ntohs (tvb, offset, hdr->drep); - offset += 2; + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_max_recv, &max_recv); - assoc_group = dcerpc_tvb_get_ntohl (tvb, offset, hdr->drep); - offset += 4; + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_assoc_group, NULL); - sec_addr_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr->drep); - offset += 2 + sec_addr_len; + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_sec_addr_len, &sec_addr_len); + offset += sec_addr_len; if (offset % 4) { offset += 4 - offset % 4; } - num_results = tvb_get_guint8 (tvb, offset); - offset++; + offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_num_results, &num_results); /* padding */ offset += 3; if (num_results == 1) { - result = dcerpc_tvb_get_ntohs (tvb, offset, hdr->drep); - offset += 2; - - reason = dcerpc_tvb_get_ntohs (tvb, offset, hdr->drep); - offset += 2; + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_cn_ack_result, + &result); + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_cn_ack_reason, + &reason); } if (check_col (pinfo->fd, COL_INFO)) { if (num_results == 1 && result == 0) { - col_add_fstr (pinfo->fd, COL_INFO, "Bind ack: accept max_xmit: %d max_recv: %d", - max_xmit, max_recv); - + col_add_fstr (pinfo->fd, COL_INFO, "%s ack: accept max_xmit: %d max_recv: %d", + hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx", + max_xmit, max_recv); } else { /* FIXME: should put in reason */ - col_add_fstr (pinfo->fd, COL_INFO, "Bind ack: %s", - result == 1 ? "User reject" : - result == 2 ? "Provider reject" : - "Unknown"); - } - } - - if (dcerpc_tree) { - offset = 16; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_max_xmit, tvb, offset, 2, max_xmit); - offset += 2; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_max_recv, tvb, offset, 2, max_recv); - offset += 2; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_assoc_group, tvb, offset, 4, assoc_group); - offset += 4; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_sec_addr_len, tvb, offset, 2, sec_addr_len); - offset +=2 + sec_addr_len; - - if (offset % 4) { - offset += 4 - offset % 4; - } - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_num_results, tvb, offset, 1, num_results); - offset++; - - /* padding */ - offset += 3; - - if (num_results == 1) { - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_ack_result, tvb, offset, 2, result); - offset += 2; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_ack_reason, tvb, offset, 2, reason); - offset += 2; + col_add_fstr (pinfo->fd, COL_INFO, "%s ack: %s", + hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx", + result == 1 ? "User reject" : + result == 2 ? "Provider reject" : + "Unknown"); } } } static void dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree, - e_dce_cn_common_hdr_t *hdr) + proto_tree *tree, e_dce_cn_common_hdr_t *hdr) { - guint32 alloc_hint; + conversation_t *conv; guint16 ctx_id; guint16 opnum; e_uuid_t obj_id; int offset = 16; - alloc_hint = dcerpc_tvb_get_ntohl (tvb, offset, hdr->drep); - offset += 4; + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_alloc_hint, NULL); - ctx_id = dcerpc_tvb_get_ntohs (tvb, offset, hdr->drep); - offset += 2; + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_ctx_id, &ctx_id); - opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr->drep); - offset += 2; + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_opnum, &opnum); if (hdr->flags & 0x80) { dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id); - offset += 16; - } - - if (check_col (pinfo->fd, COL_INFO)) { - col_add_fstr (pinfo->fd, COL_INFO, "Request: opnum: %d ctx_id:%d", - opnum, ctx_id); - } - - if (dcerpc_tree) { - offset = 16; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_alloc_hint, tvb, offset, 4, alloc_hint); - offset += 4; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_ctx_id, tvb, offset, 2, ctx_id); - offset += 2; - - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, opnum); - offset += 2; - - if (hdr->flags & 0x80) { + if (dcerpc_tree) { proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb, offset, 16, "HMMM", "Object UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", @@ -436,7 +640,75 @@ obj_id.Data4[5], obj_id.Data4[6], obj_id.Data4[7]); - offset += 16; + } + offset += 16; + } + + if (check_col (pinfo->fd, COL_INFO)) { + col_add_fstr (pinfo->fd, COL_INFO, "Request: opnum: %d ctx_id:%d", + opnum, ctx_id); + } + + conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, 0); + if (!conv) { + + } else { + dcerpc_conv_key key; + dcerpc_conv_value *value; + + key.conv = conv; + key.ctx_id = ctx_id; + + value = g_hash_table_lookup (dcerpc_convs, &key); + if (value) { + /* add an entry for this call, so we can catch the reply */ + dcerpc_call_add_map (hdr->call_id, conv, opnum, + value->ver, &value->uuid); + + /* handoff this call */ + dcerpc_try_handoff (pinfo, tree, tvb, offset, + &value->uuid, value->ver, + opnum, TRUE); + } + } +} + +static void +dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree, + proto_tree *tree, e_dce_cn_common_hdr_t *hdr) +{ + conversation_t *conv; + guint16 ctx_id; + + int offset = 16; + + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_alloc_hint, NULL); + + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_ctx_id, &ctx_id); + + offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_cancel_count, NULL); + /* padding */ + offset++; + + if (check_col (pinfo->fd, COL_INFO)) { + col_add_fstr (pinfo->fd, COL_INFO, "Response: call_id: %d ctx_id:%d", + hdr->call_id, ctx_id); + } + + conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, 0); + if (!conv) { + /* no point in creating one here, really */ + } else { + dcerpc_call_value *value = dcerpc_call_lookup (hdr->call_id, conv); + if (value) { + dcerpc_try_handoff (pinfo, tree, tvb, offset, + &value->uuid, value->ver, + value->opnum, FALSE); } } } @@ -526,15 +798,21 @@ */ switch (hdr.ptype) { case PDU_BIND: + case PDU_ALTER: dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr); break; case PDU_BIND_ACK: + case PDU_ALTER_ACK: dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr); break; case PDU_REQ: - dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, &hdr); + dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr); + break; + + case PDU_RESP: + dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr); break; default: @@ -556,6 +834,7 @@ proto_tree *dg_flags2_tree = NULL; e_dce_dg_common_hdr_t hdr; int offset = 0; + conversation_t *conv; /* * Check if this looks like a CL DCERPC call. All dg packets @@ -722,16 +1001,65 @@ proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo); offset++; } + /* + * keeping track of the conversation shouldn't really be necessary + * for connectionless packets, because everything we need to know + * to dissect is in the header for each packet. Unfortunately, + * Microsoft's implementation is buggy and often puts the + * completely wrong if_id in the header. go figure. So, keep + * track of the seqnum and use that if possible. Note: that's not + * completely correct. It should really be done based on both the + * activity_id and seqnum. I haven't seen anywhere that it would + * make a difference, but for future reference... + */ + conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, 0); + if (!conv) { + conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, NULL, 0); + } + /* * Packet type specific stuff is next. */ + switch (hdr.ptype) { + case PDU_REQ: + dcerpc_call_add_map (hdr.seqnum, conv, hdr.opnum, + hdr.if_ver, &hdr.if_id); + dcerpc_try_handoff (pinfo, tree, tvb, offset, + &hdr.if_id, hdr.if_ver, hdr.opnum, TRUE); + break; + case PDU_RESP: + { + dcerpc_call_value *v = dcerpc_call_lookup (hdr.seqnum, conv); + if (v) { + dcerpc_try_handoff (pinfo, tree, tvb, offset, + &v->uuid, v->ver, v->opnum, FALSE); + } else { + dcerpc_try_handoff (pinfo, tree, tvb, offset, + &hdr.if_id, hdr.if_ver, hdr.opnum, FALSE); + } + } + break; + } return TRUE; } +static void +dcerpc_init_protocol (void) +{ + if (dcerpc_convs != NULL) + g_hash_table_destroy (dcerpc_convs); + if (dcerpc_calls != NULL) + g_hash_table_destroy (dcerpc_calls); + dcerpc_convs = g_hash_table_new (dcerpc_conv_hash, dcerpc_conv_equal); + dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal); +} + void -proto_register_dcerpc(void) +proto_register_dcerpc (void) { static hf_register_info hf[] = { { &hf_dcerpc_ver, @@ -779,7 +1107,9 @@ { &hf_dcerpc_cn_bind_if_id, { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_cn_bind_if_ver, - { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, + { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_dcerpc_cn_bind_if_ver_minor, + { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_cn_bind_trans_id, { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_cn_bind_trans_ver, @@ -794,6 +1124,8 @@ { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_cn_ack_reason, { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_dcerpc_cn_cancel_count, + { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_dg_flags1, { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_dg_flags1_rsrvd_01, @@ -871,10 +1203,15 @@ proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc"); proto_register_field_array (proto_dcerpc, hf, array_length (hf)); proto_register_subtree_array (ett, array_length (ett)); + register_init_routine (dcerpc_init_protocol); + + dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal); + dcerpc_convs = g_hash_table_new (dcerpc_conv_hash, dcerpc_conv_equal); + dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal); } void -proto_reg_handoff_dcerpc(void) +proto_reg_handoff_dcerpc (void) { heur_dissector_add ("tcp", dissect_dcerpc_cn, proto_dcerpc); heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
Index: packet-dcerpc.h =================================================================== RCS file: /cvsroot/ethereal/packet-dcerpc.h,v retrieving revision 1.1 diff -u -r1.1 packet-dcerpc.h --- packet-dcerpc.h 2001/04/19 23:39:27 1.1 +++ packet-dcerpc.h 2001/07/09 11:20:25 @@ -88,6 +88,17 @@ 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); +typedef int (dcerpc_dissect_fnct_t)(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree); + +typedef struct _dcerpc_sub_dissector { + guint16 num; + gchar *name; + dcerpc_dissect_fnct_t *dissect_rqst; + dcerpc_dissect_fnct_t *dissect_resp; +} dcerpc_sub_dissector; + +/* registration function for subdissectors */ +void dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver, dcerpc_sub_dissector *procs); #endif /* packet-dcerpc.h */
Index: Makefile.am =================================================================== RCS file: /cvsroot/ethereal/Makefile.am,v retrieving revision 1.343 diff -u -r1.343 Makefile.am --- Makefile.am 2001/07/04 06:25:03 1.343 +++ Makefile.am 2001/07/09 11:19:59 @@ -94,6 +94,11 @@ packet-cups.c \ packet-data.c \ packet-dcerpc.c \ + packet-dcerpc-conv.c \ + packet-dcerpc-epm.c \ + packet-dcerpc-mgmt.c \ + packet-dcerpc-remact.c \ + packet-dcerpc-oxid.c \ packet-ddtp.c \ packet-dec-bpdu.c \ packet-diameter.c \
/* packet-dcerpc-epm.c * Routines for dcerpc endpoint mapper 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 <glib.h> #include "packet.h" #include "packet-dcerpc.h" static int proto_epm = -1; static gint ett_epm = -1; static e_uuid_t uuid_epm = { 0xe1af8308, 0x5d1f, 0x11c9, { 0x91, 0xa4, 0x08, 0x00, 0x2b, 0x14, 0xa0, 0xfa } }; static guint16 ver_epm = 3; static dcerpc_sub_dissector epm_dissectors[] = { { 0, "ept_insert", NULL, NULL }, { 1, "ept_delete", NULL, NULL }, { 2, "ept_lookup", NULL, NULL }, { 3, "ept_map", NULL, NULL }, { 4, "ept_lookup_handle_free", NULL, NULL }, { 5, "ept_inq_object", NULL, NULL }, { 6, "ept_mgmt_delete", NULL, NULL }, { 0, NULL, NULL, NULL }, }; void proto_register_epm (void) { static hf_register_info hf[] = { }; static gint *ett[] = { &ett_epm, }; proto_epm = proto_register_protocol ("DCE/RPC Endpoint Mapper", "EPM", "epm"); proto_register_field_array (proto_epm, hf, array_length (hf)); proto_register_subtree_array (ett, array_length (ett)); } void proto_reg_handoff_epm (void) { /* Register the protocol as dcerpc */ dcerpc_init_uuid (proto_epm, ett_epm, &uuid_epm, ver_epm, epm_dissectors); }
/* packet-dcerpc-mgmt.c * Routines for dcerpc mgmt 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 <glib.h> #include "packet.h" #include "packet-dcerpc.h" static int proto_mgmt = -1; static gint ett_mgmt = -1; static e_uuid_t uuid_mgmt = { 0xafa8bd80, 0x7d8a, 0x11c9, { 0xbe, 0xf4, 0x08, 0x00, 0x2b, 0x10, 0x29, 0x89 } }; static guint16 ver_mgmt = 1; static dcerpc_sub_dissector mgmt_dissectors[] = { { 0, "rpc__mgmt_inq_if_ids", NULL, NULL }, { 1, "rpc__mgmt_inq_stats", NULL, NULL }, { 2, "rpc__mgmt_is_server_listening", NULL, NULL }, { 3, "rpc__mgmt_stop_server_listening", NULL, NULL }, { 4, "rpc__mgmt_inq_princ_name", NULL, NULL }, { 0, NULL, NULL, NULL }, }; void proto_register_mgmt (void) { static hf_register_info hf[] = { }; static gint *ett[] = { &ett_mgmt, }; proto_mgmt = proto_register_protocol ("DCE/RPC Remote Management", "MGMT", "mgmt"); proto_register_field_array (proto_mgmt, hf, array_length (hf)); proto_register_subtree_array (ett, array_length (ett)); } void proto_reg_handoff_mgmt (void) { /* Register the protocol as dcerpc */ dcerpc_init_uuid (proto_mgmt, ett_mgmt, &uuid_mgmt, ver_mgmt, mgmt_dissectors); }
/* packet-dcerpc-conv.c * Routines for dcerpc conv 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 <glib.h> #include "packet.h" #include "packet-dcerpc.h" static int proto_conv = -1; static gint ett_conv = -1; static e_uuid_t uuid_conv = { 0x333a2276, 0x0000, 0x0000, { 0x0d, 0x00, 0x00, 0x80, 0x9c, 0x00, 0x00, 0x00 } }; static guint16 ver_conv = 3; static dcerpc_sub_dissector conv_dissectors[] = { { 0, "conv_who_are_you", NULL, NULL }, { 1, "conv_who_are_you2", NULL, NULL }, { 2, "conv_are_you_there", NULL, NULL }, { 3, "conv_who_are_you_auth", NULL, NULL }, { 4, "conv_who_are_you_auth_more", NULL, NULL }, { 0, NULL, NULL, NULL }, }; void proto_register_conv (void) { static hf_register_info hf[] = { }; static gint *ett[] = { &ett_conv, }; proto_conv = proto_register_protocol ("DCE/RPC Conversation Manager", "CONV", "conv"); proto_register_field_array (proto_conv, hf, array_length (hf)); proto_register_subtree_array (ett, array_length (ett)); } void proto_reg_handoff_conv (void) { /* Register the protocol as dcerpc */ dcerpc_init_uuid (proto_conv, ett_conv, &uuid_conv, ver_conv, conv_dissectors); }
/* packet-dcerpc-remact.c * Routines for DCOM Remote Activation * 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 <glib.h> #include "packet.h" #include "packet-dcerpc.h" static int proto_remact = -1; static gint ett_remact = -1; static e_uuid_t uuid_remact = { 0x4d9f4ab8, 0x7dac, 0x11cf, { 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57 } }; static guint16 ver_remact = 0; static dcerpc_sub_dissector remact_dissectors[] = { { 0, "RemoteActivation", NULL, NULL }, { 0, NULL, NULL, NULL }, }; void proto_register_remact (void) { static hf_register_info hf[] = { }; static gint *ett[] = { &ett_remact, }; proto_remact = proto_register_protocol ("DCOM Remote Activation", "REMACT", "remact"); proto_register_field_array (proto_remact, hf, array_length (hf)); proto_register_subtree_array (ett, array_length (ett)); } void proto_reg_handoff_remact (void) { /* Register the protocol as dcerpc */ dcerpc_init_uuid (proto_remact, ett_remact, &uuid_remact, ver_remact, remact_dissectors); }
/* packet-dcerpc-oxid.c * Routines for DCOM OXID Resolver * 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 <glib.h> #include "packet.h" #include "packet-dcerpc.h" static int proto_oxid = -1; static gint ett_oxid = -1; static e_uuid_t uuid_oxid = { 0x99fcfec4, 0x5260, 0x101b, { 0xbb, 0xcb, 0x00, 0xaa, 0x00, 0x21, 0x34, 0x7a } }; static guint16 ver_oxid = 0; static dcerpc_sub_dissector oxid_dissectors[] = { { 0, "ResolveOxid", NULL, NULL }, { 1, "SimplePing", NULL, NULL }, { 2, "ComplexPing", NULL, NULL }, { 3, "ServerAlive", NULL, NULL }, { 0, NULL, NULL, NULL }, }; void proto_register_oxid (void) { static hf_register_info hf[] = { }; static gint *ett[] = { &ett_oxid, }; proto_oxid = proto_register_protocol ("DCOM OXID Resolver", "OXID", "oxid"); proto_register_field_array (proto_oxid, hf, array_length (hf)); proto_register_subtree_array (ett, array_length (ett)); } void proto_reg_handoff_oxid (void) { /* Register the protocol as dcerpc */ dcerpc_init_uuid (proto_oxid, ett_oxid, &uuid_oxid, ver_oxid, oxid_dissectors); }
- Follow-Ups:
- References:
- Re: [Ethereal-dev] Is someone working on a DCOM/ORPC dissector?
- From: Todd Sabin
- Re: [Ethereal-dev] Is someone working on a DCOM/ORPC dissector?
- From: ulf . lamping
- Re: [Ethereal-dev] Is someone working on a DCOM/ORPC dissector?
- Prev by Date: Re: [Ethereal-dev] Displaying and comparing two traces ...
- Next by Date: Re: [Ethereal-dev] GIOP Subdissector plans
- Previous by thread: Re: [Ethereal-dev] Is someone working on a DCOM/ORPC dissector?
- Next by thread: Re: dcerpc patch (was Re: [Ethereal-dev] Is someone working on a DCOM/ORPC dissector?)
- Index(es):