Skip to content

Commit

Permalink
Add new filter elements: first seen xx, last seen xx. See also #590
Browse files Browse the repository at this point in the history
  • Loading branch information
phaag committed Jan 11, 2025
1 parent 3831e66 commit 52c93cd
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 26 deletions.
9 changes: 9 additions & 0 deletions man/nfdump.1
Original file line number Diff line number Diff line change
Expand Up @@ -1250,6 +1250,15 @@ True if the calculated duration of a flow (tend - tstart) compares to
.Ar time.
The duration is specified in msec (milliseconds)
.Pp
.It Cm first seen Ar comp timeISO8601
.It Cm last seen Ar comp timeISO8601
True if the start/end time of a flow compares to
.Ar timeISO8601.
The time follows ISO8601 format. e.g. 2024-07-11T09:15:10.020. Up to msec
may be specified. A string may be incomplete e.g. 2024-07-11T09 which is
automatically extended to 2024-07-11T09:00:00.000. At least a valid year
is required.
.Pp
.It Cm pps Ar comp num
True if the calculated value of in-packets/duration (packets per second)
compares with the number
Expand Down
36 changes: 31 additions & 5 deletions src/libnfdump/filter/grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include "ja3/ja3.h"
#include "ja4/ja4.h"
#include "nfdump.h"
#include "util.h"

#define AnyMask 0xffffffffffffffffLL

