📄 alert.c
字号:
/** This file is part of Firestorm NIDS* Copyright (c) 2002 Gianni Tedesco* This program is released under the terms of the GNU GPL version 2** This code handles alerts, it mainly just calls functions in* elog_write.c.** Functions:* o alert_cleanup() - final log rotation* o alert_hup() - rotate log on demand* o alert_init() - register cleanup handler* o cb_dir() - set log spool directory path* o cb_stormwall() - set stormwall mode* o alert_conf_hook() - do the args_parse()* o alert_conf_go() - print messages call spool_open()* o alert_ratelimit() - token bucket filter* o alert_do_ratelimit() - wrapper to do the correct ratelimit* o alert() - exported API, do an alert*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include <sys/stat.h>#include <fcntl.h>#include <netinet/in.h>#include <sys/uio.h>#include <firestorm.h>#include <packet.h>#include <elog.h>#include <elog_write.h>#include <alert.h>#include <signature.h>#include <decode.h>#include <cleanup.h>#include <sensor.h>#include <args.h>#include <capture.h>#include <target.h>/* Output file descriptor */struct elog_spool *spool=NULL;void alert_cleanup(int code, void *priv){ mesg(M_INFO,"alert: flushing logfiles"); spool_delete(spool);}/* By sending a SIGHUP firestorm can cause * a log rotation at any time */void alert_hup(void){ if ( !spool_isempty(spool) ) spool_rotate(spool, 1);}void alert_init(void){ if ( !(spool=spool_new()) ) cleanup(EXIT_ERR, "alert: spool_new(): %s", get_err()); cleanup_add(alert_cleanup, NULL);}int cb_dir(struct arg *a, void *priv){ struct elog_spool *s=priv; static char sw[]=".stormwall"; int l; if ( !s ) return 0; if ( !a->val.v_str ) return 0; if ( *a->val.v_str==0 ) return 0; if ( s->rotate_fn ) return 0; l=strlen(a->val.v_str); /* We add a slash unconditionally */ if ( a->val.v_str[l-1]=='/' ) { a->val.v_str[l-1]=0; l-=1; } /* Allocate for the log dir */ if ( !(s->log_dir=malloc(l + ALERT_FNLEN + 2)) ) { return 0; } s->rotate_fn=s->log_dir + l + 1; sprintf(s->log_dir, "%s/", a->val.v_str); /* Allocate enough space for the whole filename */ if ( !(s->alert_fn=malloc(l + strlen(ALERT_FN) + 2)) ) { free(s->log_dir); return 0; } /* Figure out stormwall fifo filename */ if ( !(s->fifo_fn=malloc(l+sizeof(sw)+2)) ) { free(s->alert_fn); free(s->log_dir); return 0; } /* Generate the filenames */ sprintf(s->alert_fn, "%s/%s", a->val.v_str, ALERT_FN); sprintf(s->fifo_fn, "%s/%s", a->val.v_str, sw); return 1;}int cb_stormwall(struct arg *a, void *priv){ struct elog_spool *s=priv; if ( !s ) return 0; if ( !strcmp("none", a->val.v_str) ) { s->stormwall=STORMWALL_NONE; }else if ( !strcmp("wait", a->val.v_str) ) { s->stormwall=STORMWALL_WAIT; }else if ( !strcmp("fail", a->val.v_str) ) { s->stormwall=STORMWALL_FAIL; }else{ mesg(M_ERR, "output: stormwall can be one of 'none'," "'wait' or 'fail'"); return 0; } return 1;}/* Config file hook for setting up output mechanisms */void alert_conf_hook(char *args){ struct arg the_args[]={ {"dir", ARGTYPE_STRING, cb_dir}, {"stormwall", ARGTYPE_STRING, cb_stormwall}, {"size", ARGTYPE_PBYTES, NULL, {vp_bytes:&spool->max_bytes}}, {"minutes", ARGTYPE_PUINT, NULL, {vp_uint:&spool->max_time}}, {"buf", ARGTYPE_PBYTES, NULL, {vp_bytes:&spool->buf_sz}}, {NULL, ARGTYPE_NOP, NULL} }; if ( !args ) return; switch ( args_parse(the_args, args, spool) ) { case -1: mesg(M_ERR, "output: parse error: %s", args); /* fall through */ case 0: cleanup(EXIT_ERR,"output: failed"); return; default: break; } if ( !spool_set_buf(spool, spool->buf_sz) ) cleanup(EXIT_ERR, "output: unable to allocate buffer"); if ( !spool->alert_fn ) cleanup(EXIT_ERR, "output: no dir specified: %s", args); if ( spool->max_bytes ) { mesg(M_INFO,"alert: %s: max log size: %uKB", spool->log_dir, spool->max_bytes/1024); } if ( spool->max_time ) { spool->max_time*=60; mesg(M_INFO,"alert: %s: max log age: %u hrs %u mins", spool->log_dir, spool->max_time/(60*60), (spool->max_time%(60*60))/60); } mesg(M_INFO, "alert: %s: %sbuffered output: %uKB buffer", spool->log_dir, spool->buf_sz ? "" : "non-", spool->buf_sz/1024);}/* Set everything up from configuration */void alert_conf_go(void){ if ( !spool_check_old(spool) ) { cleanup(EXIT_ERR, "there was a problem opening the logfile"); return; } stormwall_open(spool);}/* Token bucket rate-limiting filter. Return values: * returns -1 if events are coming in too fast * returns zero if rate is normal * returns n>0 if rate is normal but some were dropped */static inline intalert_ratelimit(struct packet *pkt, struct tokenbucket *a){ unsigned long h; int ret; if ( !a->cost ) return 0; /* Build a single time value with 0.01s resolution */ h=pkt->time.tv_sec * RATE_SEC; h+=pkt->time.tv_usec / (1000000UL/RATE_SEC); a->toks += h - a->last_msg; a->last_msg=h; if ( a->toks > a->burst ) a->toks=a->burst; if ( a->toks >= a->cost ) { ret=a->missed; a->missed=0; a->toks -= a->cost; return ret; } a->missed++; return -1;}/* return zero for OK, -1 to suppress */static inline intalert_do_ratelimit(struct generator *gen, struct packet *pkt, struct alert *a){ int missed; struct tokenbucket *tb; char *s1, *s2; /* Alert specific tocken buckets take * precedence over generator-wide ones */ if ( a->t.cost ) { tb=&a->t; s1="alert"; s2=a->alert; }else{ if ( !(tb=gen->t) ) return 0; s1="generator"; s2=gen->name; } switch ( (missed=alert_ratelimit(pkt,tb)) ) { case -1: return -1; case 0: return 0; default: mesg(M_DEBUG, "alert: [%s] %s: %i alerts suppressed", s1, s2, missed); return 0; }}/* This is where alerts come to after rate-limiting */void alert(struct generator *gen, struct packet *pkt, struct alert *a){ struct event_alert ev={.gen=gen, .pkt=pkt, .a=a}; if ( !pkt ) return; /* Alerts can be supressed */ if ( alert_do_ratelimit(gen, pkt, a)<0 ) return; /* write the packet */ spool_packet(spool, &ev);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -