diff --git a/file.c b/file.c index 97e457bebf..46159b89ef 100644 --- a/file.c +++ b/file.c @@ -94,18 +94,32 @@ static match_result match_summary_line(capture_file *cf, frame_data *fdata, wtap_rec *, Buffer *, void *criterion); static match_result match_narrow_and_wide(capture_file *cf, frame_data *fdata, wtap_rec *, Buffer *, void *criterion); +static match_result match_narrow_and_wide_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *, Buffer *, void *criterion); static match_result match_narrow_and_wide_case(capture_file *cf, frame_data *fdata, wtap_rec *, Buffer *, void *criterion); +static match_result match_narrow_and_wide_case_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *, Buffer *, void *criterion); static match_result match_narrow_case(capture_file *cf, frame_data *fdata, wtap_rec *, Buffer *, void *criterion); +static match_result match_narrow_case_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *, Buffer *, void *criterion); static match_result match_wide(capture_file *cf, frame_data *fdata, wtap_rec *, Buffer *, void *criterion); +static match_result match_wide_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *, Buffer *, void *criterion); static match_result match_wide_case(capture_file *cf, frame_data *fdata, wtap_rec *, Buffer *, void *criterion); +static match_result match_wide_case_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *, Buffer *, void *criterion); static match_result match_binary(capture_file *cf, frame_data *fdata, wtap_rec *, Buffer *, void *criterion); +static match_result match_binary_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *, Buffer *, void *criterion); static match_result match_regex(capture_file *cf, frame_data *fdata, wtap_rec *, Buffer *, void *criterion); +static match_result match_regex_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *, Buffer *, void *criterion); static match_result match_dfilter(capture_file *cf, frame_data *fdata, wtap_rec *, Buffer *, void *criterion); static match_result match_marked(capture_file *cf, frame_data *fdata, @@ -3536,11 +3550,12 @@ typedef struct { gboolean cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size, - search_direction dir) + search_direction dir, bool multiple) { cbs_t info; guint8 needles[3]; - ws_mempbrk_pattern pattern; + ws_mempbrk_pattern pattern = {0}; + ws_match_function match_function; info.data = string; info.data_len = string_size; @@ -3548,7 +3563,7 @@ cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size, /* Regex, String or hex search? */ if (cf->regex) { /* Regular Expression search */ - return find_packet(cf, match_regex, NULL, dir); + match_function = (cf->dir == SD_FORWARD) ? match_regex : match_regex_reverse; } else if (cf->string) { /* String search - what type of string? */ if (cf->case_type) { @@ -3560,13 +3575,16 @@ cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size, switch (cf->scs_type) { case SCS_NARROW_AND_WIDE: - return find_packet(cf, match_narrow_and_wide_case, &info, dir); + match_function = (cf->dir == SD_FORWARD) ? match_narrow_and_wide_case : match_narrow_and_wide_case_reverse; + break; case SCS_NARROW: - return find_packet(cf, match_narrow_case, &info, dir); + match_function = (cf->dir == SD_FORWARD) ? match_narrow_case : match_narrow_case_reverse; + break; case SCS_WIDE: - return find_packet(cf, match_wide_case, &info, dir); + match_function = (cf->dir == SD_FORWARD) ? match_wide_case : match_wide_case_reverse; + break; default: ws_assert_not_reached(); @@ -3577,23 +3595,51 @@ cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size, switch (cf->scs_type) { case SCS_NARROW_AND_WIDE: - return find_packet(cf, match_narrow_and_wide, &info, dir); + match_function = (cf->dir == SD_FORWARD) ? match_narrow_and_wide : match_narrow_and_wide_reverse; + break; case SCS_NARROW: /* Narrow, case-sensitive match is the same as looking * for a converted hexstring. */ - return find_packet(cf, match_binary, &info, dir); + match_function = (cf->dir == SD_FORWARD) ? match_binary : match_binary_reverse; + break; case SCS_WIDE: - return find_packet(cf, match_wide, &info, dir); + match_function = (cf->dir == SD_FORWARD) ? match_wide : match_wide_reverse; + break; default: ws_assert_not_reached(); return FALSE; } } - } else - return find_packet(cf, match_binary, &info, dir); + } else { + match_function = (cf->dir == SD_FORWARD) ? match_binary : match_binary_reverse; + } + + if (multiple && cf->current_frame && (cf->search_pos || cf->search_len)) { + /* Use the current frame (this will perform the equivalent of + * cf_read_current_record() in match_function). + */ + if (match_function(cf, cf->current_frame, &cf->rec, &cf->buf, &info)) { + cf->search_in_progress = TRUE; + if (cf->edt) { + field_info *fi = NULL; + /* The regex match can match an empty string. */ + if (cf->search_len) { + fi = proto_find_field_from_offset(cf->edt->tree, cf->search_pos + cf->search_len - 1, cf->edt->tvb); + } + packet_list_select_finfo(fi); + } else { + packet_list_select_row_from_data(cf->current_frame); + } + cf->search_in_progress = FALSE; + return TRUE; + } + } + cf->search_pos = 0; /* Reset the position */ + cf->search_len = 0; /* Reset length */ + return find_packet(cf, match_function, &info, dir); } static match_result @@ -3620,7 +3666,12 @@ match_narrow_and_wide(capture_file *cf, frame_data *fdata, buf_len = fdata->cap_len; buf_start = ws_buffer_start_ptr(buf); buf_end = buf_start + buf_len; - for (pd = buf_start; pd < buf_end; pd++) { + pd = buf_start; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte past the previous match start */ + pd += cf->search_pos + 1; + } + for (; pd < buf_end; pd++) { pd = (guint8 *)memchr(pd, ascii_text[0], buf_end - pd); if (pd == NULL) break; /* Try narrow match at this start location */ @@ -3632,8 +3683,8 @@ match_narrow_and_wide(capture_file *cf, frame_data *fdata, if (c_match == textlen) { result = MR_MATCHED; /* Save position and length for highlighting the field. */ - cf->search_pos = (guint32)(pd - buf_start); - cf->search_len = (guint32)(textlen); + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); goto done; } } else { @@ -3650,8 +3701,87 @@ match_narrow_and_wide(capture_file *cf, frame_data *fdata, if (c_match == textlen) { result = MR_MATCHED; /* Save position and length for highlighting the field. */ - cf->search_pos = (guint32)(pd - buf_start); - cf->search_len = (guint32)(textlen); + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); + goto done; + } + i++; + if (pd + i >= buf_end || pd[i] != '\0') break; + } else { + break; + } + } + } + +done: + return result; +} + +static match_result +match_narrow_and_wide_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *rec, Buffer *buf, void *criterion) +{ + cbs_t *info = (cbs_t *)criterion; + const guint8 *ascii_text = info->data; + size_t textlen = info->data_len; + match_result result; + guint32 buf_len; + guint8 *pd, *buf_start, *buf_end; + guint32 i; + guint8 c_char; + size_t c_match = 0; + + /* Load the frame's data. */ + if (!cf_read_record(cf, fdata, rec, buf)) { + /* Attempt to get the packet failed. */ + return MR_ERROR; + } + + result = MR_NOTMATCHED; + /* Has to be room to hold the sought data. */ + if (textlen > fdata->cap_len) { + return result; + } + buf_len = fdata->cap_len; + buf_start = ws_buffer_start_ptr(buf); + buf_end = buf_start + buf_len; + pd = buf_end - textlen; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte before the previous match start */ + pd = buf_start + cf->search_pos - 1; + } + for (; pd < buf_end; pd++) { + pd = (uint8_t *)ws_memrchr(buf_start, ascii_text[0], pd - buf_start + 1); + if (pd == NULL) break; + /* Try narrow match at this start location */ + c_match = 0; + for (i = 0; pd + i < buf_end; i++) { + c_char = pd[i]; + if (c_char == ascii_text[c_match]) { + c_match++; + if (c_match == textlen) { + result = MR_MATCHED; + /* Save position and length for highlighting the field. */ + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); + goto done; + } + } else { + break; + } + } + + /* Now try wide match at the same start location. */ + c_match = 0; + for (i = 0; pd + i < buf_end; i++) { + c_char = pd[i]; + if (c_char == ascii_text[c_match]) { + c_match++; + if (c_match == textlen) { + result = MR_MATCHED; + /* Save position and length for highlighting the field. */ + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); goto done; } i++; @@ -3694,7 +3824,12 @@ match_narrow_and_wide_case(capture_file *cf, frame_data *fdata, buf_len = fdata->cap_len; buf_start = ws_buffer_start_ptr(buf); buf_end = buf_start + buf_len; - for (pd = buf_start; pd < buf_end; pd++) { + pd = buf_start; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte past the previous match start */ + pd += cf->search_pos + 1; + } + for (; pd < buf_end; pd++) { pd = (guint8 *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char); if (pd == NULL) break; /* Try narrow match at this start location */ @@ -3706,8 +3841,8 @@ match_narrow_and_wide_case(capture_file *cf, frame_data *fdata, if (c_match == textlen) { result = MR_MATCHED; /* Save position and length for highlighting the field. */ - cf->search_pos = (guint32)(pd - buf_start); - cf->search_len = (guint32)(textlen); + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); goto done; } } else { @@ -3724,8 +3859,90 @@ match_narrow_and_wide_case(capture_file *cf, frame_data *fdata, if (c_match == textlen) { result = MR_MATCHED; /* Save position and length for highlighting the field. */ - cf->search_pos = (guint32)(pd - buf_start); - cf->search_len = (guint32)(textlen); + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); + goto done; + } + i++; + if (pd + i >= buf_end || pd[i] != '\0') break; + } else { + break; + } + } + } + +done: + return result; +} + +static match_result +match_narrow_and_wide_case_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *rec, Buffer *buf, void *criterion) +{ + cbs_t *info = (cbs_t *)criterion; + const guint8 *ascii_text = info->data; + size_t textlen = info->data_len; + ws_mempbrk_pattern *pattern = info->pattern; + match_result result; + guint32 buf_len; + guint8 *pd, *buf_start, *buf_end; + guint32 i; + guint8 c_char; + size_t c_match = 0; + + /* Load the frame's data. */ + if (!cf_read_record(cf, fdata, rec, buf)) { + /* Attempt to get the packet failed. */ + return MR_ERROR; + } + + ws_assert(pattern != NULL); + + result = MR_NOTMATCHED; + /* Has to be room to hold the sought data. */ + if (textlen > fdata->cap_len) { + return result; + } + buf_len = fdata->cap_len; + buf_start = ws_buffer_start_ptr(buf); + buf_end = buf_start + buf_len; + pd = buf_end - textlen; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte before the previous match start */ + pd = buf_start + cf->search_pos - 1; + } + for (; pd >= buf_start; pd--) { + pd = (guint8 *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char); + if (pd == NULL) break; + /* Try narrow match at this start location */ + c_match = 0; + for (i = 0; pd + i < buf_end; i++) { + c_char = g_ascii_toupper(pd[i]); + if (c_char == ascii_text[c_match]) { + c_match++; + if (c_match == textlen) { + result = MR_MATCHED; + /* Save position and length for highlighting the field. */ + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); + goto done; + } + } else { + break; + } + } + + /* Now try wide match at the same start location. */ + c_match = 0; + for (i = 0; pd + i < buf_end; i++) { + c_char = g_ascii_toupper(pd[i]); + if (c_char == ascii_text[c_match]) { + c_match++; + if (c_match == textlen) { + result = MR_MATCHED; + /* Save position and length for highlighting the field. */ + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); goto done; } i++; @@ -3768,7 +3985,12 @@ match_narrow_case(capture_file *cf, frame_data *fdata, buf_len = fdata->cap_len; buf_start = ws_buffer_start_ptr(buf); buf_end = buf_start + buf_len; - for (pd = buf_start; pd < buf_end; pd++) { + pd = buf_start; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte past the previous match start */ + pd += cf->search_pos + 1; + } + for (; pd < buf_end; pd++) { pd = (guint8 *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char); if (pd == NULL) break; c_match = 0; @@ -3779,8 +4001,69 @@ match_narrow_case(capture_file *cf, frame_data *fdata, if (c_match == textlen) { /* Save position and length for highlighting the field. */ result = MR_MATCHED; - cf->search_pos = (guint32)(pd - buf_start); - cf->search_len = (guint32)(textlen); + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); + goto done; + } + } else { + break; + } + } + } + +done: + return result; +} + +static match_result +match_narrow_case_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *rec, Buffer *buf, void *criterion) +{ + cbs_t *info = (cbs_t *)criterion; + const guint8 *ascii_text = info->data; + size_t textlen = info->data_len; + ws_mempbrk_pattern *pattern = info->pattern; + match_result result; + guint32 buf_len; + guint8 *pd, *buf_start, *buf_end; + guint32 i; + guint8 c_char; + size_t c_match = 0; + + /* Load the frame's data. */ + if (!cf_read_record(cf, fdata, rec, buf)) { + /* Attempt to get the packet failed. */ + return MR_ERROR; + } + + ws_assert(pattern != NULL); + + result = MR_NOTMATCHED; + /* Has to be room to hold the sought data. */ + if (textlen > fdata->cap_len) { + return result; + } + buf_len = fdata->cap_len; + buf_start = ws_buffer_start_ptr(buf); + buf_end = buf_start + buf_len; + pd = buf_end - textlen; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte before the previous match start */ + pd = buf_start + cf->search_pos - 1; + } + for (; pd >= buf_start; pd--) { + pd = (guint8 *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char); + if (pd == NULL) break; + c_match = 0; + for (i = 0; pd + i < buf_end; i++) { + c_char = g_ascii_toupper(pd[i]); + if (c_char == ascii_text[c_match]) { + c_match++; + if (c_match == textlen) { + /* Save position and length for highlighting the field. */ + result = MR_MATCHED; + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); goto done; } } else { @@ -3817,7 +4100,12 @@ match_wide(capture_file *cf, frame_data *fdata, buf_len = fdata->cap_len; buf_start = ws_buffer_start_ptr(buf); buf_end = buf_start + buf_len; - for (pd = buf_start; pd < buf_end; pd++) { + pd = buf_start; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte past the previous match start */ + pd += cf->search_pos + 1; + } + for (; pd < buf_end; pd++) { pd = (guint8 *)memchr(pd, ascii_text[0], buf_end - pd); if (pd == NULL) break; c_match = 0; @@ -3828,8 +4116,68 @@ match_wide(capture_file *cf, frame_data *fdata, if (c_match == textlen) { result = MR_MATCHED; /* Save position and length for highlighting the field. */ - cf->search_pos = (guint32)(pd - buf_start); - cf->search_len = (guint32)(textlen); + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); + goto done; + } + i++; + if (pd + i >= buf_end || pd[i] != '\0') break; + } else { + break; + } + } + } + +done: + return result; +} + +static match_result +match_wide_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *rec, Buffer *buf, void *criterion) +{ + cbs_t *info = (cbs_t *)criterion; + const guint8 *ascii_text = info->data; + size_t textlen = info->data_len; + match_result result; + guint32 buf_len; + guint8 *pd, *buf_start, *buf_end; + guint32 i; + guint8 c_char; + size_t c_match = 0; + + /* Load the frame's data. */ + if (!cf_read_record(cf, fdata, rec, buf)) { + /* Attempt to get the packet failed. */ + return MR_ERROR; + } + + result = MR_NOTMATCHED; + /* Has to be room to hold the sought data. */ + if (textlen > fdata->cap_len) { + return result; + } + buf_len = fdata->cap_len; + buf_start = ws_buffer_start_ptr(buf); + buf_end = buf_start + buf_len; + pd = buf_end - textlen; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte before the previous match start */ + pd = buf_start + cf->search_pos - 1; + } + for (; pd < buf_end; pd++) { + pd = (uint8_t *)ws_memrchr(buf_start, ascii_text[0], pd - buf_start + 1); + if (pd == NULL) break; + c_match = 0; + for (i = 0; pd + i < buf_end; i++) { + c_char = pd[i]; + if (c_char == ascii_text[c_match]) { + c_match++; + if (c_match == textlen) { + result = MR_MATCHED; + /* Save position and length for highlighting the field. */ + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); goto done; } i++; @@ -3872,7 +4220,12 @@ match_wide_case(capture_file *cf, frame_data *fdata, buf_len = fdata->cap_len; buf_start = ws_buffer_start_ptr(buf); buf_end = buf_start + buf_len; - for (pd = buf_start; pd < buf_end; pd++) { + pd = buf_start; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte past the previous match start */ + pd += cf->search_pos + 1; + } + for (; pd < buf_end; pd++) { pd = (guint8 *)ws_mempbrk_exec(pd, buf_end - pd, pattern, &c_char); if (pd == NULL) break; c_match = 0; @@ -3883,8 +4236,72 @@ match_wide_case(capture_file *cf, frame_data *fdata, if (c_match == textlen) { result = MR_MATCHED; /* Save position and length for highlighting the field. */ - cf->search_pos = (guint32)(pd - buf_start); - cf->search_len = (guint32)(textlen); + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); + goto done; + } + i++; + if (pd + i >= buf_end || pd[i] != '\0') break; + } else { + break; + } + } + } + +done: + return result; +} + +/* Case insensitive match */ +static match_result +match_wide_case_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *rec, Buffer *buf, void *criterion) +{ + cbs_t *info = (cbs_t *)criterion; + const guint8 *ascii_text = info->data; + size_t textlen = info->data_len; + ws_mempbrk_pattern *pattern = info->pattern; + match_result result; + guint32 buf_len; + guint8 *pd, *buf_start, *buf_end; + guint32 i; + guint8 c_char; + size_t c_match = 0; + + /* Load the frame's data. */ + if (!cf_read_record(cf, fdata, rec, buf)) { + /* Attempt to get the packet failed. */ + return MR_ERROR; + } + + ws_assert(pattern != NULL); + + result = MR_NOTMATCHED; + /* Has to be room to hold the sought data. */ + if (textlen > fdata->cap_len) { + return result; + } + buf_len = fdata->cap_len; + buf_start = ws_buffer_start_ptr(buf); + buf_end = buf_start + buf_len; + pd = buf_end - textlen; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte before the previous match start */ + pd = buf_start + cf->search_pos - 1; + } + for (; pd >= buf_start; pd--) { + pd = (guint8 *)ws_memrpbrk_exec(buf_start, pd - buf_start + 1, pattern, &c_char); + if (pd == NULL) break; + c_match = 0; + for (i = 0; pd + i < buf_end; i++) { + c_char = g_ascii_toupper(pd[i]); + if (c_char == ascii_text[c_match]) { + c_match++; + if (c_match == textlen) { + result = MR_MATCHED; + /* Save position and length for highlighting the field. */ + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)(i + 1); goto done; } i++; @@ -3906,7 +4323,7 @@ match_binary(capture_file *cf, frame_data *fdata, cbs_t *info = (cbs_t *)criterion; size_t datalen = info->data_len; match_result result; - const uint8_t *pd, *buf_start; + const uint8_t *pd = NULL, *buf_start; /* Load the frame's data. */ if (!cf_read_record(cf, fdata, rec, buf)) { @@ -3916,7 +4333,14 @@ match_binary(capture_file *cf, frame_data *fdata, result = MR_NOTMATCHED; buf_start = ws_buffer_start_ptr(buf); - pd = ws_memmem(buf_start, fdata->cap_len, info->data, datalen); + size_t offset = 0; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte past the previous match start */ + offset = cf->search_pos + 1; + } + if (offset < fdata->cap_len) { + pd = ws_memmem(buf_start + offset, fdata->cap_len - offset, info->data, datalen); + } if (pd != NULL) { result = MR_MATCHED; /* Save position and length for highlighting the field. */ @@ -3927,6 +4351,47 @@ match_binary(capture_file *cf, frame_data *fdata, return result; } +static match_result +match_binary_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *rec, Buffer *buf, void *criterion) +{ + cbs_t *info = (cbs_t *)criterion; + size_t datalen = info->data_len; + match_result result; + const uint8_t *pd = NULL, *buf_start; + + /* Load the frame's data. */ + if (!cf_read_record(cf, fdata, rec, buf)) { + /* Attempt to get the packet failed. */ + return MR_ERROR; + } + + result = MR_NOTMATCHED; + buf_start = ws_buffer_start_ptr(buf); + /* Has to be room to hold the sought data. */ + if (datalen > fdata->cap_len) { + return result; + } + pd = buf_start + fdata->cap_len - datalen; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte before the previous match start */ + pd = buf_start + cf->search_pos - 1; + } + for (; pd >= buf_start; pd--) { + pd = (uint8_t *)ws_memrchr(buf_start, info->data[0], pd - buf_start + 1); + if (pd == NULL) break; + if (memcmp(pd, info->data, datalen) == 0) { + result = MR_MATCHED; + /* Save position and length for highlighting the field. */ + cf->search_pos = (uint32_t)(pd - buf_start); + cf->search_len = (uint32_t)datalen; + break; + } + } + + return result; +} + static match_result match_regex(capture_file *cf, frame_data *fdata, wtap_rec *rec, Buffer *buf, void *criterion _U_) @@ -3940,18 +4405,62 @@ match_regex(capture_file *cf, frame_data *fdata, return MR_ERROR; } - if (ws_regex_matches_pos(cf->regex, - (const gchar *)ws_buffer_start_ptr(buf), - fdata->cap_len, 0, - result_pos)) { - //TODO: A chosen regex can match the empty string (zero length) - // which doesn't make a lot of sense for searching the packet bytes. - // Should we search with the PCRE2_NOTEMPTY option? - //TODO: Fix cast. - /* Save position and length for highlighting the field. */ - cf->search_pos = (guint32)(result_pos[0]); - cf->search_len = (guint32)(result_pos[1] - result_pos[0]); - result = MR_MATCHED; + size_t offset = 0; + if (cf->search_len || cf->search_pos) { + /* we want to start searching one byte past the previous match start */ + offset = cf->search_pos + 1; + } + if (offset < fdata->cap_len) { + if (ws_regex_matches_pos(cf->regex, + (const gchar *)ws_buffer_start_ptr(buf), + fdata->cap_len, offset, + result_pos)) { + //TODO: A chosen regex can match the empty string (zero length) + // which doesn't make a lot of sense for searching the packet bytes. + // Should we search with the PCRE2_NOTEMPTY option? + //TODO: Fix cast. + /* Save position and length for highlighting the field. */ + cf->search_pos = (guint32)(result_pos[0]); + cf->search_len = (guint32)(result_pos[1] - result_pos[0]); + result = MR_MATCHED; + } + } + return result; +} + +static match_result +match_regex_reverse(capture_file *cf, frame_data *fdata, + wtap_rec *rec, Buffer *buf, void *criterion _U_) +{ + match_result result = MR_NOTMATCHED; + size_t result_pos[2] = {0, 0}; + + /* Load the frame's data. */ + if (!cf_read_record(cf, fdata, rec, buf)) { + /* Attempt to get the packet failed. */ + return MR_ERROR; + } + + size_t offset = fdata->cap_len - 1; + if (cf->search_pos) { + /* we want to start searching one byte before the previous match */ + offset = cf->search_pos - 1; + } + for (; offset > 0; offset--) { + if (ws_regex_matches_pos(cf->regex, + (const gchar *)ws_buffer_start_ptr(buf), + fdata->cap_len, offset, + result_pos)) { + //TODO: A chosen regex can match the empty string (zero length) + // which doesn't make a lot of sense for searching the packet bytes. + // Should we search with the PCRE2_NOTEMPTY option? + //TODO: Fix cast. + /* Save position and length for highlighting the field. */ + cf->search_pos = (guint32)(result_pos[0]); + cf->search_len = (guint32)(result_pos[1] - result_pos[0]); + result = MR_MATCHED; + break; + } } return result; } @@ -4194,12 +4703,12 @@ find_packet(capture_file *cf, ws_match_function match_function, cf->search_in_progress = TRUE; found_row = packet_list_select_row_from_data(new_fd); cf->search_in_progress = FALSE; - cf->search_pos = 0; /* Reset the position */ - cf->search_len = 0; /* Reset length */ if (!found_row) { /* We didn't find a row corresponding to this frame. This means that the frame isn't being displayed currently, so we can't select it. */ + cf->search_pos = 0; /* Reset the position */ + cf->search_len = 0; /* Reset length */ simple_message_box(ESD_TYPE_INFO, NULL, "The capture file is probably not fully dissected.", "End of capture exceeded."); diff --git a/file.h b/file.h index 0c3e135a8b..bd24ca63fb 100644 --- a/file.h +++ b/file.h @@ -550,10 +550,13 @@ gboolean cf_find_packet_summary_line(capture_file *cf, const char *string, * @param string the string to find * @param string_size the size of the string to find * @param dir direction in which to search + * @param multiple whether to look for the next occurrence of the same string + * in the current packet, or to only match once per frame * @return TRUE if a packet was found, FALSE otherwise */ gboolean cf_find_packet_data(capture_file *cf, const guint8 *string, - size_t string_size, search_direction dir); + size_t string_size, search_direction dir, + bool multiple); /** * Find packet that matches a compiled display filter. diff --git a/ui/logray/logray_main_window_slots.cpp b/ui/logray/logray_main_window_slots.cpp index e592b88e27..4d08656ddb 100644 --- a/ui/logray/logray_main_window_slots.cpp +++ b/ui/logray/logray_main_window_slots.cpp @@ -1253,6 +1253,22 @@ void LograyMainWindow::setMenusForSelectedTreeRow(FieldInformation *finfo) { if (fi && fi->ds_tvb && (fi->length > 0)) { have_packet_bytes = true; } + + if (!(capture_file_.capFile()->search_in_progress && (capture_file_.capFile()->hex || (capture_file_.capFile()->string && capture_file_.capFile()->packet_data)))) { + // If we're not in the middle of a packet bytes search, then set + // search_pos and search_len so that we can start a new search + // from this point. (If we are, then we already set it.) + if (fi && capture_file_.capFile()->edt && (fi->ds_tvb == capture_file_.capFile()->edt->tvb)) { + // We can only do a Packet Bytes search in the main bytes from + // the frame, not from any secondary data sources. (XXX: This + // might be surprising to users, though.) + capture_file_.capFile()->search_pos = (uint32_t)(finfo->position().start + finfo->position().length - 1); + capture_file_.capFile()->search_len = (uint32_t)finfo->position().length; + } else { + capture_file_.capFile()->search_pos = 0; + capture_file_.capFile()->search_len = 0; + } + } } if (capture_file_.capFile() != NULL && fi != NULL) { diff --git a/ui/qt/search_frame.cpp b/ui/qt/search_frame.cpp index a7de48ed0f..e8b6cd9498 100644 --- a/ui/qt/search_frame.cpp +++ b/ui/qt/search_frame.cpp @@ -144,6 +144,9 @@ bool SearchFrame::regexCompile() if (!sf_ui_->caseCheckBox->isChecked()) { flags |= WS_REGEX_CASELESS; } + if (sf_ui_->dirCheckBox->isChecked()) { + flags |= WS_REGEX_ANCHORED; + } if (regex_) { ws_regex_free(regex_); @@ -240,7 +243,11 @@ void SearchFrame::updateWidgets() // (otherwise all strings have already been converted to UTF-8) sf_ui_->charEncodingComboBox->setEnabled(search_type == string_search_ && sf_ui_->searchInComboBox->currentIndex() == in_bytes_); - sf_ui_->multipleCheckBox->setEnabled(sf_ui_->searchInComboBox->isEnabled() && sf_ui_->searchInComboBox->currentIndex() == in_proto_tree_); + // We can search for multiple matches in the same frame if we're doing + // a Proto Tree search or a Frame Bytes search, but not a string/regex + // search in the Packet List, or a display filter search (since those + // don't highlight what fields / offsets caused the match.) + sf_ui_->multipleCheckBox->setEnabled((sf_ui_->searchInComboBox->isEnabled() && sf_ui_->searchInComboBox->currentIndex() != in_packet_list_) || search_type == hex_search_); switch (search_type) { case df_search_: @@ -303,7 +310,7 @@ void SearchFrame::on_searchInComboBox_currentIndexChanged(int idx) break; } - // We only search for multiple occurrences in packet list currently. + // We only search for multiple occurrences in packet list and bytes updateWidgets(); } @@ -474,7 +481,7 @@ void SearchFrame::on_findButton_clicked() if (cap_file_->hex) { /* Hex value in packet data */ - found_packet = cf_find_packet_data(cap_file_, bytes, nbytes, cap_file_->dir); + found_packet = cf_find_packet_data(cap_file_, bytes, nbytes, cap_file_->dir, multiple_occurrences); g_free(bytes); if (!found_packet) { /* We didn't find a packet */ @@ -504,7 +511,7 @@ void SearchFrame::on_findButton_clicked() } } else if (cap_file_->packet_data && string) { /* String in the ASCII-converted packet data */ - found_packet = cf_find_packet_data(cap_file_, (guint8 *) string, strlen(string), cap_file_->dir); + found_packet = cf_find_packet_data(cap_file_, (guint8 *) string, strlen(string), cap_file_->dir, multiple_occurrences); g_free(string); if (!found_packet) { err_string = tr("No packet contained that string in its converted data."); diff --git a/ui/qt/wireshark_main_window_slots.cpp b/ui/qt/wireshark_main_window_slots.cpp index f42a5c149c..f1a9a76342 100644 --- a/ui/qt/wireshark_main_window_slots.cpp +++ b/ui/qt/wireshark_main_window_slots.cpp @@ -1364,6 +1364,22 @@ void WiresharkMainWindow::setMenusForSelectedTreeRow(FieldInformation *finfo) { if (fi && fi->ds_tvb && (fi->length > 0)) { have_packet_bytes = true; } + + if (!(capture_file_.capFile()->search_in_progress && (capture_file_.capFile()->hex || (capture_file_.capFile()->string && capture_file_.capFile()->packet_data)))) { + // If we're not in the middle of a packet bytes search, then set + // search_pos and search_len so that we can start a new search + // from this point. (If we are, then we already set it.) + if (fi && capture_file_.capFile()->edt && (fi->ds_tvb == capture_file_.capFile()->edt->tvb)) { + // We can only do a Packet Bytes search in the main bytes from + // the frame, not from any secondary data sources. (XXX: This + // might be surprising to users, though.) + capture_file_.capFile()->search_pos = (uint32_t)(finfo->position().start + finfo->position().length - 1); + capture_file_.capFile()->search_len = (uint32_t)finfo->position().length; + } else { + capture_file_.capFile()->search_pos = 0; + capture_file_.capFile()->search_len = 0; + } + } } if (capture_file_.capFile() != NULL && fi != NULL) { diff --git a/wsutil/regex.c b/wsutil/regex.c index ee9d80effc..464a42239f 100644 --- a/wsutil/regex.c +++ b/wsutil/regex.c @@ -60,6 +60,8 @@ compile_pcre2(const char *patt, ssize_t size, char **errmsg, unsigned flags) options |= PCRE2_NEVER_UTF; if (flags & WS_REGEX_CASELESS) options |= PCRE2_CASELESS; + if (flags & WS_REGEX_ANCHORED) + options |= PCRE2_ANCHORED; /* By default UTF-8 is off. */ code = pcre2_compile_8((PCRE2_SPTR)patt, diff --git a/wsutil/regex.h b/wsutil/regex.h index 083a4ce858..199779a2af 100644 --- a/wsutil/regex.h +++ b/wsutil/regex.h @@ -26,6 +26,7 @@ ws_regex_compile(const char *patt, char **errmsg); /* By default UTF-8 is off. This option also prevents it from being * turned on using a pattern option. */ #define WS_REGEX_NEVER_UTF (1U << 1) +#define WS_REGEX_ANCHORED (1U << 2) WS_DLL_PUBLIC ws_regex_t * ws_regex_compile_ex(const char *patt, ssize_t size, char **errmsg, unsigned flags);