aboutsummaryrefslogtreecommitdiffstats
path: root/packet-eap.c
diff options
context:
space:
mode:
Diffstat (limited to 'packet-eap.c')
-rw-r--r--packet-eap.c400
1 files changed, 353 insertions, 47 deletions
diff --git a/packet-eap.c b/packet-eap.c
index d78211b9ca..64aad0826c 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.21 2002/03/23 21:24:38 guy Exp $
+ * $Id: packet-eap.c,v 1.22 2002/03/27 07:41:20 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -39,6 +39,7 @@
#include <epan/packet.h>
#include <epan/conversation.h>
#include "ppptypes.h"
+#include "reassemble.h"
static int proto_eap = -1;
static int hf_eap_code = -1;
@@ -117,25 +118,103 @@ static const value_string eap_type_vals[] = {
};
/*
+ * State information for EAP-TLS (RFC2716) and Lightweight EAP:
+ *
+ * http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt
+ *
+ * Attach to all frames containing fragments of EAP-TLS messages the
+ * EAP ID value of the first fragment, so we can determine which
+ * message is getting reassembled after the first pass through
+ * the packets. We also attach a sequence number for fragments,
+ * which starts with 0 for the first fragment.
+ *
* Attach to all frames containing LEAP messages an indication of
* the state of the LEAP negotiation, so we can properly dissect
* the LEAP message after the first pass through the packets.
+ *
+ * Attach to all conversations both pieces of information, to keep
+ * track of EAP-TLS reassembly and the LEAP state machine.
*/
-static GMemChunk *leap_state_chunk = NULL;
+static GMemChunk *conv_state_chunk = NULL;
typedef struct {
- int state;
-} leap_state_t;
+ int init_eap_id;
+ int eap_tls_seq;
+ int leap_state;
+} conv_state_t;
+
+static GMemChunk *frame_state_chunk = NULL;
+
+typedef struct {
+ int info; /* interpretation depends on EAP message type */
+} frame_state_t;
+
+/*********************************************************************
+ EAP-TLS
+RFC2716
+**********************************************************************/
+
+/*
+from RFC2716, pg 17
+
+ Flags
+
+ 0 1 2 3 4 5 6 7 8
+ +-+-+-+-+-+-+-+-+
+ |L M S R R R R R|
+ +-+-+-+-+-+-+-+-+
+
+ L = Length included
+ M = More fragments
+ S = EAP-TLS start
+ R = Reserved
+*/
+
+#define EAP_TLS_FLAG_L 0x80 /* Length included */
+#define EAP_TLS_FLAG_M 0x40 /* More fragments */
+#define EAP_TLS_FLAG_S 0x20 /* EAP-TLS start */
+
+/*
+ * reassembly of EAP-TLS
+ */
+static GHashTable *eaptls_fragment_table = NULL;
+
+static int hf_eaptls_fragment = -1;
+static int hf_eaptls_fragments = -1;
+static gint ett_eaptls_fragment = -1;
+static gint ett_eaptls_fragments = -1;
+
+/*********************************************************************
+**********************************************************************/
+
+static gboolean
+test_flag(unsigned char flag, unsigned char mask)
+{
+ return ( ( flag & mask ) != 0 );
+}
+
+static void
+eaptls_defragment_init(void)
+{
+ fragment_table_init(&eaptls_fragment_table);
+}
static void
eap_init_protocol(void)
{
- if (leap_state_chunk != NULL)
- g_mem_chunk_destroy(leap_state_chunk);
+ if (conv_state_chunk != NULL)
+ g_mem_chunk_destroy(conv_state_chunk);
+ if (frame_state_chunk != NULL)
+ g_mem_chunk_destroy(frame_state_chunk);
+
+ conv_state_chunk = g_mem_chunk_new("conv_state_chunk",
+ sizeof (conv_state_t),
+ 10 * sizeof (conv_state_t),
+ G_ALLOC_ONLY);
- leap_state_chunk = g_mem_chunk_new("leap_state_chunk",
- sizeof (leap_state_t),
- 100 * sizeof (leap_state_t),
+ frame_state_chunk = g_mem_chunk_new("frame_state_chunk",
+ sizeof (frame_state_t),
+ 100 * sizeof (frame_state_t),
G_ALLOC_ONLY);
}
@@ -149,7 +228,8 @@ dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
guint8 eap_type;
gint len;
conversation_t *conversation;
- leap_state_t *conversation_state, *packet_state;
+ conv_state_t *conversation_state;
+ frame_state_t *packet_state;
int leap_state;
proto_tree *ti;
proto_tree *eap_tree = NULL;
@@ -217,8 +297,10 @@ dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
/*
* Attach LEAP state information to the conversation.
*/
- conversation_state = g_mem_chunk_alloc(leap_state_chunk);
- conversation_state->state = -1;
+ conversation_state = g_mem_chunk_alloc(conv_state_chunk);
+ conversation_state->init_eap_id = -1;
+ conversation_state->eap_tls_seq = -1;
+ conversation_state->leap_state = -1;
conversation_add_proto_data(conversation, proto_eap, conversation_state);
}
@@ -227,7 +309,9 @@ dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
* later.
*/
if (eap_code == EAP_FAILURE)
- conversation_state->state = -1;
+ conversation_state->leap_state = -1;
+
+ eap_id = tvb_get_guint8(tvb, 1);
eap_len = tvb_get_ntohs(tvb, 2);
len = eap_len;
@@ -279,7 +363,8 @@ dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
gint size = len - offset;
switch (eap_type) {
-
+ /*********************************************************************
+ **********************************************************************/
case EAP_TYPE_ID:
if (tree) {
proto_tree_add_text(eap_tree, tvb, offset, size,
@@ -287,9 +372,12 @@ dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
size, plurality(size, "", "s"),
tvb_format_text(tvb, offset, size));
}
- conversation_state->state = 0;
+ if(!pinfo->fd->flags.visited)
+ conversation_state->leap_state = 0;
break;
-
+
+ /*********************************************************************
+ **********************************************************************/
case EAP_TYPE_NOTIFY:
if (tree) {
proto_tree_add_text(eap_tree, tvb, offset, size,
@@ -298,56 +386,258 @@ dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
tvb_format_text(tvb, offset, size));
}
break;
-
+ /*********************************************************************
+ **********************************************************************/
case EAP_TYPE_NAK:
if (tree) {
proto_tree_add_uint(eap_tree, hf_eap_type_nak, tvb,
offset, size, eap_type);
}
break;
-
+ /*********************************************************************
+ EAP-TLS
+ **********************************************************************/
case EAP_TYPE_TLS:
{
- guint8 flags = tvb_get_guint8(tvb, offset);
-
- if (tree) {
- proto_tree_add_text(eap_tree, tvb, offset, 1, "Flags(%i): %s%s%s",
+ guint8 flags = tvb_get_guint8(tvb, offset);
+ gboolean more_fragments;
+ gboolean has_length;
+ guint32 length;
+ int init_eap_id = -1;
+ int eap_tls_seq = -1;
+
+ more_fragments = test_flag(flags,EAP_TLS_FLAG_M);
+ has_length = test_flag(flags,EAP_TLS_FLAG_L);
+
+ /* Flags field, 1 byte */
+ if (tree)
+ proto_tree_add_text(eap_tree, tvb, offset, 1, "Flags(0x%X): %s%s%s",
flags,
- flags & 128 ? "Length " : "",
- flags & 64 ? "More " : "",
- flags & 32 ? "Start " : "");
- }
+ has_length ? "Length " : "",
+ more_fragments ? "More " : "",
+ test_flag(flags,EAP_TLS_FLAG_S) ? "Start " : "");
size--;
offset++;
- if (flags >> 7) {
- guint32 length = tvb_get_ntohl(tvb, offset);
- if (tree) {
- proto_tree_add_text(eap_tree, tvb, offset, 4, "Length: %i",
- length);
- }
+ /* Length field, 4 bytes, OPTIONAL. */
+ if ( test_flag(flags, EAP_TLS_FLAG_L) ) {
+ length = tvb_get_ntohl(tvb, offset);
+ if (tree)
+ proto_tree_add_text(eap_tree, tvb, offset, 4, "Length: %i",length);
size -= 4;
offset += 4;
}
if (size>0) {
+
tvbuff_t *next_tvb;
gint tvb_len;
+ gboolean save_fragmented;
tvb_len = tvb_length_remaining(tvb, offset);
if (size < tvb_len)
tvb_len = size;
- next_tvb = tvb_new_subset(tvb, offset, tvb_len, size);
- call_dissector(ssl_handle, next_tvb, pinfo, eap_tree);
+
+ /*
+ EAP/TLS is weird protocol (it comes from
+ Microsoft after all).
+
+ If we have series of fragmented packets,
+ then there's no way of knowing that from
+ the packet itself, if it is the last packet
+ in series, that is that the packet part of
+ bigger fragmented set of data.
+
+ The only way to know is, by knowing
+ that we are already in defragmentation
+ "mode" and we are expecing packet
+ carrying fragment of data. (either
+ because we have not received expected
+ amount of data, or because the packet before
+ had "F"ragment flag set.)
+
+ The situation is alleviated by fact that it
+ is simple ack/nack protcol so there's no
+ place for out-of-order packets like it is
+ possible with IP.
+
+ Anyway, point of this lengthy essay is that
+ we have to keep state information in the
+ conversation, so that we can put ourselves in
+ defragmenting mode and wait for the last packet,
+ and have to attach state to frames as well, so
+ that we can handle defragmentation after the
+ first pass through the capture.
+ */
+ /* See if we have a remembered defragmentation EAP ID. */
+ packet_state = p_get_proto_data(pinfo->fd, proto_eap);
+ if (packet_state == NULL) {
+ /*
+ * We haven't - does this message require reassembly?
+ */
+ if (!pinfo->fd->flags.visited) {
+ /*
+ * This is the first time we've looked at this frame,
+ * so it wouldn't have any remembered information.
+ *
+ * Therefore, we check whether this conversation has
+ * a reassembly operation in progress, or whether
+ * this frame has the Fragment flag set.
+ */
+ if (conversation_state->eap_tls_seq != -1) {
+ /*
+ * There's a reassembly in progress; the EAP ID of
+ * the message containing the first fragment
+ * is "conversation_state->init_eap_id", and
+ * the sequence number of the previous fragment
+ * is "conversation_state->eap_tls_seq".
+ *
+ * We must include this frame in the reassembly.
+ * We advance the sequence number, giving us the
+ * sequence number for this fragment.
+ */
+ init_eap_id = conversation_state->init_eap_id;
+ conversation_state->eap_tls_seq++;
+ eap_tls_seq = conversation_state->eap_tls_seq;
+ } else if (more_fragments && has_length) {
+ /*
+ * This message has the Fragment flag set, so it requires
+ * reassembly. It's the message containing the first
+ * fragment (if it's a later fragment, the EAP ID
+ * in the conversation state would not be -1, it'd
+ * be the EAP ID of the first fragment), so remember its
+ * EAP ID.
+ *
+ * If it doesn't include a length, however, we can't
+ * do reassembly (either the message is in error, as
+ * the first fragment *must* contain a length, or we
+ * didn't capture the first fragment, and this just
+ * happens to be the first fragment we saw), so we
+ * also check that we have a length;
+ */
+ init_eap_id = eap_id;
+ conversation_state->init_eap_id = eap_id;
+
+ /*
+ * Start the sequence number at 0.
+ */
+ conversation_state->eap_tls_seq = 0;
+ eap_tls_seq = conversation_state->eap_tls_seq;
+ }
+
+ if (init_eap_id != -1) {
+ /*
+ * This frame requires reassembly; remember the initial
+ * EAP ID for subsequent accesses to it.
+ */
+ packet_state = g_mem_chunk_alloc(frame_state_chunk);
+ packet_state->info = init_eap_id;
+ p_add_proto_data(pinfo->fd, proto_eap, packet_state);
+ }
+ }
+ } else {
+ /*
+ * This frame has an initial EAP ID associated with it, so
+ * it requires reassembly. We've already done the
+ * reassembly in the first pass, so "fragment_add_seq()"
+ * won't look at the sequence number; set it to 0.
+ *
+ * XXX - a frame isn't supposed to have more than one
+ * EAP message in it, but if it includes both an EAP-TLS
+ * message and a LEAP message, we might be mistakenly
+ * concluding it requires reassembly because the "info"
+ * field isn't -1. We could, I guess, pack both EAP-TLS
+ * ID and LEAP state into the structure, but that doesn't
+ * work if you have multiple EAP-TLS or LEAP messages in
+ * the frame.
+ *
+ * But it's not clear how much work we should do to handle
+ * a bogus message such as that; as long as we don't crash
+ * or do something else equally horrible, we may not
+ * have to worry about this at all.
+ */
+ init_eap_id = packet_state->info;
+ eap_tls_seq = 0;
+ }
+
+ /*
+ We test here to see whether EAP-TLS packet
+ carry fragmented of TLS data.
+
+ If is his case, we do reasembly below,
+ otherwise we just call dissector.
+ */
+ if (init_eap_id != -1) {
+ fragment_data *fd_head = NULL;
+
+ /*
+ * Yes, this frame contains a fragment that requires
+ * reassembly.
+ */
+ save_fragmented = pinfo->fragmented;
+ pinfo->fragmented = TRUE;
+ fd_head = fragment_add_seq(tvb, offset, pinfo,
+ init_eap_id,
+ eaptls_fragment_table,
+ eap_tls_seq,
+ size,
+ more_fragments);
+
+ if (fd_head != NULL) /* Reassembled */
+ {
+
+ fragment_data *ffd; /* fragment file descriptor */
+ proto_tree *ft=NULL;
+ proto_item *fi=NULL;
+ guint32 frag_offset;
+
+ next_tvb = tvb_new_real_data(fd_head->data,
+ fd_head->len,
+ fd_head->len);
+ tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+ add_new_data_source(pinfo->fd, next_tvb,
+ "Reassembled EAP-TLS");
+ pinfo->fragmented = FALSE;
+
+ fi = proto_tree_add_item(eap_tree, hf_eaptls_fragments,
+ next_tvb, 0, -1, FALSE);
+ ft = proto_item_add_subtree(fi, ett_eaptls_fragments);
+ frag_offset = 0;
+ for (ffd=fd_head->next; ffd; ffd=ffd->next){
+ proto_tree_add_none_format(ft, hf_eaptls_fragment,
+ next_tvb, frag_offset, ffd->len,
+ "Frame:%u payload:%u-%u",
+ ffd->frame,
+ frag_offset,
+ frag_offset+ffd->len-1
+ );
+ frag_offset += ffd->len;
+ }
+ call_dissector(ssl_handle, next_tvb, pinfo, eap_tree);
+
+ /*
+ * We're finished reassembing this frame.
+ * Reinitialize the reassembly state.
+ */
+ if (!pinfo->fd->flags.visited) {
+ conversation_state->init_eap_id = -1;
+ conversation_state->eap_tls_seq = -1;
+ }
+ }
+
+ pinfo->fragmented = save_fragmented;
+
+ } else { /* this data is NOT fragmented */
+ next_tvb = tvb_new_subset(tvb, offset, tvb_len, size);
+ call_dissector(ssl_handle, next_tvb, pinfo, eap_tree);
+ }
}
}
break; /* EAP_TYPE_TLS */
-
- /*
- Cisco's LEAP
- http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt
- */
-
+ /*********************************************************************
+ Cisco's Lightweight EAP (LEAP)
+ http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt
+ **********************************************************************/
case EAP_TYPE_LEAP:
{
guint8 field,count,namesize;
@@ -382,7 +672,6 @@ dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
/* Data (byte*Count) */
/* This part is state-dependent. */
-
/* See if we've already remembered the state. */
packet_state = p_get_proto_data(pinfo->fd, proto_eap);
if (packet_state == NULL) {
@@ -390,7 +679,7 @@ dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
* We haven't - compute the state based on the current
* state in the conversation.
*/
- leap_state = conversation_state->state;
+ leap_state = conversation_state->leap_state;
/* Advance the state machine. */
if (leap_state==0) leap_state = 1; else
@@ -403,18 +692,18 @@ dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
* Remember the state for subsequent accesses to this
* frame.
*/
- packet_state = g_mem_chunk_alloc(leap_state_chunk);
- packet_state->state = leap_state;
+ packet_state = g_mem_chunk_alloc(frame_state_chunk);
+ packet_state->info = leap_state;
p_add_proto_data(pinfo->fd, proto_eap, packet_state);
/*
* Update the conversation's state.
*/
- conversation_state->state = leap_state;
+ conversation_state->leap_state = leap_state;
}
/* Get the remembered state. */
- leap_state = packet_state->state;
+ leap_state = packet_state->info;
if (tree) {
@@ -460,7 +749,8 @@ dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
}
break; /* EAP_TYPE_LEAP */
-
+ /*********************************************************************
+ **********************************************************************/
default:
if (tree) {
proto_tree_add_text(eap_tree, tvb, offset, size,
@@ -469,7 +759,10 @@ dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
tvb_bytes_to_str(tvb, offset, size));
}
break;
+ /*********************************************************************
+ **********************************************************************/
} /* switch (eap_type) */
+
}
} /* switch (eap_code) */
@@ -508,9 +801,21 @@ proto_register_eap(void)
{ &hf_eap_type_nak, {
"Desired Auth Type", "eap.type", FT_UINT8, BASE_DEC,
VALS(eap_type_vals), 0x0, "", HFILL }},
+ { &hf_eaptls_fragment,
+ { "EAP-TLS Fragment", "eaptls.fragment",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ "EAP-TLS Fragment", HFILL }},
+ { &hf_eaptls_fragments,
+ { "EAP-TLS Fragments", "eaptls.fragments",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ "EAP-TLS Fragments", HFILL }},
+
+
};
static gint *ett[] = {
&ett_eap,
+ &ett_eaptls_fragment,
+ &ett_eaptls_fragments,
};
proto_eap = proto_register_protocol("Extensible Authentication Protocol",
@@ -521,6 +826,7 @@ proto_register_eap(void)
new_register_dissector("eap", dissect_eap, proto_eap);
new_register_dissector("eap_fragment", dissect_eap_fragment, proto_eap);
+ register_init_routine(eaptls_defragment_init);
}
void