Find: Matching multiple occurrences in Packet Bytes

Match multiple occurrence in Find Packet Bytes, both forwards
and backwards.

Also fix an issue highlighting wide strings properly reintroduced by
commit c0885fe390

For backwards searching in string and binary searches, use
the memrchr and backwards mempbrk implementations. For regex,
use PCRE2_ANCHORED to transform the user's regex expression into
one that is anchored at the start byte, and progressively search
backwards.

Fix #11269
This commit is contained in:
John Thacker 2023-10-01 11:37:21 -04:00 committed by AndersBroman
parent a6f3e61d70
commit 60a9e1124b
7 changed files with 605 additions and 51 deletions

601
file.c
View File

@ -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.");

5
file.h
View File

@ -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.

View File

@ -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) {

View File

@ -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.");

View File

@ -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) {

View File

@ -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,

View File

@ -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);