forked from osmocom/wireshark
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>
This commit is contained in:
parent
01ddd93a72
commit
1bfa581529
|
@ -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);
|
||||
|
|
|
@ -402,6 +402,23 @@ get_data_source_tvb(const struct data_source *src)
|
|||
return src->tvb;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue