From Greg Morris: code to support searches for text or raw binary data

in a frame in Find Frame.

svn path=/trunk/; revision=8067
This commit is contained in:
Guy Harris 2003-07-22 23:08:48 +00:00
parent d6ed142549
commit 487d0def6b
5 changed files with 368 additions and 19 deletions

View File

@ -1307,6 +1307,7 @@ Andrew Esh <Andrew.Esh[AT]tricord.com> {
Greg Morris <GMORRIS[AT]novell.com> { Greg Morris <GMORRIS[AT]novell.com> {
NCP - NetWare Core Protocol NCP - NetWare Core Protocol
NDPS - Novell Distributed Print System NDPS - Novell Distributed Print System
"Find Frame" code to search for text or binary data
} }
Dirk Steinberg <dws[AT]dirksteinberg.de> { Dirk Steinberg <dws[AT]dirksteinberg.de> {

View File

@ -1,7 +1,7 @@
/* cfile.h /* cfile.h
* capture_file definition & GUI-independent manipulation * capture_file definition & GUI-independent manipulation
* *
* $Id: cfile.h,v 1.1 2002/09/06 23:14:04 sahlberg Exp $ * $Id: cfile.h,v 1.2 2003/07/22 23:08:47 guy Exp $
* *
* Ethereal - Network traffic analyzer * Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com> * By Gerald Combs <gerald@ethereal.com>
@ -65,6 +65,9 @@ typedef struct _capture_file {
#endif #endif
gchar *sfilter; /* Search filter string */ gchar *sfilter; /* Search filter string */
gboolean sbackward; /* TRUE if search is backward, FALSE if forward */ gboolean sbackward; /* TRUE if search is backward, FALSE if forward */
gboolean hex; /* TRUE is Hex search is being performed */
gboolean ascii; /* TRUE is ASCII search is being performed */
char *ftype; /* Find Frame String Type */
union wtap_pseudo_header pseudo_header; /* Packet pseudo_header */ union wtap_pseudo_header pseudo_header; /* Packet pseudo_header */
guint8 pd[WTAP_MAX_PACKET_SIZE]; /* Packet data */ guint8 pd[WTAP_MAX_PACKET_SIZE]; /* Packet data */
GMemChunk *plist_chunk; /* Memory chunk for frame_data structures */ GMemChunk *plist_chunk; /* Memory chunk for frame_data structures */

242
file.c
View File

@ -1,7 +1,7 @@
/* file.c /* file.c
* File I/O routines * File I/O routines
* *
* $Id: file.c,v 1.299 2003/06/24 06:14:46 guy Exp $ * $Id: file.c,v 1.300 2003/07/22 23:08:47 guy Exp $
* *
* Ethereal - Network traffic analyzer * Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com> * By Gerald Combs <gerald@ethereal.com>
@ -1428,6 +1428,246 @@ change_time_formats(capture_file *cf)
thaw_plist(cf); thaw_plist(cf);
} }
guint8
get_int_value(char char_val)
{
switch (char_val) {
case 'a':
case 'A':
return(10);
case 'b':
case 'B':
return(11);
case 'c':
case 'C':
return(12);
case 'd':
case 'D':
return(13);
case 'e':
case 'E':
return(14);
case 'f':
case 'F':
return(15);
default:
return(atoi(&char_val));
}
}
gboolean
find_ascii(capture_file *cf, char *ascii_text, gboolean ascii_search, char *ftype)
{
frame_data *start_fd;
frame_data *fdata;
frame_data *new_fd = NULL;
progdlg_t *progbar = NULL;
gboolean stop_flag;
int count;
int err;
guint32 i;
guint16 c_match=0;
gboolean frame_matched;
int row;
float prog_val;
GTimeVal start_time;
gchar status_str[100];
guint8 c_char=0;
guint32 buf_len=0;
guint8 hex_val=0;
char char_val;
guint8 num1, num2;
start_fd = cf->current_frame;
if (start_fd != NULL) {
/* Iterate through the list of packets, starting at the packet we've
picked, calling a routine to run the filter on the packet, see if
it matches, and stop if so. */
count = 0;
fdata = start_fd;
cf->progbar_nextstep = 0;
/* When we reach the value that triggers a progress bar update,
bump that value by this amount. */
cf->progbar_quantum = cf->count/N_PROGBAR_UPDATES;
stop_flag = FALSE;
g_get_current_time(&start_time);
fdata = start_fd;
for (;;) {
/* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
when we update it, we have to run the GTK+ main loop to get it
to repaint what's pending, and doing so may involve an "ioctl()"
to see if there's any pending input from an X server, and doing
that for every packet can be costly, especially on a big file. */
if (count >= cf->progbar_nextstep) {
/* let's not divide by zero. I should never be started
* with count == 0, so let's assert that
*/
g_assert(cf->count > 0);
prog_val = (gfloat) count / cf->count;
/* Create the progress bar if necessary */
if (progbar == NULL)
progbar = delayed_create_progress_dlg("Searching", cf->sfilter, "Cancel",
&stop_flag, &start_time, prog_val);
if (progbar != NULL) {
g_snprintf(status_str, sizeof(status_str),
"%4u of %u frames", count, cf->count);
update_progress_dlg(progbar, prog_val, status_str);
}
cf->progbar_nextstep += cf->progbar_quantum;
}
if (stop_flag) {
/* Well, the user decided to abort the search. Go back to the
frame where we started. */
new_fd = start_fd;
break;
}
/* Go past the current frame. */
if (cf->sbackward) {
/* Go on to the previous frame. */
fdata = fdata->prev;
if (fdata == NULL)
fdata = cf->plist_end; /* wrap around */
} else {
/* Go on to the next frame. */
fdata = fdata->next;
if (fdata == NULL)
fdata = cf->plist; /* wrap around */
}
count++;
/* Is this packet in the display? */
if (fdata->flags.passed_dfilter) {
/* Yes. Does it match the search filter? */
/* XXX - do something with "err" */
wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
cf->pd, fdata->cap_len, &err);
frame_matched = FALSE;
buf_len = fdata->pkt_len;
for (i=0;i<buf_len;i++) {
c_char = cf->pd[i];
/* Check to see if this is an String or Hex search */
if (ascii_search) {
/* Now check the String Type */
if(strcmp(ftype,"ASCII Unicode & Non-Unicode")==0)
{
if (c_char != 0) {
if (c_char == ascii_text[c_match]) {
c_match++;
if (c_match == strlen(ascii_text)) {
frame_matched = TRUE;
break;
}
}
else
{
c_match = 0;
}
}
}
else if(strcmp(ftype,"ASCII Non-Unicode")==0)
{
if (c_char == ascii_text[c_match]) {
c_match++;
if (c_match == strlen(ascii_text)) {
frame_matched = TRUE;
break;
}
}
else
{
c_match = 0;
}
}
else if(strcmp(ftype, "ASCII Unicode")==0)
{
if (c_char == ascii_text[c_match]) {
c_match++;
i++;
if (c_match == strlen(ascii_text)) {
frame_matched = TRUE;
break;
}
}
else
{
c_match = 0;
}
}
else if(strcmp(ftype,"EBCDIC")==0)
{
simple_dialog(ESD_TYPE_CRIT, NULL,
"EBCDIC Find Not supported yet.");
return TRUE;
}
else
{
simple_dialog(ESD_TYPE_CRIT, NULL,
"Invalid String type specified.");
return TRUE;
}
}
else /* Hex Search */
{
char_val = ascii_text[c_match];
num1 = get_int_value(char_val);
char_val = ascii_text[++c_match];
num2 = get_int_value(char_val);
hex_val = (num1*0x10)+num2;
if ( c_char == hex_val) {
c_match++;
if (c_match == strlen(ascii_text)) {
frame_matched = TRUE;
break;
}
}
else
{
c_match = 0;
}
}
}
if (frame_matched) {
new_fd = fdata;
break; /* found it! */
}
}
if (fdata == start_fd) {
/* We're back to the frame we were on originally, and that frame
doesn't match the search filter. The search failed. */
break;
}
}
/* We're done scanning the packets; destroy the progress bar if it
was created. */
if (progbar != NULL)
destroy_progress_dlg(progbar);
}
if (new_fd != NULL) {
/* We found a frame. Find what row it's in. */
row = packet_list_find_row_from_data(new_fd);
g_assert(row != -1);
/* Select that row, make it the focus row, and make it visible. */
packet_list_set_selected_row(row);
return TRUE; /* success */
} else
return FALSE; /* failure */
}
gboolean gboolean
find_packet(capture_file *cf, dfilter_t *sfcode) find_packet(capture_file *cf, dfilter_t *sfcode)
{ {

4
file.h
View File

@ -1,7 +1,7 @@
/* file.h /* file.h
* Definitions for file structures and routines * Definitions for file structures and routines
* *
* $Id: file.h,v 1.99 2003/03/02 22:07:21 guy Exp $ * $Id: file.h,v 1.100 2003/07/22 23:08:47 guy Exp $
* *
* Ethereal - Network traffic analyzer * Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com> * By Gerald Combs <gerald@ethereal.com>
@ -56,6 +56,8 @@ void redissect_packets(capture_file *cf);
int print_packets(capture_file *cf, print_args_t *print_args); int print_packets(capture_file *cf, print_args_t *print_args);
void change_time_formats(capture_file *); void change_time_formats(capture_file *);
gboolean find_packet(capture_file *cf, dfilter_t *sfcode); gboolean find_packet(capture_file *cf, dfilter_t *sfcode);
guint8 get_int_value(char char_val);
gboolean find_ascii(capture_file *cf, char *ascii_text, gboolean ascii_search, char *ftype);
gboolean goto_frame(capture_file *cf, guint fnumber); gboolean goto_frame(capture_file *cf, guint fnumber);

View File

@ -1,7 +1,7 @@
/* find_dlg.c /* find_dlg.c
* Routines for "find frame" window * Routines for "find frame" window
* *
* $Id: find_dlg.c,v 1.28 2003/04/24 23:18:07 guy Exp $ * $Id: find_dlg.c,v 1.29 2003/07/22 23:08:48 guy Exp $
* *
* Ethereal - Network traffic analyzer * Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com> * By Gerald Combs <gerald@ethereal.com>
@ -39,10 +39,16 @@
#include "simple_dialog.h" #include "simple_dialog.h"
#include "dlg_utils.h" #include "dlg_utils.h"
#include "compat_macros.h" #include "compat_macros.h"
#include "prefs.h"
#include "prefs_dlg.h"
/* Capture callback data keys */ /* Capture callback data keys */
#define E_FIND_FILT_KEY "find_filter_te" #define E_FIND_FILT_KEY "find_filter_te"
#define E_FIND_BACKWARD_KEY "find_backward" #define E_FIND_BACKWARD_KEY "find_backward"
#define E_FIND_HEXDATA_KEY "find_hex"
#define E_FIND_ASCIIDATA_KEY "find_ascii"
#define E_FIND_FILTERDATA_KEY "find_filter"
#define E_FIND_STRINGTYPE_KEY "find_string_type"
static void static void
find_frame_ok_cb(GtkWidget *ok_bt, gpointer parent_w); find_frame_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
@ -66,10 +72,13 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_)
{ {
GtkWidget *main_vb, *filter_hb, *filter_bt, *filter_te, GtkWidget *main_vb, *filter_hb, *filter_bt, *filter_te,
*direction_hb, *forward_rb, *backward_rb, *direction_hb, *forward_rb, *backward_rb,
*hex_hb, *hex_rb, *ascii_rb, *filter_rb,
*combo_hb, *combo_cb, *combo_lb,
*bbox, *ok_bt, *cancel_bt; *bbox, *ok_bt, *cancel_bt;
#if GTK_MAJOR_VERSION < 2 #if GTK_MAJOR_VERSION < 2
GtkAccelGroup *accel_group; GtkAccelGroup *accel_group;
#endif #endif
GList *glist = NULL;
/* No Apply button, but "OK" not only sets our text widget, it /* No Apply button, but "OK" not only sets our text widget, it
activates it (i.e., it causes us to do the search). */ activates it (i.e., it causes us to do the search). */
static construct_args_t args = { static construct_args_t args = {
@ -145,6 +154,71 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_)
gtk_box_pack_start(GTK_BOX(direction_hb), backward_rb, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(direction_hb), backward_rb, TRUE, TRUE, 0);
gtk_widget_show(backward_rb); gtk_widget_show(backward_rb);
/* Filter/Hex/Ascii Search */
/* Filter */
hex_hb = gtk_hbox_new(FALSE, 3);
gtk_container_add(GTK_CONTAINER(main_vb), hex_hb);
gtk_widget_show(hex_hb);
#if GTK_MAJOR_VERSION < 2
filter_rb = dlg_radio_button_new_with_label_with_mnemonic(NULL, "_Display Filter",
accel_group);
#else
filter_rb = gtk_radio_button_new_with_mnemonic(NULL, "_Display Filter");
#endif
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(filter_rb), !cfile.hex && !cfile.ascii);
gtk_box_pack_start(GTK_BOX(hex_hb), filter_rb, TRUE, TRUE, 0);
gtk_widget_show(filter_rb);
/* Hex */
#if GTK_MAJOR_VERSION < 2
hex_rb = dlg_radio_button_new_with_label_with_mnemonic(
gtk_radio_button_group(GTK_RADIO_BUTTON(filter_rb)),
"_Hex", accel_group);
#else
hex_rb = gtk_radio_button_new_with_mnemonic_from_widget(
GTK_RADIO_BUTTON(filter_rb), "_Hex");
#endif
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(hex_rb), cfile.hex);
gtk_box_pack_start(GTK_BOX(hex_hb), hex_rb, TRUE, TRUE, 0);
gtk_widget_show(hex_rb);
/* ASCII Search */
#if GTK_MAJOR_VERSION < 2
ascii_rb = dlg_radio_button_new_with_label_with_mnemonic(
gtk_radio_button_group(GTK_RADIO_BUTTON(filter_rb)),
"_String", accel_group);
#else
ascii_rb = gtk_radio_button_new_with_mnemonic_from_widget(
GTK_RADIO_BUTTON(filter_rb), "_String");
#endif
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(ascii_rb), cfile.ascii);
gtk_box_pack_start(GTK_BOX(hex_hb), ascii_rb, TRUE, TRUE, 0);
gtk_widget_show(ascii_rb);
/* String Type Selection Dropdown Box */
combo_hb = gtk_hbox_new(FALSE, 3);
gtk_container_add(GTK_CONTAINER(main_vb), combo_hb);
gtk_widget_show(combo_hb);
/* Create Label */
combo_lb = gtk_label_new("Find String Type:");
gtk_box_pack_start(GTK_BOX(combo_hb), combo_lb, FALSE, FALSE, 6);
gtk_widget_show(combo_lb);
/* Create Combo Box */
combo_cb = gtk_combo_new();
/*gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "Find String Type:");*/
glist = g_list_append(glist, "ASCII Unicode & Non-Unicode");
glist = g_list_append(glist, "ASCII Non-Unicode");
glist = g_list_append(glist, "ASCII Unicode");
glist = g_list_append(glist, "EBCDIC");
gtk_combo_set_popdown_strings(GTK_COMBO(combo_cb), glist);
gtk_container_add(GTK_CONTAINER(main_vb), combo_cb);
gtk_widget_show(combo_cb);
/* Button row: OK and cancel buttons */ /* Button row: OK and cancel buttons */
bbox = gtk_hbutton_box_new(); bbox = gtk_hbutton_box_new();
gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
@ -176,6 +250,11 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_)
/* Attach pointers to needed widgets to the capture prefs window/object */ /* Attach pointers to needed widgets to the capture prefs window/object */
OBJECT_SET_DATA(find_frame_w, E_FIND_FILT_KEY, filter_te); OBJECT_SET_DATA(find_frame_w, E_FIND_FILT_KEY, filter_te);
OBJECT_SET_DATA(find_frame_w, E_FIND_BACKWARD_KEY, backward_rb); OBJECT_SET_DATA(find_frame_w, E_FIND_BACKWARD_KEY, backward_rb);
OBJECT_SET_DATA(find_frame_w, E_FIND_FILTERDATA_KEY, filter_rb);
OBJECT_SET_DATA(find_frame_w, E_FIND_HEXDATA_KEY, hex_rb);
OBJECT_SET_DATA(find_frame_w, E_FIND_ASCIIDATA_KEY, ascii_rb);
OBJECT_SET_DATA(find_frame_w, E_FIND_STRINGTYPE_KEY, combo_cb);
/* Catch the "activate" signal on the filter text entry, so that /* Catch the "activate" signal on the filter text entry, so that
if the user types Return there, we act as if the "OK" button if the user types Return there, we act as if the "OK" button
@ -197,29 +276,33 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_)
static void static void
find_frame_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w) find_frame_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
{ {
GtkWidget *filter_te, *backward_rb; GtkWidget *filter_te, *backward_rb, *hex_rb, *ascii_rb, *combo_cb;
gchar *filter_text; gchar *filter_text, *string_type;
dfilter_t *sfcode; dfilter_t *sfcode;
filter_te = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_FILT_KEY); filter_te = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_FILT_KEY);
backward_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_BACKWARD_KEY); backward_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_BACKWARD_KEY);
hex_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_HEXDATA_KEY);
ascii_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_ASCIIDATA_KEY);
combo_cb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_STRINGTYPE_KEY);
filter_text = gtk_entry_get_text(GTK_ENTRY(filter_te)); filter_text = gtk_entry_get_text(GTK_ENTRY(filter_te));
string_type = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_cb)->entry));
/* /*
* Try to compile the filter. * Try to compile the filter.
*/ */
if (!dfilter_compile(filter_text, &sfcode)) { if (!dfilter_compile(filter_text, &sfcode) && !GTK_TOGGLE_BUTTON (hex_rb)->active && !GTK_TOGGLE_BUTTON (ascii_rb)->active) {
/* The attempt failed; report an error. */ /* The attempt failed; report an error. */
simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg); simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
return; return;
} }
/* Was it empty? */ /* Was it empty? */
if (sfcode == NULL) { if (sfcode == NULL && !GTK_TOGGLE_BUTTON (hex_rb)->active && !GTK_TOGGLE_BUTTON (ascii_rb)->active) {
/* Yes - complain. */ /* Yes - complain. */
simple_dialog(ESD_TYPE_CRIT, NULL, simple_dialog(ESD_TYPE_CRIT, NULL,
"You didn't specify a filter to use when searching for a frame."); "You didn't specify valid search criteria.");
return; return;
} }
@ -231,13 +314,25 @@ find_frame_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
cfile.sfilter = g_strdup(filter_text); cfile.sfilter = g_strdup(filter_text);
cfile.sbackward = GTK_TOGGLE_BUTTON (backward_rb)->active; cfile.sbackward = GTK_TOGGLE_BUTTON (backward_rb)->active;
cfile.hex = GTK_TOGGLE_BUTTON (hex_rb)->active;
cfile.ascii = GTK_TOGGLE_BUTTON (ascii_rb)->active;
cfile.ftype = g_strdup(string_type);
if (!GTK_TOGGLE_BUTTON (hex_rb)->active && !GTK_TOGGLE_BUTTON (ascii_rb)->active ) {
if (!find_packet(&cfile, sfcode)) { if (!find_packet(&cfile, sfcode)) {
/* We didn't find the packet. */ /* We didn't find the packet. */
simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched that filter."); simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched that filter.");
return; return;
} }
}
else
{
if (!find_ascii(&cfile, filter_text, cfile.ascii, string_type)) {
/* We didn't find the packet. */
simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched search criteria.");
return;
}
}
gtk_widget_destroy(GTK_WIDGET(parent_w)); gtk_widget_destroy(GTK_WIDGET(parent_w));
} }
@ -260,13 +355,21 @@ find_previous_next(GtkWidget *w, gpointer d, gboolean sens)
{ {
dfilter_t *sfcode; dfilter_t *sfcode;
if (cfile.sfilter) { if (cfile.sfilter) {
if (!dfilter_compile(cfile.sfilter, &sfcode)) if (!dfilter_compile(cfile.sfilter, &sfcode) && !cfile.hex && !cfile.ascii)
return; return;
if (sfcode == NULL) if (sfcode == NULL && !cfile.hex && !cfile.ascii)
return; return;
cfile.sbackward = sens; cfile.sbackward = sens;
if (cfile.hex || cfile.ascii)
{
find_ascii(&cfile, cfile.sfilter, cfile.ascii, cfile.ftype);
}
else
{
find_packet(&cfile, sfcode); find_packet(&cfile, sfcode);
}
} else } else
find_frame_cb(w, d); find_frame_cb(w, d);
} }