summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Mathieson <martin.r.mathieson@googlemail.com>2017-01-22 09:01:33 -0800
committerAnders Broman <a.broman58@gmail.com>2017-01-28 03:53:09 +0000
commit1bfa581529e8edcaeaf842a87726ad6734d72292 (patch)
tree06e6bde8a5e6e513b71bfbe52f800cde3e681464
parent01ddd93a7296b54a2048de74691984a7e78e4cb9 (diff)
downloadwireshark-1bfa581529e8edcaeaf842a87726ad6734d72292.tar.gz
Snort: add a preference to show alert in reassembled frame
Change-Id: Ia29d451857995b186c88193c9722ae156eb3f66d Reviewed-on: https://code.wireshark.org/review/19729 Petri-Dish: Martin Mathieson <martin.r.mathieson@googlemail.com> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r--epan/dissectors/packet-snort.c132
-rw-r--r--epan/packet.c17
-rw-r--r--epan/packet.h1
3 files changed, 117 insertions, 33 deletions
diff --git a/epan/dissectors/packet-snort.c b/epan/dissectors/packet-snort.c
index bc3e0b7f60..567c9d0f5c 100644
--- a/epan/dissectors/packet-snort.c
+++ b/epan/dissectors/packet-snort.c
@@ -34,8 +34,9 @@
* at an inopportune time
* - would be good if could set [Snort Running] in the title bar while Snort is running,
* but don't see how a dissector could do that.
+ * - looked into writing a tap that could provide an interface for error messages/events and snort stats,
+ * but not easy as taps are not usually listening when alerts are detected
* - for a content match, find all protocol fields that cover same bytes and show in tree
- * - after tcp.reassembled_in fixed, offer to move alert to that frame?
* - other use-cases as suggested in https://sharkfesteurope.wireshark.org/assets/presentations16eu/14.pptx
*/
@@ -79,6 +80,9 @@ static int hf_snort_rule_line_number = -1;
static int hf_snort_rule_ip_var = -1;
static int hf_snort_rule_port_var = -1;
+static int hf_snort_reassembled_in = -1;
+static int hf_snort_reassembled_from = -1;
+
/* Patterns to match */
static int hf_snort_content = -1;
static int hf_snort_uricontent = -1;
@@ -137,10 +141,8 @@ static gboolean snort_show_rule_stats = FALSE;
/* Should alerts be added as expert info? */
static gboolean snort_show_alert_expert_info = FALSE;
-#if 0
/* Should we try to attach the alert to the tcp.reassembled_in frame instead of current one? */
static gboolean snort_alert_in_reassembled_frame = FALSE;
-#endif
@@ -192,6 +194,9 @@ typedef struct Alert_t {
Rule_t *matched_rule; /* Link to corresponding rule from snort config */
+ guint32 original_frame;
+ guint32 reassembled_frame;
+
/* Stats for this alert among the capture file. */
unsigned int overall_match_number;
unsigned int rule_match_number;
@@ -206,7 +211,9 @@ typedef struct Alerts_t {
} Alerts_t;
-/* Add an alert to the map stored in current_session */
+/* Add an alert to the map stored in current_session.
+ * N.B. even if preference 'snort_alert_in_reassembled_frame' is set,
+ * need to set to original frame now, and try to update it in the 2nd pass... */
static void add_alert_to_session_tree(guint frame_number, Alert_t *alert)
{
/* First look up tree to see if there is an existing entry */
@@ -214,6 +221,7 @@ static void add_alert_to_session_tree(guint frame_number, Alert_t *alert)
if (alerts == NULL) {
/* Create a new entry for the table */
alerts = (Alerts_t*)g_malloc(sizeof(Alerts_t));
+ /* Deep copy of alert */
alerts->alerts[0] = *alert;
alerts->num_alerts = 1;
wmem_tree_insert32(current_session.alerts_tree, frame_number, alerts);
@@ -221,6 +229,7 @@ static void add_alert_to_session_tree(guint frame_number, Alert_t *alert)
else {
/* See if there is room in the existing Alerts_t struct for this frame */
if (alerts->num_alerts < MAX_ALERTS_PER_FRAME) {
+ /* Deep copy of alert */
alerts->alerts[alerts->num_alerts++] = *alert;
}
}
@@ -246,6 +255,7 @@ static void fill_alert_config(SnortConfig_t *snort_config, Alert_t *alert)
/* Inform the config/rule about the alert */
rule_set_alert(snort_config, alert->matched_rule,
&global_match_number, &rule_match_number);
+
/* Copy updated counts into the alert */
alert->overall_match_number = global_match_number;
alert->rule_match_number = rule_match_number;
@@ -514,6 +524,7 @@ static gboolean snort_fast_output(GIOChannel *source, GIOCondition condition, gp
while ((line = strchr(buf, '\n'))) {
/* Have a whole line, so can parse */
Alert_t alert;
+ memset(&alert, 0, sizeof(alert));
/* Terminate received line */
*line = '\0';
@@ -539,7 +550,6 @@ static gboolean snort_fast_output(GIOChannel *source, GIOCondition condition, gp
/* Add parsed alert into session->tree */
/* Store in tree. pfino->fd->num is hidden in usec time field. */
add_alert_to_session_tree((guint)alert.tv.tv_usec, &alert);
-
}
else {
g_print("snort_fast_output() line: '%s'\n", buf);
@@ -605,15 +615,65 @@ static guint get_content_start_match(Rule_t *rule, proto_tree *tree)
return get_protocol_payload_start(rule->protocol, tree);
}
+/* Where this frame is later part of a reassembled complete PDU running over TCP, look up
+ and return that frame number. */
+static guint get_reassembled_in_frame(proto_tree *tree)
+{
+ guint value = 0;
+
+ if (tree != NULL) {
+ GPtrArray *items = proto_all_finfos(tree);
+ if (items) {
+ guint i;
+ for (i=0; i< items->len; i++) {
+ field_info *field = (field_info *)g_ptr_array_index(items,i);
+ if (strcmp(field->hfinfo->abbrev, "tcp.reassembled_in") == 0) {
+ value = field->value.value.uinteger;
+ break;
+ }
+ }
+ g_ptr_array_free(items,TRUE);
+ }
+ }
+ return value;
+}
+
+
/* Show the Snort protocol tree based on the info in alert */
static void snort_show_alert(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, Alert_t *alert)
{
proto_tree *snort_tree = NULL;
- unsigned int n;
+ guint n;
proto_item *ti, *rule_ti;
proto_tree *rule_tree;
Rule_t *rule = alert->matched_rule;
+ /* May need to move to reassembled frame to show there instead of here */
+
+ if (snort_alert_in_reassembled_frame && pinfo->fd->flags.visited && (tree != NULL)) {
+ guint reassembled_frame = get_reassembled_in_frame(tree);
+
+ if (reassembled_frame && (reassembled_frame != pinfo->num)) {
+ Alerts_t *alerts;
+
+ /* Look up alerts for this frame */
+ alerts = (Alerts_t*)wmem_tree_lookup32(current_session.alerts_tree, pinfo->num);
+
+ if (!alerts->alerts[0].reassembled_frame) {
+ /* Update all alerts from this frame! */
+ for (n=0; n < alerts->num_alerts; n++) {
+
+ /* Set forward/back frame numbers */
+ alerts->alerts[n].original_frame = pinfo->num;
+ alerts->alerts[n].reassembled_frame = reassembled_frame;
+
+ /* Add these alerts to reassembled frame */
+ add_alert_to_session_tree(reassembled_frame, &alerts->alerts[n]);
+ }
+ }
+ }
+ }
+
/* Can only find start if we have the rule and know the protocol */
guint content_start_match = 0;
if (rule) {
@@ -632,6 +692,33 @@ static void snort_show_alert(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo
"Running Snort");
snort_tree = proto_item_add_subtree(alert_ti, ett_snort);
+ if (snort_alert_in_reassembled_frame && (alert->reassembled_frame != 0)) {
+ if (alert->original_frame == pinfo->num) {
+ /* Show link forward to where alert is now shown! */
+ ti = proto_tree_add_uint(tree, hf_snort_reassembled_in, tvb, 0, 0,
+ alert->reassembled_frame);
+ PROTO_ITEM_SET_GENERATED(ti);
+ return;
+ }
+ else {
+ tvbuff_t *reassembled_tvb;
+ /* Show link back to segment where alert was detected. */
+ ti = proto_tree_add_uint(tree, hf_snort_reassembled_from, tvb, 0, 0,
+ alert->original_frame);
+ PROTO_ITEM_SET_GENERATED(ti);
+
+ /* Should find this if look late enough.. */
+ reassembled_tvb = get_data_source_tvb_by_name(pinfo, "Reassembled TCP");
+ if (reassembled_tvb) {
+ /* Will look for content using the TVB instead of just this frame's one */
+ tvb = reassembled_tvb;
+ }
+ /* TODO: for correctness, would be good to lookup + remember the offset of the source
+ * frame within the reassembled PDU frame, to make sure we find the content in the
+ * correct place for every alert */
+ }
+ }
+
/* Show in expert info if configured to. */
if (snort_show_alert_expert_info) {
expert_add_info_format(pinfo, alert_ti, &ei_snort_alert, "Alert %u: \"%s\"", alert->sid, alert->msg);
@@ -930,31 +1017,6 @@ static const char *get_user_comment_string(proto_tree *tree)
}
-#if 0
-/* TODO: unfortunately, the first frame in a series of frames to be reassembled has often been
- * seen to lack this field, despite being referenced in the reassmbled frame! */
-static guint get_reassembled_in_frame(proto_tree *tree)
-{
- guint value = 0;
-
- if (tree != NULL) {
- GPtrArray *items = proto_all_finfos(tree);
- if (items) {
- guint i;
- for (i=0; i< items->len; i++) {
- field_info *field = (field_info *)g_ptr_array_index(items,i);
- if (strcmp(field->hfinfo->abbrev, "tcp.reassembled_in") == 0) {
- value = field->value.value.uinteger;
- break;
- }
- }
- g_ptr_array_free(items,TRUE);
- }
- }
- return value;
-}
-#endif
-
/********************************************************************************/
/* Main (post-)dissector function. */
static int
@@ -1250,6 +1312,12 @@ proto_register_snort(void)
{ &hf_snort_rule_port_var,
{ "Port variable used in rule", "snort.rule-port-var", FT_NONE, BASE_NONE, NULL, 0x00,
NULL, HFILL }},
+ { &hf_snort_reassembled_in,
+ { "Reassembled frame where alert is shown", "snort.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }},
+ { &hf_snort_reassembled_from,
+ { "Segment where alert was triggered", "snort.reassembled_from", FT_FRAMENUM, BASE_NONE, NULL, 0x00,
+ NULL, HFILL }},
{ &hf_snort_content,
{ "Content", "snort.content", FT_STRINGZ, BASE_NONE, NULL, 0x00,
"Snort content field", HFILL }},
@@ -1347,12 +1415,10 @@ proto_register_snort(void)
"Show alerts in expert info",
"Whether or not expert info should be used to highlight fired alerts",
&snort_show_alert_expert_info);
-#if 0
prefs_register_bool_preference(snort_module, "show_alert_in_reassembled_frame",
"Try to show alerts in reassembled frame",
"Attempt to show alert in reassembled frame where possible",
&snort_alert_in_reassembled_frame);
-#endif
snort_handle = create_dissector_handle(snort_dissector, proto_snort);
diff --git a/epan/packet.c b/epan/packet.c
index 00d90d40a5..cad51e756d 100644
--- a/epan/packet.c
+++ b/epan/packet.c
@@ -403,6 +403,23 @@ get_data_source_tvb(const struct data_source *src)
}
/*
+ * Find and return the tvb associated with the given data source name
+ */
+tvbuff_t *
+get_data_source_tvb_by_name(packet_info *pinfo, const char *name)
+{
+ GSList *source = pinfo->data_src;
+ for (source = pinfo->data_src; source; source = source->next) {
+ struct data_source *this_source = (struct data_source *)source;
+ if (this_source->name && strcmp(this_source->name, name) == 0) {
+ return this_source->tvb;
+ }
+ }
+ return NULL;
+}
+
+
+/*
* Free up a frame's list of data sources.
*/
void
diff --git a/epan/packet.h b/epan/packet.h
index 5c128d5f4c..9d4efaf02d 100644
--- a/epan/packet.h
+++ b/epan/packet.h
@@ -696,6 +696,7 @@ WS_DLL_PUBLIC void remove_last_data_source(packet_info *pinfo);
struct data_source;
WS_DLL_PUBLIC char *get_data_source_name(const struct data_source *src);
WS_DLL_PUBLIC tvbuff_t *get_data_source_tvb(const struct data_source *src);
+WS_DLL_PUBLIC tvbuff_t *get_data_source_tvb_by_name(packet_info *pinfo, const char *name);
/*
* Free up a frame's list of data sources.