diff options
-rw-r--r-- | cfile.h | 21 | ||||
-rw-r--r-- | file.c | 819 | ||||
-rw-r--r-- | file.h | 10 | ||||
-rw-r--r-- | gtk/find_dlg.c | 345 |
4 files changed, 605 insertions, 590 deletions
@@ -1,7 +1,7 @@ /* cfile.h * capture_file definition & GUI-independent manipulation * - * $Id: cfile.h,v 1.2 2003/07/22 23:08:47 guy Exp $ + * $Id: cfile.h,v 1.3 2003/08/29 04:03:45 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -33,6 +33,14 @@ typedef enum { FILE_READ_DONE /* Read completed */ } file_state; +/* Character set for text search. */ +typedef enum { + SCS_ASCII_AND_UNICODE, + SCS_ASCII, + SCS_UNICODE + /* add EBCDIC when it's implemented */ +} search_charset_t; + typedef struct _capture_file { file_state state; /* Current state of capture file */ int filed; /* File descriptor of capture file */ @@ -64,10 +72,13 @@ typedef struct _capture_file { gchar *cfilter; /* Capture filter string */ #endif gchar *sfilter; /* Search filter string */ - 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 */ + gboolean sbackward; /* TRUE if search is backward, FALSE if forward */ + gboolean hex; /* TRUE is raw data search is being performed */ + gboolean ascii; /* TRUE is text search is being performed */ + search_charset_t scs_type; /* Character set for text search */ + gboolean case_type; /* TRUE if case-insensitive text search */ + gboolean decode_data; /* TRUE if searching protocol tree text */ + gboolean summary_data; /* TRUE if searching Info column text */ union wtap_pseudo_header pseudo_header; /* Packet pseudo_header */ guint8 pd[WTAP_MAX_PACKET_SIZE]; /* Packet data */ GMemChunk *plist_chunk; /* Memory chunk for frame_data structures */ @@ -1,7 +1,7 @@ /* file.c * File I/O routines * - * $Id: file.c,v 1.303 2003/08/14 22:32:45 sharpe Exp $ + * $Id: file.c,v 1.304 2003/08/29 04:03:45 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -42,6 +42,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <ctype.h> #include <errno.h> #include <signal.h> @@ -97,14 +98,31 @@ static void read_packet(capture_file *cf, long offset); static void rescan_packets(capture_file *cf, const char *action, const char *action_item, gboolean refilter, gboolean redissect); +static gboolean match_protocol_tree(capture_file *cf, frame_data *fdata, + void *criterion); +static void match_subtree_text(GNode *node, gpointer data); +static gboolean match_summary_line(capture_file *cf, frame_data *fdata, + void *criterion); +static gboolean match_ascii_and_unicode(capture_file *cf, frame_data *fdata, + void *criterion); +static gboolean match_ascii(capture_file *cf, frame_data *fdata, + void *criterion); +static gboolean match_unicode(capture_file *cf, frame_data *fdata, + void *criterion); +static gboolean match_binary(capture_file *cf, frame_data *fdata, + void *criterion); +static gboolean match_dfilter(capture_file *cf, frame_data *fdata, + void *criterion); +static gboolean find_packet(capture_file *cf, + gboolean (*match_function)(capture_file *, frame_data *, void *), + void *criterion); + static void freeze_plist(capture_file *cf); static void thaw_plist(capture_file *cf); -static void proto_tree_get_node(GNode *node, gpointer data); static char *file_rename_error_message(int err); static char *file_close_error_message(int err); static gboolean copy_binary_file(char *from_filename, char *to_filename); -static char decode_data[MAX_DECODE_BUFFER_SIZE]; /* Update the progress bar this many times when reading a file. */ #define N_PROGBAR_UPDATES 100 @@ -1448,543 +1466,333 @@ change_time_formats(capture_file *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)); - } -} +typedef struct { + const char *string; + size_t string_len; + capture_file *cf; + gboolean frame_matched; +} match_data; -static char* -get_info_string(epan_dissect_t* edt) +gboolean +find_packet_protocol_tree(capture_file *cf, const char *string) { - int i; + match_data mdata; - for (i=0;i<edt->pi.cinfo->num_cols;i++) { - if (strcmp(edt->pi.cinfo->col_title[i], "Info")==0) { - return edt->pi.cinfo->col_data[i]; - } - } - return NULL; + mdata.string = string; + mdata.string_len = strlen(string); + return find_packet(cf, match_protocol_tree, &mdata); } -/* - * Find the data source for a specified field, and return a pointer - * to the data in it. - */ -static const guint8 * -get_field_data(GSList *src_list, field_info *fi) +static gboolean +match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion) { - GSList *src_le; - data_source *src; - tvbuff_t *src_tvb; - - for (src_le = src_list; src_le != NULL; src_le = src_le->next) { - src = src_le->data; - src_tvb = src->tvb; - if (fi->ds_tvb == src_tvb) { - /* - * Found it. - */ - if(tvb_length_remaining(src_tvb, 0) < fi->length+fi->start){ - return NULL; - } - return tvb_get_ptr(src_tvb, fi->start, fi->length); - } - } - return NULL; /* not found */ + match_data *mdata = criterion; + epan_dissect_t *edt; + + /* Construct the protocol tree, including the displayed text */ + edt = epan_dissect_new(TRUE, TRUE); + /* We don't need the column information */ + epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL); + + /* Iterate through all the nodes, seeing if they have text that matches. */ + mdata->cf = cf; + mdata->frame_matched = FALSE; + g_node_children_foreach((GNode*) edt->tree, G_TRAVERSE_ALL, + match_subtree_text, mdata); + epan_dissect_free(edt); + return mdata->frame_matched; } -/* Print a tree's data, and any child nodes to the buffer. */ -static -void proto_tree_get_node(GNode *node, gpointer data) +static void +match_subtree_text(GNode *node, gpointer data) { - field_info *fi = PITEM_FINFO(node); - print_data *pdata = (print_data*) data; - const guint8 *pd; - gchar label_str[ITEM_LABEL_LENGTH]; - gchar *label_ptr, *string_ptr; - - string_ptr = decode_data; + match_data *mdata = (match_data*) data; + const gchar *string = mdata->string; + size_t string_len = mdata->string_len; + capture_file *cf = mdata->cf; + field_info *fi = PITEM_FINFO(node); + gchar label_str[ITEM_LABEL_LENGTH]; + gchar *label_ptr; + size_t label_len; + guint32 i; + guint8 c_char; + size_t c_match = 0; + + if (mdata->frame_matched) { + /* We already had a match; don't bother doing any more work. */ + return; + } - /* Don't print invisible entries. */ - if (!fi->visible) - return; + /* Don't match invisible entries. */ + if (!fi->visible) + return; - /* was a free format label produced? */ - if (fi->representation) { - label_ptr = fi->representation; - } - else { /* no, make a generic label */ - label_ptr = label_str; - proto_item_fill_label(fi, label_str); - } + /* was a free format label produced? */ + if (fi->representation) { + label_ptr = fi->representation; + } else { + /* no, make a generic label */ + label_ptr = label_str; + proto_item_fill_label(fi, label_str); + } - if (strlen(string_ptr)+strlen(label_ptr) < MAX_DECODE_BUFFER_SIZE) { - strcat(string_ptr, label_ptr); - } - else - { - simple_dialog(ESD_TYPE_CRIT, NULL, "Decode Buffer Size Exceeded."); - return; - } + /* Does that label match? */ + label_len = strlen(label_ptr); + for (i = 0; i < label_len; i++) { + c_char = label_ptr[i]; + if (cf->case_type) + c_char = toupper(c_char); + if (c_char == string[c_match]) { + c_match++; + if (c_match == string_len) { + /* No need to look further; we have a match */ + mdata->frame_matched = TRUE; + return; + } + } else + c_match = 0; + } + + /* Recurse into the subtree, if it exists */ + if (g_node_n_children(node) > 0) + g_node_children_foreach(node, G_TRAVERSE_ALL, match_subtree_text, mdata); +} - /* - * Find the data for this field. - */ - pd = get_field_data(pdata->src_list, fi); - if (pd!=NULL) { - if (strlen(pd) > 0) { - if (strlen(pd)+strlen(string_ptr) < MAX_DECODE_BUFFER_SIZE ) { - strcat(string_ptr, pd); - } - else - { - simple_dialog(ESD_TYPE_CRIT, NULL, "Decode Buffer Size Exceeded."); - return; - } - } - } +gboolean +find_packet_summary_line(capture_file *cf, const char *string) +{ + match_data mdata; - /* If we're printing all levels, or if this node is one with a - subtree and its subtree is expanded, recurse into the subtree, - if it exists. */ - g_assert(fi->tree_type >= -1 && fi->tree_type < num_tree_types); - if (pdata->print_all_levels || - (fi->tree_type >= 0 && tree_is_expanded[fi->tree_type])) { - if (g_node_n_children(node) > 0) { - pdata->level++; - g_node_children_foreach(node, G_TRAVERSE_ALL, - proto_tree_get_node, pdata); - pdata->level--; - } - } + mdata.string = string; + mdata.string_len = strlen(string); + return find_packet(cf, match_summary_line, &mdata); } -gboolean -find_in_gtk_data(capture_file *cf, gpointer *data, char *ascii_text, gboolean case_type, gboolean summary_search) +static gboolean +match_summary_line(capture_file *cf, frame_data *fdata, void *criterion) { - 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; - gchar *uppercase; - epan_dissect_t* new_edt; - char *info_string; - print_data ndata; - - 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; - - if (case_type) { - g_strup(ascii_text); + match_data *mdata = criterion; + const gchar *string = mdata->string; + size_t string_len = mdata->string_len; + epan_dissect_t *edt; + const char *info_column; + size_t info_column_len; + gboolean frame_matched = FALSE; + gint colx; + guint32 i; + guint8 c_char; + size_t c_match = 0; + + /* Don't bother constructing the protocol tree */ + edt = epan_dissect_new(FALSE, FALSE); + /* Get the column information */ + epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo); + + /* Find the Info column */ + for (colx = 0; colx < cf->cinfo.num_cols; colx++) { + if (cf->cinfo.fmt_matx[colx][COL_INFO]) { + /* Found it. See if we match. */ + info_column = edt->pi.cinfo->col_data[colx]; + info_column_len = strlen(info_column); + for (i = 0; i < info_column_len; i++) { + c_char = info_column[i]; + if (cf->case_type) + c_char = toupper(c_char); + if (c_char == string[c_match]) { + c_match++; + if (c_match == string_len) { + frame_matched = TRUE; + break; + } + } else + c_match = 0; } + break; + } + } + epan_dissect_free(edt); + return frame_matched; +} - 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; +typedef struct { + const guint8 *data; + size_t data_len; +} cbs_t; /* "Counted byte string" */ - /* 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); - } +gboolean +find_packet_data(capture_file *cf, const guint8 *string, size_t string_size) +{ + cbs_t info; - cf->progbar_nextstep += cf->progbar_quantum; - } + info.data = string; + info.data_len = string_size; - if (stop_flag) { - /* Well, the user decided to abort the search. Go back to the - frame where we started. */ - new_fd = start_fd; - break; - } + /* String or hex search? */ + if (cf->ascii) { + /* String search - what type of string? */ + switch (cf->scs_type) { - /* 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 */ - } + case SCS_ASCII_AND_UNICODE: + return find_packet(cf, match_ascii_and_unicode, &info); - 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); - new_edt = epan_dissect_new(TRUE, TRUE); - epan_dissect_run(new_edt, &cfile.pseudo_header, cfile.pd, fdata, &cfile.cinfo); - if (summary_search) { - info_string = get_info_string(new_edt); - if (info_string == NULL) { - simple_dialog(ESD_TYPE_CRIT, NULL, "Can't find info column. Terminating."); - return FALSE; - } - } - else - { - strcpy(decode_data,"\0"); - info_string = decode_data; - ndata.level = 0; - ndata.fh = NULL; - ndata.src_list = new_edt->pi.data_src; - ndata.encoding = new_edt->pi.fd->flags.encoding; - ndata.print_all_levels = TRUE; - ndata.print_hex_for_data = FALSE; - ndata.format = 0; - g_node_children_foreach((GNode*) new_edt->tree, G_TRAVERSE_ALL, - proto_tree_get_node, &ndata); - } - if (case_type) { - g_strup(info_string); - } - frame_matched = FALSE; - buf_len = strlen(info_string); - for (i=0;i<buf_len;i++) { - c_char = info_string[i]; - if (c_char == ascii_text[c_match]) { - 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! */ - } - epan_dissect_free(new_edt); - } + case SCS_ASCII: + return find_packet(cf, match_ascii, &info); - 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; - } - } + case SCS_UNICODE: + return find_packet(cf, match_unicode, &info); - /* We're done scanning the packets; destroy the progress bar if it - was created. */ - if (progbar != NULL) - destroy_progress_dlg(progbar); + default: + g_assert_not_reached(); + return FALSE; } + } else + return find_packet(cf, match_binary, &info); +} - 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); +static gboolean +match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion) +{ + cbs_t *info = criterion; + const char *ascii_text = info->data; + size_t textlen = info->data_len; + gboolean frame_matched; + guint32 buf_len; + guint32 i; + guint8 c_char; + size_t c_match = 0; + + frame_matched = FALSE; + buf_len = fdata->pkt_len; + for (i = 0; i < buf_len; i++) { + c_char = cf->pd[i]; + if (cf->case_type) + c_char = toupper(c_char); + if (c_char != 0) { + if (c_char == ascii_text[c_match]) { + c_match++; + if (c_match == textlen) { + frame_matched = TRUE; + break; + } + } else + c_match = 0; + } + } + return frame_matched; +} - /* Select that row, make it the focus row, and make it visible. */ - packet_list_set_selected_row(row); - return TRUE; /* success */ +static gboolean +match_ascii(capture_file *cf, frame_data *fdata, void *criterion) +{ + cbs_t *info = criterion; + const char *ascii_text = info->data; + size_t textlen = info->data_len; + gboolean frame_matched; + guint32 buf_len; + guint32 i; + guint8 c_char; + size_t c_match = 0; + + frame_matched = FALSE; + buf_len = fdata->pkt_len; + for (i = 0; i < buf_len; i++) { + c_char = cf->pd[i]; + if (cf->case_type) + c_char = toupper(c_char); + if (c_char == ascii_text[c_match]) { + c_match++; + if (c_match == textlen) { + frame_matched = TRUE; + break; + } } else - return FALSE; /* failure */ + c_match = 0; + } + return frame_matched; } -gboolean -find_ascii(capture_file *cf, char *ascii_text, gboolean ascii_search, char *ftype, gboolean case_type) +static gboolean +match_unicode(capture_file *cf, frame_data *fdata, void *criterion) { - 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; - gchar *uppercase; - - 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; - - if (case_type && ascii_search) { - g_strup(ascii_text); + cbs_t *info = criterion; + const char *ascii_text = info->data; + size_t textlen = info->data_len; + gboolean frame_matched; + guint32 buf_len; + guint32 i; + guint8 c_char; + size_t c_match = 0; + + frame_matched = FALSE; + buf_len = fdata->pkt_len; + for (i = 0; i < buf_len; i++) { + c_char = cf->pd[i]; + if (cf->case_type) + c_char = toupper(c_char); + if (c_char == ascii_text[c_match]) { + c_match++; + i++; + if (c_match == textlen) { + frame_matched = TRUE; + break; } + } else + c_match = 0; + } + return frame_matched; +} - 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++) { - if (ascii_search && case_type) { - uppercase = &cf->pd[i]; - g_strup(uppercase); - c_char = uppercase[0]; - } - else - 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; - } +static gboolean +match_binary(capture_file *cf, frame_data *fdata, void *criterion) +{ + cbs_t *info = criterion; + const guint8 *binary_data = info->data; + size_t datalen = info->data_len; + gboolean frame_matched; + guint32 buf_len; + guint32 i; + size_t c_match = 0; + + frame_matched = FALSE; + buf_len = fdata->pkt_len; + for (i = 0; i < buf_len; i++) { + if (cf->pd[i] == binary_data[c_match]) { + c_match++; + if (c_match == datalen) { + frame_matched = TRUE; + break; } + } else + c_match = 0; + } + return frame_matched; +} - /* We're done scanning the packets; destroy the progress bar if it - was created. */ - if (progbar != NULL) - destroy_progress_dlg(progbar); - } +gboolean +find_packet_dfilter(capture_file *cf, dfilter_t *sfcode) +{ + return find_packet(cf, match_dfilter, sfcode); +} - 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); +static gboolean +match_dfilter(capture_file *cf, frame_data *fdata, void *criterion) +{ + dfilter_t *sfcode = criterion; + epan_dissect_t *edt; + gboolean frame_matched; - /* 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 */ + edt = epan_dissect_new(TRUE, FALSE); + epan_dissect_prime_dfilter(edt, sfcode); + epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL); + frame_matched = dfilter_apply_edt(sfcode, edt); + epan_dissect_free(edt); + return frame_matched; } -gboolean -find_packet(capture_file *cf, dfilter_t *sfcode) +static gboolean +find_packet(capture_file *cf, + gboolean (*match_function)(capture_file *, frame_data *, void *), + void *criterion) { frame_data *start_fd; frame_data *fdata; @@ -1993,9 +1801,7 @@ find_packet(capture_file *cf, dfilter_t *sfcode) gboolean stop_flag; int count; int err; - gboolean frame_matched; int row; - epan_dissect_t *edt; float prog_val; GTimeVal start_time; gchar status_str[100]; @@ -2069,16 +1875,13 @@ find_packet(capture_file *cf, dfilter_t *sfcode) /* Is this packet in the display? */ if (fdata->flags.passed_dfilter) { - /* Yes. Does it match the search filter? */ + /* Yes. Load its data. */ /* XXX - do something with "err" */ wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header, cf->pd, fdata->cap_len, &err); - edt = epan_dissect_new(TRUE, FALSE); - epan_dissect_prime_dfilter(edt, sfcode); - epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL); - frame_matched = dfilter_apply_edt(sfcode, edt); - epan_dissect_free(edt); - if (frame_matched) { + + /* Does it match the search criterion? */ + if ((*match_function)(cf, fdata, criterion)) { new_fd = fdata; break; /* found it! */ } @@ -1,7 +1,7 @@ /* file.h * Definitions for file structures and routines * - * $Id: file.h,v 1.103 2003/08/11 22:41:09 sharpe Exp $ + * $Id: file.h,v 1.104 2003/08/29 04:03:45 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -55,7 +55,13 @@ void colorize_packets(capture_file *); void redissect_packets(capture_file *cf); int print_packets(capture_file *cf, print_args_t *print_args); void change_time_formats(capture_file *); -gboolean find_packet(capture_file *cf, dfilter_t *sfcode); + +gboolean find_packet_protocol_tree(capture_file *cf, const char *string); +gboolean find_packet_summary_line(capture_file *cf, const char *string); +gboolean find_packet_data(capture_file *cf, const guint8 *string, + size_t string_size); +gboolean find_packet_dfilter(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 case_type); gboolean find_in_gtk_data(capture_file *cf, gpointer *data, char *ascii_text, gboolean case_type, gboolean search_type); diff --git a/gtk/find_dlg.c b/gtk/find_dlg.c index cbdb97b3b8..c0ca252f1d 100644 --- a/gtk/find_dlg.c +++ b/gtk/find_dlg.c @@ -1,7 +1,7 @@ /* find_dlg.c * Routines for "find frame" window * - * $Id: find_dlg.c,v 1.32 2003/08/28 23:25:55 guy Exp $ + * $Id: find_dlg.c,v 1.33 2003/08/29 04:03:46 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -22,11 +22,13 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - #ifdef HAVE_CONFIG_H # include "config.h" #endif +#include <string.h> +#include <ctype.h> + #include <gtk/gtk.h> #include <epan/proto.h> @@ -44,17 +46,17 @@ #include "keys.h" /* Capture callback data keys */ -#define E_FIND_FILT_KEY "find_filter_te" -#define E_FIND_BACKWARD_KEY "find_backward" -#define E_FIND_HEXDATA_KEY "find_hex" -#define E_FIND_ASCIIDATA_KEY "find_ascii" +#define E_FIND_FILT_KEY "find_filter_te" +#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" -#define E_CASE_SEARCH_KEY "case_insensitive_search" -#define E_SOURCE_HEX_KEY "hex_data_source" -#define E_SOURCE_DECODE_KEY "decode_data_source" -#define E_SOURCE_SUMMARY_KEY "summary_data_source" -#define E_FILT_TE_BUTTON_KEY "find_filter_button" +#define E_CASE_SEARCH_KEY "case_insensitive_search" +#define E_SOURCE_HEX_KEY "hex_data_source" +#define E_SOURCE_DECODE_KEY "decode_data_source" +#define E_SOURCE_SUMMARY_KEY "summary_data_source" +#define E_FILT_TE_BUTTON_KEY "find_filter_button" static gboolean case_type = TRUE; static gboolean summary_data = FALSE; @@ -207,7 +209,6 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_) 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_tooltips_set_tip (tooltips, filter_rb, ("Search for data by display filter syntax.\ne.g. ip.addr==10.1.1.1"), NULL); - SIGNAL_CONNECT(filter_rb, "clicked", filter_selected_cb, find_frame_w); gtk_widget_show(filter_rb); /* Hex */ @@ -237,7 +238,6 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_) 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_tooltips_set_tip (tooltips, ascii_rb, ("Search for data by string value.\ne.g. My String"), NULL); - SIGNAL_CONNECT(ascii_rb, "clicked", ascii_selected_cb, find_frame_w); gtk_widget_show(ascii_rb); string_window_frame = gtk_frame_new("Search in"); @@ -306,8 +306,8 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_) 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"); + /* XXX - make it non-editable - or make this an option menu instead */ gtk_combo_set_popdown_strings(GTK_COMBO(combo_cb), glist); gtk_container_border_width(GTK_CONTAINER(combo_cb), 1); gtk_container_add(GTK_CONTAINER(string_char_frame), combo_cb); @@ -375,6 +375,14 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_) OBJECT_SET_DATA(find_frame_w, E_SOURCE_SUMMARY_KEY, summary_data_rb); OBJECT_SET_DATA(find_frame_w, E_FILT_TE_BUTTON_KEY, filter_bt); + /* + * Now that we've attached the pointers, connect the signals - if + * we do so before we've attached the pointers, the signals may + * be delivered before the pointers are attached; the signal + * handlers expect the pointers to be attached, and won't be happy. + */ + SIGNAL_CONNECT(ascii_rb, "clicked", ascii_selected_cb, find_frame_w); + SIGNAL_CONNECT(filter_rb, "clicked", filter_selected_cb, find_frame_w); ascii_selected_cb(NULL, find_frame_w); filter_selected_cb(NULL, find_frame_w); @@ -452,14 +460,118 @@ filter_selected_cb(GtkWidget *button_rb _U_, gpointer parent_w) return; } +static guint8 * +convert_string_to_hex(const char *string, size_t *nbytes) +{ + size_t n_bytes; + const char *p; + guchar c; + guint8 *bytes, *q, byte_val; + + n_bytes = 0; + p = &string[0]; + for (;;) { + c = *p++; + if (c == '\0') + break; + if (isspace(c)) + continue; /* allow white space */ + if (!isxdigit(c)) { + /* Not a valid hex digit - fail */ + return NULL; + } + + /* + * We can only match bytes, not nibbles; we must have a valid + * hex digit immediately after that hex digit. + */ + c = *p++; + if (!isxdigit(c)) + return NULL; + + /* 2 hex digits = 1 byte */ + n_bytes++; + } + + /* + * Were we given any hex digits? + */ + if (n_bytes == 0) { + /* No. */ + return NULL; + } + + /* + * OK, it's valid, and it generates "n_bytes" bytes; generate the + * raw byte array. + */ + bytes = g_malloc(n_bytes); + p = &string[0]; + q = &bytes[0]; + for (;;) { + c = *p++; + if (c == '\0') + break; + if (isspace(c)) + continue; /* allow white space */ + /* From the loop above, we know this is a hex digit */ + if (isdigit(c)) + byte_val = c - '0'; + else if (c >= 'a') + byte_val = (c - 'a') + 10; + else + byte_val = (c - 'A') + 10; + byte_val <<= 4; + + /* We also know this is a hex digit */ + c = *p++; + if (isdigit(c)) + byte_val |= c - '0'; + else if (c >= 'a') + byte_val |= (c - 'a') + 10; + else if (c >= 'A') + byte_val |= (c - 'A') + 10; + + *q++ = byte_val; + } + *nbytes = n_bytes; + return bytes; +} + +static char * +convert_string_case(const char *string, gboolean case_insensitive) +{ + char *out_string; + const char *p; + char c; + char *q; + + /* + * Copy if if it's a case-sensitive search; uppercase it if it's + * a case-insensitive search. + */ + if (case_insensitive) { + out_string = g_malloc(strlen(string) + 1); + for (p = &string[0], q = &out_string[0]; (c = *p) != '\0'; p++, q++) + *q = toupper((unsigned char)*p); + *q = '\0'; + } else + out_string = g_strdup(string); + return out_string; +} static void find_frame_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w) { - GtkWidget *filter_te, *backward_rb, *hex_rb, *ascii_rb, *combo_cb, *case_cb, - *decode_data_rb, *summary_data_rb; - gchar *filter_text, *string_type; - dfilter_t *sfcode; + GtkWidget *filter_te, *backward_rb, *hex_rb, *ascii_rb, *combo_cb, + *case_cb, *decode_data_rb, *summary_data_rb; + gchar *filter_text, *string_type; + search_charset_t scs_type = SCS_ASCII_AND_UNICODE; + guint8 *bytes = NULL; + size_t nbytes; + char *string = NULL; + dfilter_t *sfcode; + gboolean found_packet; filter_te = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_FILT_KEY); backward_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_BACKWARD_KEY); @@ -478,61 +590,116 @@ find_frame_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w) summary_data = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(summary_data_rb)); /* - * Try to compile the filter. + * Process the search criterion. */ - if (!dfilter_compile(filter_text, &sfcode) && !GTK_TOGGLE_BUTTON (hex_rb)->active && !GTK_TOGGLE_BUTTON (ascii_rb)->active) { - /* The attempt failed; report an error. */ - simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg); - return; - } + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (hex_rb))) { + /* + * Hex search - scan the search string to make sure it's valid hex + * and to find out how many bytes there are. + */ + bytes = convert_string_to_hex(filter_text, &nbytes); + if (bytes == NULL) { + simple_dialog(ESD_TYPE_CRIT, NULL, + "You didn't specify a valid hex string."); + return; + } + } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (ascii_rb))) { + /* + * String search. + * Get the character set type. + */ + if (strcmp(string_type, "ASCII Unicode & Non-Unicode") == 0) + scs_type = SCS_ASCII_AND_UNICODE; + else if (strcmp(string_type, "ASCII Non-Unicode") == 0) + scs_type = SCS_ASCII; + else if (strcmp(string_type, "ASCII Unicode") == 0) + scs_type = SCS_UNICODE; + else { + simple_dialog(ESD_TYPE_CRIT, NULL, "You didn't choose a valid character set."); + return; + } + string = convert_string_case(filter_text, case_type); + } else { + /* + * Display filter search - try to compile the filter. + */ + if (!dfilter_compile(filter_text, &sfcode)) { + /* The attempt failed; report an error. */ + simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg); + return; + } - /* Was it empty? */ - if (sfcode == NULL && !GTK_TOGGLE_BUTTON (hex_rb)->active && !GTK_TOGGLE_BUTTON (ascii_rb)->active) { - /* Yes - complain. */ - simple_dialog(ESD_TYPE_CRIT, NULL, - "You didn't specify valid search criteria."); - return; + /* Was it empty? */ + if (sfcode == NULL) { + /* Yes - complain. */ + simple_dialog(ESD_TYPE_CRIT, NULL, + "You didn't specify a valid filter expression."); + return; + } } /* - * Remember the filter. + * Remember the search parameters. */ if (cfile.sfilter) g_free(cfile.sfilter); cfile.sfilter = g_strdup(filter_text); - 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)) { + cfile.hex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (hex_rb)); + cfile.ascii = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (ascii_rb)); + cfile.scs_type = scs_type; + cfile.case_type = case_type; + cfile.decode_data = decode_data; + cfile.summary_data = summary_data; + + if (cfile.hex) { + found_packet = find_packet_data(&cfile, bytes, nbytes); + g_free(bytes); + if (!found_packet) { + /* We didn't find a packet */ + simple_dialog(ESD_TYPE_CRIT, NULL, "No packet contained those bytes."); + g_free(bytes); + return; + } + } else if (cfile.ascii) { + /* OK, what are we searching? */ + if (cfile.decode_data) { + /* The text in the protocol tree */ + found_packet = find_packet_protocol_tree(&cfile, string); + g_free(string); + if (!found_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 contained that string in its dissected display."); return; } - } - else - { - if (!decode_data && !summary_data) { - if (!find_ascii(&cfile, filter_text, cfile.ascii, string_type, case_type)) { - /* We didn't find the packet. */ - simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched search criteria."); - return; - } + } else if (cfile.summary_data) { + /* The text in the summary line */ + found_packet = find_packet_summary_line(&cfile, string); + g_free(string); + if (!found_packet) { + /* We didn't find the packet. */ + simple_dialog(ESD_TYPE_CRIT, NULL, "No packet contained that string in its Info column."); + return; } - else - { - /* Use the cfile.hex to indicate if summary or decode search */ - /* This way the Next and Previous find options will work */ - cfile.hex = summary_data; - if (!find_in_gtk_data(&cfile, parent_w, filter_text, case_type, summary_data)) { - /* We didn't find the packet. */ - simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched search criteria."); - return; - } + } else { + /* The raw packet data */ + found_packet = find_packet_data(&cfile, string, strlen(string)); + g_free(string); + if (!found_packet) { + /* We didn't find the packet. */ + simple_dialog(ESD_TYPE_CRIT, NULL, "No packet contained that string in its data."); + return; } + } + } else { + found_packet = find_packet_dfilter(&cfile, sfcode); + dfilter_free(sfcode); + if (!found_packet) { + /* We didn't find a packet */ + simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched that filter."); + g_free(bytes); + return; + } } gtk_widget_destroy(GTK_WIDGET(parent_w)); } @@ -554,28 +721,56 @@ find_frame_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_) static void find_previous_next(GtkWidget *w, gpointer d, gboolean sens) { + guint8 *bytes; + size_t nbytes; + char *string; dfilter_t *sfcode; - if (cfile.sfilter) { - if (!dfilter_compile(cfile.sfilter, &sfcode) && !cfile.hex && !cfile.ascii) + cfile.sbackward = sens; + if (cfile.hex) { + bytes = convert_string_to_hex(cfile.sfilter, &nbytes); + if (bytes == NULL) { + /* + * XXX - this shouldn't happen, as we've already successfully + * translated the string once. + */ return; - if (sfcode == NULL && !cfile.hex && !cfile.ascii) + } + find_packet_data(&cfile, bytes, nbytes); + g_free(bytes); + } else if (cfile.ascii) { + string = convert_string_case(cfile.sfilter, cfile.case_type); + /* OK, what are we searching? */ + if (cfile.decode_data) { + /* The text in the protocol tree */ + find_packet_protocol_tree(&cfile, string); + } else if (cfile.summary_data) { + /* The text in the summary line */ + find_packet_summary_line(&cfile, string); + } else { + /* The raw packet data */ + find_packet_data(&cfile, string, strlen(string)); + } + g_free(string); + } else { + if (!dfilter_compile(cfile.sfilter, &sfcode)) { + /* + * XXX - this shouldn't happen, as we've already successfully + * translated the string once. + */ return; - cfile.sbackward = sens; - if (cfile.hex || cfile.ascii) - { - if (!decode_data && !summary_data) { - find_ascii(&cfile, cfile.sfilter, cfile.ascii, cfile.ftype, case_type); - } - else { - find_in_gtk_data(&cfile, d, cfile.sfilter, case_type, cfile.hex); - } - } - else - { - find_packet(&cfile, sfcode); - } + } + if (sfcode == NULL) { + /* + * XXX - this shouldn't happen, as we've already found that the + * string wasn't null. + */ + return; + } + find_packet_dfilter(&cfile, sfcode); + dfilter_free(sfcode); + } } else find_frame_cb(w, d); } |