Add missing nftrack to git

This commit is contained in:
Peter Haag 2015-11-21 12:42:58 +01:00
parent 7ffa3cb493
commit 69d46a710d
6 changed files with 1675 additions and 336 deletions

View File

@ -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
View 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
View 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;
}
*/

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

View 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

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