/* $Id: report.c,v 1.6 2006/03/03 17:27:38 bhockney Exp $ */ /* (C) 2004-2006 by Bob Hockney * * Based on fwlogwatch written by * * Boris Wesslowski * * * * report generation for wfwl_syslog * * * * This code is distributed under the terms of GNU GPL */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "main.h" #include "parser.h" #include "compare.h" #include "utils.h" #include "database.h" #include "output.h" #ifdef HAVE_LIBZ #include #endif /* These are structs have global scope */ extern struct options opt; extern struct conn_data *first; extern struct input_file *first_file; extern struct field_order *fields; extern struct sort_order *sort; extern struct fields_used fields_used; extern struct select_sum select_sum; extern struct conn_data_sum *data_sum; /* select based on aggregate criteria */ struct conn_data * select_aggregate(struct conn_data *list) { struct conn_data *this, *new=NULL, *add, *old; unsigned long int numrows = 0; this = list; while (this != NULL) { if (!((select_sum.min_count != 0 && this->count < select_sum.min_count) || (select_sum.max_count != 0 && this->count > select_sum.max_count) || (select_sum.max_earliest != 0 && this->start_time > select_sum.max_earliest) || (select_sum.min_latest != 0 && this->end_time < select_sum.min_latest))) { numrows++; add = xmalloc(sizeof(struct conn_data)); *add = *this; if (new == NULL) { new = add; new->next=NULL; } else { add->next = new; new = add; } } old = this; this = this->next; free(old); } opt.report_rows = numrows; return new; } /* PARSE INPUT FILES AND OUTPUT REPORT */ /* This function is the main routine for parsing and outputting reports */ /* It calls other functions as needed */ /* Called without parameters; uses global structs, above */ void generate_report() { char buf[BUFSIZE], *input = NULL, last_file = 0; FILE *output = NULL; int j, retval, linenum = 0, hitnum = 0, hit = 0, errnum = 0, oldnum = 0, exnum = 0; struct input_file *file; struct field_order *flds; struct sort_order *srt; struct timeval *segtime; long int hostsupdtime = 0, servicesupdtime = 0, populatecachetime = 0; opt.line = xmalloc(sizeof(struct log_line)); if (opt.verbose >= VERBOSE_ERROR) { fprintf(stderr, ". = accepted\n"); fprintf(stderr, "e = excluded\n"); fprintf(stderr, "r = repeated\n"); fprintf(stderr, "_ = not packet log entry\n"); } /* get file handle of next file to process, stdin if '-' specified */ file = first_file; while (last_file == 0) { if (opt.std_in) { if (opt.verbose >= VERBOSE_INFO) fprintf(stderr, "Processing input from stdin\n"); opt.inputfd = stdin; } else { input = file->name; if (opt.verbose >= VERBOSE_INFO) fprintf(stderr, "Processing input file '%s'\n", input); #ifdef HAVE_LIBZ opt.inputfd = gzopen(input, "rb"); #else opt.inputfd = fopen(input, "r"); #endif if (opt.inputfd == NULL) { #ifdef HAVE_LIBZ fprintf(stderr, "gzopen %s: %s\n", input, strerror(errno)); #else fprintf(stderr, "fopen %s: %s\n", input, strerror(errno)); #endif } } /* read first line from input file */ #ifdef HAVE_LIBZ if (opt.std_in) { #endif retval = (fgets(buf, BUFSIZE, opt.inputfd) != NULL); #ifdef HAVE_LIBZ } else { retval = (gzgets(opt.inputfd, buf, BUFSIZE) != Z_NULL); } #endif xstrncpy(opt.filename, input + strlen(opt.pathname), FILESIZE); linenum = 0; if(opt.packet) { for (j = 1; j < opt.packet; j++) { #ifdef HAVE_LIBZ if (opt.std_in) { #endif retval = (fgets(buf, BUFSIZE, opt.inputfd) != NULL); #ifdef HAVE_LIBZ } else { retval = (gzgets(opt.inputfd, buf, BUFSIZE) != Z_NULL); } #endif } } /* process lines until EOF */ while (retval) { ++linenum; hit = PARSE_NO_HIT; hit = parse_line(buf, linenum); opt.repeated = 0; switch (hit) { case PARSE_OK: ++hitnum; opt.matched_entries++; opt.repeated = 1; break; case PARSE_WRONG_FORMAT: ++errnum; break; case PARSE_TOO_OLD: ++oldnum; break; case PARSE_EXCLUDED: ++hitnum; ++exnum; break; default: break; } /* only do one line if packet report */ if (opt.packet) break; /* get next line from input file */ #ifdef HAVE_LIBZ if (opt.std_in) { #endif retval = (fgets(buf, BUFSIZE, opt.inputfd) != NULL); #ifdef HAVE_LIBZ } else { retval = (gzgets(opt.inputfd, buf, BUFSIZE) != Z_NULL); } #endif } /* After each input file, print line break following progress indication */ if (opt.verbose >= VERBOSE_ERROR) fprintf(stderr, ".\n"); /* set next input file or indicate done with last_file=1 */ if(opt.std_in) { last_file++; } else { if (opt.verbose >= VERBOSE_WARNING) fprintf(stderr, "Done processing input from '%s'\n", input); #ifndef HAVE_LIBZ retval = fclose(opt.inputfd); if (retval == EOF) { perror("fclose"); #else retval = gzclose(opt.inputfd); if (retval != 0) { if (retval != Z_ERRNO) { fprintf(stderr, "gzclose %s: %s\n", input, gzerror(opt.inputfd, &retval)); } else { perror("gzclose"); } #endif } if (file->next != NULL) { file = file->next; } else { last_file++; } } } /* end while (last_file == 0) */ free(opt.line); if (opt.mode == LOG_SUMMARY) first = select_aggregate(first); if (opt.verbose >= VERBOSE_INFO) { fprintf(stderr, "Sorting data\n"); } srt = sort; while (srt != NULL && srt->position != SORT_INV_NO_SORT) { opt.sortfield = srt->field; opt.sortmode = srt->order; first = wfwl_sort(first); if(opt.verbose >= VERBOSE_ERROR) fprintf(stderr, "."); srt = srt->next; } if (opt.verbose >= VERBOSE_ERROR) fprintf(stderr, ".\n"); segtime = xmalloc(sizeof(struct timeval)); gettimeofday(segtime, NULL); /* resolve host and service names if specified */ if (opt.resolve_hosts & CACHE_UPDATE) { if (fields_used.dhost_name || fields_used.shost_name) { hostsupdtime = segtime->tv_sec; resolve_hosts(); gettimeofday(segtime, NULL); hostsupdtime = segtime->tv_sec - hostsupdtime; } if (fields_used.dst_service || fields_used.src_service) { servicesupdtime = segtime->tv_sec; resolve_services(); gettimeofday(segtime, NULL); servicesupdtime = segtime->tv_sec - servicesupdtime; } } if (opt.resolve_hosts & CACHE_POPULATE) { populatecachetime = segtime->tv_sec; populate_cache(); gettimeofday(segtime, NULL); populatecachetime = segtime->tv_sec - populatecachetime; } /* use outfile if specified */ if (opt.use_out) { if (opt.verbose >= VERBOSE_INFO) fprintf(stderr, "Writing to output file '%s'\n", opt.outputfile); /* redirect stdout to outfile */ output = freopen(opt.outputfile, "w", stdout); if (output == NULL) { fprintf(stderr, "freopen %s: %s\n", opt.outputfile, strerror(errno)); exit(EXIT_FAILURE); } } else { /* otherwise use stdout */ output = stdout; } /* OUTPUT DATA */ /* output contains file handle for output */ if (!opt.use_out) fprintf(output, "\n"); flds = fields; while (flds != NULL) { fprintf(output, "%s\t", flds->keyname); flds = flds->next; } fprintf(output, "\n"); show_list(output); fprintf(output, "\n"); fprintf(output, "%lu\n", opt.report_rows); fprintf(output, "%lu\n", opt.matched_entries); fprintf(output, "%li\n", hostsupdtime); fprintf(output, "%li\n", servicesupdtime); fprintf(output, "%li\n", populatecachetime); /* clean up */ free_conn_data(); free_input_file(); if (opt.use_out) { if (opt.verbose >= VERBOSE_WARNING) fprintf(stderr, "Closing '%s'\n", opt.outputfile); retval = fclose(output); if (retval == EOF) { perror("fclose"); } } }