#ifndef NCP_H #include "sancp.h" #endif /************************************************************************** **SA Network Connection Profiler [sancp] - A TCP/IP statistical/collection tool * ************************************************************************ * * Copyright (C) 2003 John Curry * * * * This program is distributed under the terms of version 1.0 of the * * Q Public License. See LICENSE.QPL for further details. * * * * 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. * * * ***********************************************************************/ void print_schemas(){ extern struct gvars gVars; if(gVars.stats_fname){ write_schema(gVars.stats_fname, gVars.stats_fmt, gVars.stats_fmt_len); } if(gVars.realtime_fname){ write_schema(gVars.realtime_fname, gVars.realtime_fmt, gVars.realtime_fmt_len); } } void write_schema(char *name, char *fmt, int fmtlen){ if(name && fmtlen){ char *tmp; char BUF[MAXENTRYLEN]; bzero(BUF,MAXENTRYLEN); // Create the schema filename snprintf(BUF,MAXENTRYLEN-1,"%s.schema",name); tmp=createFileName(BUF,false); outputFileHandle *fH = new outputFileHandle(tmp,fmt,fmtlen,WRITE_MODE); bzero(BUF,MAXENTRYLEN); // Print table header fH->write(BUF,snprintf(BUF,MAXENTRYLEN,"\nCREATE TABLE %s ( \n",name)); // Print field entries in order print_output_schema(fH,fmt,fmtlen); bzero(BUF,MAXENTRYLEN); // Print table footer fH->write(BUF,snprintf(BUF,MAXENTRYLEN,") TYPE=InnoDB; \n\n")); fH->destroy(); syslog(LOG_INFO,"Created %s\n",tmp); if(tmp) free(tmp); } } void erase_idle(int a) { extern struct gvars gVars; struct cnx *cn, *tmpptr; char *tmp; // Since this is the only function that gets the timer alarm, we better // check for expired connections (just in case we haven't processed any packets for a while) if((gVars.timeptr.tv_sec - gVars.lastrun)>gVars.default_expire_interval){ expire_connections(); gVars.lastrun=gVars.timeptr.tv_sec; } reopen_files(2); // Now check for connections to erase cn=gVars.expired_cnxs.head; while(cn) { #ifdef DEBUG printf("Erasing key:%d id:%lld\n",cn->hash,cn->cid); #endif if(cn->stats){ // We really need to check whether we actually received // any bytes from the source 'first' before we record. if(cn->reversed==CNX_REVERSED && cn->d_total_pkts==0){ cn->reversed=CNX_REREVERSED; } if(gVars.sfH) record(cn,gVars.sfH); } if(cn->fH){ cn->fH->destroy(); cn->fH=0; } tmpptr=cn; cn=tmpptr->next; if(gVars.expired_cnxs.tail==tmpptr){ gVars.expired_cnxs.head=NULL; gVars.expired_cnxs.tail=NULL; } tmpptr->CBufferPtr->Free(); tmpptr=NULL; } gVars.lastrun=gVars.timeptr.tv_sec; if(gVars.burst_mode){ // Close current stats filehandle now, and prepare the name for the next output file // it won't actually 'open' till we try to write to the file (when we're called again // or when we exit and clear connections from memory) if(gVars.sfH){ gVars.sfH->destroy(); gVars.sfH=NULL; } if(!gVars.sfH && gVars.smode){ tmp=createFileName(gVars.stats_fname,gVars.smode == OMODE_TSFILENAME); gVars.sfH = new outputFileHandle(tmp,gVars.stats_fmt,gVars.stats_fmt_len,APPEND_MODE); gVars.sfH->setFormat(gVars.stats_fmt,gVars.stats_fmt_len); gVars.sfH->setEor(gVars.stats_eor); gVars.sfH->setDelimiter(gVars.stats_delimiter); free(tmp); } }else{ // We do nothing and leave the file open // We'll close the file when we terminate or receive a kill HUP signal } // Call pthread_wait here - when we decide to use threads #ifdef DEBUG printf("Rearming alarm for %d secs\n",gVars.default_flush_interval); #endif alarm(gVars.default_flush_interval); } void expire_connections() { extern gvars gVars; struct cnx *cn, *tmpptr; int x, y; int cKey = 0; #ifdef DEBUG printf("Expiring connections (%d secs)\n",gVars.default_expire_interval); #endif y=0; for( cKey = 0; cKey < HASH_KEYS; cKey++) { cn=gVars.cnx_tail[cKey]; x=0; while((cn!=NULL) && ( ((gVars.timeptr.tv_sec - cn->last_pkt) > cn->timeout) || ( cn->proto==IPPROTO_TCP && (((cn->tcpCFlags & 0x33) == 0x33) || ((cn->tcpCFlags & 0x0c)>0) ) && ( (gVars.timeptr.tv_sec - cn->last_pkt) > cn->tcplag) )) ) { #ifdef DEBUG printf("Erasing key:%d #:%d id:%lld\n",cKey,x,cn->cid); #endif // Remove connection from current list tmpptr=cn; if(tmpptr->prev){ tmpptr->prev->next=NULL; gVars.cnx_tail[cKey]=tmpptr->prev; }else{ gVars.cnx_head[cKey]=NULL; gVars.cnx_tail[cKey]=NULL; } cn=tmpptr->prev; // Add expired connection to a different list to be recorded and freed from memory if(!gVars.expired_cnxs.head){ gVars.expired_cnxs.head=tmpptr; gVars.expired_cnxs.tail=tmpptr; tmpptr->next=tmpptr->prev=0; }else{ gVars.expired_cnxs.tail->next=tmpptr; gVars.expired_cnxs.tail=tmpptr; } } } } void snprintf_inaddr_toa(char *buf, int len, struct in_addr *in_addr, const char delimiter) { snprintf(buf,len,"%s",inet_ntoa(*in_addr)); } void snprintf_inaddr_tohl(char *buf, int len, struct in_addr *inaddr, const char delimiter) { snprintf(buf,len,"%lu",(unsigned long) ntohl(*(unsigned long*)(inaddr))); } void snprintf_gmtime(char *buf, int len, time_t timeval, const char delimiter) { char currenttime[80]; strftime(currenttime,80,"%Y-%m-%d %T",(struct tm*)gmtime(&timeval)); snprintf(buf,len,"%s",currenttime); } void snprintf_localtime(char *buf, int len, time_t timeval, const char delimiter) { char currenttime[80]; strftime(currenttime,80,"%Y-%m-%d %T",(struct tm*)localtime(&timeval)); snprintf(buf,len,"%s",currenttime); } void record(struct cnx *cn, outputFileHandle *fH) { extern struct gvars gVars; char LOG[MAXENTRYLEN]; time_t timeval=gVars.timeptr.tv_sec; char *fmtcols=fH->getFormat(); int fmtlen=fH->getFormatLen(); char delimiter=fH->getDelimiter(); char eor=fH->getEor(); bzero(LOG,MAXENTRYLEN); /* * Structure of a 48-bit Ethernet address. * struct ether_addr { u_char octet[ETHER_ADDR_LEN]; }; */ for(char x=0; xeth_hdr.ether_shost; snprintf(LOG,MAXENTRYLEN,"%0x:%0x:%0x:%0x:%0x:%0x",es->octet[0],es->octet[1],es->octet[2],es->octet[3],es->octet[4],es->octet[5]); es=NULL; break; } case dst_mac: { struct myether_addr *ed=(struct myether_addr *)&cn->eth_hdr.ether_dhost; snprintf(LOG,MAXENTRYLEN,"%0x:%0x:%0x:%0x:%0x:%0x",ed->octet[0],ed->octet[1],ed->octet[2],ed->octet[3],ed->octet[4],ed->octet[5]); ed=NULL; break; } case sancp_id: { snprintf(LOG,MAXENTRYLEN,"%lld",cn->cid); break; } case start_time_gmt: { snprintf_gmtime(LOG,MAXENTRYLEN,cn->start_time,delimiter); break; } case start_time_local: { snprintf_localtime(LOG,MAXENTRYLEN,cn->start_time,delimiter); break; } case stop_time_gmt: { snprintf_gmtime(LOG,MAXENTRYLEN,cn->last_pkt,delimiter); break; } case stop_time_local: { snprintf_localtime(LOG,MAXENTRYLEN,cn->last_pkt,delimiter); break; } case erased_time_gmt: { snprintf_gmtime(LOG,MAXENTRYLEN,timeval,delimiter); break; } case erased_time_local: { snprintf_localtime(LOG,MAXENTRYLEN,timeval,delimiter); break; } case src_ip_decimal: { if(cn->reversed==CNX_REVERSED){ snprintf_inaddr_tohl(LOG,MAXENTRYLEN,(struct in_addr*) &cn->d_ip,delimiter); }else{ snprintf_inaddr_tohl(LOG,MAXENTRYLEN,(struct in_addr*) &cn->s_ip,delimiter); } break; } case src_ip_dotted: { if(cn->reversed==CNX_REVERSED){ snprintf_inaddr_toa(LOG,MAXENTRYLEN,(struct in_addr*) &cn->d_ip,delimiter); }else{ snprintf_inaddr_toa(LOG,MAXENTRYLEN,(struct in_addr*) &cn->s_ip,delimiter); } break; } case dst_ip_decimal: { if(cn->reversed==CNX_REVERSED){ snprintf_inaddr_tohl(LOG,MAXENTRYLEN,(struct in_addr*) &cn->s_ip,delimiter); }else{ snprintf_inaddr_tohl(LOG,MAXENTRYLEN,(struct in_addr*) &cn->d_ip,delimiter); } break; } case dst_ip_dotted: { if(cn->reversed==CNX_REVERSED){ snprintf_inaddr_toa(LOG,MAXENTRYLEN,(struct in_addr*) &cn->s_ip,delimiter); }else{ snprintf_inaddr_toa(LOG,MAXENTRYLEN,(struct in_addr*) &cn->d_ip,delimiter); } break; } case eth_proto_hex: { snprintf(LOG,MAXENTRYLEN,"%02X",ntohs(cn->h_proto)); break; } case eth_proto: { snprintf(LOG,MAXENTRYLEN,"%u",(cn->h_proto)); break; } case ip_proto: { snprintf(LOG,MAXENTRYLEN,"%u",(cn->proto)); break; } case src_port: { if(cn->reversed==CNX_REVERSED){ snprintf(LOG,MAXENTRYLEN,"%u",ntohs(cn->d_port)); }else{ snprintf(LOG,MAXENTRYLEN,"%u",ntohs(cn->s_port)); } break; } case dst_port: { if(cn->reversed==CNX_REVERSED){ snprintf(LOG,MAXENTRYLEN,"%u",ntohs(cn->s_port)); }else{ snprintf(LOG,MAXENTRYLEN,"%u",ntohs(cn->d_port)); } break; } case duration: { snprintf(LOG,MAXENTRYLEN,"%lu",(long)(cn->last_pkt-cn->start_time)); break; } case timeout: { snprintf(LOG,MAXENTRYLEN,"%u",cn->timeout); break; } case src_pkts: { if(cn->reversed==CNX_REVERSED){ snprintf(LOG,MAXENTRYLEN,"%llu",cn->d_total_pkts); }else{ snprintf(LOG,MAXENTRYLEN,"%llu",cn->s_total_pkts); } break; } case dst_pkts: { if(cn->reversed==CNX_REVERSED){ snprintf(LOG,MAXENTRYLEN,"%llu",cn->s_total_pkts); }else{ snprintf(LOG,MAXENTRYLEN,"%llu",cn->d_total_pkts); } break; } case src_bytes: { if(cn->reversed==CNX_REVERSED){ snprintf(LOG,MAXENTRYLEN,"%llu",cn->d_total_bytes); }else{ snprintf(LOG,MAXENTRYLEN,"%llu",cn->s_total_bytes); } break; } case dst_bytes: { if(cn->reversed==CNX_REVERSED){ snprintf(LOG,MAXENTRYLEN,"%llu",cn->s_total_bytes); }else{ snprintf(LOG,MAXENTRYLEN,"%llu",cn->d_total_bytes); } break; } case sflags_hex: { snprintf(LOG,MAXENTRYLEN,"%02X",cn->tcpFlags[(cn->reversed==1?1:0)]); break; } case sflags: { snprintf(LOG,MAXENTRYLEN,"%u",cn->tcpFlags[(cn->reversed==1?1:0)]); break; } case dflags_hex: { snprintf(LOG,MAXENTRYLEN,"%02X",cn->tcpFlags[(cn->reversed==1?0:1)]); break; } case dflags: { snprintf(LOG,MAXENTRYLEN,"%u",cn->tcpFlags[(cn->reversed==1?0:1)]); break; } case cflags_hex: { snprintf(LOG,MAXENTRYLEN,"%02X",cn->reversed==1?((cn->tcpCFlags&0x15)<<1)|((cn->tcpCFlags&0x2A)>>1):cn->tcpCFlags); break; } case cflags: { snprintf(LOG,MAXENTRYLEN,"%u",cn->reversed==1?((cn->tcpCFlags&0x15)<<1)|((cn->tcpCFlags&0x2A)>>1):cn->tcpCFlags); break; } case ip_len_s: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.len); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.len); } break; } case ip_ttl_s: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.ttl); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.ttl); } break; } case ip_df_s: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.df?Y:N); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.df?Y:N); } break; } case tcp_wss_s: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.wss); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.wss); } break; } #ifdef EXPERIMENTAL_TCPOPTIONS case tcp_mss_s: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.mss); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.mss); } break; } case tcp_wscale_s: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.wscale); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.wscale); } break; } case tcp_sack_ok_s: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%c",cn->os_info2.sack_ok?Y:N); }else{ snprintf(LOG,MAXENTRYLEN,"%c",cn->os_info.sack_ok?Y:N); } break; } case tcp_nop_s: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%c",cn->os_info2.nop?Y:N); }else{ snprintf(LOG,MAXENTRYLEN,"%c",cn->os_info.nop?Y:N); } break; } #endif case ip_len_d: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.len); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.len); } break; } case ip_ttl_d: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.ttl); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.ttl); } break; } case ip_df_d: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.df?Y:N); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.df?Y:N); } break; } case tcp_wss_d: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.wss); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.wss); } break; } #ifdef EXPERIMENTAL_TCPOPTIONS case tcp_mss_d: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.mss); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.mss); } break; } case tcp_wscale_d: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info.wscale); }else{ snprintf(LOG,MAXENTRYLEN,"%u",cn->os_info2.wscale); } break; } case tcp_sack_ok_d: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%c",cn->os_info.sack_ok?Y:N); }else{ snprintf(LOG,MAXENTRYLEN,"%c",cn->os_info2.sack_ok?Y:N); } break; } case tcp_nop_d: { if(cn->reversed==1){ snprintf(LOG,MAXENTRYLEN,"%c",cn->os_info.nop?Y:N); }else{ snprintf(LOG,MAXENTRYLEN,"%c",cn->os_info2.nop?Y:N); } break; } #endif case total_bytes: { snprintf(LOG,MAXENTRYLEN,"%llu",cn->total_bytes); break; } case collect: { snprintf(LOG,MAXENTRYLEN,"%u",cn->cmode); break; } case collected: { snprintf(LOG,MAXENTRYLEN,"%llu",cn->collected); break; } case climit: { snprintf(LOG,MAXENTRYLEN,"%llu",cn->limit); break; } case tcplag: { snprintf(LOG,MAXENTRYLEN,"%u",cn->tcplag); break; } case pcap: { snprintf(LOG,MAXENTRYLEN,"%c",cn->pcap?Y:N); break; } case realtime: { snprintf(LOG,MAXENTRYLEN,"%c",cn->realtime?Y:N); break; } case stats: { snprintf(LOG,MAXENTRYLEN,"%c",cn->stats?Y:N); break; } case reversed: { snprintf(LOG,MAXENTRYLEN,"%u",cn->reversed); break; } case hash: { snprintf(LOG,MAXENTRYLEN,"%u",cn->hash); break; } case rid: { snprintf(LOG,MAXENTRYLEN,"%u",cn->rid); break; } case rgid: { snprintf(LOG,MAXENTRYLEN,"%u",cn->rgid); break; } case node: { snprintf(LOG,MAXENTRYLEN,"%u",cn->node); break; } case zone: { snprintf(LOG,MAXENTRYLEN,"%u",cn->zone); break; } case status: { snprintf(LOG,MAXENTRYLEN,"%u",cn->status); break; } case retro: { snprintf(LOG,MAXENTRYLEN,"%c",cn->retro?Y:N); break; } case sflags_1: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?1:0)]&0x80)?Y:N); break; } case sflags_2: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?1:0)]&0x40)?Y:N); break; } case sflags_U: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?1:0)]&0x20)?Y:N); break; } case sflags_A: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?1:0)]&0x10)?Y:N); break; } case sflags_P: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?1:0)]&0x08)?Y:N); break; } case sflags_R: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?1:0)]&0x04)?Y:N); break; } case sflags_S: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?1:0)]&0x02)?Y:N); break; } case sflags_F: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?1:0)]&0x01)?Y:N); break; } case dflags_1: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?0:1)]&0x80)?Y:N); break; } case dflags_2: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?0:1)]&0x40)?Y:N); break; } case dflags_U: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?0:1)]&0x20)?Y:N); break; } case dflags_A: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?0:1)]&0x10)?Y:N); break; } case dflags_P: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?0:1)]&0x08)?Y:N); break; } case dflags_R: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?0:1)]&0x04)?Y:N); break; } case dflags_S: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?0:1)]&0x02)?Y:N); break; } case dflags_F: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpFlags[(cn->reversed==1?0:1)]&0x01)?Y:N); break; } case cflags_DA: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpCFlags&(cn->reversed==1)?0x10:0x20)?Y:N); break; } case cflags_SA: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpCFlags&(cn->reversed==1)?0x20:0x10)?Y:N); break; } case cflags_DR: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpCFlags&(cn->reversed==1)?0x04:0x08)?Y:N); break; } case cflags_SR: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpCFlags&(cn->reversed==1)?0x08:0x04)?Y:N); break; } case cflags_DF: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpCFlags&(cn->reversed==1)?0x01:0x02)?Y:N); break; } case cflags_SF: { snprintf(LOG,MAXENTRYLEN,"%c",(cn->tcpCFlags&(cn->reversed==1)?0x02:0x01)?Y:N); break; } default: break; } if(x>0) fH->write(&delimiter,sizeof(char)); fH->write(LOG,strlen(LOG)); bzero(LOG,MAXENTRYLEN); } fH->write(&eor,sizeof(char)); } /* vim: set ts=4 sw=4 expandtab: */ /* * We define our DB field types here, so we can change * them easier... need config options */ #define DB_8BIT "INT1" #define DB_16BIT "INT2" #define DB_32BIT "INT4" #define DB_64BIT "INT8" #define DB_CHAR1 "CHAR(1)" #define DB_CHAR4 "CHAR(4)" #define DB_CHAR16 "CHAR(16)" #define DB_DATETIME "datetime" void print_output_schema(outputFileHandle *fH, char *fmtcols, int fmtlen) { char LOG[MAXENTRYLEN]; bzero(LOG,MAXENTRYLEN); for(char x=0; x0) fH->write(LOG,strlen(LOG)); bzero(LOG,MAXENTRYLEN); } fH->write("\n",sizeof(char)); } /* vim: set ts=4 sw=4 expandtab: */