dfilter: Add support for entering time in UTC
Add the option to enter a filter with an absolute time value in UTC. Otherwise the value is interpreted in local time. The syntax used is an "UTC" suffix, for example: frame.time == "Dec 31, 2002 13:55:31.3 UTC" This also changes the behavior of "Apply Selected as filter". Fields using a local time display type will use local time and fields using UTC display type will be applied using UTC. Fixes #13268.
This commit is contained in:
parent
42084c2d17
commit
0047ca961f
|
@ -55,6 +55,7 @@ They previously shipped with Npcap 1.55.
|
|||
** Adds a new strict equality operator "===" or "all_eq". The expression "a === b" is true if and only if all a's are equal to b.
|
||||
The negation of "===" can now be written as "!==" (any_ne), in addition to "~=" (introduced in Wireshark 3.6.0).
|
||||
** Adds the aliases "any_eq" for "==" and "all_ne" for "!=".
|
||||
** Absolute times can be given in UTC by appending the suffix "UTC" to time values. Otherwise local time is used.
|
||||
|
||||
* text2pcap has been updated to use the new logging output options and the
|
||||
"-d" flag has been removed. The "debug" log level corresponds to the old
|
||||
|
|
|
@ -27,11 +27,13 @@ cmp_order(const fvalue_t *a, const fvalue_t *b)
|
|||
* Get a nanoseconds value, starting at "p".
|
||||
*
|
||||
* Returns true on success, false on failure.
|
||||
*
|
||||
* If successful endptr points to the first invalid character.
|
||||
*/
|
||||
static gboolean
|
||||
get_nsecs(const char *startp, int *nsecs)
|
||||
get_nsecs(const char *startp, int *nsecs, const char **endptr)
|
||||
{
|
||||
int ndigits;
|
||||
int ndigits = 0;
|
||||
int scale;
|
||||
const char *p;
|
||||
int val;
|
||||
|
@ -39,9 +41,10 @@ get_nsecs(const char *startp, int *nsecs)
|
|||
int i;
|
||||
|
||||
/*
|
||||
* How many characters are in the string?
|
||||
* How many digits are in the string?
|
||||
*/
|
||||
ndigits = (int)strlen(startp);
|
||||
for (p = startp; g_ascii_isdigit(*p); p++)
|
||||
ndigits++;
|
||||
|
||||
/*
|
||||
* If there are N characters in the string, the last of the
|
||||
|
@ -53,7 +56,6 @@ get_nsecs(const char *startp, int *nsecs)
|
|||
/*
|
||||
* Start at the last character, and work backwards.
|
||||
*/
|
||||
p = startp + ndigits;
|
||||
val = 0;
|
||||
while (p != startp) {
|
||||
p--;
|
||||
|
@ -83,6 +85,8 @@ get_nsecs(const char *startp, int *nsecs)
|
|||
scale++;
|
||||
}
|
||||
*nsecs = val;
|
||||
if (endptr)
|
||||
*endptr = startp + ndigits;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -130,7 +134,7 @@ relative_val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_v
|
|||
/*
|
||||
* Get the nanoseconds value.
|
||||
*/
|
||||
if (!get_nsecs(curptr, &fv->value.time.nsecs))
|
||||
if (!get_nsecs(curptr, &fv->value.time.nsecs, NULL))
|
||||
goto fail;
|
||||
} else {
|
||||
/*
|
||||
|
@ -169,8 +173,10 @@ parse_month_name(const char *s, int *tm_mon)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/* Parses an absolute time value from a string. The string cannot have
|
||||
* a time zone suffix and is always interpreted in local time.
|
||||
/*
|
||||
* Parses an absolute time value from a string. The string can have
|
||||
* a UTC time zone suffix. In that case it is interpreted in UTC. Otherwise
|
||||
* it is interpreted in local time.
|
||||
*
|
||||
* OS-dependent; e.g., on 32 bit versions of Windows when compiled to use
|
||||
* _mktime32 treats dates before January 1, 1970 as invalid.
|
||||
|
@ -183,7 +189,8 @@ static gboolean
|
|||
absolute_val_from_string(fvalue_t *fv, const char *s, char **err_msg_ptr)
|
||||
{
|
||||
struct tm tm;
|
||||
char *curptr = NULL;
|
||||
const char *curptr = NULL;
|
||||
const char *endptr;
|
||||
gboolean has_seconds = TRUE;
|
||||
char *err_msg = NULL;
|
||||
|
||||
|
@ -210,23 +217,7 @@ absolute_val_from_string(fvalue_t *fv, const char *s, char **err_msg_ptr)
|
|||
curptr = ws_strptime(s,"%Y-%m-%d", &tm);
|
||||
if (curptr == NULL)
|
||||
goto fail;
|
||||
|
||||
tm.tm_isdst = -1; /* let the computer figure out if it's DST */
|
||||
fv->value.time.secs = mktime(&tm);
|
||||
if (fv->value.time.secs == (time_t)-1) {
|
||||
/*
|
||||
* XXX - should we supply an error message that mentions
|
||||
* that the time specified might be syntactically valid
|
||||
* but might not actually have occurred, e.g. a time in
|
||||
* the non-existent time range after the clocks are
|
||||
* set forward during daylight savings time (or possibly
|
||||
* that it's in the time range after the clocks are set
|
||||
* backward, so that there are two different times that
|
||||
* it could be)?
|
||||
*/
|
||||
err_msg = ws_strdup("\"%s\" cannot be converted to a valid calendar time.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (*curptr == '.') {
|
||||
/* Nanoseconds */
|
||||
|
@ -240,14 +231,11 @@ absolute_val_from_string(fvalue_t *fv, const char *s, char **err_msg_ptr)
|
|||
err_msg = ws_strdup("Subseconds value is not a number.");
|
||||
goto fail;
|
||||
}
|
||||
if (!get_nsecs(curptr, &fv->value.time.nsecs)) {
|
||||
if (!get_nsecs(curptr, &fv->value.time.nsecs, &endptr)) {
|
||||
err_msg = ws_strdup("Subseconds value is invalid.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else if (*curptr != '\0') {
|
||||
err_msg = ws_strdup("Unexpected data after time value.");
|
||||
goto fail;
|
||||
curptr = endptr;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
|
@ -256,6 +244,50 @@ absolute_val_from_string(fvalue_t *fv, const char *s, char **err_msg_ptr)
|
|||
fv->value.time.nsecs = 0;
|
||||
}
|
||||
|
||||
/* Skip whitespace */
|
||||
while (g_ascii_isspace(*curptr)) {
|
||||
curptr++;
|
||||
}
|
||||
|
||||
/* Do we have a Timezone? */
|
||||
if (strcmp(curptr, "UTC") == 0) {
|
||||
curptr += strlen("UTC");
|
||||
if (*curptr == '\0') {
|
||||
/* It's UTC */
|
||||
fv->value.time.secs = mktime_utc(&tm);
|
||||
goto done;
|
||||
}
|
||||
else {
|
||||
err_msg = ws_strdup("Unexpected data after time value.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (*curptr == '\0') {
|
||||
/* Local time */
|
||||
fv->value.time.secs = mktime(&tm);
|
||||
goto done;
|
||||
}
|
||||
else {
|
||||
err_msg = ws_strdup("Unexpected data after time value.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
done:
|
||||
if (fv->value.time.secs == (time_t)-1) {
|
||||
/*
|
||||
* XXX - should we supply an error message that mentions
|
||||
* that the time specified might be syntactically valid
|
||||
* but might not actually have occurred, e.g. a time in
|
||||
* the non-existent time range after the clocks are
|
||||
* set forward during daylight savings time (or possibly
|
||||
* that it's in the time range after the clocks are set
|
||||
* backward, so that there are two different times that
|
||||
* it could be)?
|
||||
*/
|
||||
err_msg = ws_strdup("\"%s\" cannot be converted to a valid calendar time.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
|
@ -304,6 +336,9 @@ absolute_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype
|
|||
{
|
||||
char *rep;
|
||||
|
||||
if (field_display == BASE_NONE)
|
||||
field_display = ABSOLUTE_TIME_LOCAL;
|
||||
|
||||
switch (rtype) {
|
||||
case FTREPR_DISPLAY:
|
||||
rep = abs_time_to_str_ex(scope, &fv->value.time,
|
||||
|
@ -311,10 +346,12 @@ absolute_val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype
|
|||
break;
|
||||
|
||||
case FTREPR_DFILTER:
|
||||
/* absolute_val_from_string only accepts local time,
|
||||
* with no time zone, so match that. */
|
||||
/* Only ABSOLUTE_TIME_LOCAL and ABSOLUTE_TIME_UTC
|
||||
* are supported. Normalize the field_display value. */
|
||||
if (field_display != ABSOLUTE_TIME_LOCAL)
|
||||
field_display = ABSOLUTE_TIME_UTC;
|
||||
rep = abs_time_to_str_ex(scope, &fv->value.time,
|
||||
ABSOLUTE_TIME_LOCAL, ABS_TIME_TO_STR_ADD_DQUOTES);
|
||||
field_display, ABS_TIME_TO_STR_SHOW_UTC_ONLY|ABS_TIME_TO_STR_ADD_DQUOTES);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -110,19 +110,25 @@ get_fmt_broken_down_time(field_display_e fmt, const time_t *secs)
|
|||
}
|
||||
|
||||
static const char *
|
||||
get_fmt_zonename(field_display_e fmt, struct tm *tmp)
|
||||
get_fmt_zonename(char *buf, size_t size, field_display_e fmt, struct tm *tmp, int flags)
|
||||
{
|
||||
switch (fmt) {
|
||||
case ABSOLUTE_TIME_UTC:
|
||||
case ABSOLUTE_TIME_DOY_UTC:
|
||||
case ABSOLUTE_TIME_NTP_UTC:
|
||||
return "UTC";
|
||||
case ABSOLUTE_TIME_LOCAL:
|
||||
return get_zonename(tmp);
|
||||
default:
|
||||
snprintf(buf, size, " UTC");
|
||||
break;
|
||||
case ABSOLUTE_TIME_LOCAL:
|
||||
if (flags & ABS_TIME_TO_STR_SHOW_ZONE)
|
||||
snprintf(buf, size, " %s", get_zonename(tmp));
|
||||
else
|
||||
*buf = '\0';
|
||||
break;
|
||||
default:
|
||||
ws_assert_not_reached();
|
||||
}
|
||||
ws_assert_not_reached();
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *
|
||||
|
@ -177,6 +183,9 @@ abs_time_to_str_ex(wmem_allocator_t *scope, const nstime_t *abs_time, field_disp
|
|||
char buf_nsecs[32];
|
||||
char buf_tzone[32];
|
||||
|
||||
if (fmt == BASE_NONE)
|
||||
fmt = ABSOLUTE_TIME_LOCAL;
|
||||
|
||||
ws_assert(FIELD_DISPLAY_IS_ABSOLUTE_TIME(fmt));
|
||||
|
||||
if (fmt == ABSOLUTE_TIME_NTP_UTC && abs_time->secs == 0 &&
|
||||
|
@ -195,8 +204,8 @@ abs_time_to_str_ex(wmem_allocator_t *scope, const nstime_t *abs_time, field_disp
|
|||
}
|
||||
|
||||
*buf_tzone = '\0';
|
||||
if (flags & ABS_TIME_TO_STR_SHOW_ZONE) {
|
||||
snprintf(buf_tzone, sizeof(buf_tzone), " %s", get_fmt_zonename(fmt, tmp));
|
||||
if (flags & ABS_TIME_TO_STR_SHOW_ZONE || flags & ABS_TIME_TO_STR_SHOW_UTC_ONLY) {
|
||||
get_fmt_zonename(buf_tzone, sizeof(buf_tzone), fmt, tmp, flags);
|
||||
}
|
||||
|
||||
return snprint_abs_time_secs(scope, fmt, tmp, buf_nsecs, buf_tzone, flags & ABS_TIME_TO_STR_ADD_DQUOTES);
|
||||
|
|
|
@ -132,6 +132,7 @@ WS_DLL_PUBLIC gchar* tvb_address_var_to_str(wmem_allocator_t *scope, tvbuff_t *t
|
|||
|
||||
#define ABS_TIME_TO_STR_SHOW_ZONE (1U << 0)
|
||||
#define ABS_TIME_TO_STR_ADD_DQUOTES (1U << 1)
|
||||
#define ABS_TIME_TO_STR_SHOW_UTC_ONLY (1U << 2)
|
||||
|
||||
WS_DLL_PUBLIC char *abs_time_to_str_ex(wmem_allocator_t *scope,
|
||||
const nstime_t *, field_display_e fmt,
|
||||
|
|
|
@ -79,10 +79,14 @@ class case_time(unittest.TestCase):
|
|||
dfilter = 'frame.time <= "Dec 31, 2002 13:56:31.3"'
|
||||
checkDFilterCount(dfilter, 1)
|
||||
|
||||
def test_utc_time_1(self, checkDFilterCount):
|
||||
dfilter = 'frame.time == "Dec 31, 2002 13:55:31.3 UTC"'
|
||||
checkDFilterCount(dfilter, 1)
|
||||
|
||||
def test_bad_time_1(self, checkDFilterFail):
|
||||
# No text is permitted after the time.
|
||||
dfilter = 'frame.time == "Dec 31, 2002 13:56:31.3 UTC"'
|
||||
error = 'value is invalid'
|
||||
# This is an error, only UTC timezone can be used
|
||||
dfilter = 'frame.time == "Dec 31, 2002 13:56:31.3 WET"'
|
||||
error = 'Unexpected data after time value'
|
||||
checkDFilterFail(dfilter, error)
|
||||
|
||||
def test_bad_time_2(self, checkDFilterFail):
|
||||
|
|
Loading…
Reference in New Issue