#ifndef SANCP_H #include "sancp.h" #endif //#define DEBUG /************************************************************************** **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 license(); void version(); struct acl *tacl_head=NULL, *tacl_tail=NULL; struct t_ports *tports[MAX_IP_PROTO]; void set_bpf_filter( char *); char * get_tok(char **rule, const char * accept); void parse_default(char *rule, char *accept); char * get_next_tok(char **rule, const char *delimiters); char *rev_search_vars(char *key, struct vars *var_head, int ); int fgetcline (char **buf, int size, FILE *fp){ int len; int c=0; if( fp== NULL){ syslog(LOG_ERR,"Invalid FILE handle\n"); return -1; } if(feof(fp)){ syslog(LOG_ERR,"Early END OF FILE\n"); return -1; } if (*buf == NULL){ if( size == 0) size=BUFSIZ; if((*buf = (char *)calloc(1,size)) == NULL){ syslog(LOG_ERR,"Out of memory\n"); return -1; } } len=0; // Get characters until EOF or ';' while (((c = getc(fp)) != EOF) && c!='\n' && c!='\r'){ if(c=='\\'){ if((c = getc(fp))==EOF){ break; } if(c=='\n'){ c=' '; }else{ ungetc(c,fp); c='\\'; } } if(c == '#'){ // if comment mark, FF to end of line while( (c = getc(fp))!= EOF && c !='\n'); //if(c=='\n'){ break;} //if(c==EOF){ break; } break; } if(len+1 >= size) { if(( *buf = (char *)realloc(*buf, size += BUFSIZ))==NULL){ syslog(LOG_ERR,"Out of memory\n"); free(*buf); return -1; } } if(c == ',' || c == '=' ) { c = ' '; } // // Make everything lower case for now // if(!(len==0 && (c==' ' || c=='\t'))) (*buf)[len++]=tolower(c); if(c == '\t' || c == ' ' ){ while( (c=fgetc(fp))!= EOF && c!='\n' && (c=='\t' || c==' ')); //while( (c=fgetc(fp))!= EOF && c!='\n' && (c=='\t' || c==' ' || c==',' || c=='=')); if(c=='\n'|| c==EOF){ break; } // Trunicate comments if(c=='#') (*buf)[len]='\0'; ungetc(c,fp); // If we ran into a '#' sign, then just turn the last \t or space into a null. } } if (len == 0 && c == EOF){ if(*buf!=NULL) free(*buf); return -1; } if(len>0 && ((*buf)[len-1]==' ' || (*buf)[len-1]=='\t')){ (*buf)[len-1]='\0'; return len-1; }else{ (*buf)[len++]='\0'; return len; } } void parse_args(int argc, char *argv[]) { extern struct gvars gVars; u_int64_t num; char *ftmp=0; //int ctr=0; for(int ctr=1; ctr < argc; ctr++) { if(strcmp(argv[ctr],"--schemas")==0) { // once we finished reading the config, we will print the schemas and exit gVars.print_schemas = 1; }else{ if(strcmp(argv[ctr],"--shift")==0) { // enable internal 2 byte shifting the packet read from file // 'any' interface gVars.shift = 1; }else{ if(strcmp(argv[ctr],"-K")==0 || strcmp(argv[ctr],"--console")==0) { // enable console mode - log realtimes to stdout gVars.console_mode = 1; }else{ if(strcmp(argv[ctr],"-D")==0 || strcmp(argv[ctr],"--daemon")==0) { // enable daemon mode gVars.daemon_mode = 1; openlog(NAME,LOG_CONS,gVars.log_facility); }else{ if(strcmp(argv[ctr],"-C")==0 || strcmp(argv[ctr],"--last_cnxid")==0) { // set last connection id to use - ~~~! Need to supply -d argument first !~~~ if( ctr < argc-1 ){ ctr++; ftmp=argv[ctr]; num = (u_int64_t) strtoll(argv[ctr],&ftmp,0); if(argv[ctr]==ftmp) { syslog(LOG_ERR,"Format error, invalid last_cnxid: %s, using cnxid %llu\n",argv[ctr],(long long unsigned)gVars.cnx_id); }else manage_cid(0); if(gVars.cnx_id>num){ syslog(LOG_ERR,"cnxid provided (%llu) is less than 64bit cnxid in the '.cnxid' cache file, using cnxid %llu from cache instead\n",num,(long long unsigned) gVars.cnx_id); }else{ syslog(LOG_ERR,"Using cnxid provided (%llu) rather than the last cnxid in the '.cnxid' cache file (%llu)\n",num,(long long unsigned) gVars.cnx_id); // Save the new cnx_id gVars.cnx_id=num; manage_cid(1); } }else{ syslog(LOG_ERR,"No cnxid provided with -C/--last_cnxid option\n"); exit(0); } }else{ if(strcmp(argv[ctr],"-i")==0) { // Set device name if( ctr < argc-1 ){ if(gVars.default_device){ free(gVars.default_device); } ctr++; if( (gVars.default_device = (char *)calloc(strlen(argv[ctr])+ 1,1) ) ==NULL){ syslog(LOG_ERR,"Unable to allocate memory for -i option\n"); exit(0); } bcopy(argv[ctr],gVars.default_device,strlen(argv[ctr])); gVars.shift=0; // disable shift (only needed for 'any' interface) if(strstr(gVars.default_device,DEFAULT_DEVICE)) gVars.shift=1; }else{ syslog(LOG_ERR,"No device name provided with -i option\n"); exit(0); } }else{ if(strcmp(argv[ctr],"-d")==0) { // Set log directory name if( ctr < argc-1 ){ if(gVars.log_directory){ free(gVars.log_directory); } ctr++; if( (gVars.log_directory = (char *)calloc(strlen(argv[ctr])+ 2,1) ) ==NULL){ syslog(LOG_ERR,"Unable to allocate memory for -d option\n"); exit(0); } bcopy(argv[ctr],gVars.log_directory,strlen(argv[ctr])); // We allocated an extra space for this... *(gVars.log_directory+strlen(argv[ctr]))='/'; }else{ syslog(LOG_ERR,"No directory provided with -d option\n"); exit(0); } }else{ if(strcmp(argv[ctr],"-r")==0) { // Set pcap input file name if( ctr < argc-1 ){ if(gVars.input_filename){ free(gVars.input_filename); } ctr++; if( (gVars.input_filename = (char *)calloc(strlen(argv[ctr])+1,1) ) ==NULL){ syslog(LOG_ERR,"Unable to allocate memory for -r option\n"); exit(0); } bcopy(argv[ctr],gVars.input_filename,strlen(argv[ctr])); gVars.shift=0; // disable shift (only needed for 'any' interface) }else{ syslog(LOG_ERR,"No pcap filename provided with -r option\n"); exit(0); } }else{ if(strcmp(argv[ctr],"-c")==0) { // Set configuration directory name if( ctr < argc-1 ){ if(gVars.config_file){ free(gVars.config_file); } ctr++; if( (gVars.config_file = (char *)calloc(strlen(argv[ctr])+1,1) ) ==NULL){ syslog(LOG_ERR,"Unable to allocate memory for -c option\n"); exit(0); } bcopy(argv[ctr],gVars.config_file,strlen(argv[ctr])); }else{ syslog(LOG_ERR,"No configuration filename provided with -c option\n"); exit(0); } }else{ if(strcmp(argv[ctr],"--log-facility")==0) { // Set log facility if( ctr < argc-1 ){ ctr++; if(strcmp(argv[ctr],"LOCAL1")==0) gVars.log_facility = LOG_LOCAL1; if(strcmp(argv[ctr],"LOCAL2")==0) gVars.log_facility = LOG_LOCAL2; if(strcmp(argv[ctr],"LOCAL3")==0) gVars.log_facility = LOG_LOCAL3; if(strcmp(argv[ctr],"LOCAL4")==0) gVars.log_facility = LOG_LOCAL4; if(strcmp(argv[ctr],"LOCAL5")==0) gVars.log_facility = LOG_LOCAL5; if(strcmp(argv[ctr],"LOCAL6")==0) gVars.log_facility = LOG_LOCAL6; if(strcmp(argv[ctr],"LOCAL7")==0) gVars.log_facility = LOG_LOCAL7; }else{ syslog(LOG_ERR,"No value provided with --log-facility option\n"); exit(0); } }else{ if(strcmp(argv[ctr],"-u")==0) { // Set username name if( ctr < argc-1 ){ if(gVars.username){ free(gVars.username); gVars.username=0; } ctr++; if( (gVars.username = (char *)calloc(strlen(argv[ctr])+ 1,1) ) ==NULL){ syslog(LOG_ERR,"Unable to allocate memory for -u option\n"); exit(0); } bcopy(argv[ctr],gVars.username,strlen(argv[ctr])); }else{ syslog(LOG_ERR,"No user provided with -u option\n"); exit(0); } }else{ if(strcmp(argv[ctr],"-g")==0) { // Set group name if( ctr < argc-1 ){ if(gVars.groupname){ free(gVars.groupname); gVars.groupname=0; } ctr++; if( (gVars.groupname = (char *)calloc(strlen(argv[ctr])+ 1,1) ) ==NULL){ syslog(LOG_ERR,"Unable to allocate memory for -g option\n"); exit(0); } bcopy(argv[ctr],gVars.groupname,strlen(argv[ctr])); }else{ syslog(LOG_ERR,"No group provided with -g option\n"); exit(0); } }else{ if(strcmp(argv[ctr],"-F")==0) { // Set bp filter file name if( ctr < argc-1 ){ ctr++; // We alloc mem here, but fileHandle will free it // This should be changed, but it works for now set_bpf_filter(argv[ctr]); syslog(LOG_INFO,"using file %s: %s\n",gVars.bpf_fname,argv[ctr]); //if(!gVars.daemon_mode) syslog(LOG_INFO,"enabling bpf filter from file %s: %s\n",gVars.bpf_fname,argv[ctr]); }else{ syslog(LOG_ERR,"No filename provided with -F option\n"); exit(0); } }else{ if(strcmp(argv[ctr],"--strip-80211")==0) { // enable removal of 80211 header gVars.strip_80211 = ENABLED; if(!gVars.daemon_mode) syslog(LOG_INFO,"enabling stripping of 80211 headers\n"); }else{ if(strcmp(argv[ctr],"--local-time")==0) { // disable GMT, enable localtime gVars.uselocaltime = 1; if(!gVars.daemon_mode) syslog(LOG_INFO,"enabling local timestamps instead of GMT\n"); }else{ if(strcmp(argv[ctr],"-A")==0) { // enable recording all data to tcpdump file before // processing, any strip-80211 option applies, however if(gVars.rpfH){ gVars.rpfH->destroy(); gVars.rpfH=0; } ftmp=createFileName(PCAP_RAW_FNAME); gVars.rpfH = new pcapFileHandle(ftmp); free(ftmp); gVars.pcap_raw = ENABLED; syslog(LOG_INFO,"enabling debug recording of all pcap data to a tcpdump file\n"); }else{ if(strcmp(argv[ctr],"-R")==0) { // disable realtime gVars.cmdl_realtimes_action = ACTION_PASS; gVars.rmode = OMODE_PASS; syslog(LOG_INFO,"disabling default 'realtimes' logging mode\n"); }else{ if(strcmp(argv[ctr],"-P")==0) { // disable default collect action gVars.cmdl_pcap_action = ACTION_PASS; gVars.pmode = OMODE_PASS; syslog(LOG_INFO,"disabling default 'pcap' logging mode\n"); }else{ if(strcmp(argv[ctr],"-S")==0) { // disable default log action gVars.cmdl_stats_action = ACTION_PASS; gVars.smode = OMODE_PASS; syslog(LOG_INFO,"disabling default 'stats' logging mode\n"); }else{ if(strcmp(argv[ctr],"-I")==0 || strcmp(argv[ctr],"--enable-icmp-mixed")==0) { // enable recording and tracking ICMP type/code in src and dst port fields gVars.log_icmp_type_code = 1; syslog(LOG_INFO,"enabling logging icmp type/code for s_port and d_port fields\n"); }else{ if(strcmp(argv[ctr],"-B")==0) { // The rest of this line should be the bpf expression if(gVars.bpf_filter){ free(gVars.bpf_filter); } ctr++; if(argc>ctr){ gVars.bpf_filter=(char *) calloc(1,strlen(argv[ctr])+1); strncpy(gVars.bpf_filter,argv[ctr],strlen(argv[ctr])); syslog(LOG_INFO,"enabling bpf expression %s\n",gVars.bpf_filter); } }else{ if(strcmp(argv[ctr],"-H")==0 || strcmp(argv[ctr],"--human-readable")==0) { // enable human readable mode - affects IP addressess and tcp flag fields gVars.human_readable = 1; syslog(LOG_INFO,"enabling human readable connection logging\n"); }else{ if(strcmp(argv[ctr],"-V")==0||strcmp(argv[ctr],"-v")==0) { version(); license(); exit_all(0); }else{ if(strcmp(argv[ctr],"-?")==0 || strcmp(argv[ctr],"-h")==0){ version(); usage(); exit_all(0); }else{ // See if this was a -option if(strstr(argv[ctr],"-")){ syslog(LOG_ERR,"skipping unrecognized option: %s\n",argv[ctr]); }else{ // The rest of this line should be the bpf expression //if((argc-1)>(ctr++)){ if(gVars.bpf_filter){ free(gVars.bpf_filter); gVars.bpf_filter=0; } gVars.bpf_filter=(char *) calloc(1,strlen(argv[ctr])+1); strncpy(gVars.bpf_filter,argv[ctr],strlen(argv[ctr])); syslog(LOG_INFO,"enabling bpf expression %s\n",gVars.bpf_filter); //syslog(LOG_ERR,"Unknown option: %s\n",argv[ctr]); } //} }}}}}}}}}}}}}}}}}}}}}}}} } } void build_config(int a){ extern struct gvars gVars; int lc=0; FILE *config_file; int size=0; int mylen=0; char *rule=NULL; char *accept="\t ,="; struct vars *tmp_var=NULL; struct acl *tmp_acl=0; struct t_ports *ports_head; struct t_ports *tmp_port; int p=0; if(!gVars.config_file){ return; } if((config_file=fopen(gVars.config_file,"r")) == NULL ) { return; } // Drop the vars now while(gVars.var_head!=NULL){ tmp_var=gVars.var_head; gVars.var_head=gVars.var_head->next; if(tmp_var->key)free(tmp_var->key); if(tmp_var->value)free(tmp_var->value); free(tmp_var); } gVars.var_head=NULL; /* the first field should tell us everything we need to know about * what to expect in the rule */ #ifdef DEBUG fprintf(stdout,"Reading config\n"); #endif while((mylen=fgetcline(&rule, size, config_file)) >= 0){ lc++; if(mylen<2){ #ifdef DEBUG fprintf(stdout,"Line: %d rule too small, skipping %s\n",lc, rule); #endif continue; } #ifdef DEBUG fprintf(stdout,"Processing %s\n",rule); #endif if(strncmp(rule,"format",6)==0) { parse_format(rule,accept); } else if(strncmp(rule,"known_ports",11)==0) { parse_known_ports(rule,gVars.var_head,accept); } else if(strncmp(rule,"default",7)==0) { parse_default(rule,accept); }else if(strncmp(rule,"var",3)==0) { parse_var(rule,accept); #ifdef DEBUG if(gVars.var_head!=NULL) fprintf(stdout,"Have var, %s/%s\n",gVars.var_head->key,gVars.var_head->value); #endif }else{ parse_connection_rule(rule,gVars.var_head,accept); } if(rule){ #ifdef DEBUG printf("freeing %X\n",(u_int32_t) &rule); #endif free(rule); rule=NULL; } } fclose(config_file); #ifdef DEBUG printf("Done reading rules\n"); #endif // swap out old rules with new rules tmp_acl=gVars.acl_head; gVars.acl_head=tacl_head; tacl_head=tmp_acl; #ifdef DEBUG printf("Disposing old rules\n"); #endif // dispose of previous rules while(tacl_head!=NULL){ tmp_acl=tacl_head; tacl_head=tacl_head->next; free(tmp_acl);} tacl_head=NULL; tacl_tail=NULL; #ifdef DEBUG printf("Disposing old ports\n"); #endif //while(acl_head!=NULL){ tmpptr=acl_head; acl_head=acl_head->next; free(tmpptr); } // dispose of previous ports for(p=0; pnext; free(tmp_port); } gVars.ports[p]=tports[p]; tports[p]=NULL; } // Dispose of temporary rule variables // } void parse_format(const char *c_rule,const char *accept) { extern struct gvars gVars; extern char fmtnames[MAXFLDS][MAXFLDSIZE]; char *rule=(char *)calloc(1,strlen(c_rule)+1); memcpy(rule,c_rule,strlen(c_rule)); char *rules=rule; char *tok=0; if((tok = get_tok(&rules,accept))==NULL){ syslog(LOG_ERR,"Skipping, Invalid default, rule trunicated %s\n",rule); return; }else if((tok = get_tok(&rules,accept))==NULL){ syslog(LOG_ERR,"Skipping, Invalid default, rule trunicated %s\n",rule); return; } int type=0; if(strcmp(tok,"realtime")==0) type=1; if(strcmp(tok,"stats")==0) type=2; if(strcmp(tok,"stdout")==0) type=4; char delimiter=0; if(strncmp(rules,"delimiter",9)==0){ if((tok = get_tok(&rules,accept))==NULL){ syslog(LOG_ERR,"Skipping, Invalid delimiter, rule trunicated %s\n",rule); return; }else if((tok = get_tok(&rules,accept))==NULL){ syslog(LOG_ERR,"Skipping, Invalid delimiter, rule trunicated %s\n",rule); return; } delimiter=tok[0]; if(delimiter=='\\'){ if(tok[1]=='s') delimiter=' '; if(tok[1]=='t') delimiter='\t'; if(tok[1]=='n') delimiter='\n'; } } char eor=0; if(strncmp(rules,"eor",3)==0){ if((tok = get_tok(&rules,accept))==NULL){ syslog(LOG_ERR,"Skipping, Invalid eor, rule trunicated %s\n",rule); return; }else if((tok = get_tok(&rules,accept))==NULL){ syslog(LOG_ERR,"Skipping, Invalid eor, rule trunicated %s\n",rule); return; } eor=tok[0]; if(eor=='\\'){ if(tok[1]=='s') eor=' '; if(tok[1]=='t') eor='\t'; if(tok[1]=='n') eor='\n'; } } char *tmpfldnames; int col=0; int icol=0; int fmtval=0; char fmt[MAXFLDS]; while(rules && (tok = get_tok(&rules,accept))!=NULL && *tok != 0) { tmpfldnames=(char *)fmtnames; while((fmtvalMAXFLDS-1){ syslog(LOG_ERR,"Exceeded maximum columns allowed (%d) , skipping remaining format fields at column %d: %s",MAXFLDS,icol,rules); break; } icol++; fmtval=0; } if(type==1){ if(gVars.realtime_fmt_len){ free(gVars.realtime_fmt); gVars.realtime_fmt_len=0; } gVars.realtime_fmt=(char *) calloc(col,1); memcpy(gVars.realtime_fmt,fmt,col); gVars.realtime_fmt_len=col; if(eor) gVars.realtime_eor=eor; if(delimiter) gVars.realtime_delimiter=delimiter; if(gVars.rfH){ gVars.rfH->setFormat(gVars.realtime_fmt,gVars.realtime_fmt_len); gVars.rfH->setEor(gVars.realtime_eor); gVars.rfH->setDelimiter(gVars.realtime_delimiter); } } if(type==2){ if(gVars.stats_fmt_len){ free(gVars.stats_fmt); gVars.stats_fmt_len=0; } gVars.stats_fmt=(char *) calloc(col,1); memcpy(gVars.stats_fmt,fmt,col); gVars.stats_fmt_len=col; if(eor) gVars.stats_eor=eor; if(delimiter) gVars.stats_delimiter=delimiter; if(gVars.sfH){ gVars.sfH->setFormat(gVars.stats_fmt,gVars.stats_fmt_len); gVars.sfH->setEor(gVars.stats_eor); gVars.sfH->setDelimiter(gVars.stats_delimiter); } } if(type==4){ if(gVars.stdout_fmt_len){ free(gVars.stdout_fmt); gVars.stdout_fmt_len=0; } gVars.stdout_fmt=(char *) calloc(col,1); memcpy(gVars.stdout_fmt,fmt,col); gVars.stdout_fmt_len=col; if(eor) gVars.stdout_eor=eor; if(delimiter) gVars.stdout_delimiter=delimiter; if(gVars.sdF){ gVars.sdF->setFormat(gVars.stdout_fmt,gVars.stdout_fmt_len); gVars.sdF->setEor(gVars.stdout_eor); gVars.sdF->setDelimiter(gVars.stdout_delimiter); } } if(rule) free(rule); } void parse_default(char *c_rule,char *accept) { extern struct gvars gVars; char *rule=(char *)calloc(1,strlen(c_rule)+1); memcpy(rule,c_rule,strlen(c_rule)); char *rules=rule; char *tok=0; char *tmp=0; char *ftmp=0; char *pptr=0; if((tok = get_tok(&rules,accept))==NULL){ syslog(LOG_ERR,"Skipping, Invalid default, rule trunicated %s\n",rule); free(rule); return; }else if((tok = get_tok(&rules,accept))==NULL){ syslog(LOG_ERR,"Skipping, Invalid default, rule trunicated %s\n",rule); free(rule); return; } if(strcmp(tok,"expire_interval")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default expire_interval specified but none provided, using default expire_interval %d\n",DEFAULT_EXPIRE_INTERVAL); gVars.default_expire_interval = DEFAULT_EXPIRE_INTERVAL; free(rule); return; } pptr=tmp; gVars.default_expire_interval = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid expire_interval %s, using default expire_interval %d\n",tmp,DEFAULT_EXPIRE_INTERVAL); } free(rule); return; } if(strcmp(tok,"flush_interval")==0) { int reset_alarm=gVars.default_flush_interval; if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default flush_interval specified but none provided, using default flush_interval %d\n",DEFAULT_FLUSH_INTERVAL); gVars.default_flush_interval = DEFAULT_FLUSH_INTERVAL; free(rule); return; } pptr=tmp; gVars.default_flush_interval = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid flush_interval %s, using default flush_interval %d\n",tmp,DEFAULT_FLUSH_INTERVAL); } // If the default flush_interval in the config file changed, we // need to reset the alarm to the new interval if(reset_alarm){ alarm(gVars.default_flush_interval); } free(rule); return; } if(strcmp(tok,"zone")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default zone specified but none provided, using default zone %d\n",DEFAULT_ZONE); gVars.default_zone = DEFAULT_ZONE; free(rule); return; } pptr=tmp; gVars.default_zone = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid zone %s, using default zone %d\n",tmp,DEFAULT_ZONE); } free(rule); return; } if(strcmp(tok,"node")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default node specified but none provided, using default node %d\n",DEFAULT_NODE); gVars.default_node = DEFAULT_NODE; free(rule); return; } pptr=tmp; gVars.default_node = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid node %s, using default node %d\n",tmp,DEFAULT_NODE); } free(rule); return; } if(strcmp(tok,"rid")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default rid specified but none provided, using default rid %d\n",DEFAULT_RID); gVars.default_rid = DEFAULT_RID; free(rule); return; } pptr=tmp; gVars.default_rid = (u_int32_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid rid %s, using default rid %d\n",tmp,DEFAULT_RID); } free(rule); return; } if(strcmp(tok,"rgid")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default rgid specified but none provided, using default rgid %d\n",DEFAULT_RGID); gVars.default_rgid = DEFAULT_RGID; free(rule); return; } pptr=tmp; gVars.default_rgid = (u_int32_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid rid %s, using default rid %d\n",tmp,DEFAULT_RID); } free(rule); return; } if(strcmp(tok,"status")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default status specified but none provided, using default status %d\n",DEFAULT_STATUS); gVars.default_status = DEFAULT_STATUS; free(rule); return; } pptr=tmp; gVars.default_status = (u_int8_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid status %s, using default status %d\n",tmp,DEFAULT_STATUS); } free(rule); return; } if(strcmp(tok,"use_pcap_time")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default for use_pcap_time specified but no value provided%s\n",rule); free(rule); return; } if(strcmp(tmp,"enable")==0) { gVars.use_pcap_time = ENABLED; } if(strcmp(tmp,"disable")==0) { gVars.use_pcap_time = DISABLED; } #ifdef DEBUG fprintf(stdout,"Setting default for %s to %s\n",tok,tmp); #endif free(rule); return; } if(strcmp(tok,"burst_mode")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default for burst_mode specified but no value provided%s\n",rule); free(rule); return; } if(strcmp(tmp,"enable")==0) { gVars.burst_mode = ENABLED; } if(strcmp(tmp,"disable")==0) { gVars.burst_mode = DISABLED; } #ifdef DEBUG fprintf(stdout,"Setting default for %s to %s\n",tok,tmp); #endif free(rule); return; } if(strcmp(tok,"debug_pcap_raw")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default for debug_pcap_raw specified but no value provided%s\n",rule); free(rule); return; } if(strcmp(tmp,"enable")==0) { if(gVars.rpfH){ gVars.rpfH->destroy(); gVars.rpfH=0; } ftmp=createFileName("tcpdump"); gVars.rpfH = new pcapFileHandle(ftmp); free(ftmp); gVars.pcap_raw = ENABLED; } if(strcmp(tmp,"disable")==0) { if(gVars.rpfH){ gVars.rpfH->destroy(); gVars.rpfH=0; } gVars.pcap_raw = DISABLED; } #ifdef DEBUG fprintf(stdout,"Setting default for %s to %s\n",tok,tmp); #endif free(rule); return; } if(strcmp(tok,"strip-80211")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default for strip_80211 specified but no value provided%s\n",rule); free(rule); return; } if(strcmp(tmp,"enable")==0) { gVars.strip_80211 = ENABLED; } if(strcmp(tmp,"disable")==0) { gVars.strip_80211 = DISABLED; } #ifdef DEBUG fprintf(stdout,"Setting default for %s to %s\n",tok,tmp); #endif free(rule); return; } if(strcmp(tok,"pcapfilter")==0) { // We don't parse pcapfilter after initial startup, so see if we have an open pcap handle if( gVars.ph!=0 ){ free(rule); return; } gVars.bpf_filter=(char *) calloc(1,strlen(rules)+1); strncpy(gVars.bpf_filter,rules,strlen(rules)); syslog(LOG_INFO,"setting pcap filter expression %s\n",gVars.bpf_filter); #ifdef DEBUG fprintf(stdout,"Setting default for %s to %s\n",tok,tmp); #endif free(rule); return; } if(strcmp(tok,"stats")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default for stats specified but no value provided%s\n",rule); free(rule); return; } if(strcmp(tmp,"log")==0) // log all matching traffic { if(gVars.stats_fname){ free(gVars.stats_fname); } gVars.stats_fname=(char *) calloc(1,strlen(STATS_FNAME)+1); strncpy(gVars.stats_fname,STATS_FNAME,strlen(STATS_FNAME)); if(gVars.sfH){ gVars.sfH->destroy(); gVars.sfH=0; } ftmp=createFileName(gVars.stats_fname); gVars.sfH = new outputFileHandle((const char*)ftmp,gVars.stats_fmt,gVars.stats_fmt_len,APPEND_MODE); free(ftmp); gVars.smode=OMODE_LOG; } if(strcmp(tmp,"pass")==0) { if(gVars.sfH){ gVars.sfH->destroy(); gVars.sfH=0; } gVars.smode=OMODE_PASS; } if(strcmp(tmp,"filename")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default filename for stats specified but no value provided%s\n",rule); return; } if(gVars.stats_fname){ free(gVars.stats_fname); } gVars.stats_fname=(char *) calloc(1,strlen(tmp)+1); strncpy(gVars.stats_fname,tmp,strlen(tmp)); gVars.smode=OMODE_FILENAME; if(gVars.sfH){ gVars.sfH->destroy(); gVars.sfH=0; } ftmp=createFileName(gVars.stats_fname,gVars.smode == OMODE_TSFILENAME); gVars.sfH = new outputFileHandle((const char*)ftmp,gVars.stats_fmt,gVars.stats_fmt_len,APPEND_MODE); gVars.sfH->setEor(gVars.stats_eor); gVars.sfH->setDelimiter(gVars.stats_delimiter); free(ftmp); } if(strcmp(tmp,"tsfilename")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default tsfilename for stats specified but no value provided%s\n",rule); free(rule); return; } if(gVars.stats_fname){ free(gVars.stats_fname); } gVars.stats_fname=(char *) calloc(1,strlen(tmp)+1); strncpy(gVars.stats_fname,tmp,strlen(tmp)); gVars.smode=OMODE_TSFILENAME; if(gVars.sfH){ gVars.sfH->destroy(); gVars.sfH=0; } ftmp=createFileName(gVars.stats_fname,gVars.smode == OMODE_TSFILENAME); gVars.sfH = new outputFileHandle((const char*)ftmp,gVars.stats_fmt,gVars.stats_fmt_len,APPEND_MODE); gVars.sfH->setEor(gVars.stats_eor); gVars.sfH->setDelimiter(gVars.stats_delimiter); free(ftmp); } #ifdef DEBUG fprintf(stdout,"Setting default for %s to %s\n",tok,tmp); #endif free(rule); return; } if(strcmp(tok,"pcap")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default for pcap specified but no value provided%s\n",rule); free(rule); return; } if(strcmp(tmp,"log")==0) // log all matching traffic { gVars.pmode = OMODE_LOG; if(gVars.pcap_fname){ free(gVars.pcap_fname); } gVars.pcap_fname=(char *) calloc(1,strlen(PCAP_FNAME)+1); strncpy(gVars.pcap_fname,PCAP_FNAME,strlen(PCAP_FNAME)); if(gVars.pfH){ gVars.pfH->destroy(); gVars.pfH=0; } ftmp=createFileName(gVars.pcap_fname); gVars.pfH = new pcapFileHandle(ftmp); free(ftmp); } if(strcmp(tmp,"pass")==0) { gVars.pmode=OMODE_PASS; if(gVars.pfH){ gVars.pfH->destroy(); gVars.pfH=0; } } if(strcmp(tmp,"filename")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default filename for pcap specified but no value provided%s\n",rule); free(rule); return; } if(gVars.pcap_fname){ free(gVars.pcap_fname); } gVars.pcap_fname=(char *) calloc(1,strlen(tmp)+1); strncpy(gVars.pcap_fname,tmp,strlen(tmp)); gVars.pmode=OMODE_FILENAME; if(gVars.pfH){ gVars.pfH->destroy(); gVars.pfH=0; } ftmp=createFileName(gVars.pcap_fname,gVars.pmode == OMODE_TSFILENAME ); gVars.pfH = new pcapFileHandle(ftmp); free(ftmp); } if(strcmp(tmp,"tsfilename")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default tsfilename for pcap specified but no value provided%s\n",rule); free(rule); return; } if(gVars.pcap_fname){ free(gVars.pcap_fname); } gVars.pcap_fname=(char *) calloc(1,strlen(tmp)+1); strncpy(gVars.pcap_fname,tmp,strlen(tmp)); gVars.pmode=OMODE_TSFILENAME; if(gVars.pfH){ gVars.pfH->destroy(); gVars.pfH=0; } ftmp=createFileName(gVars.pcap_fname,gVars.pmode == OMODE_TSFILENAME); gVars.pfH = new pcapFileHandle(ftmp); free(ftmp); } #ifdef DEBUG fprintf(stdout,"Setting default for %s to %s\n",tok,tmp); #endif free(rule); return; } if(strcmp(tok,"realtime")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default for realtime specified but no value provided%s\n",rule); free(rule); return; } if(strcmp(tmp,"log")==0) // log all matching traffic { if(gVars.realtime_fname){ free(gVars.realtime_fname); } gVars.realtime_fname=(char *) calloc(1,strlen(REALTIME_FNAME)+1); strncpy(gVars.realtime_fname,REALTIME_FNAME,strlen(REALTIME_FNAME)); if(gVars.rfH){ gVars.rfH->destroy(); gVars.rfH=0; } ftmp=createFileName(gVars.realtime_fname); gVars.rfH = new outputFileHandle((const char*)ftmp,gVars.realtime_fmt,gVars.realtime_fmt_len,APPEND_MODE); free(ftmp); gVars.rmode=OMODE_LOG; } if(strcmp(tmp,"pass")==0) { if(gVars.rfH){ gVars.rfH->destroy(); gVars.rfH=0; } gVars.rmode=OMODE_PASS; } if(strcmp(tmp,"filename")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default filename for realtime specified but no value provided%s\n",rule); free(rule); return; } if(gVars.realtime_fname){ free(gVars.realtime_fname); } gVars.realtime_fname=(char *) calloc(1,strlen(tmp)+1); strncpy(gVars.realtime_fname,tmp,strlen(tmp)); gVars.rmode=OMODE_FILENAME; if(gVars.rfH){ gVars.rfH->destroy(); gVars.rfH=0; } ftmp=createFileName(gVars.realtime_fname,gVars.rmode == OMODE_TSFILENAME); gVars.rfH = new outputFileHandle((const char*)ftmp,gVars.realtime_fmt,gVars.realtime_fmt_len,APPEND_MODE); gVars.rfH->setEor(gVars.realtime_eor); gVars.rfH->setDelimiter(gVars.realtime_delimiter); free(ftmp); } if(strcmp(tmp,"tsfilename")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default tsfilename for realtime specified but no value provided%s\n",rule); free(rule); return; } if(gVars.realtime_fname){ free(gVars.realtime_fname); } gVars.realtime_fname=(char *) calloc(1,strlen(tmp)+1); strncpy(gVars.realtime_fname,tmp,strlen(tmp)); gVars.rmode=OMODE_TSFILENAME; if(gVars.rfH){ gVars.rfH->destroy(); gVars.rfH=0; } ftmp=createFileName(gVars.realtime_fname,gVars.rmode == OMODE_TSFILENAME); gVars.rfH = new outputFileHandle((const char*)ftmp,gVars.realtime_fmt,gVars.realtime_fmt_len,APPEND_MODE); gVars.rfH->setEor(gVars.realtime_eor); gVars.rfH->setDelimiter(gVars.realtime_delimiter); free(ftmp); } #ifdef DEBUG fprintf(stdout,"Setting default for %s to '%s'\n",tok,tmp); #endif free(rule); return; } if(strcmp(tok,"limit")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, limit specified but none provided, using default limit %d\n",DEFAULT_LIMIT); free(rule); return; } pptr=tmp; gVars.default_limit = (u_int64_t) strtoll(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid limit %s, using default limit %d\n",tmp,DEFAULT_LIMIT); gVars.default_limit = DEFAULT_LIMIT; } free(rule); return; } if(strcmp(tok,"timeout")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, default timeout specified but none provided, using timeout value %d\n",DEFAULT_TIMEOUT); free(rule); return; } pptr=tmp; gVars.default_timeout = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid timeout %s, using default timeout %d\n",tmp,DEFAULT_TIMEOUT); gVars.default_timeout = DEFAULT_TIMEOUT; } free(rule); return; } if(strcmp(tok,"tcplag")==0) { if((tmp = get_tok(&rules,accept))==NULL) { syslog(LOG_ERR,"Format error, tcplag specified but none provided, using tcplag value %d\n",DEFAULT_LAG); free(rule); return; } pptr=tmp; gVars.default_tcplag = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid tcplag %s, using default tcplag %d\n",tmp,DEFAULT_LAG); gVars.default_tcplag = DEFAULT_LAG; } free(rule); return; #ifdef DEBUG fprintf(stdout,"Didn't set default for %s to %s\n",tok,tmp); #endif } } void parse_var(char *c_rule, char *accept) { extern struct gvars gVars; char *rule=(char *)calloc(1,strlen(c_rule)+1); memcpy(rule,c_rule,strlen(c_rule)); char **rules=&rule; char *tok=NULL; struct vars *n_var; rules=&rule; if((n_var=(struct vars *)calloc(1,sizeof(struct vars)))==NULL){ printf ("Out of Memory?\n"); return;} n_var->key=NULL; n_var->value=NULL; n_var->next=NULL; if((tok = get_tok(rules,accept))==NULL || strcmp(tok,"var")!=0) { syslog(LOG_ERR,"Skipping, Invalid rule trunicated when expecting var type %s\n",rule); free(n_var); free(rule); return; } else { if((tok = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Skipping, Invalid rule trunicated when expecting var key %s\n",rule); free(n_var); free(rule); return; } else { if((n_var->key=(char *)calloc(1,sizeof(char)*strlen(tok)+1))==NULL){ printf ("Out of Memory?\n"); free(n_var); free(rule); return;} strncpy(n_var->key,tok,sizeof(char)*strlen(tok)); if((tok = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Skipping, Invalid rule trunicated when expecting var value %s\n",rule); free(n_var->key); n_var->key=NULL; free(n_var); free(rule); return; } else { if((n_var->value=(char *)calloc(1,sizeof(char)*strlen(tok)+1))==NULL){ printf ("Out of Memory?\n"); free(n_var->key); free(n_var); free(rule); return;} strncpy(n_var->value,tok,sizeof(char)*strlen(tok)); } } } // If we made it this var, then we have a valid var if(!gVars.var_head){ gVars.var_head=n_var; } else { n_var->next = gVars.var_head; gVars.var_head=n_var; } free(rule); } char *search_vars(char *key, struct vars *var_head, int vclass) { struct vars *tmp; tmp = var_head; #ifdef DEBUG syslog(LOG_ERR,"Searching for key '%s'\n",key); #endif while(tmp!=NULL) { #ifdef DEBUG fprintf(stdout,"Checking key/value (%d) '%s'/'%s' for (%d) '%s'\n",strlen(tmp->key),tmp->key,tmp->value,strlen(key),key); #endif if(strcmp(tmp->key,key)==0) { #ifdef DEBUG syslog(LOG_ERR,"Found key/value %s/%s\n",key,tmp->value); #endif // Mark the variable class that we were looking in // so we will 'remember' which values pertained to which // class of keys when we do a reverse lookup later. // i.e. The value of 8 may exist in two or more classes // Different class variables, having the same name, may // cause undefined results. tmp->vclass=vclass; return tmp->value; } tmp=tmp->next; } #ifdef DEBUG fprintf(stdout,"Key not found '%s'\n",key); #endif return NULL; } char *rev_search_vars(char *value, struct vars *var_head, int vclass) { struct vars *tmp; tmp = var_head; #ifdef DEBUG syslog(LOG_INFO,"REV Search %d:'%s' for %d:'%s'\n",tmp->vclass,tmp->value,vclass,value); #endif while(tmp!=NULL) { if( tmp->vclass==vclass && strcmp(tmp->value,value)==0) { #ifdef DEBUG syslog(LOG_ERR,"Found key/value %s/'%s'\n",tmp->key,tmp->value); #endif return tmp->key; } tmp=tmp->next; } #ifdef DEBUG fprintf(stdout,"Value not found '%s'\n",value); #endif return NULL; } void parse_known_ports(char *rule, struct vars *var_head, char *accept) { extern struct t_ports *tports[MAX_IP_PROTO]; char *tmp=NULL, *pptr=NULL,*tok=NULL; char **rules=NULL; struct t_ports *n_ports=NULL; int proto = 0; char ptok[256]; u_int16_t port_h=0; u_int16_t port_l=0; rules=&rule; if((tok = get_tok(rules,accept))!=NULL) { if((tok = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Skipping, Invalid rule trunicated when expecting ports protocol %s\n",rule); return; } if((tmp=search_vars(tok,var_head,VCLASS_2))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); tok=ptok; } pptr=tok; proto = (u_int8_t) strtol(tok,&pptr,0); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid protocol value found: %s\n",tok); return; } while((tok = get_tok(rules,accept))!=NULL && *tok != 0) { if((tmp=search_vars(tok,var_head,VCLASS_3))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); tok=ptok; } if((tmp = get_next_tok(&tok,"-"))!=NULL) { pptr=tmp; port_l = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Skipping, Invalid port start of range found: %s\n",tmp); return; } pptr=tok; port_h = (u_int16_t) strtol(tok,&pptr,0); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid port end of range found: %s\n",tok); return; } }else{ pptr=tok; port_l = (u_int16_t) strtol(tok,&pptr,0); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid port found: %X.\n",*tok); return; } #ifdef DEBUG syslog(LOG_ERR,"Port found: %s\n",tok); #endif port_h=port_l; } // if we made it this far we have a valid oort if((n_ports=(struct t_ports *)calloc(1,sizeof(struct t_ports)))==NULL){ printf ("Out of Memory?\n"); return;} n_ports->h_port=port_h; n_ports->l_port=port_l; n_ports->next=NULL; if(!tports[proto]){ tports[proto]=n_ports; } else { n_ports->next = tports[proto]; tports[proto]=n_ports; } } }else{ syslog(LOG_ERR,"Skipping, Invalid rule trunicated when expecting ports protocol %s\n",rule); } } void parse_connection_rule(char *rule, struct vars *var_head, char *accept) { // THIS FUNCTION DOES NOT EXIT THE PROGRAM WHEN IT RECEIVES A // BAD RULE!!! THIS IS DONE TO ENSURE THIS TOOL CONTINUES COLLECTION // SPECIFICALLY IN CASE IT READS A BAD CONFIGURATION FILE AFTER RECEIVING // A KILL -HUP SIGNAL - SO ALWAYS CHECK THE SYSLOG FOR ERRORS // IF THE DEFAULT PCAP MODE IS TO RECORD EVERYTHING THEN BAD RULES WILL // NOT MEAN LOST DATA. YOU CAN ALWAYS RE-PROCESS PCAP DATA BUT CAN'T // RECOVER FROM DATA YOU DIDN'T RECORD char *tmp, *tok=NULL; char **rules=NULL; char *pptr=NULL; char *ftmp=0; char ptok[256]; struct acl *n_acl; extern struct gvars gVars; extern struct acl *tacl_head, *tacl_tail; bzero(ptok,256); rules=&rule; if((n_acl=(struct acl *)calloc(1,sizeof(struct acl)))==NULL){ syslog (LOG_CRIT,"Unable to allocate ACL - Out of Memory!\n"); return;} bzero(n_acl,sizeof(struct acl)); n_acl->next=NULL; n_acl->cmode = CMODE_BOTH; n_acl->pcap = gVars.pmode?1:0; n_acl->pmode = gVars.pmode; n_acl->stats = gVars.smode?1:0; n_acl->smode = gVars.smode; n_acl->realtime = gVars.rmode?1:0; n_acl->rmode = gVars.rmode; n_acl->timeout = gVars.default_timeout; n_acl->limit = gVars.default_limit; n_acl->status = gVars.default_status; n_acl->rid = gVars.default_rid; n_acl->tcplag = gVars.default_tcplag; if(gVars.pfH && gVars.pmode){ n_acl->fH = gVars.pfH->attach(); }else{ n_acl->fH = 0; } // FIELD 0 - required - Get the h_proto n_acl->h_proto_h = 0xFFFF; n_acl->h_proto_l = 0x0000; if((tok = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Skipping, Invalid rule trunicated when expecting hw protocol %s\n",rule); free(n_acl); return; } else if(strcmp(tok,"any")){ if((tmp=search_vars(tok,gVars.var_head,VCLASS_0))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); tok=ptok; } if((tmp = get_next_tok(&tok,"-"))!=NULL) { pptr=tmp; n_acl->h_proto_l = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Skipping, Invalid start of h_proto range found: %s\n",tmp); free(n_acl); return; } pptr=tok; n_acl->h_proto_h = (u_int16_t) strtol(tok,&pptr,0); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid end of h_proto range found: %s\n",tok); free(n_acl); return; } }else{ pptr=tok; n_acl->h_proto_l = (u_int16_t) strtol(tok,&pptr,0); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid h_protocol value found: %s\n",tok); free(n_acl); return; } n_acl->h_proto_h = n_acl->h_proto_l; } } // FIELD 1 - required - Get the source address and mask fields n_acl->s_mask=0xFFFFFFFF; n_acl->s_ip=0x00000000; if((tok = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Skipping, Invalid rule trunicated when expecting source address and mask %s\n",rule); free(n_acl); return; } else if(strcmp(tok,"any")){ if((tmp=search_vars(tok,gVars.var_head,VCLASS_1))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); tok=ptok; } if((tmp = get_next_tok(&tok,"/"))!=NULL) { if(inet_aton(tmp,(struct in_addr *)&n_acl->s_ip)==0) { syslog(LOG_ERR,"Skipping, Invalid source address found: %s/%s %s\n",tmp,tok,rule); free(n_acl); return; } if(strstr(tok,".")) { if(inet_aton(tok,(struct in_addr *)&n_acl->s_mask)==0) { syslog(LOG_ERR,"Skipping, Invalid source mask found: %s/%s %s\n",tmp,tok,rule); free(n_acl); return; } } else { pptr=tok; n_acl->s_mask=htonl(0xFFFFFFF<<(32-(u_int8_t)(strtol(tok,&pptr,0)))); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid source mask found: %s/%s %s\n",tmp,tok,rule); free(n_acl); return; } } }else{ if(inet_aton(tok,(struct in_addr *)&n_acl->s_ip)==0) { syslog(LOG_ERR,"Skipping, Invalid source address found: %s %s\n",tok,rule); free(n_acl); return; } } } // FIELD 3 - required - Get the destination address and mask fields n_acl->d_mask=0xFFFFFFFF; n_acl->d_ip=0x00000000; if((tok = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Skipping, Invalid rule trunicated when expecting destination address and mask %s\n",rule); free(n_acl); return; } else if(strcmp(tok,"any")){ if((tmp=search_vars(tok,gVars.var_head,VCLASS_1))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); tok=ptok; } if((tmp = get_next_tok(&tok,"/"))!=NULL) { if(inet_aton(tmp,(struct in_addr *)&n_acl->d_ip)==0) { syslog(LOG_ERR,"Skipping, Invalid destination address found: %s/%s %s\n",tmp,tok,rule); free(n_acl); return; } if(strstr(tok,".")) { if(inet_aton(tok,(struct in_addr *)&n_acl->d_mask)==0) { syslog(LOG_ERR,"Skipping, Invalid destination mask found: %s/%s %s\n",tmp,tok,rule); free(n_acl); return; } } else { pptr=tok; n_acl->d_mask=htonl(0xFFFFFFFF<<(32-(u_int8_t)(strtol(tok,&pptr,0)))); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid destination mask found: %s/%s %s\n",tmp,tok,rule); free(n_acl); return; } } }else{ if(inet_aton(tok,(struct in_addr *)&n_acl->d_ip)==0) { syslog(LOG_ERR,"Skipping, Invalid destination address found: %s %s\n",tok,rule); free(n_acl); return; } } } // FIELD 4 - required - Get the protocol field n_acl->proto_l = 0x00; n_acl->proto_h = 0xFF; if((tok = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Skipping, Invalid rule trunicated when expecting protocol %s\n",rule); free(n_acl); return; } else if(strcmp(tok,"any")){ if((tmp=search_vars(tok,gVars.var_head,VCLASS_2))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); tok=ptok; } // Use the defaults for ANY if((tmp = get_next_tok(&tok,"-"))!=NULL) { pptr=tmp; n_acl->proto_l = (u_int8_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Skipping, Invalid start of proto range found: %s\n",tmp); free(n_acl); return; } pptr=tok; n_acl->proto_h = (u_int8_t) strtol(tok,&pptr,0); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid end of proto range found: %s\n",tok); free(n_acl); return; } }else{ pptr=tok; n_acl->proto_l = (u_int8_t) strtol(tok,&pptr,0); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid protocol value found: %s\n",tok); free(n_acl); return; } n_acl->proto_h = n_acl->proto_l; } } // FIELD 5 - required - Get the source ports field n_acl->s_port_l=0x0000; n_acl->s_port_h=0xFFFF; if((tok = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Skipping, Invalid rule trunicated when expecting source ports %s\n",rule); free(n_acl); return; } else if(strcmp(tok,"any")){ if((tmp=search_vars(tok,gVars.var_head,VCLASS_3))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); tok=ptok; } // Use the defaults for ANY if((tmp = get_next_tok(&tok,"-"))!=NULL) { pptr=tmp; n_acl->s_port_l = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Skipping, Invalid source port start of range found: %s\n",tmp); free(n_acl); return; } pptr=tok; n_acl->s_port_h = (u_int16_t) strtol(tok,&pptr,0); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid source port end of range found: %s\n",tok); free(n_acl); return; } }else{ pptr=tok; n_acl->s_port_l = (u_int16_t) strtol(tok,&pptr,0); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid source port found: %s\n",tok); free(n_acl); return; } n_acl->s_port_h=n_acl->s_port_l; } } // FIELD 6 - required - Get the destination ports field n_acl->d_port_l=0x0000; n_acl->d_port_h=0xFFFF; if((tok = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Skipping, Invalid rule trunicated when expecting destination ports %s\n",rule); free(n_acl); return; } else if(strcmp(tok,"any")){ if((tmp=search_vars(tok,gVars.var_head,VCLASS_3))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); tok=ptok; } if((tmp = get_next_tok(&tok,"-"))!=NULL ) { pptr=tmp; n_acl->d_port_l = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Skipping, Invalid destination port start of range found: %s\n",tmp); free(n_acl); return; } pptr=tok; n_acl->d_port_h = (u_int16_t) strtol(tok,&pptr,0); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid destination port end of range found: %s\n",tok); free(n_acl); return; } }else{ pptr=tok; n_acl->d_port_l = (u_int16_t) strtol(tok,&pptr,0); if(tok==pptr) { syslog(LOG_ERR,"Skipping, Invalid destination port found: %s\n",tok); free(n_acl); return; } n_acl->d_port_h=n_acl->d_port_l; } } // REMAINING FIELDs - not required - limit and timeout while((tok = get_tok(rules,accept))!=NULL && *tok!=0 ) { if(strcmp(tok,"rid")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, rid specified but none provided, using default rid %u\n",gVars.default_rid); return; } if((tok=search_vars(tmp,gVars.var_head,VCLASS_4))!=NULL) { bzero(ptok,256); strncpy(ptok,tok,sizeof(char)*strlen(tok)); tmp=ptok; } pptr=tmp; n_acl->rid = (u_int32_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid rid %s, using default rid %u\n",tmp,gVars.default_rid); // Let's restore the delimiter and put back our token // this might be the next option tmp[sizeof(tmp)-1]=' '; *rules=tmp; } continue; } if(strcmp(tok,"rgid")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, rgid specified but none provided, using default rgid %u\n",gVars.default_rgid); return; } if((tok=search_vars(tmp,gVars.var_head,VCLASS_5))!=NULL) { bzero(ptok,256); strncpy(ptok,tok,sizeof(char)*strlen(tok)); tmp=ptok; } pptr=tmp; n_acl->rgid = (u_int32_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid rgid %s, using default rgid %u\n",tmp,gVars.default_rgid); // Let's restore the delimiter and put back our token // this might be the next option tmp[sizeof(tmp)-1]=' '; *rules=tmp; } continue; } if(strcmp(tok,"zone")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, zone specified but none provided, using default zone %d\n",gVars.default_zone); return; } if((tok=search_vars(tmp,gVars.var_head,VCLASS_6))!=NULL) { bzero(ptok,256); strncpy(ptok,tok,sizeof(char)*strlen(tok)); tmp=ptok; } pptr=tmp; n_acl->zone = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid zone %s, using default zone %d\n",tmp,gVars.default_zone); // Let's restore the delimiter and put back our token // this might be the next option tmp[sizeof(tmp)-1]=' '; *rules=tmp; } continue; } if(strcmp(tok,"node")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, node specified but none provided, using default node %d\n",gVars.default_node); return; } if((tok=search_vars(tmp,gVars.var_head,VCLASS_7))!=NULL) { bzero(ptok,256); strncpy(ptok,tok,sizeof(char)*strlen(tok)); tmp=ptok; } pptr=tmp; n_acl->node = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid node %s, using default node %d\n",tmp,gVars.default_node); // Let's restore the delimiter and put back our token // this might be the next option tmp[sizeof(tmp)-1]=' '; *rules=tmp; } continue; } if(strcmp(tok,"status")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, status specified but none provided, using default status %d\n",gVars.default_status); return; } if((tok=search_vars(tmp,gVars.var_head,VCLASS_8))!=NULL) { bzero(ptok,256); strncpy(ptok,tok,sizeof(char)*strlen(tok)); tmp=ptok; } pptr=tmp; n_acl->status = (u_int8_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid status %s, using default status %d\n",tmp,gVars.default_status); // Let's restore the delimiter and put back our token // this might be the next option tmp[sizeof(tmp)-1]=' '; *rules=tmp; } continue; } if(strcmp(tok,"timeout")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, timeout specified but none provided, using default timeout %d\n",gVars.default_timeout); return; } pptr=tmp; n_acl->timeout = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid timeout %s, using default timeout\n",tmp); // Let's restore the delimiter and put back our token // this might be the next option tmp[sizeof(tmp)-1]=' '; *rules=tmp; } continue; } if(strcmp(tok,"tcplag")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, tcplag specified but none provided, using default tcplag %d\n",gVars.default_tcplag); return; } pptr=tmp; n_acl->tcplag = (u_int16_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid tcplag %s, using default tcplag \n",tmp); tmp[sizeof(tmp)-1]=' '; *rules=tmp; } continue; } if(strcmp(tok,"limit")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, limit specified but none provided, using default limit %llu\n",(long long unsigned)gVars.default_limit); return; } pptr=tmp; n_acl->limit = (u_int64_t) strtol(tmp,&pptr,0); if(tmp==pptr) { syslog(LOG_ERR,"Format error, invalid limit %s, using default limit %llu\n",tmp,(long long unsigned)gVars.default_limit); // Let's restore the delimiter and put back our token // this might be the next option tmp[sizeof(tmp)-1]=' '; *rules=tmp; } continue; } if(strcmp(tok,"realtime")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, realtime specified but no option provided%s\n",rule); return; } if(strcmp(tmp,"log")==0) // log all matching traffic { n_acl->realtime = ACTION_LOG; n_acl->rmode = OMODE_LOG; continue; } if(strcmp(tmp,"pass")==0) { n_acl->realtime = ACTION_PASS; n_acl->rmode = OMODE_PASS; continue; } syslog(LOG_ERR,"Skipping, invalid realtime option in rule: %s %s\n",tok,tmp); return; } if(strcmp(tok,"stats")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, stats specified but no option provided%s\n",rule); return; } if(strcmp(tmp,"log")==0) // log all matching traffic { n_acl->stats=ACTION_LOG; n_acl->smode=OMODE_LOG; continue; } if(strcmp(tmp,"pass")==0) { n_acl->stats = ACTION_PASS; n_acl->smode = OMODE_PASS; continue; } syslog(LOG_ERR,"Skipping, invalid stats option in rule: %s %s\n",tok,tmp); return; } if(strcmp(tok,"pcap")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, output specified but none provided, using default output%s\n",rule); return; } if(strcmp(tmp,"log")==0) // log all matching traffic { if(n_acl->fH){ n_acl->fH->destroy(); n_acl->fH=0; } n_acl->fH = gVars.pfH->attach(); n_acl->pcap = ACTION_LOG; n_acl->pmode = OMODE_LOG; continue; } if(strcmp(tmp,"pass")==0) { if(n_acl->fH){ n_acl->fH->destroy(); n_acl->fH=0; } n_acl->fH = 0; n_acl->pcap = ACTION_PASS; n_acl->pmode = OMODE_PASS; n_acl->cmode = CMODE_NONE; continue; } if(strcmp(tmp,"rule")==0) { if(n_acl->fH){ n_acl->fH->destroy(); n_acl->fH=0; } n_acl->fH = new pcapFileHandle(createPcapFileName(n_acl)); n_acl->pcap = ACTION_LOG; n_acl->pmode=OMODE_RULE; continue; } if(strcmp(tmp,"connection")==0) { n_acl->fH=0; n_acl->pcap = ACTION_LOG; n_acl->pmode=OMODE_UNIQ; continue; } if(strcmp(tmp,"filename")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, filename specified but none provided, using default filename %s\n",rule); return; }else{ if(n_acl->fH){ n_acl->fH->destroy(); n_acl->fH=0; } // Create this filename without a timestamp ftmp=createFileName(tmp,false); n_acl->fH = new pcapFileHandle(ftmp); free(ftmp); n_acl->pcap = ACTION_LOG; n_acl->pmode=OMODE_FILENAME; } continue; } if(strcmp(tmp,"tsfilename")==0) { if((tmp = get_tok(rules,accept))==NULL) { syslog(LOG_ERR,"Format error, tsfilename specified but none provided, using default pcap output file%s\n",rule); return; }else{ if(n_acl->fH){ n_acl->fH->destroy(); n_acl->fH=0; } // Create this filename with a timestamp ftmp=createFileName(tmp,true); n_acl->fH = new pcapFileHandle(ftmp); free(ftmp); n_acl->pcap = ACTION_LOG; n_acl->pmode=OMODE_TSFILENAME; } continue; } syslog(LOG_ERR,"Skipping, invalid pcap option in rule: %s %s\n",tok,tmp); return; } if(strcmp(tok,"logdst")==0) { n_acl->cmode = CMODE_DST; continue; } if(strcmp(tok,"logsrc")==0) { n_acl->cmode = CMODE_SRC; continue; } if(strcmp(tok,"ignore")==0) { // We should ignore everything for this rule n_acl->stats=n_acl->realtime=n_acl->pcap=ACTION_PASS; n_acl->cmode = CMODE_NONE; n_acl->pmode = OMODE_PASS; continue; } if(strcmp(tok,"retro")==0) // Apply rule to pre-existing connections in memory { n_acl->retro = true; continue; } syslog(LOG_ERR,"Skipping, invalid option in rule: %s %s\n", tok,*rules); return; } // If we made it this far, the rule is good // So we will add it to our list if(tacl_head){ tacl_tail->next=n_acl; }else{ tacl_head=n_acl; } tacl_tail=n_acl; if(n_acl->retro){ #ifdef DEBUG printf("Applying rule retro-actively!\n"); #endif retroactive(n_acl); } } /* * char * get_tok (char **rule, const char *delimiters ) * Uses strpbrk to locate the first occurrance of a character in *delimiters, * replaces this character with a null '\0', modifying **rule to point * one byte past the delimiter character. * * Returns pointer to beginning of token, or NULL if no delimiter is found. * */ // Returns the rule you were pointing to and modifies rule char * get_tok(char **rule, const char *delimiters) { char *tok=*rule; char *tmp=0; int len=0; if(*rule==NULL) return NULL; len=strlen(tok); if((tmp = strpbrk(*rule,delimiters))!=NULL){ *tmp=0; if(tmp>*rule) *rule=++tmp; } else { *rule=NULL; } return tok; } // Returns next tok or NULL char * get_next_tok(char **rule, const char *delimiters) { char *tok=*rule; char *tmp; int len=0; if(*rule==NULL) return NULL; len=strlen(tok); if((tmp = strpbrk(*rule,delimiters))!=NULL){ *tmp='\0'; if(tmp>*rule) *rule=++tmp; return tok; } else { return NULL; } } void print_acl(int a){ extern struct gvars gVars; struct t_ports *tmp_port; struct t_ports *ports_head; char currenttime[80]; time_t timestr=gVars.timeptr.tv_sec; struct acl* tmpptr; int p, cidr,bits; char ptok[256]; char *tmp; u_int32_t tmpint; char LOG[1024]; tmpptr=gVars.acl_head; if(gVars.uselocaltime){ strftime(currenttime,80,"%Y-%m-%d %T",(struct tm *)localtime(×tr)); }else{ strftime(currenttime,80,"%Y-%m-%d %T GMT",(struct tm *)gmtime(×tr)); } bzero(LOG,1024); sprintf(LOG,"#\n# Running configuration as of %s\n#\n",currenttime); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); char type[10][36]={ {"unused or unassociated vars"},{"ethernet protocols"},{"networks and hosts"},{"ip protocols"},{"udp/tcp ports"},{ "rule ids"},{"rule groups (kinds of traffic)"},{"zones"},{"nodes"},{"status"}}; int unused=0; struct vars *tvars=gVars.var_head; for(int x=1; x<10; x++){ sprintf(LOG,"\n#\n# defined %s\n#\n",type[x]); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); while(tvars!=NULL){ if(tvars->vclass==x){ sprintf(LOG,"var %s %s\n",tvars->key,tvars->value); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); } if(tvars->vclass==0){ unused=1; } tvars=tvars->next; } tvars=gVars.var_head; } if(unused){ sprintf(LOG,"\n#\n# %s\n#\n",type[0]); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); while(tvars!=NULL){ if(tvars->vclass==0){ sprintf(LOG,"var %s %s\n",tvars->key,tvars->value); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); } tvars=tvars->next; } } sprintf(LOG,"\n#\n# define defaults\n#\n"); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); if(gVars.rmode==OMODE_FILENAME){ sprintf(LOG,"default realtime filename %s\n",gVars.realtime_fname); }else if(gVars.rmode==OMODE_TSFILENAME){ sprintf(LOG,"default realtime tsfilename %s\n",gVars.realtime_fname); }else{ sprintf(LOG,"default realtime=%s\n",gVars.pmode?"log":"pass"); } LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); if(gVars.smode==OMODE_FILENAME){ sprintf(LOG,"default stats filename %s\n",gVars.stats_fname); }else if(gVars.smode==OMODE_TSFILENAME){ sprintf(LOG,"default stats tsfilename %s\n",gVars.stats_fname); }else{ sprintf(LOG,"default stats=%s\n",gVars.smode?"log":"pass"); } LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); if(gVars.pmode==OMODE_FILENAME){ sprintf(LOG,"default pcap filename %s\n",gVars.pcap_fname); }else if(gVars.pmode==OMODE_TSFILENAME){ sprintf(LOG,"default pcap tsfilename %s\n",gVars.pcap_fname); }else{ sprintf(LOG,"default pcap=%s\n",gVars.pmode?"log":"pass"); } LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); if(gVars.pcap_raw){ sprintf(LOG,"default debug_pcap_raw=%s\n",gVars.pcap_raw?"enable":"disable"); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); } if(gVars.strip_80211){ sprintf(LOG,"default strip-80211=%s\n",gVars.strip_80211?"enable":"disable"); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); } sprintf(LOG,"default flush_interval=%u\n",gVars.default_flush_interval); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); sprintf(LOG,"default expire_interval=%u\n",gVars.default_expire_interval); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); sprintf(LOG,"default burst_mode=%s\n",gVars.burst_mode?"enable":"disable"); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); sprintf(LOG,"default status=%u\n",gVars.default_status); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); sprintf(LOG,"default node=%u\n",gVars.default_node); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); sprintf(LOG,"default zone=%u\n",gVars.default_zone); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); sprintf(LOG,"default rid=%u\n",gVars.default_rid); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); sprintf(LOG,"default rgid=%u\n",gVars.default_rgid); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); sprintf(LOG,"default timeout=%d\n",gVars.default_timeout); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); sprintf(LOG,"default limit=%llu\n",(long long unsigned)gVars.default_limit); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); sprintf(LOG,"default tcplag=%d\n",gVars.default_tcplag); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); if(gVars.bpf_filter){ sprintf(LOG,"default pcapfilter \"%s\"\n",gVars.bpf_filter); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); } sprintf(LOG,"\n#\n# define known_ports\n#\n"); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); for(p=0; pnext; bzero(ptok,256); sprintf(ptok,"%d",tmp_port->l_port); if(tmp_port->l_port!=tmp_port->h_port) sprintf(ptok,"%s-%d",ptok,tmp_port->h_port); if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_3))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); } sprintf(LOG,"%s%s",LOG,ptok); if(tmp_port->next) strcat(LOG,","); } strcat(LOG,"\n"); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); } } sprintf(LOG,"\n#\n# Running rules as of %s\n#\n",currenttime); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); while(tmpptr!=NULL){ // // ETHPROTO (VCLASS_0) // bzero(ptok,256); if(tmpptr->h_proto_l==tmpptr->h_proto_h){ sprintf(ptok,"%d",tmpptr->h_proto_l); }else{ sprintf(ptok,"%d-%d",tmpptr->h_proto_l,tmpptr->h_proto_h); } if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_0))!=NULL){ bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); }else if(tmpptr->h_proto_l==0 && tmpptr->h_proto_h==0xFFFF ){ bzero(ptok,256); strncpy(ptok,"any",sizeof(char)*strlen("any")); } sprintf(LOG,"%s ",ptok); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); // // SOURCE IP (VCLASS_1) // bzero(ptok,256); sprintf(ptok,"%s",inet_ntoa(*(struct in_addr*) &tmpptr->s_ip)); if(tmpptr->s_mask!=0xFFFFFFFF){ tmpint = htonl(tmpptr->s_mask); cidr=bits=0; while((tmpint&0xC0000000)!=0x40000000){ bits++; if((tmpint&0xC0000000)!=0xC0000000){ cidr=bits; break; } tmpint<<=1; } if(htonl(tmpptr->s_mask)==(u_int32_t)(0xFFFFFFFF<<(32-cidr))){ sprintf(ptok,"%s/%d",ptok,cidr); }else{ sprintf(ptok,"%s/%s",ptok,inet_ntoa(*(struct in_addr*) &tmpptr->s_mask)); } } if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_1))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); }else if(tmpptr->s_ip==0){ bzero(ptok,256); strncpy(ptok,"any",sizeof(char)*strlen("any")); } sprintf(LOG,"%s ",ptok); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); // // DESTINATION IP (VCLASS_1) // bzero(ptok,256); sprintf(ptok,"%s",inet_ntoa(*(struct in_addr*) &tmpptr->d_ip)); if(tmpptr->d_mask!=0xFFFFFFFF){ tmpint = htonl(tmpptr->d_mask); cidr=bits=0; while((tmpint&0xC0000000)!=0x40000000){ bits++; if((tmpint&0xC0000000)!=0xC0000000){ cidr=bits; break; } tmpint<<=1; } if(htonl(tmpptr->d_mask)==(u_int32_t)(0xFFFFFFFF<<(32-cidr))){ sprintf(ptok,"%s/%d",ptok,cidr); }else{ sprintf(ptok,"%s/%s",ptok,inet_ntoa(*(struct in_addr*) &tmpptr->d_mask)); } } if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_1))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); }else if(tmpptr->d_ip==0){ bzero(ptok,256); strncpy(ptok,"any",sizeof(char)*strlen("any")); } sprintf(LOG,"%s ",ptok); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); // // IPPROTO (VCLASS_2) // bzero(ptok,256); sprintf(ptok,"%d",tmpptr->proto_l); if(tmpptr->proto_l!=tmpptr->proto_h){ sprintf(ptok,"%s-%d",ptok,tmpptr->proto_h); } if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_2))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); }else if(tmpptr->proto_l==0x00 && tmpptr->proto_h==0xFF){ bzero(ptok,256); strncpy(ptok,"any",sizeof(char)*strlen("any")); } sprintf(LOG,"%s ",ptok); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); // // Source TCP_UDP_PORT (VCLASS_3) // bzero(ptok,256); sprintf(ptok,"%d",tmpptr->s_port_l); if(tmpptr->s_port_l!=tmpptr->s_port_h){ sprintf(ptok,"%s-%d",ptok,tmpptr->s_port_h); } if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_2))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); }else if(tmpptr->s_port_l==0 && tmpptr->s_port_h==0xFFFF){ bzero(ptok,256); strncpy(ptok,"any",sizeof(char)*strlen("any")); } sprintf(LOG,"%s ",ptok); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); // // Destination TCP_UDP_PORT (VCLASS_3) // bzero(ptok,256); sprintf(ptok,"%d",tmpptr->d_port_l); if(tmpptr->d_port_l!=tmpptr->d_port_h){ sprintf(ptok,"%s-%d",ptok,tmpptr->d_port_h); } if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_2))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); }else if(tmpptr->d_port_l==0 && tmpptr->d_port_h==0xFFFF){ bzero(ptok,256); strncpy(ptok,"any",sizeof(char)*strlen("any")); } sprintf(LOG,"%s",ptok); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); // // Logging options // if(!tmpptr->stats && !tmpptr->realtime && !tmpptr->pcap){ // no logging options are enabled strcat(LOG,", ignore"); }else{ // // Only display logging actions that differ from the default logging actions // // // STATS // if(tmpptr->stats!=gVars.smode){ strcat(LOG,", stats"); if(tmpptr->smode==OMODE_PASS) strcat(LOG,"=pass"); else if(tmpptr->smode==OMODE_LOG) strcat(LOG,"=log"); } // // REALTIME // if(tmpptr->realtime!=gVars.rmode){ strcat(LOG,", realtime"); if(tmpptr->rmode==OMODE_PASS) strcat(LOG,"=pass"); else if(tmpptr->rmode==OMODE_LOG) strcat(LOG,"=log"); } // // PCAP // if(tmpptr->pmode!=gVars.pmode){ strcat(LOG,", pcap"); if(tmpptr->pmode==OMODE_PASS) strcat(LOG,"=pass"); else if(tmpptr->pmode==OMODE_LOG) strcat(LOG,"=log"); else if(tmpptr->pmode==OMODE_RULE) strcat(LOG,"=rule"); else if(tmpptr->pmode==OMODE_UNIQ) strcat(LOG,"=connection"); else if(tmpptr->pmode==OMODE_FILENAME && gVars.pfH->getFileHandle()!=tmpptr->fH->getFileHandle()) sprintf(LOG,"%s filename=%s",LOG,tmpptr->fH->getFileName()); else if(tmpptr->pmode==OMODE_TSFILENAME) sprintf(LOG,"%s tsfilename=%s",LOG,tmpptr->fH->getFileName()); } // // Half-stream direction collection flag // if(tmpptr->cmode==CMODE_SRC) strcat(LOG,", logsrc"); if(tmpptr->cmode==CMODE_DST) strcat(LOG,", logdst"); } // // REMAINING OPTIONS // // LIMIT if(tmpptr->limit!=gVars.default_limit) sprintf(LOG,"%s, limit=%llu",LOG,(long long unsigned)tmpptr->limit); // TIMEOUT if(tmpptr->timeout!=gVars.default_timeout) sprintf(LOG,"%s, timeout=%d",LOG,tmpptr->timeout); // TCPLAG if(tmpptr->tcplag!=gVars.default_tcplag) sprintf(LOG,"%s, tcplag=%d",LOG,tmpptr->tcplag); // RID VCLASS_4 if(tmpptr->rid) { bzero(ptok,256); sprintf(ptok,"%u",tmpptr->rid); if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_4))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); } sprintf(LOG,"%s, rid=%s",LOG,ptok); } // RGID VCLASS_5 if(tmpptr->rgid) { bzero(ptok,256); sprintf(ptok,"%u",tmpptr->rgid); if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_5))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); } sprintf(LOG,"%s, rgid=%s",LOG,ptok); } // ZONE VCLASS_6 if(tmpptr->zone) { bzero(ptok,256); sprintf(ptok,"%u",tmpptr->zone); if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_6))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); } sprintf(LOG,"%s, zone=%s",LOG,ptok); } // NODE VCLASS_7 if(tmpptr->node) { bzero(ptok,256); sprintf(ptok,"%u",tmpptr->node); if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_7))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); } sprintf(LOG,"%s, node=%s",LOG,ptok); } // STATUS VCLASS_8 if(tmpptr->status!=gVars.default_status) { bzero(ptok,256); sprintf(ptok,"%u",tmpptr->status); if((tmp=rev_search_vars(ptok,gVars.var_head,VCLASS_8))!=NULL) { bzero(ptok,256); strncpy(ptok,tmp,sizeof(char)*strlen(tmp)); } sprintf(LOG,"%s, status=%s",LOG,ptok); } // RETRO if(tmpptr->retro) strcat(LOG,", retro"); // DEFAULT RULE MATCHES sprintf(LOG,"%s # Matches: %d\n",LOG,tmpptr->ctr); tmpptr=tmpptr->next; LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); } sprintf(LOG,"# Implicit rule matches: %d\n",gVars.default_ctr); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); if(gVars.username || gVars.groupname){ sprintf(LOG,"# Running as: %s:%s\n",gVars.username,gVars.groupname); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); } if(gVars.config_file){ sprintf(LOG,"# Configuration file: %s \n",gVars.config_file?gVars.config_file:"CWD"); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); } if(gVars.log_directory){ sprintf(LOG,"# Output directory: %s \n",gVars.log_directory); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); } if(gVars.input_filename){ sprintf(LOG,"# Reading from file: %s \n",gVars.input_filename); LOG[1023]='\0'; gVars.sdF->write(LOG,strlen(LOG)); bzero(LOG,1024); } } void license() { fprintf(stdout,"\n -- Released under the QPL LICENSE --\n \n Copyright (C) 2003 John Curry \n \n No Warranty Expressed or Implied\n "); } void version() { fprintf(stdout,"SA Network Connection Profiler v %s\n",VERSION); } void set_bpf_filter(char *argv) { extern struct gvars gVars; long len; if(gVars.bpf_fname){ free(gVars.bpf_fname); } gVars.bpf_fname=(char *) calloc(1,strlen(argv)+1); strncpy(gVars.bpf_fname,argv,strlen(argv)); if(gVars.bfH){ gVars.bfH->destroy(); gVars.bfH=0; } gVars.bfH = new fileHandle(gVars.bpf_fname); gVars.bfH->setMode(READ_MODE); gVars.bfH->seek(0,SEEK_END); len=gVars.bfH->tell(); if(gVars.bpf_filter){ free(gVars.bpf_filter); } if((gVars.bpf_filter = (char *) calloc(1,len+1))==NULL) { #ifdef DEBUG syslog(LOG_CRIT,"Out of memory - bpf filter too big?\n"); return; #endif } gVars.bfH->seek(0,0); gVars.bfH->close(); gVars.bfH->setMode(READ_MODE); if(gVars.bfH->read(gVars.bpf_filter,len)==-1) { switch (errno){ case EINTR: syslog(LOG_ERR,"Error reading bpf filter: EINTR\n"); break; case EAGAIN: syslog(LOG_ERR,"Error reading bpf filter: EAGAIN\n"); break; case EIO: syslog(LOG_ERR,"Error reading bpf filter: EIO\n"); break; case EISDIR: syslog(LOG_ERR,"Error reading bpf filter: EISDIR\n"); break; case EBADF: syslog(LOG_ERR,"Error reading bpf filter: EBADF\n"); break; case EINVAL: syslog(LOG_ERR,"Error reading bpf filter: EINVAL\n"); break; case EFAULT: syslog(LOG_ERR,"Error reading bpf filter: EFAULT\n"); break; } } if(gVars.bpf_filter[len-1]=='\n') gVars.bpf_filter[len-1]=0; /* We'll get rid of bpF here - close_files() * is not a good place for this right now * cause it gets called by reload_config() * and that may be confusing, until we can apply * new bpf filters -after- start-up */ if(gVars.bfH){ gVars.bfH->destroy(); gVars.bfH=NULL; } }