/* ** Modular Logfile Analyzer ** Copyright 2000 Jan Kneschke ** ** Homepage: http://www.modlogan.org ** This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version, and provided that the above copyright and permission notice is included with all distributed copies of this or derived software. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ** ** $Id: generate.c,v 1.27 2003/06/03 16:35:52 ostborn Exp $ */ #include #include #include #include #include #include #include #include #include #include "mconfig.h" #include "mstate.h" #include "mlocale.h" #include "mhash.h" #include "mlist.h" #include "mdatatypes.h" #include "mplugins.h" #include "plugin_config.h" #if 0 #define DEBUG_STRREP #endif int mplugins_output_text_ippl_generate_monthly_output(mconfig *ext_conf, mstate *state, const char *subpath); int mplugins_output_text_mail_generate_monthly_output(mconfig *ext_conf, mstate *state, const char *subpath); char *put_gap_before( float ); int show_data_stat_ippl(mconfig *ext_conf, FILE *f, mhash *h, int count, int formlenght); mdata_ipplwatchelement **sort_ipplwatchelements( mdata_ipplwatchelement **src, int num); mdata_ipplwatchelement **sort_ipplwatchelements( mdata_ipplwatchelement **src, int num ) { int i, ii; mdata_ipplwatchelement **tosort, **sorted; if (num<2) return src; tosort = malloc( sizeof(mdata_ipplwatchelement *) * num); memcpy( tosort, src, num * sizeof(mdata_ipplwatchelement *)); sorted = malloc( sizeof(mdata_ipplwatchelement *) * num); for (ii=0; iicount >= countnum) { countnum = tosort[i]->count; elemaxnum = i; } } if (elemaxnum > -1) { sorted[ii] = tosort[elemaxnum]; tosort[elemaxnum] = NULL; } else { fprintf(stderr, "%s.%d: Fatal error: something screwed up in sort!\n", __FILE__, __LINE__ ); } } return sorted; } int mlist_sumup(mlist *l) { int c = 0; if (!l) return 0; while (l) { if (l->data) { c += mdata_get_count(l->data); } l = l->next; } return c; } long mhash_sumup(mhash *h) { int i, c = 0; if (!h) return 0; for ( i = 0; i < h->size; i++) { c += mlist_sumup(h->data[i]->list); } return c; } mlist * get_next_element(mhash *h) { mlist *ret = NULL; int max = 0, i; for ( i = 0; i < h->size; i++) { mlist *l = h->data[i]->list; while (l) { if (l->data) { mdata *data = l->data; if ( mdata_get_count(data) > max) { max = mdata_get_count(data); ret = l; } } l = l->next; } } if (ret) { mdata_set_count(ret->data, -mdata_get_count(ret->data)); } return ret; } int cleanup_elements(mhash *h) { int i; for ( i = 0; i < h->size; i++) { mlist *l = h->data[i]->list; while (l) { if (l->data) { mdata *data = l->data; mdata_set_count(data, -mdata_get_count(data)); } l = l->next; } } return 0; } int show_visit_path (mconfig *ext_conf, FILE *f, mhash *h, int count) { int i = 0; mlist *l; long sum; if (!h) return 0; sum = mhash_sumup(h); while ((l = get_next_element(h)) && i < count) { if (l->data) { mdata *data = l->data; int c = -mdata_get_count(data); i++; fprintf(f,"%2d %8d %6.2f %s\n", i, c, c * 100.0 / sum, data->key); } } cleanup_elements(h); return 0; } int show_port_stat_ippl(mconfig *ext_conf, FILE *f, mhash *h, int count) { return show_data_stat_ippl( ext_conf, f, h, count, 5 ); } int show_host_stat_ippl(mconfig *ext_conf, FILE *f, mhash *h, int count) { return show_data_stat_ippl( ext_conf, f, h, count, 15 ); } int show_data_stat_ippl(mconfig *ext_conf, FILE *f, mhash *h, int count, int formlength) { int i = 0; mlist *l; long sum; if (!h) return 0; sum = mhash_sumup(h); while ((l = get_next_element(h)) && i < count) { if (l->data) { mdata *data = l->data; int c = -mdata_get_count(data); i++; fprintf(f, "| %2d | %8d | %s%3.2f | %*s |\n", i, c, put_gap_before( c * 100.0 / sum ), c * 100.0 / sum, formlength, data->key); } } cleanup_elements(h); return 0; } int mplugins_output_text_generate_monthly_output(mconfig *ext_conf, mstate *state, const char *subpath) { if (state == NULL) return -1; if (state->ext == NULL) return -1; switch (state->ext_type ) { case M_STATE_TYPE_MAIL: return mplugins_output_text_mail_generate_monthly_output(ext_conf, state, subpath); case M_STATE_TYPE_IPPL: return mplugins_output_text_ippl_generate_monthly_output(ext_conf, state, subpath); default: return -1; } } char* strrep( char *torep, int num ) { int resize; char *result; if (!num) return NULL; if (num==1) { return strdup( torep ); } #ifdef DEBUG_STRREP fprintf( stderr, "Calculating result size..." ); #endif resize = num * strlen( torep ) + 1; #ifdef DEBUG_STRREP fprintf( stderr, "done, %d.\nAllocating result memory and filling w/ original content...", resize ); #endif /* we use strn* because we don't want buffer overrun for * extremely _long_ strings.. (Miham) */ result = strncpy( malloc( resize ), torep, (resize-1) / num ); result[1] = 0; #ifdef DEBUG_STRREP fprintf( stderr, "done, '%s'.\nEntering while-loop...", result ); #endif while( --num ) { #ifdef DEBUG_STRREP fprintf( stderr, "done.\nConcatenating to '%s'...", result ); #endif result = strncat( result, torep, (resize-1) / num ); } #ifdef DEBUG_STRREP fprintf( stderr, "done.\nResult is '%s'.\nReturning result and leaving strrep...\n", result ); #endif return result; } char *put_gap_before( float percent ) { if (percent < 10.0 ) return " "; if (percent < 100.0) return " "; return ""; } int mplugins_output_text_ippl_generate_monthly_output(mconfig *ext_conf, mstate *state, const char *subpath) { FILE *f = NULL; char filename[255]; config_output *conf = ext_conf->plugin_conf; mstate_ippl *staipl = NULL; marray_ippl sum; int i; int pad; char *padstr; long psum; if (state == NULL) return -1; if (state->ext == NULL) return -1; if (state->ext_type != M_STATE_TYPE_IPPL) return -1; staipl = state->ext; if (subpath) { sprintf(filename, "%s/%s/", conf->outputdir ? conf->outputdir : ".", subpath); mkdir(filename, 0755); } sprintf(filename, "%s%s%s/index-%04d%02d.txt", conf->outputdir ? conf->outputdir : ".", subpath ? "/" : "", subpath ? subpath : "", state->year, state->month ); if (!(f = fopen(filename, "w"))) { return -1; } /* Main title */ pad = 80 - 19 - strlen( conf->hostname ); if (pad > 1) { pad /= 2; padstr = strrep( strdup(" "), pad); } else { padstr = 0; } fprintf(f, "\n%s+----------------%s-+\n", padstr, strrep( strdup("-"), strlen( conf->hostname ) ) ); fprintf(f, "%s| ippl-stats for %s |\n", padstr, conf->hostname); fprintf(f, "%s+----------------%s-+\n\n", padstr, strrep( strdup("-"), strlen( conf->hostname ) ) ); /* hourly stat */ sum.packets = 0; sum.hosts = 0; sum.ports = 0; sum.portscannum = 0; fprintf(f, "\n+------------------------------------------------+\n"); fprintf(f, "| Hourly statistics for packets, hosts and ports |\n"); fprintf(f, "+-------+----------+----------+----------+-------+--+\n"); fprintf(f,"| %5s | %8s | %8s | %8s | %8s |\n", "hour", "packets", "hosts", "ports", "portscan"); fprintf(f, "+-------+----------+----------+----------+----------+\n"); for ( i = 0; i < 24; i++) { fprintf(f,"| %5d | %8ld | %8ld | %8ld | %8ld |\n", i, staipl->hours[i].packets, staipl->hours[i].hosts, staipl->hours[i].ports, staipl->hours[i].portscannum ); sum.packets += staipl->hours[i].packets; sum.hosts += staipl->hours[i].hosts; sum.ports += staipl->hours[i].ports; sum.portscannum += staipl->hours[i].portscannum; } fprintf(f, "+-------+----------+----------+----------+----------+\n"); fprintf(f,"| %5s | %8ld | %8ld | %8ld | %8ld |\n", "TOTAL", sum.packets, sum.hosts, sum.ports, sum.portscannum ); fprintf(f, "+-------+----------+----------+----------+----------+\n\n\n"); sum.packets = 0; sum.hosts = 0; sum.ports = 0; sum.portscannum = 0; /* Daily stat */ fprintf(f, "+-----------------------------------------------+\n"); fprintf(f, "| Daily statistics for packets, hosts and ports |\n"); fprintf(f, "+-------+----------+----------+----------+------+---+\n"); fprintf(f,"| %5s | %8s | %8s | %8s | %8s |\n", "day", "packets", "hosts", "ports", "portscan"); for ( i = 0; i < 31; i++) { fprintf(f,"| %5d | %8ld | %8ld | %8ld | %8ld |\n", i, staipl->days[i].packets, staipl->days[i].hosts, staipl->days[i].ports, staipl->days[i].portscannum ); sum.packets += staipl->days[i].packets; sum.hosts += staipl->days[i].hosts; sum.ports += staipl->days[i].ports; sum.portscannum += staipl->days[i].portscannum; } fprintf(f, "+-------+----------+----------+----------+----------+\n"); fprintf(f,"| %5s | %8ld | %8ld | %8ld | %8ld |\n", "TOTAL", sum.packets, sum.hosts, sum.ports, sum.portscannum ); fprintf(f, "+-------+----------+----------+----------+----------+\n\n\n"); /* packettypes */ fprintf(f, "+-----------------+\n"); fprintf(f, "| Packets by type |\n"); psum = staipl->protocols.icmp + staipl->protocols.udp + staipl->protocols.tcp + staipl->protocols.other; fprintf(f, "+-------+---------+--------+\n"); fprintf(f, "| Type | Number | %% |\n"); fprintf(f, "+-------+---------+--------+\n"); fprintf(f, "| %5s | %7ld | %s%3.2f |\n", "ICMP", staipl->protocols.icmp, put_gap_before( 100.0 * staipl->protocols.icmp / psum ), 100.0 * staipl->protocols.icmp / psum); fprintf(f, "| %5s | %7ld | %s%3.2f |\n", "TCP", staipl->protocols.tcp, put_gap_before( 100.0 * staipl->protocols.tcp / psum ), 100.0 * staipl->protocols.tcp / psum); fprintf(f, "| %5s | %7ld | %s%3.2f |\n", "UDP", staipl->protocols.udp, put_gap_before( 100.0 * staipl->protocols.udp / psum ), 100.0 * staipl->protocols.udp / psum); fprintf(f, "| %5s | %7ld | %s%3.2f |\n", "OTHER", staipl->protocols.other, put_gap_before( 100.0 * staipl->protocols.other / psum ), 100.0 * staipl->protocols.other / psum); fprintf(f, "+-------+---------+--------+\n\n\n"); /* ipopts stat */ fprintf(f, "+--------------------+\n"); fprintf(f, "| Packets by IP opts |\n"); psum = staipl->ipopts.has_ipopts + staipl->ipopts.has_no_ipopts; fprintf(f, "+-------------+------+--+--------+\n"); fprintf(f, "| Has IP-opts | Number | %% |\n"); fprintf(f, "+-------------+---------+--------+\n"); fprintf(f, "| %11s | %7ld | %s%3.2f |\n", "Yes", staipl->ipopts.has_ipopts, put_gap_before( 100.0 * staipl->ipopts.has_ipopts / psum ), 100.0 * staipl->ipopts.has_ipopts / psum); fprintf(f, "| %11s | %7ld | %s%3.2f |\n", "No", staipl->ipopts.has_no_ipopts, put_gap_before( 100.0 * staipl->ipopts.has_no_ipopts / psum ), 100.0 * staipl->ipopts.has_no_ipopts / psum); fprintf(f, "+-------------+---------+--------+\n\n\n"); /* source hosts */ fprintf(f, "+--------------+\n"); fprintf(f, "| source hosts |\n"); fprintf(f, "+----+---------++--------+-----------------+\n"); fprintf(f, "| # | %8s | %% | %15s |\n", "number", "IP" ); fprintf(f, "+----+----------+--------+-----------------+\n"); show_host_stat_ippl(ext_conf, f, staipl->source_ips, 20); fprintf(f, "+----+----------+--------+-----------------+\n\n\n"); /* destination ports */ fprintf(f, "+-------------------+\n"); fprintf(f, "| destination ports |\n"); fprintf(f, "+----+----------+---+----+-------+\n"); fprintf(f, "| # | %8s | %% | %5s |\n", "number", "port" ); fprintf(f, "+----+----------+--------+-------+\n"); show_port_stat_ippl(ext_conf, f, staipl->destination_ports, 20); fprintf(f, "+----+----------+--------+-------+\n\n\n"); /* fully remembered source hosts, if any */ if (mhash_count( staipl->watched_shosts )) { int wi; mdata **watches = mhash_sorted_to_marray(staipl->watched_shosts,M_SORTBY_KEY,M_SORTDIR_ASC); fprintf(f, "+----------------------+\n"); fprintf(f, "| Watched source hosts |\n"); fprintf(f, "+-------+--------------+----------------------+\n"); fprintf(f, "| # NUM | Source host |\n"); fprintf(f, "+-------+--------------------------+----------+\n"); fprintf(f, "| Port | Last timestamp | Count |\n"); fprintf(f, "+=======+==========================+==========+\n"); for (wi = 0; watches[wi] != NULL; wi++) { int wj; char *ctimedata; mdata *actw = watches[wi]; mdata_ipplwatchelement **actcs = sort_ipplwatchelements(actw->data.ipplwatch->watches, actw->data.ipplwatch->count); fprintf(f, "| %4d. | %35s |\n", wi+1, actw->key ); fprintf(f, "+-------+--------------------------+----------+\n"); for (wj = 0; wj < actw->data.ipplwatch->count && actcs[wj] != NULL; wj++ ) { ctimedata = malloc(45); if( !strftime(ctimedata, 44, "%c", localtime( &(actcs[wj]->timestamp) ) ) ) { fprintf(stderr, "%s.%d: Time formating failed!\n", __FILE__, __LINE__); } fprintf(f, "| %5s | %24s | %8ld |\n", actcs[wj]->data, ctimedata, actcs[wj]->count ); free(ctimedata); } free(actcs); fprintf(f, "+=======+==========================+==========+\n"); } fprintf(f,"\n\n"); } /* fully remembered destination ports, if any */ if (mhash_count( staipl->watched_dports )) { int wi; mdata **watches = mhash_sorted_to_marray(staipl->watched_dports,M_SORTBY_KEY,M_SORTDIR_ASC); fprintf(f, "+---------------------------+\n"); fprintf(f, "| Watched destination ports |\n"); fprintf(f, "+-----------------+---------+---------------------------+\n"); fprintf(f, "| # NUM | Destination port |\n"); fprintf(f, "+-----------------+--------------------------+----------+\n"); fprintf(f, "| Host | Last timestamp | Count |\n"); fprintf(f, "+=================+==========================+==========+\n"); for (wi = 0; watches[wi] != NULL; wi++) { int wj; char *ctimedata; mdata *actw = watches[wi]; mdata_ipplwatchelement **actcs = sort_ipplwatchelements(actw->data.ipplwatch->watches, actw->data.ipplwatch->count); fprintf(f, "| %14d. | %35s |\n", wi+1, actw->key ); fprintf(f, "+-----------------+--------------------------+----------+\n"); for (wj = 0; wj < actw->data.ipplwatch->count && actcs[wj] != NULL; wj++ ) { ctimedata = malloc(45); if( !strftime(ctimedata, 44, "%c", localtime( &(actcs[wj]->timestamp) ) ) ) { fprintf(stderr, "%s.%d: Time formating failed!\n", __FILE__, __LINE__); } fprintf(f, "| %15s | %24s | %8ld |\n", actcs[wj]->data, ctimedata, actcs[wj]->count); free(ctimedata); } free(actcs); fprintf(f, "+=================+==========================+==========+\n"); } fprintf(f,"\n\n"); } fclose(f); return 0; } int mplugins_output_text_mail_generate_monthly_output(mconfig *ext_conf, mstate *state, const char *subpath) { FILE *f = NULL; char filename[255]; config_output *conf = ext_conf->plugin_conf; mstate_mail *stamail = NULL; marray_mail sum; int i,j; if (state == NULL) return -1; if (state->ext == NULL) return -1; if (state->ext_type != M_STATE_TYPE_MAIL) return -1; stamail = state->ext; if (subpath) { sprintf(filename, "%s/%s/", conf->outputdir ? conf->outputdir : ".", subpath); mkdir(filename, 0755); } sprintf(filename, "%s%s%s/index-%04d%02d.txt", conf->outputdir ? conf->outputdir : ".", subpath ? "/" : "", subpath ? subpath : "", state->year, state->month ); if (!(f = fopen(filename, "w"))) { return -1; } sum.incoming_mails = 0; sum.outgoing_mails = 0; sum.incoming_bytes = 0; sum.outgoing_bytes = 0; fprintf(f, "Oo. mailstats for %s.oO\n\n", conf->hostname); fprintf(f, ".-= mailcount and traffic by day =-.\n"); fprintf(f," %5s %10s %10s %10s %10s\n", "hour", "mail-in", "mail-out", "bytes-in", "bytes-out"); for ( i = 0; i < 24; i++) { fprintf(f," %5d %10ld %10ld %10ld %10ld\n", i, stamail->hours[i].incoming_mails, stamail->hours[i].outgoing_mails, stamail->hours[i].incoming_bytes, stamail->hours[i].outgoing_bytes ); sum.incoming_mails += stamail->hours[i].incoming_mails; sum.outgoing_mails += stamail->hours[i].outgoing_mails; sum.incoming_bytes += stamail->hours[i].incoming_bytes; sum.outgoing_bytes += stamail->hours[i].outgoing_bytes; } fprintf(f," %5s %10ld %10ld %10ld %10ld\n", "sum", sum.incoming_mails, sum.outgoing_mails, sum.incoming_bytes, sum.outgoing_bytes ); fprintf(f, "\n.-= mailcount and traffic by hour =-.\n"); sum.incoming_mails = 0; sum.outgoing_mails = 0; sum.incoming_bytes = 0; sum.outgoing_bytes = 0; fprintf(f," %5s %10s %10s %10s %10s\n", "day", "mail-in", "mail-out", "bytes-in", "bytes-out"); for ( i = 0; i < 31; i++) { fprintf(f," %5d %10ld %10ld %10ld %10ld\n", i, stamail->days[i].incoming_mails, stamail->days[i].outgoing_mails, stamail->days[i].incoming_bytes, stamail->days[i].outgoing_bytes ); sum.incoming_mails += stamail->days[i].incoming_mails; sum.outgoing_mails += stamail->days[i].outgoing_mails; sum.incoming_bytes += stamail->days[i].incoming_bytes; sum.outgoing_bytes += stamail->days[i].outgoing_bytes; } fprintf(f," %5s %10ld %10ld %10ld %10ld\n", "sum", sum.incoming_mails, sum.outgoing_mails, sum.incoming_bytes, sum.outgoing_bytes ); fprintf(f, "\n.-= mails by sender =-.\n"); show_visit_path (ext_conf, f, stamail->sender, 20); fprintf(f, "\n.-= mails by receipient =-.\n"); show_visit_path (ext_conf, f, stamail->receipient, 20); fprintf(f, "\n.-= queuepolution =-.\n"); fprintf(f, "%s %s %s %s %s %s %s %s\n", "day", "day", "local-cur", "local-max", "remote-cur", "remote-cur", "deliver-cur", "queue-cur"); for (i = 0; i < 31; i++) { for (j = 0; j < 24; j++) { if (stamail->qstat[i][j].count) { fprintf(f, "%5d %3d %9.0f %9.0f %10.0f %10.0f %11.0f %9.0f\n", i+1, j, stamail->qstat[i][j].local_cur / stamail->qstat[i][j].count, stamail->qstat[i][j].local_max / stamail->qstat[i][j].count, stamail->qstat[i][j].remote_cur / stamail->qstat[i][j].count, stamail->qstat[i][j].remote_max / stamail->qstat[i][j].count, stamail->qstat[i][j].deliver_cur / stamail->qstat[i][j].count, stamail->qstat[i][j].queue_cur / stamail->qstat[i][j].count ); } } } fclose(f); return 0; } int mplugins_output_generate_history_output(mconfig *ext_conf, mlist *history, const char *subpath) { return 0; }