aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/packet.c83
-rw-r--r--epan/packet.h24
-rw-r--r--packet-eap.c44
-rw-r--r--packet-radius.c218
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);