#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. * * * ***********************************************************************/ /************* *Global Vars* *************/ u_int64_t cnx_id=0; u_int16_t bytes_in=0; u_int16_t bytes_out=0; u_int16_t pkts_in=0; u_int16_t pkts_out=0; u_int16_t l_bytes_in=0; u_int16_t l_bytes_out=0; u_int16_t l_pkts_in=0; u_int16_t l_pkts_out=0; struct gvars gVars; /* Here are all the possible output fields */ /* MAXFLDS & MAXFLDSIZE are defined in sancp.h */ /* Modifications to this statement can cause alignment problems with 'enum id' in gvars.h */ /* Make certain all strings are represented in the same order (as barewords) in 'enum id' in gvars.h */ char fmtnames[MAXFLDS][MAXFLDSIZE] = { {"null"},{"sancp_id"},{"start_time_gmt"},{"start_time_local"},{"stop_time_gmt"},{"stop_time_local"},{"erased_time_gmt"},{"erased_time_local"},{"eth_proto_hex"},{"eth_proto"},{"ip_proto"},{"src_ip_decimal"},{"src_ip_dotted"},{"src_port"},{"dst_ip_decimal"},{"dst_ip_dotted"},{"dst_port"},{"duration"},{"timeout"},{"src_pkts"},{"dst_pkts"},{"src_bytes"},{"dst_bytes"},{"sflags_hex"},{"sflags"},{"sflags_1"},{"sflags_2"},{"sflags_U"},{"sflags_A"},{"sflags_P"},{"sflags_R"},{"sflags_S"},{"sflags_F"},{"dflags_hex"},{"dflags"},{"dflags_1"},{"dflags_2"},{"dflags_U"},{"dflags_A"},{"dflags_P"},{"dflags_R"},{"dflags_S"},{"dflags_F"},{"cflags_hex"},{"cflags"},{"cflags_DA"},{"cflags_SA"},{"cflags_DR"},{"cflags_SR"},{"cflags_DF"},{"cflags_SF"},{"ip_len_s"},{"ip_ttl_s"},{"ip_df_s"},{"tcp_wss_s"},{"tcp_mss_s"},{"tcp_wscale_s"},{"tcp_sack_ok_s"},{"tcp_nop_s"},{"ip_len_d"},{"ip_ttl_d"},{"ip_df_d"},{"tcp_wss_d"},{"tcp_mss_d"},{"tcp_wscale_d"},{"tcp_sack_ok_d"},{"tcp_nop_d"},{"total_bytes"},{"collect"},{"collected"},{"climit"},{"tcplag"},{"pcap"},{"realtime"},{"stats"},{"reversed"},{"hash"},{"rid"},{"rgid"},{"node"},{"zone"},{"status"},{"retro"},{"src_mac"},{"dst_mac"} }; /* This will be our default stats and realtime layout */ char dfltfmt[]= { sancp_id,start_time_gmt,stop_time_gmt,erased_time_gmt,eth_proto,ip_proto,src_ip_decimal,src_port,dst_ip_decimal,dst_port,duration,timeout,src_pkts,dst_pkts,src_bytes,dst_bytes,sflags,dflags,cflags,ip_len_s,ip_ttl_s,ip_df_s,tcp_wss_s,tcp_mss_s,tcp_wscale_s,tcp_sack_ok_s,tcp_nop_s,ip_len_d,ip_ttl_d,ip_df_d,tcp_wss_d,tcp_mss_d,tcp_wscale_d,tcp_sack_ok_d,tcp_nop_d,total_bytes,collect,collected,climit,tcplag,pcap,realtime,stats,reversed,hash,rid,rgid,node,zone,status,retro,src_mac,dst_mac }; //char dfltfmt[]= { sancp_id,start_time_gmt,src_mac,dst_mac,eth_proto,src_ip_dotted,dst_ip_dotted,ip_proto,src_port,dst_port }; char dfltfmt_human_readable[]= { sancp_id,start_time_gmt,stop_time_gmt,erased_time_gmt,eth_proto,ip_proto,src_ip_dotted,src_port,dst_ip_dotted,dst_port,duration,timeout,src_pkts,dst_pkts,src_bytes,dst_bytes,sflags_hex,dflags_hex,cflags_hex,ip_len_s,ip_ttl_s,ip_df_s,tcp_wss_s,tcp_mss_s,tcp_wscale_s,tcp_sack_ok_s,tcp_nop_s,ip_len_d,ip_ttl_d,ip_df_d,tcp_wss_d,tcp_mss_d,tcp_wscale_d,tcp_sack_ok_d,tcp_nop_d,total_bytes,collect,collected,climit,tcplag,pcap,realtime,stats,reversed,hash,rid,rgid,node,zone,status,retro,src_mac,dst_mac }; /************* * Main * *************/ int main(int argc, char *argv[]) { extern struct gvars gVars; int cKey; pid_t pid=0; /* * Setup our defaults for the enviroment */ bzero(&gVars,sizeof(struct gvars)); gVars.default_timeout=DEFAULT_TIMEOUT; gVars.default_limit=DEFAULT_LIMIT; gVars.default_tcplag=DEFAULT_LAG; gVars.shift=1; //DEFAULT_DEVICE is 'any' so we need this set from the start gVars.cmdl_pcap_action=ACTION_LOG; gVars.cmdl_stats_action=ACTION_LOG; gVars.cmdl_realtimes_action=ACTION_LOG; gVars.default_flush_interval=DEFAULT_FLUSH_INTERVAL; gVars.default_expire_interval=DEFAULT_EXPIRE_INTERVAL; gVars.print_schemas=0; //gVars.log_facility=LOG_DAEMON; gVars.log_facility=LOG_LOCAL1; gVars.pmode=OMODE_TSFILENAME; gVars.smode=OMODE_TSFILENAME; gVars.rmode=OMODE_TSFILENAME; gVars.burst_mode=ENABLED; gVars.strip_80211=DISABLED; gVars.cnx_pool = new CMemoryPool(true,sizeof(struct cnx),1024);// gVars.acl_pool = new CMemoryPool(true,sizeof(struct acl),24);// gVars.timeptr.tv_sec=gVars.lastrun=gVars.restart_time=gVars.start_time=time(0); gVars.realtime_fmt_len=sizeof(dfltfmt); gVars.realtime_fmt=(char *) calloc(gVars.realtime_fmt_len,1); memcpy(gVars.realtime_fmt,dfltfmt,gVars.realtime_fmt_len); gVars.realtime_delimiter=DEFAULT_DELIMITER; gVars.realtime_eor=DEFAULT_EOR; gVars.stats_fmt_len=sizeof(dfltfmt); gVars.stats_fmt=(char *) calloc(gVars.stats_fmt_len,1); memcpy(gVars.stats_fmt,dfltfmt,gVars.stats_fmt_len); gVars.stats_delimiter=DEFAULT_DELIMITER; gVars.stats_eor=DEFAULT_EOR; gVars.stdout_fmt_len=sizeof(dfltfmt); gVars.stdout_fmt=(char *) calloc(gVars.stdout_fmt_len,1); memcpy(gVars.stdout_fmt,dfltfmt,gVars.stdout_fmt_len); gVars.stdout_delimiter=DEFAULT_DELIMITER; gVars.stdout_eor=DEFAULT_EOR; for(cKey=0; cKey 0){ printf("(%d) sancp daemonized successfully!\n",pid); exit(0); /* parent */ } setsid(); } } /* Retrieve the last cnxid from cache file if we haven't already in parse_args() */ if(!gVars.cnx_id) manage_cid(0); /* Do we have a default device set yet? If not, we will read from all network devices. */ if(!gVars.default_device) { if((gVars.default_device = (char *)calloc(strlen("any")+1,1))==NULL){ syslog(LOG_ERR,"Unable to allocate memory for -u option\n"); exit(0); } bcopy("any",gVars.default_device,strlen("any")); } /* We should decide on a log directory now */ if(!gVars.log_directory) { if( (gVars.log_directory = (char *)calloc(strlen(LOG_DIR)+1,1) ) ==NULL){ syslog(LOG_ERR,"Unable to allocate memory for -u option\n"); exit(0); } bcopy(LOG_DIR,gVars.log_directory,strlen(LOG_DIR)); } /* Set an initial default pcap output filename */ gVars.pcap_fname=(char *) calloc(1,strlen(PCAP_FNAME)+1); strncpy(gVars.pcap_fname,PCAP_FNAME,strlen(PCAP_FNAME)); /* Set an initial default stats output filename */ gVars.stats_fname=(char *) calloc(1,strlen(STATS_FNAME)+1); strncpy(gVars.stats_fname,STATS_FNAME,strlen(STATS_FNAME)); /* Set an initial default realtime output filename */ gVars.realtime_fname=(char *) calloc(1,strlen(REALTIME_FNAME)+1); strncpy(gVars.realtime_fname,REALTIME_FNAME,strlen(REALTIME_FNAME)); /* Create the default output files for stats, pcap, and realtime (and debug_pcap_raw) */ open_files(); /* Read default collection mode settings and the rules */ build_config(1); /* Open files for output */ /* Be r3al l33t h3r3 */ if(gVars.print_schemas){ SChangeUserGroup(); print_schemas(); exit_all(0); } #ifdef DEBUG fprintf(stdout,"built the acls\n"); #endif if(gVars.input_filename) { /* Read from a pcap file */ gVars.ph=open_pcap_file(gVars.bpf_filter,gVars.input_filename); if(gVars.ph==0){ perror("open_pcap_file"); exit_all(0); } }else{ /* Read from an interface */ if(gVars.bpf_filter!=0) syslog(LOG_INFO,"Opening with filter: '%s'\n",gVars.bpf_filter); gVars.ph=open_pcap_live(gVars.bpf_filter,gVars.default_device); if(gVars.ph==0){ perror("open_pcap_live"); exit_all(0); } } SChangeUserGroup(); /* If we read from a file or 'any' then we expect two extra bytes prefixing each packet */ if(gVars.shift) { gVars.pcap_shift=2; } /* Setup the signal handling routines */ set_signals(); alarm(gVars.default_flush_interval); syslog(LOG_INFO,"started normally"); /* Call our C function to call pcap_loop() */ start_pcap_loop(gVars.ph); /* We should exit if we make it this far */ exit_all(0); return 1; } /************** * End of Main* **************/ #ifdef DEBUG /* Dummy function * Used for debugging */ void notify(){ return; } #endif /******************************************************************* * Function for C code to call C++ code (used by pcap_functions.c) * *******************************************************************/ extern "C" void ProcessMyPacket(char *user, struct pcap_pkthdr * pkthdr, u_char * pkt) { extern struct gvars gVars; CBuffer *buffer; struct cnx *new_cnx=0; gVars.timeptr.tv_sec=pkthdr->ts.tv_sec; gVars.timeptr.tv_usec=pkthdr->ts.tv_usec; /* Strip the 80211 header off */ if( gVars.strip_80211 && (*(u_int16_t*)(pkt + 12 + gVars.pcap_shift)==ETHPROTO_8021Q)){ #ifdef DEBUG printf("Have 8021Q, %.4x\n",*(u_int32_t*)(pkt + 12 + gVars.pcap_shift)); #endif /* shift packet data over 4 bytes to access encapsulated packet */ /* this works even regardless of pcap_shift !!! NEED TO FIX THIS !!!*/ memmove(pkt+4,pkt,4); pkthdr->caplen-=4; pkt+=4; } if(gVars.pcap_raw){ if(gVars.rpfH){ gVars.rpfH->write((char *)pkt+gVars.pcap_shift,pkthdr->caplen,&gVars.timeptr); } } /* Copy the complete packet into an ethernet header structure for easy access */ if((buffer=gVars.cnx_pool->Alloc())==NULL){ syslog(LOG_CRIT,"Out of Memory?\n"); return; } new_cnx = (struct cnx *) buffer->GetBuffer(); bzero((char *) new_cnx,sizeof(struct cnx)); new_cnx->CBufferPtr = buffer; #ifdef DEBUG if(gVars.cnx_pool->GetFreeBuffers() + gVars.cnx_pool->GetUsedBuffers() != gVars.cnx_pool->GetTotalBuffers()) { /* We should notify someone that we have an inconsistency in our memory pool */ notify(); // dummy function } #endif /* * Decode Packet */ decode(new_cnx,pkthdr->caplen,pkt+gVars.pcap_shift); #ifdef DEBUG notify(); // dummy function //pktcnt++; #endif /* * Now we have something to work with... */ process(new_cnx,pkthdr->caplen,pkt+gVars.pcap_shift); if((gVars.timeptr.tv_sec - gVars.lastrun)>gVars.default_expire_interval){ /* * If we are configured to use the timestamp in the packets * to determine when to flush a file, then we should handle that here */ if(gVars.use_pcap_time && ((gVars.timeptr.tv_sec - gVars.lastrun)>gVars.default_flush_interval)) erase_idle(2); // This function will call expire_conections() for us else expire_connections(); gVars.lastrun=gVars.timeptr.tv_sec; } }