Allow dissectors to be registered as "old-style" or "new-style"

dissectors.  "Old-style" dissectors return nothing.  "New-style"
dissectors return one of:

	a positive integer, giving the number of bytes worth of data in
	the tvbuff that it considered to be part of the PDU in the
	tvbuff;

	zero, if it didn't consider the data in the tvbuff to be a PDU
	for its protocol;

	a negative integer, giving the number of additional bytes worth
	of data in needs to get the complete PDU (for use with
	fragmentation/segmentation when the length of the PDU isn't
	known to the protocol atop the one the dissector is dissecting).

Have "call_dissector()" return the return value of new-style dissectors,
and the length of the tvbuff handed to it for old-style dissectors.

Have "dissector_try_port()" return FALSE if the subdissector is a
new-style dissector and returned 0.

Make the EAP dissector a new-style dissector, and have a "EAP fragment"
dissector that is also a new-style dissector and handles fragmentation
of EAP messages (as happens above, for example, RADIUS).  Also, clean up
some signed vs. unsigned comparison problems.

Reassemble EAP-Message AVPs in RADIUS.

svn path=/trunk/; revision=4811
This commit is contained in:
Guy Harris 2002-02-26 11:55:39 +00:00
parent fa431b988f
commit 193b8c9bfb
4 changed files with 282 additions and 79 deletions

View File

@ -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,7 +1006,32 @@ 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);
}
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,
@ -991,11 +1039,12 @@ register_dissector(const char *name, dissector_t dissector, int proto)
}
/* Call a dissector through a handle. */
void
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;
}

View File

@ -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. */

View File

@ -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

View File

@ -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);
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;
}
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;
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);
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);
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);
}
/*
* 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);
offset=offset+avph.avp_length;
avplength=avplength-avph.avp_length;
/*
* 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);