Expand Down Expand Up @@ -150,6 +151,8 @@ static int AddObservation(char *type, char *subType, uint16_t comp, uint64_t num

static int AddVRF(direction_t direction, uint16_t comp, uint64_t number);

static int AddTimeSting(char *firstLast, uint16_t comp, char *timeString);

static int AddPFString(char *type, char *arg);

static int AddPFNumber(char *type, uint16_t comp, uint64_t number);
Expand Down Expand Up @@ -187,7 +190,7 @@ static int AddASList(direction_t direction, void *U64List);
%token PACKETS BYTES FLOWS ETHERTYPE
%token MASK FLOWDIR TOS FWDSTAT LATENCY ASA ACL PAYLOAD VRF
%token OBSERVATION PF
%token FIRST LAST SEEN
%token SEEN
%token <s> STRING
%token <s> GEOSTRING
%token <value> NUMBER
Expand Down Expand Up @@ -446,12 +449,15 @@ term: ANY { /* this is an unconditionally true expression, as a filter applies i
$$.self = AddVRF($1.direction, $3.comp, $4); if ( $$.self < 0 ) YYABORT;
}

| FIRST SEEN comp STRING {
$$.self = 1;
| STRING SEEN comp STRING {
$$.self = AddTimeSting($1, $3.comp, $4);
}

LAST SEEN comp STRING {
$$.self = 1;
| STRING SEEN comp NUMBER {
char s[32] = {0};
int i = $4;
snprintf(s, 31, "%d", i );
$$.self = AddTimeSting($1, $3.comp, s);
}

| PF STRING STRING {
Expand Down Expand Up @@ -1491,6 +1497,26 @@ static int AddVRF(direction_t direction, uint16_t comp, uint64_t number) {
return ret;
} // End of AddVRF

static int AddTimeSting(char *firstLast, uint16_t comp, char *timeString) {

int ret = -1;
uint64_t number = ParseTime8601(timeString);
if ( number == 0 ) {
yyprintf("Invalid ISO8601 time string: %s", timeString);
return ret;
}

if ( strcasecmp(firstLast, "first") == 0 ) { // first seen
ret = NewElement(EXgenericFlowID, OFFmsecFirst, SIZEmsecFirst, number, comp, FUNC_NONE, NULLPtr);
} if ( strcasecmp(firstLast, "last") == 0 ) { // last seen
ret = NewElement(EXgenericFlowID, OFFmsecLast, SIZEmsecLast, number, comp, FUNC_NONE, NULLPtr);
} else {
yyprintf("Unexpected token: %s", timeString);
}

return ret;
} // End of AddTimeSting

static int AddPFString(char *type, char *arg) {

int ret = -1;
Expand Down
2 changes: 0 additions & 2 deletions src/libnfdump/filter/scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,6 @@ ingress { return INGRESS;}
egress { return EGRESS; }
client { return CLIENT; }
server { return SERVER; }
first { return FIRST; }
last { return LAST; }
seen { return SEEN; }

and { return AND; }
Expand Down
47 changes: 28 additions & 19 deletions src/libnffile/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ static int verbose = 4;
/* Function prototypes */
static int check_number(char *s, int len);

static int ParseTime(char *s, time_t *t_start);
static uint64_t ParseTime(char *s, time_t *t_start);

static int use_syslog = 0;

Expand Down Expand Up @@ -305,7 +305,7 @@ static int check_number(char *s, int len) {
} // End of check_number

// Parse ISO 8601 time string - accept legacy format
static int ParseTime(char *s, time_t *t_start) {
static uint64_t ParseTime(char *s, time_t *t_start) {
/* A time string may look like:
* yyyy-MM-ddThh:mm:ss.s or
* 012345678901234567890
Expand Down Expand Up @@ -345,7 +345,7 @@ static int ParseTime(char *s, time_t *t_start) {
if (q >= eos) {
ts.tm_mday = 1;
*t_start = mktime(&ts);
return 1;
return 1000LL * (uint64_t)*t_start;
}

// split month and parse
Expand All @@ -364,7 +364,7 @@ static int ParseTime(char *s, time_t *t_start) {
if (q >= eos) {
ts.tm_mday = 1;
*t_start = mktime(&ts);
return 1;
return 1000LL * (uint64_t)*t_start;
}

// split day and parse
Expand All @@ -383,7 +383,7 @@ static int ParseTime(char *s, time_t *t_start) {
ts.tm_mday = num;
if (q >= eos) {
*t_start = mktime(&ts);
return 1;
return 1000LL * (uint64_t)*t_start;
}

// split hour and parse
Expand All @@ -401,7 +401,7 @@ static int ParseTime(char *s, time_t *t_start) {
ts.tm_hour = num;
if (q >= eos) {
*t_start = mktime(&ts);
return 1;
return 1000LL * (uint64_t)*t_start;
}

// split and parse minute
Expand All @@ -419,7 +419,7 @@ static int ParseTime(char *s, time_t *t_start) {
ts.tm_min = num;
if (q >= eos) {
*t_start = mktime(&ts);
return 1;
return 1000LL * (uint64_t)*t_start;
}

// split and parse second
Expand All @@ -437,7 +437,7 @@ static int ParseTime(char *s, time_t *t_start) {
ts.tm_sec = num;
if (q >= eos) {
*t_start = mktime(&ts);
return 1;
return 1000LL * (uint64_t)*t_start;
}

// msec
Expand All @@ -448,16 +448,17 @@ static int ParseTime(char *s, time_t *t_start) {
num = atoi(p);

uint64_t tmsec = (uint64_t)(*t_start) * 1000LL + (uint64_t)num;
printf("Msec window: %llu\n", tmsec);
return 1;
dbg_printf("Msec window: %llu\n", tmsec);
return tmsec;

} // End of ParseTime

timeWindow_t *ScanTimeFrame(char *tstring) {
timeWindow_t *timeWindow;
char *p;

if (!tstring) {
if (!tstring || strlen(tstring) < 4) {
LogError("Time string format error '%s'", tstring ? tstring : "NullString");
return NULL;
}

Expand All @@ -467,17 +468,17 @@ timeWindow_t *ScanTimeFrame(char *tstring) {
return NULL;
}

if (strlen(tstring) < 4) {
LogError("Time string format error '%s'", tstring);
return NULL;
}

if ((p = strchr(tstring, '-')) == NULL) {
ParseTime(tstring, &timeWindow->first);
if (ParseTime(tstring, &timeWindow->first) == 0) {
free(timeWindow);
return NULL;
}
} else {
*p++ = 0;
ParseTime(tstring, &timeWindow->first);
ParseTime(p, &timeWindow->last);
if (ParseTime(tstring, &timeWindow->first) == 0 || ParseTime(p, &timeWindow->last) == 0) {
free(timeWindow);
return NULL;
}
}

#ifdef DEVEL
Expand Down Expand Up @@ -605,6 +606,14 @@ time_t ISO2UNIX(char *timestring) {

} // End of ISO2UNIX

uint64_t ParseTime8601(char *s) {
time_t t = 0;
char *tmp = strdup(s);
uint64_t tmsec = ParseTime(tmp, &t);
free(tmp);
return tmsec;
} // End of ParseTime8601

long getTick(void) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
Expand Down
2 changes: 2 additions & 0 deletions src/libnffile/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ char *UNIX2ISO(time_t t);

time_t ISO2UNIX(char *timestring);

uint64_t ParseTime8601(char *s);

long getTick(void);

char *DurationString(double duration);
Expand Down
20 changes: 20 additions & 0 deletions src/test/nftest.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,26 @@ static void runTest(void) {
CheckFilter("bpp 2", recordHandle, 1);
CheckFilter("bpp > 2", recordHandle, 0);

// Test with time 2024-07-11T09:15:10.010
genericFlow->msecFirst = ParseTime8601("2024-07-11T09:15:10.010");
CheckFilter("first seen 2024-07-11T09:15:10.010", recordHandle, 1);
CheckFilter("first seen > 2024-07-11T09:15:10.010", recordHandle, 0);
CheckFilter("first seen > 2024-07-11T09:15:10.009", recordHandle, 1);
CheckFilter("first seen > 2024-07-10T09:15:10.010", recordHandle, 1);
CheckFilter("first seen < 2024-07-11T09:15:10.011", recordHandle, 1);
CheckFilter("first seen < 2024-07-11T09:15:10.010", recordHandle, 0);
CheckFilter("first seen < 2024-07-10T09:15:10.010", recordHandle, 0);

genericFlow->msecLast = ParseTime8601("2024-07-11T09:15:10.010");
genericFlow->msecFirst = 0;
CheckFilter("last seen 2024-07-11T09:15:10.010", recordHandle, 1);
CheckFilter("last seen > 2024-07-11T09:15:10.010", recordHandle, 0);
CheckFilter("last seen > 2024-07-11T09:15:10.009", recordHandle, 1);
CheckFilter("last seen > 2024-07-10T09:15:10.010", recordHandle, 1);
CheckFilter("last seen < 2024-07-11T09:15:10.011", recordHandle, 1);
CheckFilter("last seen < 2024-07-11T09:15:10.010", recordHandle, 0);
CheckFilter("last seen < 2024-07-10T09:15:10.010", recordHandle, 0);

genericFlow->proto = IPPROTO_TCP;
genericFlow->tcpFlags = 1; // FIN
CheckFilter("flags F", recordHandle, 1);
Expand Down

0 comments on commit 52c93cd

Please sign in to comment.