/* ** 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: process.c,v 1.3 2004/08/27 20:06:19 ostborn Exp $ */ #include #include #include #include #include #include #include #include #include #include "config.h" #include "mrecord.h" #include "mlocale.h" #include "mconfig.h" #include "mplugins.h" #include "mstate.h" #include "mdatatypes.h" #include "misc.h" #include "plugin_config.h" #include "datatypes/count/datatype.h" #include "datatypes/state/datatype.h" #include "datatypes/ipplwatch/datatype.h" #if 0 #define DEBUG_IPPLPROC 1 #define DEBUG_WATCHES 1 #endif int process_watched_shost( config_processor *, mstate_ippl *, mlogrec * ); int process_watched_dport( config_processor *, mstate_ippl *, mlogrec * ); int is_portscan( mlogrec *record, mstate *state ) { return 0; } int process_watched_shost( config_processor *conf, mstate_ippl *staipl, mlogrec *record ) { /* We could assume record is traffic-ippl record.. */ mlist *l; int matched = 0; if( !conf || !staipl || !record ) return 0; #ifdef DEBUG_WATCHES int i = 1; #endif for (l = conf->watched_shosts; l; l=l->next ) { #ifdef DEBUG_WATCHES fprintf(stderr,"%s.%d: Processing the %d. watched host... ", __FILE__, __LINE__, i); #endif mdata *data = l->data; mlogrec_traffic *rectrf = record->ext; #define N 20 int ovector[3 * N], n; if (!data) continue; if (data->type != M_DATA_TYPE_MATCH) { fprintf( stderr, "%s.%d: wrong datatype for a match: %d\n", __FILE__, __LINE__, data->type ); continue; } #ifdef DEBUG_WATCHES fprintf(stderr, "matching... "); #endif /* match the string .. */ if ((n = pcre_exec(data->data.match.match, data->data.match.study, rectrf->src, strlen( rectrf->src), 0, 0, ovector, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { fprintf(stderr, "%s.%d: execution error while matching: %d\n", __FILE__, __LINE__, n); return 0; } } /* we matched .. */ if (n >= 0) { mdata *wu = mdata_datatype_init( M_DATA_TYPE_IPPLWATCH ); mlogrec_traffic_ippl *recipl = rectrf->ext; char *portstr = malloc( 6 ); #ifdef DEBUG_WATCHES fprintf(stderr, "matched!\n"); #endif matched = 1; if (recipl->dst_port) sprintf( portstr, "%d", recipl->dst_port); else sprintf( portstr, "%s", "PING" ); #ifdef DEBUG_WATCHES fprintf(stderr, "Calling mdata_IpplWatch_setdata()... " ); #endif if( mdata_IpplWatch_setdata( wu, rectrf->src, record->timestamp, portstr, M_DATA_HOST, 1 ) ) return 0; #ifdef DEBUG_WATCHES fprintf(stderr, "called OK!\nInserting mdata into mhash... " ); #endif mhash_insert_sorted( staipl->watched_shosts, wu ); #ifdef DEBUG_WATCHES fprintf(stderr, "done!\n"); #endif free(portstr); break; #ifdef DEBUG_WATCHES } else { fprintf(stderr, "NOT matched!\n"); #endif } #ifdef DEBUG_WATCHES i++; #endif } #ifdef DEBUG_WATCHES if (!matched) fprintf( stderr, "%s.%d: No source-host matches found.", __FILE__, __LINE__ ); #endif return 0; } int process_watched_dport( config_processor *conf, mstate_ippl *staipl, mlogrec *record ) { /* We could assume record is traffic-ippl record.. */ mlist *l; int matched = 0; if( !conf || !staipl || !record ) return 0; #ifdef DEBUG_WATCHES int i = 1; #endif for (l = conf->watched_dports; l && !matched; l=l->next ) { #ifdef DEBUG_WATCHES fprintf(stderr,"%s.%d: Processing the %d. watched dport... ", __FILE__, __LINE__, i); #endif mdata *data = l->data; mlogrec_traffic *rectrf = record->ext; mlogrec_traffic_ippl *recipl = rectrf->ext; char * portstr; #define N 20 int ovector[3 * N], n; if (!data) continue; portstr = malloc( 6 ); sprintf( portstr, "%d", recipl->dst_port); if (data->type != M_DATA_TYPE_MATCH) { fprintf( stderr, "%s.%d: wrong datatype for a match: %d\n", __FILE__, __LINE__, data->type ); continue; } #ifdef DEBUG_WATCHES fprintf(stderr, "matching... "); #endif /* match the string .. */ if ((n = pcre_exec(data->data.match.match, data->data.match.study, portstr, strlen( portstr), 0, 0, ovector, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { fprintf(stderr, "%s.%d: execution error while matching: %d\n", __FILE__, __LINE__, n); return 0; } } /* we matched .. */ if (n >= 0) { mdata *wu = mdata_datatype_init( M_DATA_TYPE_IPPLWATCH ); #ifdef DEBUG_WATCHES fprintf(stderr, "%s\n", "matched!" ); #endif matched = 1; #ifdef DEBUG_WATCHES fprintf(stderr, "Calling mdata_IpplWatch_setdata()!... "); #endif if( mdata_IpplWatch_setdata( wu, portstr, record->timestamp, rectrf->src, M_DATA_PORT, 1 ) ) return 0; #ifdef DEBUG_WATCHES fprintf(stderr, "Called OK!\nInserting data into mhash... " ); #endif mhash_insert_sorted( staipl->watched_dports, wu ); #ifdef DEBUG_WATCHES fprintf(stderr, "Done! Finished!\n" ); } else { fprintf(stderr, "NOT matched!\n"); #endif } free(portstr); #ifdef DEBUG_WATCHES i++; #endif } #ifdef DEBUG_WATCHES if (!matched) fprintf( stderr, "%s.%d: No destination-port matches found.\n", __FILE__, __LINE__ ); #endif return 0; } int mplugins_processor_ippl_insert_record(mconfig *ext_conf, mlist *state_list, mlogrec *record) { /* fill the state_list with data */ config_processor *conf = ext_conf->plugin_conf; struct tm *tm; mlogrec_traffic *rectrf = NULL; /* HACK */ mlogrec_traffic_ippl *recipl = NULL; mstate_ippl *staipl = NULL; mdata *data = state_list->data; mstate *state = NULL; mdata *srchost, *dsthost, *remident, *protoname; #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Creating data if needed... ", __FILE__, __LINE__ ); #endif if (!data) { const char *key = splaytree_insert(ext_conf->strings, ""); data = mdata_State_create(key,NULL,NULL); assert(data); mlist_insert(state_list, data); #ifdef DEBUG_IPPLPROC fprintf( stderr, "yes, we created.\n" ); } else { fprintf( stderr, "no, not needed.\n" ); #endif } #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Recovering state variable..\n", __FILE__, __LINE__ ); #endif state = data->data.state.state; if (state == NULL) return -1; #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Checking record type..\n", __FILE__, __LINE__ ); #endif if (record->ext_type != M_RECORD_TYPE_TRAFFIC) return -1; if (record->ext == NULL) return -1; rectrf = record->ext; #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Checking record sub-type..\n", __FILE__, __LINE__ ); #endif if (rectrf->ext_type == M_RECORD_TYPE_TRAFFIC_IPPL && rectrf->ext != NULL) recipl = rectrf->ext; else { fprintf(stderr, "%s.%d: unsupported recordtype: %d\n", __FILE__, __LINE__, rectrf->ext_type); return -1; } #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Checking state type..\n", __FILE__, __LINE__ ); #endif if (state->ext) { switch(state->ext_type) { case M_STATE_TYPE_IPPL: staipl = state->ext; break; default: fprintf(stderr, "%s.%d: unsupported state subtype\n", __FILE__, __LINE__); return -1; } } else { state->ext = mstate_init_ippl(); state->ext_type = M_STATE_TYPE_IPPL; staipl = state->ext; } #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Modifying state timestamp..\n", __FILE__, __LINE__ ); #endif state->timestamp = record->timestamp; #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Checking subrecord fields..\n", __FILE__, __LINE__ ); #endif if (!rectrf->src || !rectrf->dst) { #ifdef DEBUG_IPPLPROC fprintf(stderr, "%s.%d: No %s in traffic subrecord!\n", __FILE__, __LINE__, (rectrf->src ? "dst" : "src" ) ); #endif return -1; } #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Setting timestamp-related datas..\n", __FILE__, __LINE__ ); #endif if ((tm = localtime(&(record->timestamp)))) { char *tmp; /* perhaps we have created a new state */ if (!state->timestamp) { state->year = tm->tm_year+1900; state->month = tm->tm_mon+1; } staipl->hours[tm->tm_hour].packets++; staipl->days[tm->tm_mday-1].packets++; #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Checking whether host has already been counted..", __FILE__, __LINE__ ); #endif if( !mhash_in_hash( staipl->source_ips, rectrf->src) ) { staipl->hours[tm->tm_hour].hosts++; staipl->days[tm->tm_mday-1].hosts++; #ifdef DEBUG_IPPLPROC fprintf( stderr, "no.\n" ); } else { fprintf( stderr, "yes.\n" ); #endif } #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Checking whether port has already been counted.. ", __FILE__, __LINE__ ); #endif tmp = malloc( 15 ); // We could overestimate this at max 8 byte #ifdef DEBUG_IPPLPROC fprintf( stderr, "(sprintf) "); #endif sprintf( tmp, "%d", recipl->dst_port ); if( recipl->dst_port && !mhash_in_hash( staipl->destination_ports, tmp ) ) { staipl->hours[tm->tm_hour].ports++; staipl->days[tm->tm_mday-1].ports++; #ifdef DEBUG_IPPLPROC fprintf( stderr, "no.\n" ); } else { fprintf( stderr, "yes.\n" ); #endif } #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Checking whether it's part of a portscan.. ", __FILE__, __LINE__ ); #endif if( conf->check_portscan && is_portscan( record, state ) ) { staipl->hours[tm->tm_hour].portscannum++; staipl->hours[tm->tm_mday-1].portscannum++; #ifdef DEBUG_IPPLPROC fprintf( stderr, "yes.\n" ); } else { fprintf( stderr, "no.\n" ); #endif } } /* Watched sourcehosts.. */ if( !mlist_is_empty( conf->watched_shosts ) ) { #ifdef DEBUG_WATCHES fprintf(stderr,"%s.%d: About to call process_watched_shost()!\n", __FILE__, __LINE__); #endif process_watched_shost( conf, staipl, record ); #ifdef DEBUG_WATCHES fprintf(stderr,"%s.%d: process_watched_shost() called successfully!\n", __FILE__, __LINE__); #endif } #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Setting source ip datas.. ", __FILE__, __LINE__ ); #endif /* source host */ srchost = mdata_Count_init(); srchost->key = strdup(rectrf->src); srchost->data.count.count = 1; mhash_insert_sorted( staipl->source_ips, srchost); #ifdef DEBUG_IPPLPROC fprintf( stderr, "done.\n"); #endif #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Setting destination ip datas.. ", __FILE__, __LINE__ ); #endif /* destination host */ dsthost = mdata_Count_init(); dsthost->key = strdup(rectrf->dst); dsthost->data.count.count = 1; mhash_insert_sorted( staipl->destination_ips, dsthost); #ifdef DEBUG_IPPLPROC fprintf( stderr, "done.\n"); #endif #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Checking whether there is some source port data available.. ", __FILE__, __LINE__ ); #endif if (recipl->src_port) { /* source port */ mdata *srcport = mdata_Count_init(); srcport->key = malloc( 6 ); // it's overestimated in some case with the maximum of 4 bytes.. sprintf(srcport->key, "%d", recipl->src_port ); srcport->data.count.count = 1; mhash_insert_sorted( staipl->source_ports, srcport); #ifdef DEBUG_IPPLPROC fprintf( stderr, "yes.\n"); } else { fprintf( stderr, "no.\n"); #endif } /* Watched destination ports .. */ if( recipl->dst_port && !mlist_is_empty( conf->watched_dports ) ) { #ifdef DEBUG_WATCHES fprintf(stderr,"%s.%d: About to call process_watched_dport()!\n", __FILE__, __LINE__); #endif process_watched_dport( conf, staipl, record ); #ifdef DEBUG_WATCHES fprintf(stderr,"%s.%d: process_watched_dport() called successfully!\n", __FILE__, __LINE__); #endif } #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Checking whether there is some destination port data available.. ", __FILE__, __LINE__ ); #endif if (recipl->dst_port) { /* destination port */ mdata *dstport = mdata_Count_init(); dstport->key = malloc( 6 ); sprintf(dstport->key, "%d", recipl->dst_port ); dstport->data.count.count = 1; mhash_insert_sorted( staipl->destination_ports, dstport); #ifdef DEBUG_IPPLPROC fprintf( stderr, "yes.\n"); } else { fprintf( stderr, "no.\n"); #endif } #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Setting remote ident datas.. ", __FILE__, __LINE__ ); #endif /* remote idents */ remident = mdata_Count_init(); if( !recipl->remident ) { remident->key = strdup( "-" ); } else remident->key = strdup( recipl->remident ); remident->data.count.count = 1; mhash_insert_sorted( staipl->remote_idents, remident); #ifdef DEBUG_IPPLPROC fprintf( stderr, "done.\n"); #endif #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Setting protocol-name datas.. ", __FILE__, __LINE__ ); #endif /* protocol names */ protoname = mdata_Count_init(); if( !recipl->protoname ) { protoname->key = strdup( "unknown" ); } else protoname->key = strdup( recipl->protoname ); protoname->data.count.count = 1; mhash_insert_sorted( staipl->protocol_names, protoname); #ifdef DEBUG_IPPLPROC fprintf( stderr, "done.\n"); #endif #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Setting protocolname datas.. ", __FILE__, __LINE__ ); #endif switch( recipl->prototype ) { case M_RECORD_IPPL_PROTOCOL_TCP: staipl->protocols.tcp++; break; case M_RECORD_IPPL_PROTOCOL_UDP: staipl->protocols.udp++; break; case M_RECORD_IPPL_PROTOCOL_ICMP: staipl->protocols.icmp++; break; default: staipl->protocols.other++; break; } #ifdef DEBUG_IPPLPROC fprintf( stderr, "done.\n"); #endif #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Checking whether there are ICMP related data available.. ", __FILE__, __LINE__ ); #endif /* icmp params */ if( recipl->prototype == M_RECORD_IPPL_PROTOCOL_ICMP ) { mdata *icmpparam = mdata_Count_init(); icmpparam->key = /* process_icmpparam(*/ strdup( recipl->protoname ) /* ) */; icmpparam->data.count.count = 1; mhash_insert_sorted( staipl->icmp_params, icmpparam); #ifdef DEBUG_IPPLPROC fprintf( stderr, "yes.\n" ); } else { fprintf( stderr, "no.\n" ); #endif } #ifdef DEBUG_IPPLPROC fprintf( stderr, "%s.%d: Setting ipopts datas.. ", __FILE__, __LINE__ ); #endif if( recipl->has_ipopts ) staipl->ipopts.has_ipopts++; else staipl->ipopts.has_no_ipopts++; #ifdef DEBUG_IPPLPROC fprintf( stderr, "done.\n"); #endif /* ready -- currently */ return 0; }