aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGraeme Lunt <graeme.lunt@smhs.co.uk>2007-07-04 16:16:32 +0000
committerGraeme Lunt <graeme.lunt@smhs.co.uk>2007-07-04 16:16:32 +0000
commit1066b988e639258757ef23d7273ad2b8130a5d3e (patch)
treefe67c7eb71101048e5948d5b6f57c2e021adb7ef
parentde416e9532c1a2c46177c662e8e71fc6af971333 (diff)
New preference to allow for the reassembly of SMTP DATA and subsequent dissection as Internet Message Format (imf).
(imf dissector in separate patch). svn path=/trunk/; revision=22240
-rw-r--r--epan/dissectors/packet-smtp.c200
1 files changed, 180 insertions, 20 deletions
diff --git a/epan/dissectors/packet-smtp.c b/epan/dissectors/packet-smtp.c
index fe3f05ee35..76188d7c87 100644
--- a/epan/dissectors/packet-smtp.c
+++ b/epan/dissectors/packet-smtp.c
@@ -40,6 +40,7 @@
#include <epan/prefs.h>
#include <epan/strutil.h>
#include <epan/emem.h>
+#include <epan/reassemble.h>
#define TCP_PORT_SMTP 25
@@ -52,11 +53,51 @@ static int hf_smtp_req_parameter = -1;
static int hf_smtp_rsp_code = -1;
static int hf_smtp_rsp_parameter = -1;
+static int hf_smtp_data_fragments = -1;
+static int hf_smtp_data_fragment = -1;
+static int hf_smtp_data_fragment_overlap = -1;
+static int hf_smtp_data_fragment_overlap_conflicts = -1;
+static int hf_smtp_data_fragment_multiple_tails = -1;
+static int hf_smtp_data_fragment_too_long_fragment = -1;
+static int hf_smtp_data_fragment_error = -1;
+static int hf_smtp_data_reassembled_in = -1;
+
static int ett_smtp = -1;
static int ett_smtp_cmdresp = -1;
+static gint ett_smtp_data_fragment = -1;
+static gint ett_smtp_data_fragments = -1;
+
/* desegmentation of SMTP command and response lines */
static gboolean smtp_desegment = TRUE;
+static gboolean smtp_data_desegment = TRUE;
+
+static GHashTable *smtp_data_segment_table = NULL;
+static GHashTable *smtp_data_reassembled_table = NULL;
+
+static const fragment_items smtp_data_frag_items = {
+ /* Fragment subtrees */
+ &ett_smtp_data_fragment,
+ &ett_smtp_data_fragments,
+ /* Fragment fields */
+ &hf_smtp_data_fragments,
+ &hf_smtp_data_fragment,
+ &hf_smtp_data_fragment_overlap,
+ &hf_smtp_data_fragment_overlap_conflicts,
+ &hf_smtp_data_fragment_multiple_tails,
+ &hf_smtp_data_fragment_too_long_fragment,
+ &hf_smtp_data_fragment_error,
+ /* Reassembled in field */
+ &hf_smtp_data_reassembled_in,
+ /* Tag */
+ "DATA fragments"
+};
+
+/* Define media_type/Content type table */
+static dissector_table_t media_type_dissector_table;
+
+
+static dissector_handle_t imf_handle = NULL;
/*
* A CMD is an SMTP command, MESSAGE is the message portion, and EOM is the
@@ -69,6 +110,7 @@ static gboolean smtp_desegment = TRUE;
struct smtp_proto_data {
guint16 pdu_type;
+ guint16 conversation_id;
};
/*
@@ -77,8 +119,37 @@ struct smtp_proto_data {
struct smtp_request_val {
gboolean reading_data; /* Reading message data, not commands */
guint16 crlf_seen; /* Have we seen a CRLF on the end of a packet */
+ guint16 data_seen; /* Have we seen a DATA command yet */
};
+
+static void dissect_smtp_data(tvbuff_t *tvb, int offset, proto_tree *smtp_tree)
+{
+ gint next_offset;
+
+ while (tvb_offset_exists(tvb, offset)) {
+
+ /*
+ * Find the end of the line.
+ */
+ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
+
+ /*
+ * Put this line.
+ */
+ proto_tree_add_text(smtp_tree, tvb, offset, next_offset - offset,
+ "Message: %s",
+ tvb_format_text(tvb, offset, next_offset - offset));
+
+ /*
+ * Step to the next line.
+ */
+ offset = next_offset;
+
+ }
+
+}
+
static void
dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
@@ -98,6 +169,8 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
gint next_offset;
gboolean is_continuation_line;
int cmdlen;
+ fragment_data *frag_msg = NULL;
+ tvbuff_t *next_tvb;
/* As there is no guarantee that we will only see frames in the
* the SMTP conversation once, and that we will see them in
@@ -177,6 +250,7 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
request_val = se_alloc(sizeof(struct smtp_request_val));
request_val->reading_data = FALSE;
request_val->crlf_seen = 0;
+ request_val->data_seen = 0;
conversation_add_proto_data(conversation, proto_smtp, request_val);
@@ -227,6 +301,8 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
frame_data = se_alloc(sizeof(struct smtp_proto_data));
+ frame_data->conversation_id = conversation->index;
+
if (request_val->reading_data) {
/*
* This is message data.
@@ -271,6 +347,7 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
*/
frame_data->pdu_type = SMTP_PDU_CMD;
request_val->reading_data = TRUE;
+ request_val->data_seen = TRUE;
} else {
@@ -290,7 +367,8 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
* Assume it's message data.
*/
- frame_data->pdu_type = SMTP_PDU_MESSAGE;
+
+ frame_data->pdu_type = request_val->data_seen ? SMTP_PDU_MESSAGE : SMTP_PDU_CMD;
}
@@ -323,7 +401,7 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
switch (frame_data->pdu_type) {
case SMTP_PDU_MESSAGE:
- col_set_str(pinfo->cinfo, COL_INFO, "Message Body");
+ col_set_str(pinfo->cinfo, COL_INFO, smtp_data_desegment ? "DATA fragment" : "Message Body");
break;
case SMTP_PDU_EOM:
@@ -372,29 +450,29 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
case SMTP_PDU_MESSAGE:
- /*
- * Message body.
- * Put its lines into the protocol tree, a line at a time.
- */
- while (tvb_offset_exists(tvb, offset)) {
+ if(smtp_data_desegment) {
- /*
- * Find the end of the line.
- */
- tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
+ frag_msg = fragment_add_seq_next (tvb, 0, pinfo,
+ frame_data->conversation_id, smtp_data_segment_table,
+ smtp_data_reassembled_table, tvb_length_remaining(tvb,0), TRUE);
- /*
- * Put this line.
- */
- proto_tree_add_text(smtp_tree, tvb, offset, next_offset - offset,
- "Message: %s",
- tvb_format_text(tvb, offset, next_offset - offset));
+
+ if (frag_msg && pinfo->fd->num != frag_msg->reassembled_in) {
+ /* Add a "Reassembled in" link if not reassembled in this frame */
+ proto_tree_add_uint (smtp_tree, *(smtp_data_frag_items.hf_reassembled_in),
+ tvb, 0, 0, frag_msg->reassembled_in);
+ }
+
+ pinfo->fragmented = TRUE;
+ } else {
/*
- * Step to the next line.
+ * Message body.
+ * Put its lines into the protocol tree, a line at a time.
*/
- offset = next_offset;
+ dissect_smtp_data(tvb, offset, smtp_tree);
+
}
break;
@@ -412,6 +490,32 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_text(smtp_tree, tvb, offset, linelen,
"EOM: %s", format_text(line, linelen));
+ if(smtp_data_desegment) {
+
+ /* terminate the desegmentation */
+ frag_msg = fragment_end_seq_next (pinfo, frame_data->conversation_id, smtp_data_segment_table,
+ smtp_data_reassembled_table);
+
+ next_tvb = process_reassembled_data (tvb, offset, pinfo, "Reassembled DATA",
+ frag_msg, &smtp_data_frag_items, NULL, smtp_tree);
+
+ /* XXX: this is presumptious - we may have negotiated something else */
+ if(imf_handle)
+ call_dissector(imf_handle, next_tvb, pinfo, tree);
+ else {
+
+ /*
+ * Message body.
+ * Put its lines into the protocol tree, a line at a time.
+ */
+
+ dissect_smtp_data(tvb, offset, smtp_tree);
+
+ }
+
+ pinfo->fragmented = FALSE;
+ }
+
break;
case SMTP_PDU_CMD:
@@ -515,6 +619,13 @@ dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
}
+static void smtp_data_reassemble_init (void)
+{
+ fragment_table_init (&smtp_data_segment_table);
+ reassembled_table_init (&smtp_data_reassembled_table);
+}
+
+
/* Register all the bits needed by the filtering engine */
void
@@ -541,11 +652,43 @@ proto_register_smtp(void)
{ &hf_smtp_rsp_parameter,
{ "Response parameter", "smtp.rsp.parameter", FT_STRING, BASE_NONE, NULL, 0x0,
- "", HFILL }}
+ "", HFILL }},
+
+ /* Fragment entries */
+ { &hf_smtp_data_fragments,
+ { "DATA fragments", "smtp.data.fragments", FT_NONE, BASE_NONE,
+ NULL, 0x00, "Message fragments", HFILL } },
+ { &hf_smtp_data_fragment,
+ { "DATA fragment", "smtp.data.fragment", FT_FRAMENUM, BASE_NONE,
+ NULL, 0x00, "Message fragment", HFILL } },
+ { &hf_smtp_data_fragment_overlap,
+ { "DATA fragment overlap", "smtp.data.fragment.overlap", FT_BOOLEAN,
+ BASE_NONE, NULL, 0x00, "Message fragment overlap", HFILL } },
+ { &hf_smtp_data_fragment_overlap_conflicts,
+ { "DATA fragment overlapping with conflicting data",
+ "smtp.data.fragment.overlap.conflicts", FT_BOOLEAN, BASE_NONE, NULL,
+ 0x00, "Message fragment overlapping with conflicting data", HFILL } },
+ { &hf_smtp_data_fragment_multiple_tails,
+ { "DATA has multiple tail fragments",
+ "smtp.data.fragment.multiple_tails", FT_BOOLEAN, BASE_NONE,
+ NULL, 0x00, "Message has multiple tail fragments", HFILL } },
+ { &hf_smtp_data_fragment_too_long_fragment,
+ { "DATA fragment too long", "smtp.data.fragment.too_long_fragment",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x00, "Message fragment too long",
+ HFILL } },
+ { &hf_smtp_data_fragment_error,
+ { "DATA defragmentation error", "smtp.data.fragment.error", FT_FRAMENUM,
+ BASE_NONE, NULL, 0x00, "Message defragmentation error", HFILL } },
+ { &hf_smtp_data_reassembled_in,
+ { "Reassembled DATA in frame", "smtp.data.reassembled.in", FT_FRAMENUM, BASE_NONE,
+ NULL, 0x00, "This DATA fragment is reassembled in this frame", HFILL } },
};
static gint *ett[] = {
&ett_smtp,
&ett_smtp_cmdresp,
+ &ett_smtp_data_fragment,
+ &ett_smtp_data_fragments,
+
};
module_t *smtp_module;
@@ -555,6 +698,7 @@ proto_register_smtp(void)
proto_register_field_array(proto_smtp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
+ register_init_routine (&smtp_data_reassemble_init);
/* Allow dissector to find be found by name. */
register_dissector("smtp", dissect_smtp, proto_smtp);
@@ -566,6 +710,13 @@ proto_register_smtp(void)
"Whether the SMTP dissector should reassemble command and response lines spanning multiple TCP segments."
" To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
&smtp_desegment);
+
+ prefs_register_bool_preference(smtp_module, "desegment_data",
+ "Reassemble SMTP DATA commands spanning multiple TCP segments",
+ "Whether the SMTP dissector should reassemble DATA command and lines spanning multiple TCP segments."
+ " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
+ &smtp_data_desegment);
+
}
/* The registration hand-off routine */
@@ -576,4 +727,13 @@ proto_reg_handoff_smtp(void)
smtp_handle = create_dissector_handle(dissect_smtp, proto_smtp);
dissector_add("tcp.port", TCP_PORT_SMTP, smtp_handle);
+
+ /*
+ * Get the content type and Internet media type table
+ */
+ media_type_dissector_table = find_dissector_table("media_type");
+
+ /* find the IMF dissector */
+ imf_handle = find_dissector("imf");
+
}