aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-smtp.c
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 /epan/dissectors/packet-smtp.c
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
Diffstat (limited to 'epan/dissectors/packet-smtp.c')
-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");
+
}