Add missing nftrack to git
This commit is contained in:
parent
7ffa3cb493
commit
69d46a710d
336
config.h.in~
336
config.h.in~
@ -1,336 +0,0 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
#undef AC_APPLE_UNIVERSAL_BUILD
|
||||
|
||||
/* Define to 1 if the `closedir' function returns void instead of `int'. */
|
||||
#undef CLOSEDIR_VOID
|
||||
|
||||
/* Define to 1 if you have the `alarm' function. */
|
||||
#undef HAVE_ALARM
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Define to 1 if you have the <arpa/nameser_compat.h> header file. */
|
||||
#undef HAVE_ARPA_NAMESER_COMPAT_H
|
||||
|
||||
/* Define to 1 if you have the <arpa/nameser.h> header file. */
|
||||
#undef HAVE_ARPA_NAMESER_H
|
||||
|
||||
/* Define to 1 if you have the <bzlib.h> header file. */
|
||||
#undef HAVE_BZLIB_H
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#undef HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the <features.h> header file. */
|
||||
#undef HAVE_FEATURES_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
/* Define to 1 if you have the `fpurge' function. */
|
||||
#undef HAVE_FPURGE
|
||||
|
||||
/* Define to 1 if you have the <fts.h> header file. */
|
||||
#undef HAVE_FTS_H
|
||||
|
||||
/* Define to 1 if you have the `gethostbyname' function. */
|
||||
#undef HAVE_GETHOSTBYNAME
|
||||
|
||||
/* Define to 1 if the function (or macro) htonll exists. */
|
||||
#undef HAVE_HTONLL
|
||||
|
||||
/* Define to 1 if you have the `inet_ntoa' function. */
|
||||
#undef HAVE_INET_NTOA
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <iso/limits_iso.h> header file. */
|
||||
#undef HAVE_ISO_LIMITS_ISO_H
|
||||
|
||||
/* Define to 1 if you have the `nsl' library (-lnsl). */
|
||||
#undef HAVE_LIBNSL
|
||||
|
||||
/* Define to 1 if you have the `resolv' library (-lresolv). */
|
||||
#undef HAVE_LIBRESOLV
|
||||
|
||||
/* */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
/* Define to 1 if you have the `z' library (-lz). */
|
||||
#undef HAVE_LIBZ
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#undef HAVE_MALLOC
|
||||
|
||||
/* Define to 1 if you have the `memcmp' function. */
|
||||
#undef HAVE_MEMCMP
|
||||
|
||||
/* Define to 1 if you have the `memcpy' function. */
|
||||
#undef HAVE_MEMCPY
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#undef HAVE_MEMSET
|
||||
|
||||
/* Define to 1 if you have the <nameser8_compat.h> header file. */
|
||||
#undef HAVE_NAMESER8_COMPAT_H
|
||||
|
||||
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||
#undef HAVE_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#undef HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if you have the <net/bpf.h> header file. */
|
||||
#undef HAVE_NET_BPF_H
|
||||
|
||||
/* Define to 1 if you have the <pcap-bpf.h> header file. */
|
||||
#undef HAVE_PCAP_BPF_H
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
||||
and to 0 otherwise. */
|
||||
#undef HAVE_REALLOC
|
||||
|
||||
/* Define to 1 if you have the <resolv.h> header file. */
|
||||
#undef HAVE_RESOLV_H
|
||||
|
||||
/* Define to 1 if you have the <rrd.h> header file. */
|
||||
#undef HAVE_RRD_H
|
||||
|
||||
/* Define to 1 if you have the `scandir' function. */
|
||||
#undef HAVE_SCANDIR
|
||||
|
||||
/* Define if sys/sem.h defines struct semun */
|
||||
#undef HAVE_SEMUN
|
||||
|
||||
/* Define to 1 if you have the `setsockopt' function. */
|
||||
#undef HAVE_SETSOCKOPT
|
||||
|
||||
/* Define to 1 if you have a printf() that supports the %z format string. */
|
||||
#undef HAVE_SIZE_T_Z_FORMAT
|
||||
|
||||
/* define if socket address structures have length fields */
|
||||
#undef HAVE_SOCKADDR_SA_LEN
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#undef HAVE_SOCKET
|
||||
|
||||
/* Define to 1 if `stat' has the bug that it succeeds when given the
|
||||
zero-length file name argument. */
|
||||
#undef HAVE_STAT_EMPTY_STRING_BUG
|
||||
|
||||
/* Define to 1 if stdbool.h conforms to C99. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#undef HAVE_STDDEF_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#undef HAVE_STRCHR
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#undef HAVE_STRDUP
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the `strftime' function. */
|
||||
#undef HAVE_STRFTIME
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strrchr' function. */
|
||||
#undef HAVE_STRRCHR
|
||||
|
||||
/* Define to 1 if you have the `strstr' function. */
|
||||
#undef HAVE_STRSTR
|
||||
|
||||
/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
|
||||
#undef HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
|
||||
/* Define to 1 if `ss_family' is a member of `struct sockaddr_storage'. */
|
||||
#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
|
||||
|
||||
/* Define to 1 if `ss_len' is a member of `struct sockaddr_storage'. */
|
||||
#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
|
||||
|
||||
/* Define to 1 if `__ss_family' is a member of `struct sockaddr_storage'. */
|
||||
#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY
|
||||
|
||||
/* Define to 1 if `__ss_len' is a member of `struct sockaddr_storage'. */
|
||||
#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#undef HAVE_SYSLOG_H
|
||||
|
||||
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_DIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#undef HAVE_SYS_NDIR_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#undef HAVE_VFORK
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
#undef HAVE_VFORK_H
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
#undef HAVE_WORKING_FORK
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#undef HAVE_WORKING_VFORK
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
|
||||
/* Define to 1 if you have the `__fpurge' function. */
|
||||
#undef HAVE___FPURGE
|
||||
|
||||
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
||||
slash. */
|
||||
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* The size of `int', as computed by sizeof. */
|
||||
#undef SIZEOF_INT
|
||||
|
||||
/* The size of `long', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG
|
||||
|
||||
/* The size of `long long', as computed by sizeof. */
|
||||
#undef SIZEOF_LONG_LONG
|
||||
|
||||
/* The size of `ptrdiff_t', as computed by sizeof. */
|
||||
#undef SIZEOF_PTRDIFF_T
|
||||
|
||||
/* The size of `short', as computed by sizeof. */
|
||||
#undef SIZEOF_SHORT
|
||||
|
||||
/* The size of `size_t', as computed by sizeof. */
|
||||
#undef SIZEOF_SIZE_T
|
||||
|
||||
/* The size of `void *', as computed by sizeof. */
|
||||
#undef SIZEOF_VOID_P
|
||||
|
||||
/* The size of `__int64', as computed by sizeof. */
|
||||
#undef SIZEOF___INT64
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#undef TIME_WITH_SYS_TIME
|
||||
|
||||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||
#undef TM_IN_SYS_TIME
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# undef WORDS_BIGENDIAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
|
||||
`char[]'. */
|
||||
#undef YYTEXT_POINTER
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to rpl_malloc if the replacement function should be used. */
|
||||
#undef malloc
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to `long' if <sys/types.h> does not define. */
|
||||
#undef ptrdiff_t
|
||||
|
||||
/* Define to rpl_realloc if the replacement function should be used. */
|
||||
#undef realloc
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define as `fork' if `vfork' does not work. */
|
||||
#undef vfork
|
536
extra/nftrack/nftrack.c
Normal file
536
extra/nftrack/nftrack.c
Normal file
@ -0,0 +1,536 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Author: peter $
|
||||
*
|
||||
* $Id: nftrack.c 224 2014-02-16 12:59:29Z peter $
|
||||
*
|
||||
* $LastChangedRevision: 224 $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "nf_common.h"
|
||||
#include "nffile.h"
|
||||
#include "flist.h"
|
||||
#include "rbtree.h"
|
||||
#include "nftree.h"
|
||||
#include "nfdump.h"
|
||||
#include "nfx.h"
|
||||
#include "util.h"
|
||||
#include "grammar.h"
|
||||
|
||||
#include "nftrack_stat.h"
|
||||
#include "nftrack_rrd.h"
|
||||
|
||||
// We have 288 slot ( 1 day ) for stat record
|
||||
#define AVG_STAT 1
|
||||
|
||||
/* Externals */
|
||||
extern int yydebug;
|
||||
|
||||
/* Global Variables */
|
||||
FilterEngine_data_t *Engine;
|
||||
int byte_mode, packet_mode;
|
||||
uint32_t byte_limit, packet_limit; // needed for linking purpose only
|
||||
|
||||
extension_map_list_t *extension_map_list;
|
||||
|
||||
/* Local Variables */
|
||||
static const char *nfdump_version = VERSION;
|
||||
|
||||
/* Function Prototypes */
|
||||
static void usage(char *name);
|
||||
|
||||
static int CheckRunningOnce(char *pidfile);
|
||||
|
||||
static data_row *process(char *filter);
|
||||
|
||||
/* Functions */
|
||||
|
||||
#include "nffile_inline.c"
|
||||
|
||||
static void usage(char *name) {
|
||||
printf("usage %s [options] [\"filter\"]\n"
|
||||
"-h\t\tthis text you see right here\n"
|
||||
"-l\t\tLast update of Ports DB\n"
|
||||
"-V\t\tPrint version and exit.\n"
|
||||
"-I\t\tInitialize Ports DB files.\n"
|
||||
"-d <db_dir>\tPorts DB directory.\n"
|
||||
"-r <input>\tread from file. default: stdin\n"
|
||||
"-p\t\tOnline output mode.\n"
|
||||
"-s\t\tCreate port statistics for timeslot -t\n"
|
||||
"-t <time>\tTimeslot for statistics\n"
|
||||
"-S\t\tCreate port statistics for last day\n"
|
||||
"-w <file>\twrite output to file\n"
|
||||
"-f <filter>\tfilter syntaxfile\n"
|
||||
, name);
|
||||
} /* usage */
|
||||
|
||||
static int CheckRunningOnce(char *pidfile) {
|
||||
int pidf;
|
||||
pid_t pid;
|
||||
char pidstr[32];
|
||||
|
||||
pidf = open(pidfile, O_RDONLY, 0);
|
||||
if ( pidf > 0 ) {
|
||||
// pid file exists
|
||||
char s[32];
|
||||
ssize_t len;
|
||||
len = read(pidf, (void *)s, 31);
|
||||
close(pidf);
|
||||
s[31] = '\0';
|
||||
if ( len < 0 ) {
|
||||
LogError("read() error existing pid file: %s\n", strerror(errno));
|
||||
return 0;
|
||||
} else {
|
||||
unsigned long pid = atol(s);
|
||||
if ( pid == 0 ) {
|
||||
// garbage - use this file
|
||||
unlink(pidfile);
|
||||
} else {
|
||||
if ( kill(pid, 0) == 0 ) {
|
||||
// process exists
|
||||
LogError("An nftrack process with pid %lu is already running!\n", pid);
|
||||
return 0;
|
||||
} else {
|
||||
// no such process - use this file
|
||||
LogError("The nftrack process with pid %lu died unexpectedly!\n", pid);
|
||||
unlink(pidfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pid = getpid();
|
||||
pidf = open(pidfile, O_RDWR|O_TRUNC|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if ( pidf == -1 ) {
|
||||
LogError("Error opening nftrack pid file: '%s' %s", pidfile, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
snprintf(pidstr,31,"%lu\n", (unsigned long)pid);
|
||||
if ( write(pidf, pidstr, strlen(pidstr)) <= 0 ) {
|
||||
LogError("Error write nftrack pid file: '%s' %s", pidfile, strerror(errno));
|
||||
}
|
||||
close(pidf);
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of CheckRunningOnce
|
||||
|
||||
static data_row *process(char *filter) {
|
||||
master_record_t master_record;
|
||||
common_record_t *flow_record;
|
||||
nffile_t *nffile;
|
||||
int i, done, ret;
|
||||
data_row * port_table;
|
||||
uint64_t total_bytes;
|
||||
|
||||
nffile = GetNextFile(NULL, 0, 0);
|
||||
if ( !nffile ) {
|
||||
LogError("GetNextFile() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
if ( nffile == EMPTY_LIST ) {
|
||||
LogError("Empty file list. No files to process\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
port_table = (data_row *)calloc(65536, sizeof(data_row));
|
||||
if ( !port_table) {
|
||||
LogError("malloc() allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset((void *)port_table, 0, 65536 * sizeof(data_row));
|
||||
|
||||
// setup Filter Engine to point to master_record, as any record read from file
|
||||
// is expanded into this record
|
||||
Engine->nfrecord = (uint64_t *)&master_record;
|
||||
|
||||
total_bytes = 0;
|
||||
done = 0;
|
||||
while ( !done ) {
|
||||
|
||||
// get next data block from file
|
||||
ret = ReadBlock(nffile);
|
||||
|
||||
switch (ret) {
|
||||
case NF_CORRUPT:
|
||||
case NF_ERROR:
|
||||
if ( ret == NF_CORRUPT )
|
||||
LogError("Skip corrupt data file '%s'\n",GetCurrentFilename());
|
||||
else
|
||||
LogError("Read error in file '%s': %s\n",GetCurrentFilename(), strerror(errno) );
|
||||
// fall through - get next file in chain
|
||||
case NF_EOF: {
|
||||
nffile_t *next = GetNextFile(nffile, 0, 0);
|
||||
if ( next == EMPTY_LIST ) {
|
||||
done = 1;
|
||||
}
|
||||
if ( next == NULL ) {
|
||||
done = 1;
|
||||
LogError("Unexpected end of file list\n");
|
||||
}
|
||||
// else continue with next file
|
||||
continue;
|
||||
|
||||
} break; // not really needed
|
||||
default:
|
||||
// successfully read block
|
||||
total_bytes += ret;
|
||||
}
|
||||
|
||||
if ( nffile->block_header->id == Large_BLOCK_Type ) {
|
||||
// skip
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( nffile->block_header->id != DATA_BLOCK_TYPE_2 ) {
|
||||
LogError("Can't process block type %u\n", nffile->block_header->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
flow_record = nffile->buff_ptr;
|
||||
|
||||
for ( i=0; i < nffile->block_header->NumRecords; i++ ) {
|
||||
int ret;
|
||||
|
||||
switch ( flow_record->type ) {
|
||||
case CommonRecordV0Type:
|
||||
case CommonRecordType: {
|
||||
if ( extension_map_list->slot[flow_record->ext_map] == NULL ) {
|
||||
LogError("Corrupt data file! No such extension map id: %u. Skip record", flow_record->ext_map );
|
||||
} else {
|
||||
ExpandRecord_v2( flow_record, extension_map_list->slot[flow_record->ext_map], NULL, &master_record);
|
||||
|
||||
ret = (*Engine->FilterEngine)(Engine);
|
||||
|
||||
if ( ret == 0 ) { // record failed to pass the filter
|
||||
// increment pointer by number of bytes for netflow record
|
||||
flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
|
||||
// go to next record
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Add to stat record
|
||||
if ( master_record.prot == 6 ) {
|
||||
port_table[master_record.dstport].proto[tcp].type[flows]++;
|
||||
port_table[master_record.dstport].proto[tcp].type[packets] += master_record.dPkts;
|
||||
port_table[master_record.dstport].proto[tcp].type[bytes] += master_record.dOctets;
|
||||
} else if ( master_record.prot == 17 ) {
|
||||
port_table[master_record.dstport].proto[udp].type[flows]++;
|
||||
port_table[master_record.dstport].proto[udp].type[packets] += master_record.dPkts;
|
||||
port_table[master_record.dstport].proto[udp].type[bytes] += master_record.dOctets;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case ExtensionMapType: {
|
||||
extension_map_t *map = (extension_map_t *)flow_record;
|
||||
|
||||
if ( Insert_Extension_Map(extension_map_list, map) ) {
|
||||
// flush new map
|
||||
} // else map already known and flushed
|
||||
} break;
|
||||
case ExporterInfoRecordType:
|
||||
case ExporterStatRecordType:
|
||||
case SamplerInfoRecordype:
|
||||
// Silently skip exporter records
|
||||
break;
|
||||
default: {
|
||||
LogError("Skip unknown record type %i\n", flow_record->type);
|
||||
}
|
||||
}
|
||||
|
||||
// Advance pointer by number of bytes for netflow record
|
||||
flow_record = (common_record_t *)((pointer_addr_t)flow_record + flow_record->size);
|
||||
}
|
||||
} // while
|
||||
|
||||
CloseFile(nffile);
|
||||
DisposeFile(nffile);
|
||||
|
||||
PackExtensionMapList(extension_map_list);
|
||||
|
||||
return port_table;
|
||||
|
||||
} // End of process
|
||||
|
||||
|
||||
int main( int argc, char **argv ) {
|
||||
struct stat stat_buff;
|
||||
char *wfile, *rfile, *Rfile, *Mdirs, *ffile, *filter, *timeslot, *DBdir;
|
||||
char datestr[64];
|
||||
char pidfile[MAXPATHLEN];
|
||||
int c, ffd, ret, DBinit, AddDB, GenStat, AvStat, output_mode, topN;
|
||||
unsigned int lastupdate;
|
||||
data_row *port_table;
|
||||
time_t when;
|
||||
struct tm * t1;
|
||||
|
||||
wfile = rfile = Rfile = Mdirs = ffile = filter = DBdir = timeslot = NULL;
|
||||
DBinit = AddDB = GenStat = AvStat = 0;
|
||||
lastupdate = output_mode = 0;
|
||||
topN = 10;
|
||||
while ((c = getopt(argc, argv, "d:hln:pr:st:w:AIM:L:R:SV")) != EOF) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'I':
|
||||
DBinit = 1;
|
||||
break;
|
||||
case 'M':
|
||||
Mdirs = strdup(optarg);
|
||||
break;
|
||||
case 'R':
|
||||
Rfile = strdup(optarg);
|
||||
break;
|
||||
case 'd':
|
||||
DBdir = strdup(optarg);
|
||||
ret = stat(DBdir, &stat_buff);
|
||||
if ( !(stat_buff.st_mode & S_IFDIR) ) {
|
||||
fprintf(stderr, "No such directory: %s\n", DBdir);
|
||||
exit(255);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
lastupdate = 1;
|
||||
break;
|
||||
case 'n':
|
||||
topN = atoi(optarg);
|
||||
if ( topN < 0 ) {
|
||||
fprintf(stderr, "TopnN number %i out of range\n", topN);
|
||||
exit(255);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
output_mode = 1;
|
||||
break;
|
||||
case 'r':
|
||||
rfile = strdup(optarg);
|
||||
break;
|
||||
case 'w':
|
||||
wfile = strdup(optarg);
|
||||
break;
|
||||
case 's':
|
||||
GenStat = 1;
|
||||
break;
|
||||
case 't':
|
||||
timeslot = optarg;
|
||||
if ( !ISO2UNIX(timeslot) ) {
|
||||
exit(255);
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
AddDB = 1;
|
||||
break;
|
||||
case 'L':
|
||||
if ( !InitLog("nftrack", optarg) )
|
||||
exit(255);
|
||||
break;
|
||||
case 'S':
|
||||
AvStat = 1;
|
||||
break;
|
||||
case 'V':
|
||||
printf("%s: Version: %s\n",argv[0], nfdump_version);
|
||||
exit(0);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind > 1) {
|
||||
usage(argv[0]);
|
||||
exit(255);
|
||||
} else {
|
||||
/* user specified a pcap filter */
|
||||
filter = argv[optind];
|
||||
}
|
||||
|
||||
if ( !filter && ffile ) {
|
||||
if ( stat(ffile, &stat_buff) ) {
|
||||
LogError("stat() filter file: '%s' %s", ffile, strerror(errno));
|
||||
exit(255);
|
||||
}
|
||||
filter = (char *)malloc(stat_buff.st_size);
|
||||
if ( !filter ) {
|
||||
LogError("malloc() allocation error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
exit(255);
|
||||
}
|
||||
ffd = open(ffile, O_RDONLY);
|
||||
if ( ffd < 0 ) {
|
||||
LogError("open() filter file: '%s' %s", ffile, strerror(errno));
|
||||
exit(255);
|
||||
}
|
||||
ret = read(ffd, (void *)filter, stat_buff.st_size);
|
||||
if ( ret < 0 ) {
|
||||
LogError("read() filter file: '%s' %s", ffile, strerror(errno));
|
||||
close(ffd);
|
||||
exit(255);
|
||||
}
|
||||
close(ffd);
|
||||
}
|
||||
|
||||
if ( !DBdir ) {
|
||||
LogError("DB directory required\n");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
InitStat(DBdir);
|
||||
|
||||
// check if pid file exists and if so, if a process with registered pid is running
|
||||
snprintf(pidfile, MAXPATHLEN-1, "%s/nftrack.pid", DBdir);
|
||||
pidfile[MAXPATHLEN-1]= '\0';
|
||||
if ( !CheckRunningOnce(pidfile) ) {
|
||||
LogError("Run once check failed.\n");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
if ( !filter )
|
||||
filter = "any";
|
||||
|
||||
Engine = CompileFilter(filter);
|
||||
if ( !Engine ) {
|
||||
unlink(pidfile);
|
||||
exit(254);
|
||||
}
|
||||
|
||||
if ( DBinit ) {
|
||||
when = time(NULL);
|
||||
when -= ((when % 300) + 300);
|
||||
InitStatFile();
|
||||
if ( !CreateRRDBs(DBdir, when) ) {
|
||||
LogError("Init DBs failed\n");
|
||||
unlink(pidfile);
|
||||
exit(255);
|
||||
}
|
||||
LogInfo("Port DBs initialized.\n");
|
||||
unlink(pidfile);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
extension_map_list = InitExtensionMaps(NEEDS_EXTENSION_LIST);
|
||||
|
||||
if ( lastupdate ) {
|
||||
when = RRD_LastUpdate(DBdir);
|
||||
if ( !when ) {
|
||||
unlink(pidfile);
|
||||
exit(255);
|
||||
}
|
||||
t1 = localtime(&when);
|
||||
strftime(datestr, 63, "%b %d %Y %T", t1);
|
||||
LogInfo("Last Update: %i, %s\n", (int)when, datestr);
|
||||
unlink(pidfile);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
port_table = NULL;
|
||||
if ( Mdirs || Rfile || rfile ) {
|
||||
SetupInputFileSequence(Mdirs, rfile, Rfile);
|
||||
port_table = process(filter);
|
||||
// Lister(port_table);
|
||||
if ( !port_table ) {
|
||||
unlink(pidfile);
|
||||
exit(255);
|
||||
}
|
||||
if ( AddDB ) {
|
||||
if ( !timeslot ) {
|
||||
LogError("Timeslot required!\n");
|
||||
unlink(pidfile);
|
||||
exit(255);
|
||||
}
|
||||
UpdateStat(port_table, ISO2UNIX(timeslot));
|
||||
RRD_StoreDataRow(DBdir, timeslot, port_table);
|
||||
}
|
||||
}
|
||||
|
||||
if ( AvStat ) {
|
||||
port_table = GetStat();
|
||||
if ( !port_table ) {
|
||||
LogError("Unable to get port table!\n");
|
||||
unlink(pidfile);
|
||||
exit(255);
|
||||
}
|
||||
// DoStat
|
||||
Generate_TopN(port_table, topN, AVG_STAT, 0, output_mode, wfile);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ( GenStat ) {
|
||||
when = ISO2UNIX(timeslot);
|
||||
if ( !port_table ) {
|
||||
if ( !timeslot ) {
|
||||
LogError("Timeslot required!\n");
|
||||
unlink(pidfile);
|
||||
exit(255);
|
||||
}
|
||||
port_table = RRD_GetDataRow(DBdir, when);
|
||||
}
|
||||
if ( !port_table ) {
|
||||
LogError("Unable to get port table!\n");
|
||||
unlink(pidfile);
|
||||
exit(255);
|
||||
}
|
||||
// DoStat
|
||||
Generate_TopN(port_table, topN, 0, when, output_mode, wfile);
|
||||
}
|
||||
|
||||
CloseStat();
|
||||
unlink(pidfile);
|
||||
|
||||
return 0;
|
||||
}
|
545
extra/nftrack/nftrack_rrd.c
Normal file
545
extra/nftrack/nftrack_rrd.c
Normal file
@ -0,0 +1,545 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Author: peter $
|
||||
*
|
||||
* $Id: nftrack_rrd.c 224 2014-02-16 12:59:29Z peter $
|
||||
*
|
||||
* $LastChangedRevision: 224 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "rrd.h"
|
||||
#include "nftrack_stat.h"
|
||||
#include "nftrack_rrd.h"
|
||||
|
||||
#define BUFF_CHECK(num,buffsize) if ( (num) >= (buffsize) ) { \
|
||||
fprintf(stderr, "No enough space to create RRD arg\n"); \
|
||||
exit(0); \
|
||||
}
|
||||
|
||||
// temporary RRD file
|
||||
#define TMPRRD "ports.rrd"
|
||||
|
||||
#define MAXBUFF 15 * 1024;
|
||||
|
||||
/* global const */
|
||||
static const char *proto[] = { "tcp", "udp" };
|
||||
static const char *type[] = { "flows", "packets", "bytes" };
|
||||
|
||||
/* Local prototypes */
|
||||
|
||||
static void CreateRRDB (char *filename, time_t when);
|
||||
|
||||
/* Functions */
|
||||
|
||||
static void CreateRRDB (char *filename, time_t when) {
|
||||
char *buff, *s, *rrd_arg[1100];
|
||||
long i, num, buffsize, argc;
|
||||
|
||||
optind = 0; opterr = 0;
|
||||
argc = 0;
|
||||
/*
|
||||
Create bufferspace for create args:
|
||||
1024 DS records: each ~ 23 bytes in average +
|
||||
3 RRA records + filename + start time => 512 bytes should be more than enough
|
||||
*/
|
||||
buffsize = 23 * 1024 + 512;
|
||||
buff = (char *)malloc(buffsize);
|
||||
if ( !buff ) {
|
||||
perror("Memory error!");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
s = buff;
|
||||
|
||||
unlink(filename);
|
||||
|
||||
rrd_arg[argc++] = "create";
|
||||
|
||||
// add DB name
|
||||
rrd_arg[argc++] = filename;
|
||||
|
||||
// Add start time
|
||||
num = snprintf(s, buffsize, "--start=%lld", (long long)when);
|
||||
num++; // include '\0'
|
||||
BUFF_CHECK(num,buffsize);
|
||||
rrd_arg[argc++] = s;
|
||||
|
||||
buffsize -= num;
|
||||
s += num;
|
||||
|
||||
/* Add the DS strings */
|
||||
for ( i=0; i<1024; i++) {
|
||||
num = snprintf(s, buffsize, "DS:p%ld:GAUGE:600:0:U", i);
|
||||
num++; // include '\0'
|
||||
// printf("I: %ld ", i);
|
||||
BUFF_CHECK(num,buffsize);
|
||||
rrd_arg[argc++] = s;
|
||||
|
||||
buffsize -= num;
|
||||
s += num;
|
||||
}
|
||||
|
||||
/*
|
||||
RRD DB layout:
|
||||
1 x 5min = 5 min samples 7 * 288 ( per day ) = 2016 => 7 days
|
||||
24 x 5min = 2 hour samples 60 * 12 ( per day ) = 720 => 60 days
|
||||
288 x 5min = 1 day samples 180 * 1 ( per day ) = 180 => 180 days
|
||||
*/
|
||||
|
||||
num = snprintf(s, buffsize, "RRA:AVERAGE:0.5:1:2016");
|
||||
num++; // include '\0'
|
||||
BUFF_CHECK(num,buffsize);
|
||||
rrd_arg[argc++] = s;
|
||||
|
||||
buffsize -= num;
|
||||
s += num;
|
||||
|
||||
num = snprintf(s, buffsize, "RRA:AVERAGE:0.5:24:720");
|
||||
num++; // include '\0'
|
||||
BUFF_CHECK(num,buffsize);
|
||||
rrd_arg[argc++] = s;
|
||||
|
||||
buffsize -= num;
|
||||
s += num;
|
||||
|
||||
num = snprintf(s, buffsize, "RRA:AVERAGE:0.5:288:180");
|
||||
num++; // include '\0'
|
||||
BUFF_CHECK(num,buffsize);
|
||||
rrd_arg[argc] = s;
|
||||
|
||||
/*
|
||||
for ( i=0; i<=argc; i++ ) {
|
||||
printf("I:%ld %s\n", i, rrd_arg[i]);
|
||||
}
|
||||
*/
|
||||
|
||||
rrd_clear_error();
|
||||
if ( ( i=rrd_create(argc, rrd_arg))) {
|
||||
fprintf(stderr, "Create DB Error: %ld %s\n", i, rrd_get_error());
|
||||
}
|
||||
|
||||
} // End of CreateRRDB
|
||||
|
||||
int CreateRRDBs (char *path, time_t when) {
|
||||
const char progress[] = { '|', '/', '-', '|', '\\', '-' };
|
||||
char rrd_filename[1024];
|
||||
int fd, i, p, t, len, total;
|
||||
struct stat statbuf;
|
||||
void *buff;
|
||||
|
||||
// Check if path exists
|
||||
if ( (stat(path, &statbuf) < 0 ) || !(statbuf.st_mode & S_IFDIR) ) {
|
||||
fprintf(stderr, "No such directory: '%s'\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make stdout unbuffered for progress pointer
|
||||
setvbuf(stdout, (char *)NULL, _IONBF, 0);
|
||||
|
||||
printf("Create DBs ... ");
|
||||
|
||||
/*
|
||||
* we create an RRD DB file and will copy this file
|
||||
* that many time as required - so every RRD file looks the
|
||||
* same. They only distinguish by their name
|
||||
*/
|
||||
len = snprintf(rrd_filename, 1024, "%s/%s", path, TMPRRD);
|
||||
if ( len >= 1024 ) {
|
||||
fprintf(stderr, "Failed to concat RRD filename: string overflow");
|
||||
return 0;
|
||||
}
|
||||
|
||||
CreateRRDB(rrd_filename, when);
|
||||
if ( (i = stat(rrd_filename, &statbuf) < 0 )) {
|
||||
fprintf(stderr, "Can't create RRD file '%s': %s\n", rrd_filename, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
buff = malloc(statbuf.st_size);
|
||||
if ( !buff ) {
|
||||
perror("Buffer allocation failed");
|
||||
unlink(rrd_filename);
|
||||
return 0;
|
||||
}
|
||||
fd = open(rrd_filename, O_RDONLY, 0);
|
||||
if ( fd < 0 ) {
|
||||
perror("Failed to open RRD file");
|
||||
unlink(rrd_filename);
|
||||
return 0;
|
||||
}
|
||||
if ( read(fd, buff, statbuf.st_size) != statbuf.st_size ) {
|
||||
perror("Failed to read data from RRD file");
|
||||
close(fd);
|
||||
unlink(rrd_filename);
|
||||
return 0;
|
||||
}
|
||||
close(fd);
|
||||
unlink(rrd_filename);
|
||||
printf("\n");
|
||||
|
||||
// we are now ready to multiplicate the DB files
|
||||
total = 384; // 2 * 3 * 64 files total
|
||||
for (p=tcp; p<=udp; p++) { // for TCP and UDP
|
||||
for (t=flows; t<=bytes; t++) { // for flows, packets and bytes
|
||||
for (i=0; i<64; i++) { // Create 64 times an RRD DB - each for 1024 ports
|
||||
printf("Creating %s:%s %c Left: %d files \r", proto[p], type[t], progress[i % 6], total );
|
||||
len = snprintf(rrd_filename, 1024, "%s/%s-%s-%d.rrd", path, proto[p], type[t], i);
|
||||
if ( len >= 1024 ) {
|
||||
fprintf(stderr, "Failed to concat RRD filename: string overflow");
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
fd = open(rrd_filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
|
||||
if ( fd < 0 ) {
|
||||
fprintf(stderr, "Failed to create RRD file '%s': %s\n", rrd_filename, strerror(errno));
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
if ( write(fd, buff, statbuf.st_size) != statbuf.st_size ) {
|
||||
fprintf(stderr, "Failed to write RRD file '%s': %s\n", rrd_filename, strerror(errno));
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
close(fd);
|
||||
total--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
return 1;
|
||||
|
||||
} // End of CreateRRDBs
|
||||
|
||||
int RRD_StoreDataRow(char *path, char *iso_time, data_row *row) {
|
||||
char rrd_filename[1024], *buff, *s;
|
||||
char *rrd_arg[10];
|
||||
time_t when, frag;
|
||||
int i, j, len, p, t, buffsize, argc;
|
||||
uint32_t pnum;
|
||||
struct stat statbuf;
|
||||
|
||||
buffsize = MAXBUFF;
|
||||
buff = (char *)malloc(buffsize);
|
||||
if ( !buff ) {
|
||||
perror("Memory error!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
when = ISO2UNIX(iso_time);
|
||||
if ( !when )
|
||||
return 0;
|
||||
|
||||
// make sure, we are at a 5min boundary
|
||||
frag = when % 300;
|
||||
if ( frag ) {
|
||||
fprintf(stderr, "Round to next timeslot: offset %lld\n", (long long)frag);
|
||||
when -= frag;
|
||||
}
|
||||
|
||||
for ( p=tcp; p<=udp; p++ ) {
|
||||
// for every protocol TCP - UDP
|
||||
for ( t=flows; t<=bytes; t++ ) {
|
||||
// for every type flows - packets - bytes
|
||||
for (j=0; j<64; j++) {
|
||||
// for all 64 RRD files in proto - type
|
||||
len = snprintf(rrd_filename, 1024, "%s/%s-%s-%d.rrd", path, proto[p], type[t], j);
|
||||
if ( len >= 1024 ) {
|
||||
fprintf(stderr, "Failed to concat RRD filename: string overflow");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if RRD file exists
|
||||
if ( (stat(rrd_filename, &statbuf) < 0 ) || !(statbuf.st_mode & S_IFREG) ) {
|
||||
fprintf(stderr, "No such RRD file: '%s'\n", rrd_filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffsize = MAXBUFF;
|
||||
s = buff;
|
||||
|
||||
/* add time to RRD arg string */
|
||||
len = snprintf(s, buffsize, "%lld:", (long long)when);
|
||||
buffsize -= len;
|
||||
s += len;
|
||||
|
||||
/* add port data to RRD arg string */
|
||||
for ( i=0; i<1024; i++) {
|
||||
pnum = ( j << 10 ) + i;
|
||||
/*
|
||||
if ( row[pnum].proto[p].type[t] ) {
|
||||
fprintf(stderr, "%d %d %d\n", pnum, p, t);
|
||||
}
|
||||
*/
|
||||
len = snprintf(s, buffsize, "%llu:", (long long unsigned)row[pnum].proto[p].type[t]);
|
||||
if ( len >= buffsize ) {
|
||||
fprintf(stderr, "No enough space to create RRD arg\n");
|
||||
return 0;
|
||||
}
|
||||
buffsize -= len;
|
||||
s += len;
|
||||
}
|
||||
s--;
|
||||
*s = '\0';
|
||||
|
||||
// Create arg vector
|
||||
argc = 0;
|
||||
rrd_arg[argc++] = "update";
|
||||
rrd_arg[argc++] = rrd_filename;
|
||||
rrd_arg[argc++] = buff;
|
||||
rrd_arg[argc] = NULL;
|
||||
|
||||
optind = 0; opterr = 0;
|
||||
rrd_clear_error();
|
||||
if ( ( i=rrd_update(argc, rrd_arg))) {
|
||||
fprintf(stderr, "RRD: %s Insert Error: %d %s\n", rrd_filename, i, rrd_get_error());
|
||||
}
|
||||
} // for all 64 rrd files
|
||||
} // for every type flows - packets - bytes
|
||||
} // for every protocol TCP - UDP
|
||||
|
||||
return 1;
|
||||
} // End of RRD_StoreDataRow
|
||||
|
||||
data_row *RRD_GetDataRow(char *path, time_t when) {
|
||||
time_t last, frag;
|
||||
struct tm * t1, *t2;
|
||||
struct stat statbuf;
|
||||
char datestr1[64] , datestr2[64], rrd_filename[1024];
|
||||
char *rrd_arg[10];
|
||||
char **ds_namv;
|
||||
int ret, i, j, p, t, len, argc;
|
||||
unsigned long step, ds_cnt, pnum;
|
||||
data_row *row;
|
||||
rrd_value_t *data;
|
||||
uint64_t dummy;
|
||||
|
||||
data = NULL;
|
||||
frag = when % 300;
|
||||
if ( frag ) {
|
||||
fprintf(stderr, "Round to next timeslot: offset %lld\n", (long long)frag);
|
||||
when -= frag;
|
||||
}
|
||||
|
||||
last = RRD_LastUpdate(path);
|
||||
if ( when > last ) {
|
||||
t1 = localtime(&when);
|
||||
strftime(datestr1, 63, "%b %d %Y %T", t1);
|
||||
|
||||
t2 = localtime(&last);
|
||||
strftime(datestr2, 63, "%b %d %Y %T", t2);
|
||||
|
||||
fprintf(stderr, "Error get data: Requested time slot '%s' later then last available time slot '%s'\n",
|
||||
datestr1, datestr2);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
row = (data_row *)calloc(65536, sizeof(data_row));
|
||||
if ( !row ) {
|
||||
perror("Memory allocation error");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = snprintf(datestr1, 64, "--start=%lld", (long long)when);
|
||||
if ( len >= 64 ) {
|
||||
fprintf(stderr, "String overflow --start\n");
|
||||
free(row);
|
||||
return NULL;
|
||||
}
|
||||
len = snprintf(datestr2, 64, "--end=%lld", (long long)when);
|
||||
if ( len >= 64 ) {
|
||||
fprintf(stderr, "String overflow --end\n");
|
||||
free(row);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( p=tcp; p<=udp; p++ ) {
|
||||
// for every protocol TCP - UDP
|
||||
for ( t=flows; t<=bytes; t++ ) {
|
||||
// for every type flows - packets - bytes
|
||||
for (j=0; j<64; j++) {
|
||||
// for all 64 RRD files in proto - type
|
||||
len = snprintf(rrd_filename, 1024, "%s/%s-%s-%d.rrd", path, proto[p], type[t], j);
|
||||
if ( len >= 1024 ) {
|
||||
fprintf(stderr, "Failed to concat RRD filename: string overflow");
|
||||
free(row);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check if RRD file exists
|
||||
if ( (stat(rrd_filename, &statbuf) < 0 ) || !(statbuf.st_mode & S_IFREG) ) {
|
||||
fprintf(stderr, "No such RRD file: '%s'\n", rrd_filename);
|
||||
free(row);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Create arg vector
|
||||
argc = 0;
|
||||
rrd_arg[argc++] = "fetch";
|
||||
rrd_arg[argc++] = rrd_filename;
|
||||
rrd_arg[argc++] = "AVERAGE";
|
||||
rrd_arg[argc++] = datestr1;
|
||||
rrd_arg[argc++] = datestr2;
|
||||
rrd_arg[argc] = NULL;
|
||||
|
||||
optind = 0; opterr = 0;
|
||||
rrd_clear_error();
|
||||
if ( ( ret=rrd_fetch(argc, rrd_arg, &when, &when, &step, &ds_cnt, &ds_namv, &data))) {
|
||||
fprintf(stderr, "RRD: %s Fetch Error: %d %s\n", rrd_filename, ret, rrd_get_error());
|
||||
}
|
||||
if ( ds_cnt != 1024 ) {
|
||||
fprintf(stderr, "RRD: %s Fetch Error: Short read: Expected 1024 records got %lu\n",
|
||||
rrd_filename, ds_cnt);
|
||||
free(row);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( i=0; i<1024; i++) {
|
||||
pnum = ( j << 10 ) + i;
|
||||
dummy = data[0];
|
||||
row[pnum].proto[p].type[t] = dummy;
|
||||
}
|
||||
|
||||
free(ds_namv);
|
||||
free(data);
|
||||
|
||||
} // for all 64 rrd files
|
||||
} // for every type flows - packets - bytes
|
||||
} // for every protocol TCP - UDP
|
||||
|
||||
return row;
|
||||
|
||||
} // End of RRD_GetDataRow
|
||||
|
||||
time_t RRD_LastUpdate(char *path) {
|
||||
struct stat statbuf;
|
||||
char rrd_filename[1024];
|
||||
char *rrd_arg[10];
|
||||
time_t when;
|
||||
int len, argc;
|
||||
|
||||
// Get timestamp from the first file
|
||||
len = snprintf(rrd_filename, 1024, "%s/%s-%s-%d.rrd", path, "tcp", "flows", 0);
|
||||
if ( len >= 1024 ) {
|
||||
fprintf(stderr, "Failed to concat RRD filename: string overflow");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if RRD file exists
|
||||
if ( (stat(rrd_filename, &statbuf) < 0 ) || !(statbuf.st_mode & S_IFREG) ) {
|
||||
fprintf(stderr, "RRD files not found in '%s'\n", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
argc = 0;
|
||||
rrd_arg[argc++] = "last";
|
||||
rrd_arg[argc++] = rrd_filename;
|
||||
rrd_arg[argc] = NULL;
|
||||
|
||||
when = rrd_last(argc, rrd_arg);
|
||||
|
||||
return when;
|
||||
|
||||
} // End of RRD_LastUpdate
|
||||
|
||||
/*
|
||||
int main () {
|
||||
char *buff, *s, *rrd_arg[10];
|
||||
long i, num, buffsize, argc;
|
||||
time_t now;
|
||||
|
||||
CreateRRDBs("/data/rrd-db");
|
||||
exit(0);
|
||||
|
||||
buffsize = 15 * 1024;
|
||||
buff = (char *)malloc(buffsize);
|
||||
if ( !buff ) {
|
||||
perror("Memory error!");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
s = buff;
|
||||
now = time(NULL);
|
||||
now -= now % 300;
|
||||
|
||||
num = snprintf(s, buffsize, "%ld:", now);
|
||||
// num = snprintf(s, buffsize, "N:");
|
||||
buffsize -= num;
|
||||
s += num;
|
||||
|
||||
for ( i=0; i<1024; i++) {
|
||||
num = snprintf(s, buffsize, "%ld:", i);
|
||||
if ( num >= buffsize ) {
|
||||
fprintf(stderr, "No enough space to create RRD arg\n");
|
||||
exit(0);
|
||||
}
|
||||
buffsize -= num;
|
||||
s += num;
|
||||
}
|
||||
s--;
|
||||
*s = '\0';
|
||||
printf("String: %s\n", buff);
|
||||
|
||||
argc = 0;
|
||||
rrd_arg[argc++] = "update";
|
||||
rrd_arg[argc++] = "ports.rrd";
|
||||
rrd_arg[argc++] = buff;
|
||||
rrd_arg[argc] = NULL;
|
||||
|
||||
rrd_clear_error();
|
||||
if ( ( i=rrd_update(argc, rrd_arg))) {
|
||||
fprintf(stderr, "Insert Error: %ld %s\n", i, rrd_get_error());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
*/
|
50
extra/nftrack/nftrack_rrd.h
Normal file
50
extra/nftrack/nftrack_rrd.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* Copyright (c) 2004-2008, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Author: peter $
|
||||
*
|
||||
* $Id: nftrack_rrd.h 224 2014-02-16 12:59:29Z peter $
|
||||
*
|
||||
* $LastChangedRevision: 224 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
int CreateRRDBs (char *path, time_t when);
|
||||
|
||||
int RRD_StoreDataRow(char *path, char *iso_time, data_row *row);
|
||||
|
||||
data_row *RRD_GetDataRow(char *path, time_t when);
|
||||
|
||||
time_t RRD_LastUpdate(char *path);
|
||||
|
||||
time_t RRD_First(char *path);
|
||||
|
||||
time_t ISO2UNIX(char *tstring);
|
478
extra/nftrack/nftrack_stat.c
Normal file
478
extra/nftrack/nftrack_stat.c
Normal file
@ -0,0 +1,478 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Author: peter $
|
||||
*
|
||||
* $Id: nftrack_stat.c 224 2014-02-16 12:59:29Z peter $
|
||||
*
|
||||
* $LastChangedRevision: 224 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "nftrack_stat.h"
|
||||
#include "nftrack_rrd.h"
|
||||
|
||||
#define STATFILE "ports.stat"
|
||||
|
||||
#define NUMPORTS 65536
|
||||
|
||||
// 288 slots per day
|
||||
#define MAX_SLOTS 288
|
||||
|
||||
typedef struct stat_header_s {
|
||||
uint16_t version;
|
||||
int av_num;
|
||||
time_t last;
|
||||
} stat_header_t;
|
||||
|
||||
typedef struct topN_vector_s {
|
||||
uint16_t port;
|
||||
uint64_t count;
|
||||
} topN_vector_t;
|
||||
|
||||
static stat_header_t stat_header;
|
||||
static data_row *stat_record;
|
||||
static char statfile[MAXPATHLEN];
|
||||
static char dbpath[MAXPATHLEN];
|
||||
static int dirty;
|
||||
|
||||
/* prototypes */
|
||||
static void ReadStat(void);
|
||||
static void heapSort(topN_vector_t *vector, int array_size, int topN);
|
||||
static void siftDown(topN_vector_t *vector, int root, int bottom);
|
||||
|
||||
int InitStat(char *path) {
|
||||
int len;
|
||||
stat_header.version = 0;
|
||||
stat_record = NULL;
|
||||
|
||||
len = snprintf(statfile, MAXPATHLEN, "%s/%s", path, STATFILE);
|
||||
if ( len >= MAXPATHLEN ) {
|
||||
LogError("String overflow: statfile name\n");
|
||||
statfile[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
len = snprintf(dbpath, MAXPATHLEN, "%s", path);
|
||||
dirty = 0;
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of InitStat
|
||||
|
||||
int InitStatFile(void) {
|
||||
ssize_t num;
|
||||
int fd;
|
||||
|
||||
if ( statfile[0] == 0 )
|
||||
return 0;
|
||||
|
||||
stat_record = (data_row *)calloc(NUMPORTS, sizeof(data_row));
|
||||
if ( !stat_record ) {
|
||||
LogError("calloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd = open(statfile, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
|
||||
if ( fd < 0 ) {
|
||||
LogError("open() error for %s in %s line %d: %s\n", statfile, __FILE__, __LINE__, strerror(errno) );
|
||||
free(stat_record);
|
||||
stat_record = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
stat_header.version = 1;
|
||||
stat_header.av_num = 0;
|
||||
stat_header.last = 0;
|
||||
|
||||
num = write(fd, &stat_header, sizeof(stat_header));
|
||||
num = write(fd, stat_record, NUMPORTS * sizeof(data_row));
|
||||
if ( num < 0 ) {
|
||||
LogError("write() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
stat_header.version = 0;
|
||||
free(stat_record);
|
||||
stat_record = NULL;
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of InitStatFile
|
||||
|
||||
data_row *GetStat(void) {
|
||||
|
||||
if ( !stat_record )
|
||||
ReadStat();
|
||||
|
||||
return stat_record;
|
||||
|
||||
} // End of GetStat
|
||||
|
||||
int CloseStat(void) {
|
||||
int fd;
|
||||
ssize_t num;
|
||||
|
||||
if ( statfile[0] == 0 || !dirty )
|
||||
return 1;
|
||||
|
||||
fd = open(statfile, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
|
||||
if ( fd < 0 ) {
|
||||
LogError("open() error for %s in %s line %d: %s\n", statfile, __FILE__, __LINE__, strerror(errno) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = write(fd, (void *)&stat_header, sizeof(stat_header));
|
||||
if ( num < 0 ) {
|
||||
LogError("write() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = write(fd, stat_record, NUMPORTS * sizeof(data_row));
|
||||
if ( num < 0 ) {
|
||||
LogError("write() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(stat_record);
|
||||
stat_record = NULL;
|
||||
stat_header.version = 0;
|
||||
close(fd);
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of CloseStat
|
||||
|
||||
static void ReadStat(void) {
|
||||
int fd;
|
||||
ssize_t num;
|
||||
|
||||
if ( statfile[0] == 0 )
|
||||
return;
|
||||
|
||||
stat_record = (data_row *)calloc(NUMPORTS, sizeof(data_row));
|
||||
if ( !stat_record ) {
|
||||
LogError("calloc() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open(statfile, O_RDONLY );
|
||||
if ( fd < 0 ) {
|
||||
// allow to delete the stat file to restart stat from scratch
|
||||
if ( errno == ENOENT ) {
|
||||
LogError("Missing stat file - re-initialise\n");
|
||||
if ( InitStatFile() ) {
|
||||
fd = open(statfile, O_RDONLY );
|
||||
if ( fd < 0 ) {
|
||||
LogError("open() error for %s in %s line %d: %s\n", statfile, __FILE__, __LINE__, strerror(errno) );
|
||||
free(stat_record);
|
||||
stat_record = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LogError("open() error for %s in %s line %d: %s\n", statfile, __FILE__, __LINE__, strerror(errno) );
|
||||
free(stat_record);
|
||||
stat_record = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
num = read(fd, (void *)&stat_header, sizeof(stat_header));
|
||||
if ( num < 0 ) {
|
||||
LogError("read() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
free(stat_record);
|
||||
stat_record = NULL;
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( stat_header.version != 1 ) {
|
||||
LogError("Version error stat file. Found version: %d expected: 1\n", stat_header.version);
|
||||
free(stat_record);
|
||||
stat_record = NULL;
|
||||
stat_header.version = 0;
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
num = read(fd, stat_record, NUMPORTS * sizeof(data_row));
|
||||
if ( num < 0 ) {
|
||||
LogError("read() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
|
||||
free(stat_record);
|
||||
stat_record = NULL;
|
||||
stat_header.version = 0;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
} // End of ReadStat
|
||||
|
||||
void ClearStat(void) {
|
||||
memset((void *)stat_record, 0, NUMPORTS * sizeof(data_row));
|
||||
stat_header.av_num = 0;
|
||||
stat_header.last = 0;
|
||||
} // End of ClearStat
|
||||
|
||||
int UpdateStat(data_row *row, time_t when) {
|
||||
int pnum, p, t;
|
||||
time_t last_rrd, first_stat;
|
||||
|
||||
if ( !stat_record ) {
|
||||
ReadStat();
|
||||
if ( !stat_record )
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( stat_header.av_num > MAX_SLOTS ) {
|
||||
LogError("Too many slots aggregated: %i. Expected max. %i", stat_header.av_num, MAX_SLOTS);
|
||||
LogError("Stat: Num : %i", stat_header.av_num);
|
||||
LogError("Stat: last: %s", ctime(&stat_header.last));
|
||||
// should not happend - anyway consider stat record to be corrupt - > clear
|
||||
ClearStat();
|
||||
}
|
||||
|
||||
last_rrd = RRD_LastUpdate(dbpath);
|
||||
if ( stat_header.last && (last_rrd != stat_header.last) ) {
|
||||
LogError("RRD and stat record out of sync. %i != %i", last_rrd, stat_header.last);
|
||||
LogError("Stat: Num : %i", stat_header.av_num);
|
||||
LogError("Stat: last: %s", ctime(&stat_header.last));
|
||||
LogError("RRD : last: %s", ctime(&last_rrd));
|
||||
// should not happend - anyway consider stat record to be corrupt - > clear
|
||||
ClearStat();
|
||||
}
|
||||
|
||||
if ( stat_header.last && ((when - (300*MAX_SLOTS)) > stat_header.last) ) {
|
||||
LogError("Last stat update too far in the past -> clear stat record");
|
||||
LogError("Stat: Num : %i", stat_header.av_num);
|
||||
LogError("Stat: last: %s", ctime(&stat_header.last));
|
||||
// last update too far in the past -> clear stat record
|
||||
ClearStat();
|
||||
}
|
||||
if ( stat_header.last && (when - stat_header.last) > 1800 ) {
|
||||
LogError("Last stat update too far in the past -> clear stat record");
|
||||
LogError("Stat: Num : %i", stat_header.av_num);
|
||||
LogError("Stat: last: %s", ctime(&stat_header.last));
|
||||
// last update too far in the past -> clear stat record
|
||||
ClearStat();
|
||||
}
|
||||
|
||||
if ( stat_header.av_num ) {
|
||||
first_stat = stat_header.last - (stat_header.av_num-1)*300;
|
||||
} else {
|
||||
first_stat = 0;
|
||||
}
|
||||
|
||||
if ( stat_header.av_num == MAX_SLOTS ) {
|
||||
time_t tslot;
|
||||
data_row *oldrow;
|
||||
for ( tslot = first_stat; tslot < when - ((MAX_SLOTS-1)*300); tslot += 300 ) {
|
||||
oldrow = RRD_GetDataRow(dbpath, tslot);
|
||||
if ( !oldrow ) {
|
||||
LogError("Failed to fetch RRD datarow");
|
||||
break;
|
||||
}
|
||||
LogInfo("Remove stat line %s\n", ctime(&tslot));
|
||||
for(pnum=0; pnum<NUMPORTS; pnum++ ) {
|
||||
for (p=0; p<2; p++) {
|
||||
for (t=0; t<3; t++) {
|
||||
stat_record[pnum].proto[p].type[t] -= oldrow[pnum].proto[p].type[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
stat_header.av_num--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add new slot
|
||||
for(pnum=0; pnum<NUMPORTS; pnum++ ) {
|
||||
for (p=0; p<2; p++) {
|
||||
for (t=0; t<3; t++) {
|
||||
stat_record[pnum].proto[p].type[t] += row[pnum].proto[p].type[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
stat_header.av_num++;
|
||||
stat_header.last = when;
|
||||
dirty = 1;
|
||||
|
||||
LogInfo("UpdateStat: Num : %i\n", stat_header.av_num);
|
||||
LogInfo("UpdateStat: last: %s\n", ctime(&stat_header.last));
|
||||
|
||||
return 1;
|
||||
|
||||
} // End of UpdateStat
|
||||
|
||||
void Generate_TopN(data_row *row, int n, int scale, time_t when, int output_mode, char *wfile) {
|
||||
int i, p, t, pnum;
|
||||
FILE *wfd;
|
||||
topN_vector_t *topN_vector;
|
||||
static const char *proto[] = { "TCP", "UDP" };
|
||||
static const char *type[] = { "Flows", "Packets", "Bytes" };
|
||||
|
||||
if ( wfile ) {
|
||||
wfd = strcmp(wfile, "-") == 0 ? stdout :
|
||||
fopen(wfile, "w");
|
||||
if ( wfd == NULL ) {
|
||||
perror("Can't open output file for writing");
|
||||
return;
|
||||
}
|
||||
} else
|
||||
wfd = stdout;
|
||||
|
||||
topN_vector = (topN_vector_t *)malloc((NUMPORTS+1) * sizeof(struct topN_vector_s));
|
||||
if ( !topN_vector ) {
|
||||
perror("Memory error");
|
||||
exit(255);
|
||||
}
|
||||
|
||||
// Add new slot
|
||||
if ( when == 0 )
|
||||
when = stat_header.last;
|
||||
if ( output_mode != 0 )
|
||||
fprintf(wfd, "%i\n", (int)when);
|
||||
for (p=0; p<2; p++) {
|
||||
for (t=0; t<3; t++) {
|
||||
for(pnum=0; pnum<NUMPORTS; pnum++ ) {
|
||||
topN_vector[pnum].port = pnum;
|
||||
topN_vector[pnum].count = row[pnum].proto[p].type[t];
|
||||
if ( scale && stat_header.av_num ) {
|
||||
topN_vector[pnum].count /= stat_header.av_num;
|
||||
}
|
||||
}
|
||||
heapSort(topN_vector, NUMPORTS, n);
|
||||
if ( output_mode == 0 ) {
|
||||
fprintf(wfd, "Top %i %s Proto %s\n", n, type[t], proto[p]);
|
||||
for (i = NUMPORTS-1; i > ( NUMPORTS-n-1 ); i--)
|
||||
fprintf(wfd, "%u %llu\n", topN_vector[i].port, (long long unsigned)topN_vector[i].count);
|
||||
fprintf(wfd, "\n");
|
||||
} else {
|
||||
fprintf(wfd, "%i %i %i\n", n, t, p);
|
||||
for (i = NUMPORTS-1; i > ( NUMPORTS-n-1 ); i--)
|
||||
fprintf(wfd, "%u ", topN_vector[i].port);
|
||||
fprintf(wfd, "\n");
|
||||
for (i = NUMPORTS-1; i > ( NUMPORTS-n-1 ); i--)
|
||||
fprintf(wfd, "%llu ", (long long unsigned)topN_vector[i].count);
|
||||
fprintf(wfd, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( wfile )
|
||||
fclose(wfd);
|
||||
|
||||
} // End of TopN
|
||||
|
||||
static void heapSort(topN_vector_t *vector, int array_size, int topN) {
|
||||
topN_vector_t temp;
|
||||
int32_t i, top_count;
|
||||
|
||||
for (i = (array_size / 2)-1; i >= 0; i--)
|
||||
siftDown(vector, i, array_size);
|
||||
|
||||
top_count = 1;
|
||||
|
||||
for (i = array_size-1; i >= 1; i--) {
|
||||
temp = vector[0];
|
||||
vector[0] = vector[i];
|
||||
vector[i] = temp;
|
||||
siftDown(vector, 0, i-1);
|
||||
if ( top_count == topN )
|
||||
return;
|
||||
top_count++;
|
||||
}
|
||||
|
||||
} // End of heapSort
|
||||
|
||||
|
||||
static void siftDown(topN_vector_t *vector, int root, int bottom) {
|
||||
uint32_t done, maxChild;
|
||||
topN_vector_t temp;
|
||||
|
||||
done = 0;
|
||||
while ((root*2 <= bottom) && (!done)) {
|
||||
if (root*2 == bottom)
|
||||
maxChild = root * 2;
|
||||
else if (vector[root * 2].count > vector[root * 2 + 1].count)
|
||||
maxChild = root * 2;
|
||||
else
|
||||
maxChild = root * 2 + 1;
|
||||
|
||||
if (vector[root].count < vector[maxChild].count ) {
|
||||
temp = vector[root];
|
||||
vector[root] = vector[maxChild];
|
||||
vector[maxChild] = temp;
|
||||
root = maxChild;
|
||||
} else
|
||||
done = 1;
|
||||
}
|
||||
} // End of siftDown
|
||||
|
||||
int Lister(data_row *row) {
|
||||
int pnum, p, t;
|
||||
|
||||
if ( !row ) {
|
||||
LogError("Lister: Empty row!\n");
|
||||
return 0;
|
||||
}
|
||||
for(pnum=0; pnum<NUMPORTS; pnum++ ) {
|
||||
for (p=0; p<2; p++) {
|
||||
for (t=0; t<3; t++) {
|
||||
if ( row[pnum].proto[p].type[t] ) {
|
||||
LogError("%d %d %d: %llu\n", pnum, p, t, (long long unsigned)row[pnum].proto[p].type[t]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
} // List
|
||||
|
||||
|
66
extra/nftrack/nftrack_stat.h
Normal file
66
extra/nftrack/nftrack_stat.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Peter Haag
|
||||
* Copyright (c) 2009, Peter Haag
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Author: peter $
|
||||
*
|
||||
* $Id: nftrack_stat.h 224 2014-02-16 12:59:29Z peter $
|
||||
*
|
||||
* $LastChangedRevision: 224 $
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
typedef struct data_element_s {
|
||||
uint64_t type[3]; // 0 - flows 1 - packets 2- bytes
|
||||
} data_element;
|
||||
|
||||
typedef struct data_row_s {
|
||||
data_element proto[2]; // 0 - tcp 1 - udp
|
||||
} data_row;
|
||||
|
||||
// to be used as index
|
||||
enum { tcp = 0, udp };
|
||||
enum { flows = 0, packets, bytes };
|
||||
|
||||
int InitStat(char *path);
|
||||
|
||||
int CloseStat(void);
|
||||
|
||||
int InitStatFile(void);
|
||||
|
||||
data_row *GetStat(void);
|
||||
|
||||
void ClearStat(void);
|
||||
|
||||
int UpdateStat(data_row *row, time_t when);
|
||||
|
||||
void Generate_TopN(data_row *row, int n, int scale, time_t when, int output_mode, char *wfile);
|
||||
|
||||
int Lister(data_row *row);
|
Loading…
x
Reference in New Issue
Block a user