# --- SDE-COPYRIGHT-NOTE-BEGIN --- # This copyright note is auto-generated by ./scripts/Create-CopyPatch. # # Filename: package/.../sancp/sancp-1.6.1-stable-prelude-3.diff # Copyright (C) 2007 The OpenSDE Project # # More information can be found in the files COPYING and README. # # This patch file is dual-licensed. It is available under the license the # patched project is licensed under, as long as it is an OpenSource license # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms # of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # --- SDE-COPYRIGHT-NOTE-END --- diff -ruN sancp-1.6.1-stable.vanilla/Makefile sancp-1.6.1-stable/Makefile --- sancp-1.6.1-stable.vanilla/Makefile 2007-07-07 00:46:11.000000000 +0200 +++ sancp-1.6.1-stable/Makefile 2007-07-24 13:44:01.000000000 +0200 @@ -9,7 +9,7 @@ # LINUX and BSD CFLAGS -CFLAGS = -O3 -I/usr/include/pcap -I/usr/local/include/pcap -I./ -L/usr/lib/libsocket.so -g -L/opt/csw/lib -ggdb +CFLAGS = -g -O3 -I/usr/include/pcap -I/usr/local/include/pcap -I./ -L/usr/lib/libsocket.so -g -L/opt/csw/lib -ggdb `libprelude-config --cflags` # LINUX LFLAGS LFLAGS = -lresolv -lnsl -lpcap -L/usr/lib/libpcap.so.0.6.2 @@ -41,10 +41,10 @@ bsd : @(echo "#define PLATFORM_BSD" > platform.h) @make final - g++ -Wall $(BFLAGS) $(CFLAGS) -o sancp sancp.o misc_functs.o check_packet.o statefull_logging.o build_acl.o apply_rule.o decode.o pcap_functions.o pcapFileHandle.o fileHandle.o MemoryPool.o permissions.o outputFileHandle.o help.o + g++ -Wall $(BFLAGS) $(CFLAGS) -o sancp sancp.o misc_functs.o check_packet.o statefull_logging.o build_acl.o apply_rule.o decode.o pcap_functions.o pcapFileHandle.o fileHandle.o MemoryPool.o permissions.o outputFileHandle.o help.o `libprelude-config --libs` `libprelude-config --ldflags` linux : @(echo "#define PLATFORM_LINUX" > platform.h) @make final - g++ -Wall $(LFLAGS) $(CFLAGS) -o sancp sancp.o misc_functs.o check_packet.o statefull_logging.o build_acl.o apply_rule.o decode.o pcap_functions.o pcapFileHandle.o fileHandle.o MemoryPool.o permissions.o outputFileHandle.o help.o + g++ -Wall $(LFLAGS) $(CFLAGS) -o sancp sancp.o misc_functs.o check_packet.o statefull_logging.o build_acl.o apply_rule.o decode.o pcap_functions.o pcapFileHandle.o fileHandle.o MemoryPool.o permissions.o outputFileHandle.o help.o `libprelude-config --libs` `libprelude-config --ldflags` diff -ruN sancp-1.6.1-stable.vanilla/apply_rule.cc sancp-1.6.1-stable/apply_rule.cc --- sancp-1.6.1-stable.vanilla/apply_rule.cc 2007-07-05 18:12:20.000000000 +0200 +++ sancp-1.6.1-stable/apply_rule.cc 2007-07-24 13:44:01.000000000 +0200 @@ -47,6 +47,12 @@ tc->tcplag=myacl->tcplag; tc->status=myacl->status; tc->rid=myacl->rid; + tc->prelude_impact_severity=myacl->prelude_impact_severity; + tc->prelude_impact_completion=myacl->prelude_impact_completion; + tc->prelude_impact_type=myacl->prelude_impact_type; + tc->prelude_confidence_rating=myacl->prelude_confidence_rating; + + if(myacl->pmode==OMODE_UNIQ) { @@ -112,6 +118,10 @@ nc->rgid=myacl->rgid; nc->zone=myacl->zone; nc->node=myacl->node; + nc->prelude_impact_severity=myacl->prelude_impact_severity; + nc->prelude_impact_completion=myacl->prelude_impact_completion; + nc->prelude_impact_type=myacl->prelude_impact_type; + nc->prelude_confidence_rating=myacl->prelude_confidence_rating; myacl->ctr++; return; } @@ -130,6 +140,10 @@ nc->timeout=gVars.default_timeout; nc->tcplag=gVars.default_tcplag; nc->node=gVars.default_node; + nc->prelude_impact_severity=gVars.prelude_impact_severity; + nc->prelude_impact_completion=gVars.prelude_impact_completion; + nc->prelude_impact_type=gVars.prelude_impact_type; + nc->prelude_confidence_rating=gVars.prelude_confidence_rating; gVars.default_ctr++; #ifdef DEBUG printf("Setting stats: %d pcap: %d realtime: %d limit: %d timeout: %d tcplag: %d\n", nc->stats, nc->pcap, nc->realtime, nc->limit, nc->timeout, nc->tcplag); diff -ruN sancp-1.6.1-stable.vanilla/build_acl.cc sancp-1.6.1-stable/build_acl.cc --- sancp-1.6.1-stable.vanilla/build_acl.cc 2007-07-05 18:12:20.000000000 +0200 +++ sancp-1.6.1-stable/build_acl.cc 2007-07-24 13:44:01.000000000 +0200 @@ -1168,6 +1168,62 @@ fprintf(stdout,"Didn't set default for %s to %s\n",tok,tmp); #endif } + if(strcmp(tok,"prelude_impact_severity")==0) + { + if((tmp = get_tok(&rules,accept))==NULL) + { + syslog(LOG_ERR,"Format error, prelude_impact_severity specified but none provided, using prelude_impact_severity %s\n",PRELUDE_IMPACT_SEVERITY); + free(rule); + return; + } + gVars.prelude_impact_severity = strdup(tmp); + free(rule); + } + if(strcmp(tok,"prelude_impact_completion")==0) + { + if((tmp = get_tok(&rules,accept))==NULL) + { + syslog(LOG_ERR,"Format error, prelude_impact_completion specified but none provided, using prelude_impact_completion %s\n",PRELUDE_IMPACT_COMPLETION); + free(rule); + return; + } + gVars.prelude_impact_completion = strdup(tmp); + free(rule); + } + if(strcmp(tok,"prelude_impact_type")==0) + { + if((tmp = get_tok(&rules,accept))==NULL) + { + syslog(LOG_ERR,"Format error, prelude_impact_type specified but none provided, using prelude_impact_type %s\n",PRELUDE_IMPACT_TYPE); + free(rule); + return; + } + gVars.prelude_impact_type = strdup(tmp); + free(rule); + } + if(strcmp(tok,"prelude_confidence_rating")==0) + { + if((tmp = get_tok(&rules,accept))==NULL) + { + syslog(LOG_ERR,"Format error, prelude_confidence_rating specified but none provided, using prelude_confidence_rating %s\n",PRELUDE_CONFIDENCE_RATING); + free(rule); + return; + } + gVars.prelude_confidence_rating = strdup(tmp); + free(rule); + } + if(strcmp(tok,"prelude_profile")==0) + { + if((tmp = get_tok(&rules,accept))==NULL) + { + syslog(LOG_ERR,"Format error, prelude_profile specified but none provided, using prelude_profile %s\n",PRELUDE_PROFILE); + free(rule); + return; + } + gVars.prelude_profile = strdup(tmp); + free(rule); + } + } void parse_var(char *c_rule, char *accept) @@ -1426,6 +1482,10 @@ }else{ n_acl->fH = 0; } + n_acl->prelude_impact_severity = gVars.prelude_impact_severity; + n_acl->prelude_impact_completion = gVars.prelude_impact_completion; + n_acl->prelude_impact_type = gVars.prelude_impact_type; + n_acl->prelude_confidence_rating = gVars.prelude_confidence_rating; // FIELD 0 - required - Get the h_proto n_acl->h_proto_h = 0xFFFF; @@ -2061,6 +2121,46 @@ n_acl->retro = true; continue; } + if(strcmp(tok,"severity")==0) + { + if((tmp = get_tok(rules,accept))==NULL) + { + syslog(LOG_ERR,"Format error, severity specified but no option provided%s\n",rule); + return; + } + n_acl->prelude_impact_severity = strdup(tmp); + continue; + } + if(strcmp(tok,"completion")==0) + { + if((tmp = get_tok(rules,accept))==NULL) + { + syslog(LOG_ERR,"Format error, completion specified but no option provided%s\n",rule); + return; + } + n_acl->prelude_impact_completion = strdup(tmp); + continue; + } + if(strcmp(tok,"type")==0) + { + if((tmp = get_tok(rules,accept))==NULL) + { + syslog(LOG_ERR,"Format error, type specified but no option provided%s\n",rule); + return; + } + n_acl->prelude_impact_type = strdup(tmp); + continue; + } + if(strcmp(tok,"confidence")==0) + { + if((tmp = get_tok(rules,accept))==NULL) + { + syslog(LOG_ERR,"Format error, confidence specified but no option provided%s\n",rule); + return; + } + n_acl->prelude_confidence_rating = strdup(tmp); + continue; + } syslog(LOG_ERR,"Skipping, invalid option in rule: %s %s\n", tok,*rules); return; } diff -ruN sancp-1.6.1-stable.vanilla/build_acl.cc~ sancp-1.6.1-stable/build_acl.cc~ --- sancp-1.6.1-stable.vanilla/build_acl.cc~ 1970-01-01 01:00:00.000000000 +0100 +++ sancp-1.6.1-stable/build_acl.cc~ 2007-07-05 18:12:20.000000000 +0200 @@ -0,0 +1,2648 @@ +#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; + } + +} diff -ruN sancp-1.6.1-stable.vanilla/docs/README sancp-1.6.1-stable/docs/README --- sancp-1.6.1-stable.vanilla/docs/README 2007-07-06 03:33:14.000000000 +0200 +++ sancp-1.6.1-stable/docs/README 2007-07-24 13:44:01.000000000 +0200 @@ -277,6 +277,10 @@ strip-80211 { disable|enable } node debug_pcap_raw { disable|enable } + prelude_impact_severity [string] + prelude_impact_completion [string] + prelude_impact_type [string] + prelude_confidence_rating [string] known_port syntax: -----------------------: @@ -310,6 +314,9 @@ b) tagging options i.e. status=16 rid=1112 node=2 + c) prelude options + i.e. severity=severe, completion=succeeded, type=other, confidence=high + [[-] [|}>] [|}>] [{tcp|udp|icmp|[-] }] [{-[]}] [{-[]}] { ignore | stats [{log|pass}] | realtime [{log|pass}] | diff -ruN sancp-1.6.1-stable.vanilla/gvars.h sancp-1.6.1-stable/gvars.h --- sancp-1.6.1-stable.vanilla/gvars.h 2007-07-05 18:12:20.000000000 +0200 +++ sancp-1.6.1-stable/gvars.h 2007-07-24 13:44:01.000000000 +0200 @@ -17,7 +17,8 @@ /* Make certain all id's are represented in the same order (as strings) in fmtnames[] */ /* 'null' is a place holder - in the list for field 0 */ -enum id {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 }; +enum id +{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,prelude_impact_sevirty,prelude_impact_completion,prelude_impact_type,prelude_confidence_rating,prelude_profile }; struct cnx_queue { struct cnx *head; @@ -102,5 +103,10 @@ int stdout_fmt_len; pcap_t *ph; // pcap handle struct pcap_pkthdr *g_pkthdr;// + char *prelude_impact_severity; + char *prelude_impact_completion; + char *prelude_impact_type; + char *prelude_confidence_rating; + char *prelude_profile; }; diff -ruN sancp-1.6.1-stable.vanilla/sancp.cc sancp-1.6.1-stable/sancp.cc --- sancp-1.6.1-stable.vanilla/sancp.cc 2007-07-05 18:12:20.000000000 +0200 +++ sancp-1.6.1-stable/sancp.cc 2007-07-24 13:44:01.000000000 +0200 @@ -48,7 +48,40 @@ //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 }; +prelude_client_t *client; +static idmef_analyzer_t *idmef_analyzer; +int sancp_alert_init(prelude_client_t *client) +{ + int ret; + prelude_string_t *string; + + idmef_analyzer = prelude_client_get_analyzer(client); + if ( ! idmef_analyzer ) + return -1; + + ret = idmef_analyzer_new_model(idmef_analyzer, &string); + if ( ret < 0 ) + return -1; + prelude_string_set_constant(string, PRELUDE_ANALYZER_MODEL); + + ret = idmef_analyzer_new_class(idmef_analyzer, &string); + if ( ret < 0 ) + return -1; + prelude_string_set_constant(string, PRELUDE_ANALYZER_CLASS); + + ret = idmef_analyzer_new_manufacturer(idmef_analyzer, &string); + if ( ret < 0 ) + return -1; + prelude_string_set_constant(string, PRELUDE_ANALYZER_MANUFACTURER); + + ret = idmef_analyzer_new_version(idmef_analyzer, &string); + if ( ret < 0 ) + return -1; + prelude_string_set_constant(string, VERSION); + + return 0; +} /************* * Main * *************/ @@ -56,6 +89,7 @@ int main(int argc, char *argv[]) { extern struct gvars gVars; int cKey; + int ret; pid_t pid=0; /* @@ -102,6 +136,14 @@ gVars.stdout_delimiter=DEFAULT_DELIMITER; gVars.stdout_eor=DEFAULT_EOR; + gVars.prelude_impact_severity=PRELUDE_IMPACT_SEVERITY; + gVars.prelude_impact_completion=PRELUDE_IMPACT_COMPLETION; + gVars.prelude_impact_type=PRELUDE_IMPACT_TYPE; + gVars.prelude_confidence_rating=PRELUDE_CONFIDENCE_RATING; + gVars.prelude_profile=PRELUDE_PROFILE; + + + for(cKey=0; cKey +#include +#include + #define NCP_H #define Y 'Y' #define N 'N' @@ -79,6 +83,7 @@ struct vars *next; }; +extern prelude_client_t *client; int main(int argc, char *argv[]); struct cnx *process(struct cnx*, int len, u_char * pkt); char * createPcapFileName(); @@ -185,6 +190,15 @@ #define OMODE_RULE 5 #define OMODE_UNIQ 6 +#define PRELUDE_IMPACT_SEVERITY "medium" +#define PRELUDE_IMPACT_COMPLETION "succeeded" +#define PRELUDE_IMPACT_TYPE "other" +#define PRELUDE_CONFIDENCE_RATING "high" +#define PRELUDE_ANALYZER_MODEL "Sancp" +#define PRELUDE_ANALYZER_CLASS "NIDS" +#define PRELUDE_ANALYZER_MANUFACTURER "http://www.metre.net/sancp.html" +#define PRELUDE_PROFILE "sancp" + // Need to distinguish between classes of variables #define VCLASS_0 1 // eth_proto class vars #define VCLASS_1 2 // ip_addr class vars @@ -276,6 +290,10 @@ u_int16_t rgid; u_int16_t node; u_int16_t zone; + char *prelude_impact_severity; + char *prelude_impact_completion; + char *prelude_impact_type; + char *prelude_confidence_rating; CBuffer *CBufferPtr; struct acl *next; }; @@ -314,6 +332,10 @@ u_int16_t rgid; u_int16_t node; u_int16_t zone; + char *prelude_impact_severity; + char *prelude_impact_completion; + char *prelude_impact_type; + char *prelude_confidence_rating; CBuffer *CBufferPtr; struct os_info os_info; struct os_info os_info2; diff -ruN sancp-1.6.1-stable.vanilla/sancp.h~ sancp-1.6.1-stable/sancp.h~ --- sancp-1.6.1-stable.vanilla/sancp.h~ 1970-01-01 01:00:00.000000000 +0100 +++ sancp-1.6.1-stable/sancp.h~ 2007-07-06 06:18:04.000000000 +0200 @@ -0,0 +1,327 @@ +/************************************************************************** + **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. + * * + * ***********************************************************************/ + +#define SANCP_H + + +//#define DEBUG 1 + +#include // set_signals(), SIGHUP, signal, SIGUSR1, SIGUSR2, SIGTERM, SIGINT, SIGKILL, SIGQUIT +#include // inet_aton(), inet_ntoa() +#include // errno, EINTR, EAGAIN, EIO, EISDIR, EBADF, EINVAL, EFAULT +#include // LOG_ERR, LOG_CONS, LOG_INFO, LOG_CRIT + // LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7 + +#include +#include +//#include + +//#include +//#include +//#include + +// Required for BSD +#include + +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +#ifndef GVARS_H +#include "gvars.h" +#endif + +#define NCP_H +#define Y 'Y' +#define N 'N' +#define MIN_WAIT_TIME 4 // We will wait at least this many seconds before expiring a closed connection + +// Include our own version of ether_addr since linux/solaris +// differ from bsd systems on definition of struct ether_addr + +#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ + +struct myether_addr { + u_char octet[ETHER_ADDR_LEN]; +}; + +/* + * Structure of a 10Mb/s Ethernet header. + */ +struct ether_header { // we pulled this from net/ethernet.h + u_char ether_dhost[ETHER_ADDR_LEN]; + u_char ether_shost[ETHER_ADDR_LEN]; + u_short ether_type; +}; + + + +struct vars { + char *key; + char *value; + int vclass; // variable class + struct vars *next; +}; + +int main(int argc, char *argv[]); +struct cnx *process(struct cnx*, int len, u_char * pkt); +char * createPcapFileName(); +char * createFileName(const char* filename); +char * createFileName(const char* filename, bool); +char * createPcapFileName(const struct acl* tacl); +char * createPcapFileName(const struct cnx* tcnx); +extern "C" pcap_t * open_pcap_live(char *,char *); +extern "C" pcap_t * open_pcap_file(char *,char *); +extern "C" void close_pcap_file(pcap_t *); +extern "C" void start_pcap_loop(pcap_t *); +extern "C" void print_linktype(pcap_t *); +void erase_idle(int a); +void reopen_files(int a); +void expire_connections(); +struct cnx *update_state_node(struct cnx *); +void build_config(int a); +void parse_args(int arg, char* argv[]); +void parse_format(const char *,const char *); +void print_acl(int a); +void print_stats(int a); +void print_output_schema(outputFileHandle *fH, char *fmtcols, int fmtlen); +void write_schema(char *name, char *fmt, int fmtlen); +void print_schemas(); +int fgetcline(char **buf, int size, FILE *fp); +int promisc_mode(char *, int); +void close_files(int a); +void open_files(); +void reload_config(int a); +void record_all(int a); +void free_all(int a); +void exit_all(int a); +void manage_cid(int a); + +void record(struct cnx *, outputFileHandle *fH); +void set_signals(); +void decode(struct cnx*, int len, const u_char * pkt); +void decode_pcap(struct cnx*,struct pcap_pkthdr * pkthdr, u_char * pkt); +int CheckPort(u_int8_t proto,u_int16_t port); +void SChangeUserGroup(); +void apply_rule(struct cnx*); +void parse_var(char *,char *); +void parse_known_ports(char *, struct vars*, char *); +void parse_connection_rule(char *, struct vars*, char *); +void open_pcap_output(); + +/* Hash Table Protos */ +#define DEFAULT_FLUSH_INTERVAL 1800 +#define DEFAULT_EXPIRE_INTERVAL 10 +#define VERSION "1.6.1-stable" +#define NAME "sancp" +#define LOG_DIR "./" /* default relative to current working directory */ +#define CONFIG_DIR "/etc/sancp/" +#define CONFIG_FILE "sancp.conf" +#define PCAP_RAW_FNAME "debug_pcap_raw" +#define PCAP_FNAME "pcap" +#define STATS_FNAME "stats" +#define REALTIME_FNAME "realtime" +#define true 1 +#define false 0 +#define PROMISC 1 +#define MAX_VAR 256 +#define MAXFLDS 85 // define number of elements in fmtnames[] +#define MAXFLDSIZE 19 // define largest element in fmtnames[MAXFLDS][MAXFLDLEN] +#define MAXENTRYLEN 256 +#define DELIMITER '|' +#define READ_TIMEOUT 500 +#define ETHPROTO_IP 0x0008 +// network order bytes 0x0806 +#define ETHPROTO_ARP 0x0608 +// network order bytes 0x8035 +#define ETHPROTO_RARP 0x3580 +// network order bytes 0x8100 +#define ETHPROTO_8021Q 0x0081 +#define DEFAULT_DEVICE "any" +#define DEFAULT_NODE 0 +#define DEFAULT_LIMIT 0 +#define DEFAULT_RID 0 +#define DEFAULT_RGID 0 +#define DEFAULT_ZONE 0 +//#define TCP_TIMEOUT 120 +//#define UDP_TIMEOUT 300 +//#define ICMP_TIMEOUT 120 +#define DEFAULT_TIMEOUT 300 +#define DEFAULT_STATUS 0 +#define DEFAULT_LAG 0 +#define DEFAULT_DELIMITER '|' +#define DEFAULT_EOR '\n' +#define MAX_PORTS 65536 +#define FROM_INITIATOR 0 +#define FROM_TARGET 1 +#define ACTION_PASS 0 +#define ACTION_LOG 1 +#define ACTION_DEFAULT 2 +#define CMODE_NONE 0 +#define CMODE_BOTH 1 +#define CMODE_SRC 2 +#define CMODE_DST 3 +#define OMODE_PASS 0 +#define OMODE_LOG 1 +#define OMODE_DEFAULT 2 +#define OMODE_FILENAME 3 +#define OMODE_TSFILENAME 4 +#define OMODE_RULE 5 +#define OMODE_UNIQ 6 + +// Need to distinguish between classes of variables +#define VCLASS_0 1 // eth_proto class vars +#define VCLASS_1 2 // ip_addr class vars +#define VCLASS_2 3 // ip_proto class vars +#define VCLASS_3 4 // port class vars +#define VCLASS_4 5 // rid class vars +#define VCLASS_5 6 // rgid class vars +#define VCLASS_6 7 // zone class vars +#define VCLASS_7 8 // node class vars +#define VCLASS_8 9 // status class vars + +#define DISABLED 0 +#define ENABLED 1 +#define CNX_REVERSED 1 +#define CNX_BOTH_PORTS_KNOWN 2 +#define CNX_BOTH_PORTS_UNKNOWN 3 +#define CNX_REREVERSED 4 +#define MAX_PACK_LEN 20000 /* Sufficient for ethernet packets. */ +#define ETHER_SIZE 14 +#ifdef EXPERIMENTAL_TCPOPTIONS +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOPT_SACKOK 4 /* Experimental */ +#define TCPOPT_WSCALE 3 +#define TCPOPTIONS_MAX 8 /* Maximum number of tcpoptions to parse */ +#endif + + +#define R_FIN 0x01 +#define R_SYN 0x02 +#define R_RST 0x04 +#define R_PSH 0x08 +#define R_ACK 0x10 +#define R_URG 0x20 +#define R_RES2 0x40 +#define R_RES1 0x80 +#define max(i,j) (((i)>(j)) ? (i) : (j)) +#define SIZE_OF_CLASS_C 11 + +struct t_ports { + u_int16_t l_port; + u_int16_t h_port; + struct t_ports *next; +}; + + +struct os_info { + u_int8_t ttl; + u_int16_t len; + u_int16_t wss; +#ifdef EXPERIMENTAL_TCPOPTIONS + u_int8_t df:1, nop:1, sack_ok:1; + u_int16_t mss; + short wscale; +#else + u_int8_t df:1; +#endif + +}; + + +struct acl { + struct ether_header eth_hdr; + u_int16_t h_proto_h; + u_int16_t h_proto_l; + u_int32_t s_ip; + u_int32_t s_mask; + u_int16_t s_port_l; + u_int16_t s_port_h; + u_int32_t d_ip; + u_int32_t d_mask; + u_int16_t d_port_l; + u_int16_t d_port_h; + u_int8_t proto_l; + u_int8_t proto_h; + u_int32_t offset; + u_int32_t mask; + u_int32_t value; + pcapFileHandle * fH; + u_int8_t stats:1, realtime:1, pcap:1, retro:1, smode:2, rmode:2; + u_int8_t cmode:2, pmode:4; + u_int16_t tcplag; + u_int16_t timeout; + u_int64_t limit; + u_int16_t status; + u_int32_t ctr; + u_int32_t rid; + u_int16_t rgid; + u_int16_t node; + u_int16_t zone; + CBuffer *CBufferPtr; + struct acl *next; +}; + +void retroactive(struct acl*); + +struct cnx { + struct ether_header eth_hdr; + u_int16_t h_proto; + u_int8_t proto; + u_int32_t s_ip; + u_int32_t d_ip; + u_int16_t s_port; + u_int16_t d_port; + u_int64_t s_total_pkts; + u_int64_t s_total_bytes; + u_int64_t d_total_pkts; + u_int64_t d_total_bytes; + u_int64_t total_bytes; + time_t start_time; + time_t last_pkt; + u_int8_t free:1,direction:1; + pcapFileHandle *fH; + u_int8_t cmode:4, pcap:1, realtime:1, stats:1, retro:1; + u_int8_t tcpFlags[2]; + u_int8_t tcpCFlags; + u_int8_t reversed; + u_int16_t tcplag; + u_int64_t limit; + u_int16_t status; + u_int64_t collected; + u_int64_t cid; + u_int16_t timeout; + u_int16_t hash; + u_int32_t rid; + u_int16_t rgid; + u_int16_t node; + u_int16_t zone; + CBuffer *CBufferPtr; + struct os_info os_info; + struct os_info os_info2; + struct cnx *next; + struct cnx *prev; +}; + + +void usage(); +void outputfields(); +void rule_syntax(); diff -ruN sancp-1.6.1-stable.vanilla/statefull_logging.cc sancp-1.6.1-stable/statefull_logging.cc --- sancp-1.6.1-stable.vanilla/statefull_logging.cc 2007-07-05 18:12:20.000000000 +0200 +++ sancp-1.6.1-stable/statefull_logging.cc 2007-07-24 13:44:01.000000000 +0200 @@ -183,6 +183,208 @@ snprintf(buf,len,"%s",currenttime); } +static int add_idmef_object(idmef_message_t *message, const char *object, const char *value) +{ + int ret; + idmef_value_t *val; + idmef_path_t *path; + + ret = idmef_path_new(&path, object); + if ( ret < 0 ) + return -1; + + ret = idmef_value_new_from_path(&val, path, value); + if ( ret < 0 ) { + idmef_path_destroy(path); + return -1; + } + + ret = idmef_path_set(path, message, val); + + idmef_value_destroy(val); + idmef_path_destroy(path); + + return ret; +} + +#define IDMEF(x) { \ + int ret = (x); \ + if (ret < 0) { idmef_message_destroy(idmef); printf("error\n"); return; } \ + } + +void record_prelude(struct cnx *cn) { + char LOG[MAXENTRYLEN]; + + idmef_message_t *idmef; + idmef_alert_t *alert; + idmef_time_t *time; + + struct servent *sourceservent; + struct protoent *protoent; + + IDMEF(idmef_message_new(&idmef)); + IDMEF(idmef_message_new_alert(idmef, &alert)); + + /* alert.detecttime */ + if (cn->start_time) { + IDMEF(idmef_time_new_from_time(&time, &cn->start_time)); + } else { + /* using the curen time */ + IDMEF(idmef_time_new_from_gettimeofday(&time)); + } + idmef_alert_set_detect_time(alert, time); + + /* alert.createtime */ + time = NULL; + IDMEF(idmef_time_new_from_gettimeofday(&time)); + idmef_alert_set_create_time(alert, time); + + /* alert.analyzer */ + idmef_alert_set_analyzer(alert,idmef_analyzer_ref(prelude_client_get_analyzer(client)),0); + + /* alert.classification.text */ + add_idmef_object(idmef, "alert.classification.text", + "Unauthorized network connectivity"); + + /* alert.messageid */ + snprintf(LOG,MAXENTRYLEN,"%lld",cn->cid); + add_idmef_object(idmef, "alert.messageid", LOG); + + /* alert.impact.severity */ + add_idmef_object(idmef, "alert.assessment.impact.severity", + cn->prelude_impact_severity); + + /* alert.impact.completion */ + add_idmef_object(idmef, "alert.assessment.impact.completion", + cn->prelude_impact_completion); + + /* alert.impact.type */ + add_idmef_object(idmef, "alert.assessment.impact.type", + cn->prelude_impact_type); + + /* alert.confidence.rating */ + add_idmef_object(idmef, "alert.assessment.confidence.rating", + cn->prelude_confidence_rating); + + /* alert.additionaldata(0) */ + add_idmef_object(idmef, "alert.additionaldata(0).type", "integer"); + add_idmef_object(idmef, "alert.additionaldata(0).meaning", "status"); + snprintf(LOG,MAXENTRYLEN,"%u",cn->status); + add_idmef_object(idmef, "alert.additionaldata(0).integer", LOG); + + /* alert.additionaldata(1) */ + add_idmef_object(idmef, "alert.additionaldata(1).type", "integer"); + add_idmef_object(idmef, "alert.additionaldata(1).meaning", "Network node"); + snprintf(LOG,MAXENTRYLEN,"%u",cn->node); + add_idmef_object(idmef, "alert.additionaldata(1).integer", LOG); + + /* IP versios */ + if (cn->h_proto == 8) { + add_idmef_object(idmef, "alert.source(0).service.ip_version", "4"); + add_idmef_object(idmef, "alert.target(0).service.ip_version", "4"); + } else { + /* bail out */ + idmef_message_destroy(idmef); + return; + } + + /* alert.source(0).node.address(0) (ip address) */ + if(cn->reversed==CNX_REVERSED){ + snprintf_inaddr_toa(LOG,MAXENTRYLEN,(struct in_addr*) &cn->d_ip,'\0'); + }else{ + snprintf_inaddr_toa(LOG,MAXENTRYLEN,(struct in_addr*) &cn->s_ip,'\0'); + } + add_idmef_object(idmef, "alert.source(0).node.address(0).category", + "ipv4-addr"); + add_idmef_object(idmef, "alert.source(0).node.address(0).address", LOG); + + /* alert.source(0).node.address(1) (mac address) */ + add_idmef_object(idmef, "alert.source(0).node.address(1).category", "mac"); + { + struct myether_addr *es=(struct myether_addr *)&cn->eth_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]); + } + add_idmef_object(idmef, "alert.source(0).node.address(1).address", LOG); + + protoent = getprotobynumber(cn->proto); + + /* alert.source(0).iana_protocol_number */ + snprintf(LOG,MAXENTRYLEN,"%u",(cn->proto)); + add_idmef_object(idmef, "alert.source(0).service.iana_protocol_number", LOG); + + /* alert.target(0).iana_protocol_number */ + add_idmef_object(idmef, "alert.target(0).service.iana_protocol_number", LOG); + + + if (protoent) { + /* alert.source(0).iana_protocol_name */ + add_idmef_object(idmef, "alert.source(0).service.iana_protocol_name", + protoent->p_name); + + /* alert.target(0).iana_protocol_name */ + add_idmef_object(idmef, "alert.target(0).service.iana_protocol_name", + protoent->p_name); + + /* alert.source(0).service */ + setservent(1); + if(cn->reversed==CNX_REVERSED){ + snprintf(LOG,MAXENTRYLEN,"%u",ntohs(cn->d_port)); + sourceservent = getservbyport(ntohs(cn->d_port), protoent->p_name); + }else{ + snprintf(LOG,MAXENTRYLEN,"%u",ntohs(cn->s_port)); + sourceservent = getservbyport(ntohs(cn->s_port), protoent->p_name); + } + + if (sourceservent && sourceservent->s_name) + add_idmef_object(idmef, "alert.source(0).service.name", + sourceservent->s_name ); + add_idmef_object(idmef, "alert.source(0).service.port", + LOG); + add_idmef_object(idmef, "alert.source(0).service.protocol", + protoent->p_name); + + /* alert.target(0).service */ + if(cn->reversed==CNX_REVERSED){ + snprintf(LOG,MAXENTRYLEN,"%u",ntohs(cn->s_port)); + sourceservent = getservbyport(ntohs(cn->s_port), protoent->p_name); + }else{ + snprintf(LOG,MAXENTRYLEN,"%u",ntohs(cn->d_port)); + sourceservent = getservbyport(ntohs(cn->d_port), protoent->p_name); + } + + if (sourceservent && sourceservent->s_name) + add_idmef_object(idmef, "alert.target(0).service.name", + sourceservent->s_name ); + add_idmef_object(idmef, "alert.target(0).service.port", + LOG); + add_idmef_object(idmef, "alert.target(0).service.protocol", + protoent->p_name); + } +/* +*/ + + /* alert.target(0).node.address(0) (ip address) */ + if(cn->reversed==CNX_REVERSED){ + snprintf_inaddr_toa(LOG,MAXENTRYLEN,(struct in_addr*) &cn->s_ip,'\0'); + }else{ + snprintf_inaddr_toa(LOG,MAXENTRYLEN,(struct in_addr*) &cn->d_ip,'\0'); + } + add_idmef_object(idmef, "alert.target(0).node.address(0).category", + "ipv4-addr"); + add_idmef_object(idmef, "alert.target(0).node.address(0).address", LOG); + + /* alert.target(0).node_address(1) (mac address) */ + add_idmef_object(idmef, "alert.target(0).node.address(1).category", "mac"); + { + struct myether_addr *es=(struct myether_addr *)&cn->eth_hdr.ether_dhost; + 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]); + } + add_idmef_object(idmef, "alert.target(0).node.address(1).address", LOG); + + prelude_client_send_idmef(client, idmef); + idmef_message_destroy(idmef); +} + void record(struct cnx *cn, outputFileHandle *fH) { @@ -199,8 +401,15 @@ char eor=fH->getEor(); + /* do we want prelude alert generation for this record? */ + bzero(LOG,MAXENTRYLEN); + if (fH == gVars.sfH) { + record_prelude(cn); + } + + /* * Structure of a 48-bit Ethernet address.