diff options
-rw-r--r-- | epan/packet.c | 83 | ||||
-rw-r--r-- | epan/packet.h | 24 | ||||
-rw-r--r-- | packet-eap.c | 44 | ||||
-rw-r--r-- | packet-radius.c | 218 |
4 files changed, 286 insertions, 83 deletions
diff --git a/epan/packet.c b/epan/packet.c index 0e3b766d51..865cebe4ef 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -1,7 +1,7 @@ /* packet.c * Routines for packet disassembly * - * $Id: packet.c,v 1.62 2002/02/25 21:02:10 guy Exp $ + * $Id: packet.c,v 1.63 2002/02/26 11:55:39 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -312,7 +312,11 @@ dissect_packet(epan_dissect_t *edt, union wtap_pseudo_header *pseudo_header, */ struct dissector_handle { const char *name; /* dissector name */ - dissector_t dissector; + gboolean is_new; /* TRUE if new-style dissector */ + union { + dissector_t old; + new_dissector_t new; + } dissector; int proto_index; }; @@ -496,9 +500,11 @@ dissector_try_port(dissector_table_t sub_dissectors, guint32 port, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { dtbl_entry_t *dtbl_entry; + struct dissector_handle *handle; const char *saved_proto; guint32 saved_match_port; guint16 saved_can_desegment; + int ret; dtbl_entry = g_hash_table_lookup(sub_dissectors->hash_table, GUINT_TO_POINTER(port)); @@ -506,7 +512,8 @@ dissector_try_port(dissector_table_t sub_dissectors, guint32 port, /* * Is there currently a dissector handle for this entry? */ - if (dtbl_entry->current == NULL) { + handle = dtbl_entry->current; + if (handle == NULL) { /* * No - pretend this dissector didn't exist, * so that other dissectors might have a chance @@ -518,8 +525,8 @@ dissector_try_port(dissector_table_t sub_dissectors, guint32 port, /* * Yes - is its protocol enabled? */ - if (dtbl_entry->current->proto_index != -1 && - !proto_is_protocol_enabled(dtbl_entry->current->proto_index)) { + if (handle->proto_index != -1 && + !proto_is_protocol_enabled(handle->proto_index)) { /* * No - pretend this dissector didn't exist, * so that other dissectors might have a chance @@ -545,15 +552,31 @@ dissector_try_port(dissector_table_t sub_dissectors, guint32 port, */ pinfo->can_desegment = saved_can_desegment-(saved_can_desegment>0); pinfo->match_port = port; - if (dtbl_entry->current->proto_index != -1) { + if (handle->proto_index != -1) { pinfo->current_proto = - proto_get_protocol_short_name(dtbl_entry->current->proto_index); + proto_get_protocol_short_name(handle->proto_index); + } + if (handle->is_new) + ret = (*handle->dissector.new)(tvb, pinfo, tree); + else { + (*handle->dissector.old)(tvb, pinfo, tree); + ret = 1; } - (*dtbl_entry->current->dissector)(tvb, pinfo, tree); pinfo->current_proto = saved_proto; pinfo->match_port = saved_match_port; pinfo->can_desegment = saved_can_desegment; - return TRUE; + + /* + * If a new-style dissector returned 0, it means that + * it didn't think this tvbuff represented a packet for + * its protocol, and didn't dissect anything. + * + * Old-style dissectors can't reject the packet. + * + * If the packet was rejected, we return FALSE, otherwise + * we return TRUE. + */ + return ret != 0; } return FALSE; } @@ -983,19 +1006,45 @@ register_dissector(const char *name, dissector_t dissector, int proto) handle = g_malloc(sizeof (struct dissector_handle)); handle->name = name; - handle->dissector = dissector; + handle->is_new = FALSE; + handle->dissector.old = dissector; handle->proto_index = proto; g_hash_table_insert(registered_dissectors, (gpointer)name, (gpointer) handle); } -/* Call a dissector through a handle. */ void +new_register_dissector(const char *name, new_dissector_t dissector, int proto) +{ + struct dissector_handle *handle; + + /* Create our hash table if it doesn't already exist */ + if (registered_dissectors == NULL) { + registered_dissectors = g_hash_table_new(g_str_hash, g_str_equal); + g_assert(registered_dissectors != NULL); + } + + /* Make sure the registration is unique */ + g_assert(g_hash_table_lookup(registered_dissectors, name) == NULL); + + handle = g_malloc(sizeof (struct dissector_handle)); + handle->name = name; + handle->is_new = TRUE; + handle->dissector.new = dissector; + handle->proto_index = proto; + + g_hash_table_insert(registered_dissectors, (gpointer)name, + (gpointer) handle); +} + +/* Call a dissector through a handle. */ +int call_dissector(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { const char *saved_proto; + int ret; if (handle->proto_index != -1 && !proto_is_protocol_enabled(handle->proto_index)) { @@ -1004,8 +1053,8 @@ call_dissector(dissector_handle_t handle, tvbuff_t *tvb, */ g_assert(data_handle != NULL); g_assert(data_handle->proto_index != -1); - call_dissector(data_handle,tvb, pinfo, tree); - return; + call_dissector(data_handle, tvb, pinfo, tree); + return tvb_length(tvb); } saved_proto = pinfo->current_proto; @@ -1013,6 +1062,12 @@ call_dissector(dissector_handle_t handle, tvbuff_t *tvb, pinfo->current_proto = proto_get_protocol_short_name(handle->proto_index); } - (*handle->dissector)(tvb, pinfo, tree); + if (handle->is_new) + ret = (*handle->dissector.new)(tvb, pinfo, tree); + else { + (*handle->dissector.old)(tvb, pinfo, tree); + ret = tvb_length(tvb); + } pinfo->current_proto = saved_proto; + return ret; } diff --git a/epan/packet.h b/epan/packet.h index 3adb41364e..8429ee4457 100644 --- a/epan/packet.h +++ b/epan/packet.h @@ -1,7 +1,7 @@ /* packet.h * Definitions for packet disassembly structures and routines * - * $Id: packet.h,v 1.53 2002/02/24 06:45:14 guy Exp $ + * $Id: packet.h,v 1.54 2002/02/26 11:55:39 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -90,9 +90,25 @@ typedef struct dissector_handle *dissector_handle_t; struct dissector_table; typedef struct dissector_table *dissector_table_t; -/* types for sub-dissector lookup */ +/* + * Dissector that returns nothing. + */ typedef void (*dissector_t)(tvbuff_t *, packet_info *, proto_tree *); +/* + * Dissector that returns: + * + * the amount of data in the protocol's PDU, if it was able to + * dissect all the data; + * + * 0, if the tvbuff doesn't contain a PDU for that protocol; + * + * the negative of the amount of additional data needed, if + * we need more data (e.g., from subsequent TCP segments) to + * dissect the entire PDU. + */ +typedef int (*new_dissector_t)(tvbuff_t *, packet_info *, proto_tree *); + typedef void (*DATFunc) (gchar *table_name, gpointer key, gpointer value, gpointer user_data); typedef void (*DATFunc_handle) (gchar *table_name, gpointer value, gpointer user_data); @@ -184,6 +200,8 @@ extern gboolean dissector_try_heuristic(heur_dissector_list_t sub_dissectors, /* Register a dissector. */ extern void register_dissector(const char *name, dissector_t dissector, int proto); +extern void new_register_dissector(const char *name, new_dissector_t dissector, + int proto); /* Get the short name of the protocol for a dissector handle. */ extern char *dissector_handle_get_short_name(dissector_handle_t handle); @@ -196,7 +214,7 @@ extern dissector_handle_t create_dissector_handle(dissector_t dissector, int proto); /* Call a dissector through a handle. */ -extern void call_dissector(dissector_handle_t handle, tvbuff_t *tvb, +extern int call_dissector(dissector_handle_t handle, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); /* Do all one-time initialization. */ diff --git a/packet-eap.c b/packet-eap.c index 8a66b9627f..c66b9fa494 100644 --- a/packet-eap.c +++ b/packet-eap.c @@ -2,7 +2,7 @@ * Routines for EAP Extensible Authentication Protocol dissection * RFC 2284 * - * $Id: packet-eap.c,v 1.14 2002/02/26 00:51:41 guy Exp $ + * $Id: packet-eap.c,v 1.15 2002/02/26 11:55:37 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -79,14 +79,15 @@ static const value_string eap_type_vals[] = { { 0, NULL } }; -static void -dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +static int +dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + gboolean fragmented) { guint8 eap_code; guint8 eap_id; guint16 eap_len; guint8 eap_type; - guint len; + gint len; proto_tree *ti; proto_tree *eap_tree = NULL; @@ -103,9 +104,17 @@ dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) eap_len = tvb_get_ntohs(tvb, 2); len = eap_len; - /* at least for now, until we get defragmentation support */ - if (len>tvb_length(tvb)) - len=tvb_length(tvb); + if (fragmented) { + /* + * This is an EAP fragment inside, for example, RADIUS. If we don't + * have all of the packet data, return the negative of the amount of + * additional data we need. + */ + int reported_len = tvb_reported_length_remaining(tvb, 0); + + if (reported_len < len) + return -(len - reported_len); + } if (tree) { ti = proto_tree_add_item(tree, proto_eap, tvb, 0, len, FALSE); @@ -133,8 +142,8 @@ dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) proto_tree_add_uint(eap_tree, hf_eap_type, tvb, 4, 1, eap_type); if (len > 5) { - guint offset = 5; - guint size = len - offset; + int offset = 5; + gint size = len - offset; switch (eap_type) { @@ -181,6 +190,20 @@ dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } } } + + return tvb_length(tvb); +} + +static int +dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + return dissect_eap_data(tvb, pinfo, tree, FALSE); +} + +static int +dissect_eap_fragment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + return dissect_eap_data(tvb, pinfo, tree, TRUE); } void @@ -209,7 +232,8 @@ proto_register_eap(void) proto_register_field_array(proto_eap, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); - register_dissector("eap", dissect_eap, proto_eap); + new_register_dissector("eap", dissect_eap, proto_eap); + new_register_dissector("eap_fragment", dissect_eap_fragment, proto_eap); } void diff --git a/packet-radius.c b/packet-radius.c index 51cf7e9295..2b2d01e98f 100644 --- a/packet-radius.c +++ b/packet-radius.c @@ -2,7 +2,9 @@ * Routines for RADIUS packet disassembly * Copyright 1999 Johan Feyaerts * - * $Id: packet-radius.c,v 1.48 2002/02/26 00:51:41 guy Exp $ + * RFC 2865, RFC 2866, RFC 2867, RFC 2868, RFC 2869 + * + * $Id: packet-radius.c,v 1.49 2002/02/26 11:55:37 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -53,7 +55,7 @@ static gint ett_radius = -1; static gint ett_radius_avp = -1; static gint ett_radius_eap = -1; -static dissector_handle_t eap_handle; +static dissector_handle_t eap_fragment_handle; #define UDP_PORT_RADIUS 1645 #define UDP_PORT_RADIUS_NEW 1812 @@ -874,11 +876,15 @@ gchar *rd_value_to_str(e_avphdr *avph, tvbuff_t *tvb, int offset) void dissect_attribute_value_pairs(tvbuff_t *tvb, int offset,proto_tree *tree, - int avplength,packet_info *pinfo) { + int avplength,packet_info *pinfo) +{ /* adds the attribute value pairs to the tree */ e_avphdr avph; gchar *avptpstrval; gchar *valstr; + guint8 *reassembled_data = NULL; + int reassembled_data_len = 0; + int data_needed = 0; if (avplength==0) { @@ -886,59 +892,159 @@ void dissect_attribute_value_pairs(tvbuff_t *tvb, int offset,proto_tree *tree, return; } - while (avplength > 0 ) - { + /* + * In case we throw an exception, clean up whatever stuff we've + * allocated (if any). + */ + CLEANUP_PUSH(g_free, reassembled_data); - tvb_memcpy(tvb,(guint8 *)&avph,offset,sizeof(e_avphdr)); - avptpstrval=match_strval(avph.avp_type, radius_attrib_type_vals); - if (avptpstrval == NULL) avptpstrval="Unknown Type"; - if (avph.avp_length < 2) { - /* - * This AVP is bogus - the length includes the type and length - * fields, so it must be >= 2. - */ - proto_tree_add_text(tree, tvb, offset, avph.avp_length, - "t:%s(%u) l:%u (length not >= 2)", - avptpstrval,avph.avp_type,avph.avp_length); - break; - } - - if (avph.avp_type == RD_TP_EAP_MESSAGE) { - proto_item *ti; - proto_tree *eap_tree; - gint tvb_len; - tvbuff_t *next_tvb; - ti = proto_tree_add_text(tree, tvb,offset,avph.avp_length,"t:%s(%u) l:%u", - avptpstrval,avph.avp_type,avph.avp_length); - eap_tree = proto_item_add_subtree(ti, ett_radius_eap); - tvb_len = tvb_length_remaining(tvb, offset+2); - if (avph.avp_length-2 < tvb_len) - tvb_len = avph.avp_length-2; - next_tvb = tvb_new_subset(tvb, offset+2, tvb_len, avph.avp_length-2); - - /* - * Set the columns non-writable, so that the packet list - * shows this as an RADIUS packet, not as an EAP packet. - * - * XXX - we'll call the EAP dissector only if we're building - * a protocol tree. The EAP dissector currently saves no state, - * and won't be modifying the columns, so that's OK right now, - * but it might call the SSL dissector - if that maintains state - * needed for dissection, we'll have to arrange that AVPs be - * dissected even if we're not building a protocol tree. - */ - col_set_writable(pinfo->cinfo, FALSE); - call_dissector(eap_handle, next_tvb, pinfo, eap_tree); - } else { - valstr=rd_value_to_str(&avph, tvb, offset); - proto_tree_add_text(tree, tvb,offset,avph.avp_length, - "t:%s(%u) l:%u, %s", - avptpstrval,avph.avp_type,avph.avp_length,valstr); - } - - offset=offset+avph.avp_length; - avplength=avplength-avph.avp_length; + while (avplength > 0) + { + tvb_memcpy(tvb,(guint8 *)&avph,offset,sizeof(e_avphdr)); + avptpstrval = match_strval(avph.avp_type, radius_attrib_type_vals); + if (avptpstrval == NULL) + avptpstrval = "Unknown Type"; + if (avph.avp_length < 2) { + /* + * This AVP is bogus - the length includes the type and length + * fields, so it must be >= 2. + */ + proto_tree_add_text(tree, tvb, offset, avph.avp_length, + "t:%s(%u) l:%u (length not >= 2)", + avptpstrval,avph.avp_type,avph.avp_length); + break; + } + + if (avph.avp_type == RD_TP_EAP_MESSAGE) { + proto_item *ti; + proto_tree *eap_tree; + gint tvb_len; + tvbuff_t *next_tvb; + int data_len; + int result; + + ti = proto_tree_add_text(tree, tvb,offset,avph.avp_length,"t:%s(%u) l:%u", + avptpstrval,avph.avp_type,avph.avp_length); + eap_tree = proto_item_add_subtree(ti, ett_radius_eap); + tvb_len = tvb_length_remaining(tvb, offset+2); + data_len = avph.avp_length-2; + if (data_len < tvb_len) + tvb_len = data_len; + next_tvb = tvb_new_subset(tvb, offset+2, tvb_len, data_len); + + /* + * Set the columns non-writable, so that the packet list + * shows this as an RADIUS packet, not as an EAP packet. + * + * XXX - we'll call the EAP dissector only if we're building + * a protocol tree. The EAP dissector currently saves no state, + * and won't be modifying the columns, so that's OK right now, + * but it might call the SSL dissector - if that maintains state + * needed for dissection, we'll have to arrange that AVPs be + * dissected even if we're not building a protocol tree. + */ + col_set_writable(pinfo->cinfo, FALSE); + + /* + * RFC 2869 says, in section 5.13, describing the EAP-Message + * attribute: + * + * The String field contains EAP packets, as defined in [3]. If + * multiple EAP-Message attributes are present in a packet their + * values should be concatenated; this allows EAP packets longer than + * 253 octets to be passed by RADIUS. + * + * Do reassembly of EAP-Message attributes. + */ + + /* Are we in the process of reassembling? */ + if (reassembled_data != NULL) { + /* Yes - show this as an EAP fragment. */ + proto_tree_add_text(eap_tree, next_tvb, 0, -1, "EAP fragment"); + + /* + * Do we have all of the data in this fragment? + */ + if (tvb_len >= data_len) { + /* + * Yes - add it to the reassembled data. + */ + tvb_memcpy(next_tvb, reassembled_data + reassembled_data_len, + 0, data_len); + reassembled_data_len += data_len; + data_needed -= data_len; + if (data_needed <= 0) { + /* + * We got at least as much data as we needed; we're done + * reassembling. + * XXX - what if we got more? + */ + + /* + * Allocate a new tvbuff, referring to the reassembled payload. + */ + next_tvb = tvb_new_real_data(reassembled_data, reassembled_data_len, + reassembled_data_len); + + /* + * We have a tvbuff that refers to this data, so we shouldn't + * free this data if we throw an exception; clear + * "reassembled_data", so the cleanup handler won't free it. + */ + reassembled_data = NULL; + reassembled_data_len = 0; + data_needed = 0; + + /* + * Arrange that the allocated packet data copy be freed when the + * tvbuff is freed. + */ + tvb_set_free_cb(next_tvb, g_free); + + /* + * Add the tvbuff to the list of tvbuffs to which the tvbuff we + * were handed refers, so it'll get cleaned up when that tvbuff + * is cleaned up. + */ + tvb_set_child_real_data_tvbuff(tvb, next_tvb); + + /* Add the defragmented data to the data source list. */ + add_new_data_source(pinfo->fd, next_tvb, "Reassembled EAP"); + + /* Now dissect it. */ + call_dissector(eap_fragment_handle, next_tvb, pinfo, eap_tree); + } + } + } else { + /* + * No - hand it to the dissector. + */ + result = call_dissector(eap_fragment_handle, next_tvb, pinfo, eap_tree); + if (result < 0) { + /* This is only part of the full EAP packet; start reassembly. */ + proto_tree_add_text(eap_tree, next_tvb, 0, -1, "EAP fragment"); + reassembled_data_len = data_len; + data_needed = -result; + reassembled_data = g_malloc(reassembled_data_len + data_needed); + tvb_memcpy(next_tvb, reassembled_data, 0, reassembled_data_len); + } + } + } else { + valstr = rd_value_to_str(&avph, tvb, offset); + proto_tree_add_text(tree, tvb,offset,avph.avp_length, + "t:%s(%u) l:%u, %s", + avptpstrval,avph.avp_type,avph.avp_length,valstr); + } + + offset = offset+avph.avp_length; + avplength = avplength-avph.avp_length; } + + /* + * Call the cleanup handler to free any reassembled data we haven't + * attached to a tvbuff, and pop the handler. + */ + CLEANUP_CALL_AND_POP; } static void dissect_radius(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) @@ -1046,9 +1152,9 @@ proto_reg_handoff_radius(void) dissector_handle_t radius_handle; /* - * Get a handle for the EAP dissector. + * Get a handle for the EAP fragment dissector. */ - eap_handle = find_dissector("eap"); + eap_fragment_handle = find_dissector("eap_fragment"); radius_handle = create_dissector_handle(dissect_radius, proto_radius); dissector_add("udp.port", UDP_PORT_RADIUS, radius_handle); |