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:
parent
a6f3e61d70
commit
60a9e1124b
601
file.c
601
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.");
|
||||
|
|
5
file.h
5
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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue