#ifndef NCP_H #include "sancp.h" #endif #include /************************************************************************** **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. * * * ***********************************************************************/ // // use to set/get the current connection counter to/from a file // a = 0 GET CID, a = 1 SET CID void manage_cid(int a) { extern struct gvars gVars; u_int64_t cid=0; int len; char *tmp; // We need a connection id fileHandle // Connection ID tracking fileHandle if(!gVars.cfH){ tmp = createFileName(".cnxid",false); gVars.cfH = new fileHandle(tmp,WRITE_MODE); free(tmp); } // Are we suppose to write once to the file? if(a==1) { if(gVars.cfH->getMode()!=WRITE_MODE){ gVars.cfH->setMode(WRITE_MODE); gVars.cfH->reopen(); } gVars.cfH->write((char *)&gVars.cnx_id,8); }else{ if(gVars.cfH->getMode()!=READ_MODE){ gVars.cfH->setMode(READ_MODE); gVars.cfH->reopen(); } if(!gVars.cfH->open()){ syslog (LOG_ERR,"Unable to open file %s\n",gVars.cfH->getFileName()) ; } gVars.cfH->seek(0L,SEEK_SET); if((len = gVars.cfH->read((char *)&cid,8))==0){ syslog(LOG_ERR,"Didn't retrieved last connection ID, read on %d bytes\n", len); gVars.cnx_id=0; }else{ syslog(LOG_INFO,"Retrieved last connection ID: %llu %d %d\n", cid,len,errno); gVars.cnx_id=cid; } switch (errno){ case EINTR: syslog(LOG_ERR,"Error reading: EINTR\n"); break; case EAGAIN: syslog(LOG_ERR,"Error reading: EAGAIN\n"); break; case EIO: syslog(LOG_ERR,"Error reading: EIO\n"); break; case EISDIR: syslog(LOG_ERR,"Error reading: EISDIR\n"); break; case EBADF: syslog(LOG_ERR,"Error reading: EBADF\n"); break; case EINVAL: syslog(LOG_ERR,"Error reading: EINVAL\n"); break; case EFAULT: syslog(LOG_ERR,"Error reading: EFAULT\n"); break; } #ifdef DEBUG printf("Retrieved last connection ID: %llu\n", cid); #endif } } void open_files() { extern struct gvars gVars; char *tmp=0; // Pcap fileHandle if(!gVars.pfH && gVars.pmode){ tmp=createFileName(gVars.pcap_fname,gVars.pmode == OMODE_TSFILENAME); gVars.pfH = new pcapFileHandle(tmp); free(tmp); } // Realtime fileHandle if(!gVars.rfH && gVars.rmode){ tmp=createFileName(gVars.realtime_fname,gVars.rmode == OMODE_TSFILENAME); gVars.rfH = new outputFileHandle(tmp,gVars.stats_fmt,gVars.stats_fmt_len,APPEND_MODE); gVars.rfH->setFormat(gVars.realtime_fmt,gVars.realtime_fmt_len); gVars.rfH->setEor(gVars.realtime_eor); gVars.rfH->setDelimiter(gVars.realtime_delimiter); free(tmp); } // Stats fileHandle -- moved to erase_idle - the only function that writes to it 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); } // This is done in manage_cid() as needed // Connection ID tracking fileHandle //if(!gVars.cfH && gVars.enable_cid){ //tmp = createFileName(".cid",false); //gVars.cfH = new fileHandle(tmp); //free(tmp); //} // Debug Pcap Raw fileHandle if(!gVars.rpfH && gVars.pcap_raw){ tmp=createFileName(PCAP_RAW_FNAME); gVars.rpfH = new pcapFileHandle(tmp); free(tmp); } // stdout fileHandle if(!gVars.sdF){ gVars.sdF = new outputFileHandle(stdout,APPEND_MODE,gVars.stdout_fmt,gVars.stdout_fmt_len); gVars.sdF->setFormat(gVars.stdout_fmt,gVars.stdout_fmt_len); gVars.sdF->setEor(gVars.stdout_eor); gVars.sdF->setDelimiter(gVars.stdout_delimiter); } // // bpf files are only created once at startup for now // //if(!gVars.bfH && strlen(gVars.bpf_fname)) //{ //tmp=createFileName(BPF_FNAME); //gVars.bfH = new fileHandle(gVars.bpf_fname); //free(tmp); //} } void close_files(int a){ extern struct gvars gVars; if(gVars.pfH){ gVars.pfH->destroy(); gVars.pfH=NULL; } if(gVars.rfH){ gVars.rfH->destroy(); gVars.rfH=NULL; } if(gVars.sfH && !(a==2 && gVars.burst_mode==1)){ gVars.sfH->destroy(); gVars.sfH=NULL; } if(gVars.cfH){ gVars.cfH->destroy(); gVars.cfH=NULL; } if(gVars.rpfH){ gVars.rpfH->destroy(); gVars.rpfH=NULL; } if(gVars.sdF){ gVars.sdF->destroy(); gVars.sdF=NULL; } // bpf files are only handled, when specified at startup, for now //if(gVars.bfH) //gVars.bfH->destroy(); } char * createFileName(const char *name) { return createFileName(name,true); } char * createFileName(const char *name, bool enable_timestamp = true) { extern struct gvars gVars; //extern time_t restart_time; char *f = (char *) calloc( 1, MAX_VAR ); if(enable_timestamp){ if(name[0]=='/' || !gVars.log_directory){ snprintf(f,MAX_VAR,"%s.%s.%ld",name,gVars.default_device,(long)gVars.restart_time); }else{ snprintf(f,MAX_VAR,"%s%s.%s.%ld",gVars.log_directory,name,gVars.default_device,(long)gVars.restart_time); } }else{ if(name[0]=='/' || !gVars.log_directory){ snprintf(f,MAX_VAR,"%s",name); }else{ snprintf(f,MAX_VAR,"%s%s",gVars.log_directory,name); } } return f; } char * createPcapFileName(const struct cnx *c) { extern struct gvars gVars; //extern time_t restart_time; char *x = (char *) calloc( 1, MAX_VAR+1 ); char *f = (char *) calloc( 1, MAX_VAR+1 ); snprintf(x,MAX_VAR,"%s%s",gVars.log_directory,inet_ntoa(*(struct in_addr*) &c->s_ip)); bzero(f,MAX_VAR); snprintf(f,MAX_VAR,"%s:%d_%s:%d-%d.%ld",x,ntohs(c->s_port),inet_ntoa(*(struct in_addr*) &c->d_ip),ntohs(c->d_port),c->proto,(long)gVars.restart_time); free(x); return f; } char * createPcapFileName(const struct acl *a) { extern struct gvars gVars; //extern time_t restart_time; char *x = (char *) calloc( 1, 256 ); char *f = (char *) calloc( 1, 256 ); snprintf(f,255,"%s%s",gVars.log_directory,inet_ntoa(*(struct in_addr*) &a->s_ip)); bzero(x,255); snprintf(x,255,"%s-%s",f,inet_ntoa(*(struct in_addr*) &a->s_mask)); bzero(f,255); snprintf(f,255,"%s:%s",x,inet_ntoa(*(struct in_addr*) &a->d_ip)); bzero(x,255); snprintf(x,255,"%s-%s",f,inet_ntoa(*(struct in_addr*) &a->d_mask)); bzero(f,255); snprintf(f,255,"%s_%d-%d:%d-%d_%d-%d.%ld",x,a->s_port_l,a->s_port_h,a->d_port_l,a->d_port_h,a->proto_l,a->proto_h,(long)gVars.restart_time); free(x); return f; } void set_signals() { signal(SIGHUP, reload_config); signal(SIGALRM, erase_idle); signal(SIGUSR1, print_acl); signal(SIGUSR2, record_all); signal(SIGTERM, exit_all); signal(SIGINT, exit_all); signal(SIGKILL, exit_all); signal(SIGQUIT, exit_all); } void reopen_files(int a){ extern struct gvars gVars; // Close default pcap, stats, realtime and debug_pcap_raw close_files(a); //manage_cid(0); gVars.restart_time = time(0); // Open default pcap, stats, realtime and debug_pcap_raw open_files(); } void reload_config(int a){ manage_cid(1); build_config(1); syslog(LOG_INFO,"Reloading configuration"); } void exit_all(int a){ extern gvars gVars; // We should stop collecting packets now close_pcap_file(gVars.ph); if(gVars.console_mode && !gVars.daemon_mode) record_all(1); manage_cid(1); free_all(1); syslog(LOG_INFO,"Exiting"); close_files(1); // close syslog closelog(); exit(0); } void free_all(int a) { extern struct gvars gVars; //extern struct acl *acl_head; struct acl *acl_tmp; //extern struct cnx *cnx_head[]; struct cnx *cnx_tmp; struct cnx *cnx_thead; //extern struct t_ports *ports[]; struct t_ports *ports_head, *tmp_port; int p=0; int cKey; ////printf("FreeAll... predelete T: %d U: %d F: %d\n",cnx_pool.GetTotalBuffers(),cnx_pool.GetUsedBuffers(),cnx_pool.GetFreeBuffers() ); while(gVars.acl_head!=NULL){ acl_tmp=gVars.acl_head; gVars.acl_head=acl_tmp->next; if(acl_tmp->fH){ acl_tmp->fH->destroy(); acl_tmp->fH=0; } free(acl_tmp); } while(gVars.expired_cnxs.head!=NULL){ //We really need to check whether we actually recieved //any bytes from the source 'first' before we record. cnx_tmp=gVars.expired_cnxs.head; gVars.expired_cnxs.head=gVars.expired_cnxs.head->next; free(cnx_tmp); } if(!gVars.sfH && gVars.smode && gVars.stats_fname){ char *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); } for(cKey=0; cKey< HASH_KEYS; cKey++) { cnx_thead=gVars.cnx_head[cKey]; while(cnx_thead!=NULL){ cnx_tmp=cnx_thead; if(cnx_tmp->stats){ // We check whether we ever actually received any bytes from the // source - to avoid recording an obvious, 'reversed' connection // and we will record out decision too if( cnx_tmp->reversed==CNX_REVERSED && cnx_tmp->d_total_pkts==0){ cnx_tmp->reversed=CNX_REREVERSED; } if(gVars.sfH) record(cnx_tmp,gVars.sfH); } cnx_thead=cnx_tmp->next; if(cnx_tmp->fH){ cnx_tmp->fH->destroy(); cnx_tmp->fH=0;} cnx_tmp->CBufferPtr->Free(); cnx_tmp->CBufferPtr=NULL; cnx_tmp=NULL; } } for(p=0; pnext; free(tmp_port); } } // Clear out any memory allocated to gVars free(gVars.cnx_pool); free(gVars.acl_pool); if(gVars.bpf_filter) free(gVars.bpf_filter); if(gVars.bpf_fname) free(gVars.bpf_fname); if(gVars.pcap_fname) free(gVars.pcap_fname); if(gVars.username) free(gVars.username); if(gVars.groupname) free(gVars.groupname); if(gVars.stdout_fmt) free(gVars.stdout_fmt); if(gVars.stats_fmt) free(gVars.stats_fmt); if(gVars.realtime_fmt) free(gVars.realtime_fmt); } void record_all(int a){ extern struct gvars gVars; struct cnx *cnx_tmp; int cKey; for(cKey=0; cKey< HASH_KEYS; cKey++) { cnx_tmp=gVars.cnx_head[cKey]; while(cnx_tmp!=NULL){ // We really need to check whether we actually recieved // any bytes from the source 'first' before we record. if(cnx_tmp->reversed==CNX_REVERSED && cnx_tmp->d_total_pkts==0){ cnx_tmp->reversed=CNX_REREVERSED; } record(cnx_tmp,gVars.sdF); cnx_tmp=cnx_tmp->next; } } cnx_tmp=gVars.expired_cnxs.head; gVars.expired_cnxs.head=NULL; gVars.expired_cnxs.tail=NULL; while(cnx_tmp!=NULL){ // We really need to check whether we actually recieved // any packets from the 'source' before we record. if(cnx_tmp->reversed==CNX_REVERSED && cnx_tmp->d_total_pkts==0){ cnx_tmp->reversed=CNX_REREVERSED; } record(cnx_tmp,gVars.sdF); cnx_tmp=cnx_tmp->next; } } // To be re-discovered... void print_stats(int a){ extern u_int16_t pkts_in, pkts_out, bytes_in, bytes_out; extern u_int16_t l_pkts_in, l_pkts_out, l_bytes_in, l_bytes_out; extern struct gvars gVars; u_int16_t pavg_in, pavg_out, bavg_in, bavg_out, dpkts, dbytes; u_int32_t dtime; if((dtime=gVars.timeptr.tv_sec-gVars.timelast.tv_sec)==0){ dtime=1; } dpkts=pkts_in-l_pkts_in; pavg_in=(u_int16_t)dpkts/dtime; dpkts=pkts_out-l_pkts_out; pavg_out=(u_int16_t)dpkts/dtime; dbytes=bytes_in-l_bytes_in; bavg_in=(u_int16_t)dbytes/dtime; dbytes=bytes_out-l_bytes_out; bavg_out=(u_int16_t)dbytes/dtime; fprintf(stdout,"# PKTS\tIN\tOUT\t BYTES\tIN\tOUT\n"); fprintf(stdout,"# \t%d\t%d\t \t%d\t%d\n",pkts_in,pkts_out,bytes_in,bytes_out); fprintf(stdout,"# \t%d/s\t%d/s\t \t%d/s\t%d/s\n",pavg_in,pavg_out,bavg_in,bavg_out); l_pkts_in=pkts_in; l_pkts_out=pkts_out; l_bytes_in=bytes_in; l_bytes_out=bytes_out; //pkts_in=pkts_out=bytes_in=bytes_out=0; gVars.timelast.tv_sec=gVars.timeptr.tv_sec; gVars.timelast.tv_usec=gVars.timeptr.tv_usec; } int CheckPort(u_int8_t proto, u_int16_t port) { extern struct gvars gVars; struct t_ports *ports_head; struct t_ports *tp; ports_head=gVars.ports[proto]; while(ports_head!=NULL){ if(port >= ports_head->l_port && port <= ports_head->h_port) return 1; tp=ports_head; ports_head=tp->next; } return 0; }