⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 elog_write.c

📁 Firestorm NIDS是一个性能非常高的网络入侵检测系统 (NIDS)。目前
💻 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** Alert Spool API*  o spool_new() - create a new spool object*  o spool_open() - open logfile and write header*  o spool_close() - flus buffer, close file*  o spool_rotate() - rotate a logfile, creation of new file is optional*  o spool_check_old() - hack to rotate after a crash*  o spool_delete() - close and destroy a spool object*  o spool_do_packet() - construct an elog record*  o spool_write_slow() - unbuffered write to the spool*  o spool_flush() - flush any buffers*  o spool_write() - write a packet*  o spool_packet() - log a packet** Stormwall Notification API*  o stormwall_msg() - send a message to stormwall*  o stormwall_open() - open the stormwall fifo*  o stormwall_close() - close the stormwall fifo** TODO*  o Need to do clever things when writes fail.*  o Round-robin spooling*  o Weighted round-robin*/#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 <cleanup.h>#include <alert.h>#include <signature.h>#include <decode.h>#include <stormwall.h>#include <elog.h>#include <elog_write.h>/* A blank 4 byte area we can point to for zero padding */static const char alert_padding[4]={0,0,0,0};/* create a new spool object */struct elog_spool *spool_new(void){	struct elog_spool *ret;	if ( !(ret=calloc(1, sizeof(*ret))) )		return NULL;	ret->fd=-1;	ret->stormwall=STORMWALL_NONE;	ret->fifo_fd=-1;	ret->max_bytes=SPOOL_DEFAULT_SIZE;	ret->max_time=SPOOL_DEFAULT_MINS;	ret->buf_sz=SPOOL_DEFAULT_BUFFER;	return ret;}/* Set the buffer size */int spool_set_buf(struct elog_spool *s, size_t sz){	if ( sz ) {		if ( !(s->buf=malloc(sz)) ) {			return 0;		}	}	s->ptr=s->buf;	s->buf_len=sz;	s->buf_sz=sz;	return 1;}/* Open a new logfile and write the header */int spool_open(struct elog_spool *s){	struct efile_hdr fhdr;	int ret;	/* Open up the log file */	if ( (s->fd=open(s->alert_fn,		O_WRONLY|O_CREAT|O_EXCL, 0600))<0 ) {		mesg(M_CRIT,"%s: open(): %s", s->alert_fn, get_err());		return 0;	}	/* Construct header */	fhdr.magic=htonl(EF_MAGIC);	fhdr.flags=0;	fhdr.vers_minor=EF_VERS_MIN;	fhdr.vers_major=EF_VERS_MAJ;	/* Write header */	if ( (ret=write(s->fd, &fhdr, sizeof(fhdr)))<sizeof(fhdr) ) {		if ( ret < 0 ) {			mesg(M_CRIT,"elog: %s: write(): %s",				s->alert_fn, get_err());			return 0;		}else{			mesg(M_CRIT,"elog: %s: writing file header: "				"truncated", s->alert_fn);			return 0;		}	}	/* Setup the structures */	s->size=sizeof(struct efile_hdr);	return 1;}/* spool_close() - flush data to disk and close file */void spool_close(struct elog_spool *s){	spool_flush(s);	if ( fsync(s->fd) )		mesg(M_CRIT,"alert: fsync(): %s", get_err());	if ( close(s->fd) )		mesg(M_CRIT,"alert: close(): %s", get_err());	s->fd=-1;}/* All-in-one function to perform a log rotation */void spool_rotate(struct elog_spool *s, int new){	struct stat st;	/* XXX: Never happens right? */	if ( s->fd<0 ) {		mesg(M_DEBUG, "alert: spool_rotate fd=%i", s->fd);		spool_open(s);		return;	}	/* Get the inode number before closing */	if ( fstat(s->fd, &st) ) {		mesg(M_CRIT, "alert: fstat(): %s", get_err());		st.st_ino=0xdeadbeef; /* uh-oh */	}	/* Flush and close the old one */	spool_close(s);	/* Build a name to rotate the old file to */	snprintf(s->rotate_fn, ALERT_FNLEN+1, "@%.8lx.%.8lx.elog",		s->tv.tv_sec, st.st_ino);	/* Rotate it */	if ( rename(s->alert_fn, s->log_dir) ) {		mesg(M_CRIT,"alert: rename(): %s", get_err());	}else{		mesg(M_DEBUG,"logrotate: %s", s->log_dir);	}	/* Wake up the stormwall daemon if necessary */	stormwall_msg(s, STORMWALL_ROTATE);	s->tv.tv_sec=0;	/* Open a new one */	if ( new )		spool_open(s);}/* Rotate a stale logfile. It's racy, but fuck it. */int spool_check_old(struct elog_spool *s){	struct {		struct efile_hdr fh;		struct elog_pkthdr pkth;	}buf;	if ( (s->fd=open(s->alert_fn, O_RDONLY))<0 )		return spool_open(s);	/* Read the date of the first packet and then rotate it */	if ( read(s->fd, &buf, sizeof(buf))<sizeof(buf) ) {		goto kill_it;	}	/* Check it aint corrupt */	if ( ntohl(buf.fh.magic) != EF_MAGIC ||		buf.fh.vers_major != EF_VERS_MAJ ||		buf.fh.vers_minor != EF_VERS_MIN )		goto kill_it;	/* Grab the timestamp of the first entry */	s->tv.tv_sec=buf.pkth.h.ts.tv_sec;	s->tv.tv_usec=buf.pkth.h.ts.tv_usec;	/* Rotate it */	spool_rotate(s, 1);	return 1;kill_it:	close(s->fd);	/* If there is no first packet, just unlink it */	if ( unlink(s->alert_fn) ) {		mesg(M_WARN, "alert: %s: unlink(): ", s->alert_fn, get_err());		return 0;	}	mesg(M_WARN, "alert: obliterated %s", s->alert_fn);	return spool_open(s);}/* finish up with a spool */void spool_delete(struct elog_spool *s){	if ( !spool_isempty(s) ) {		/* If we have logged to this file then rotate it */		spool_rotate(s, 0);	}else if ( s->fd>=0 ) {		/* If not, then close and delete it */		spool_close(s);		if ( unlink(s->alert_fn) )			mesg(M_CRIT,"alert: unlink(): %s", get_err());	}	/* Close stormwall */	stormwall_close(s);	/* Free up all our path information */	if ( s->alert_fn )		free(s->alert_fn);	if ( s->log_dir )		free(s->log_dir);	if ( s->fifo_fn )		free(s->fifo_fn);	if ( s->buf )		free(s->buf);	free(s);}/* Send a message to stormwall */int stormwall_msg(struct elog_spool *s, int msg){	unsigned char code=msg&0xff;	if ( s->stormwall ) {		if ( write(s->fifo_fd, (char *)&code, sizeof(code))<0 ) {			mesg(M_CRIT, "alert: stormwall: %s", get_err());			return -1;		}	}	return 0;}/* Open the stormwall communications FIFO */void stormwall_open(struct elog_spool *s){	int flags=0;	if ( s->stormwall==STORMWALL_FAIL ) {		flags=O_NONBLOCK;	}else if ( s->stormwall==STORMWALL_WAIT ) {		mesg(M_DEBUG,"alert: attempting to contact stormwall...");	}else return;	if ( (s->fifo_fd=open(s->fifo_fn, O_WRONLY|flags))<0 ) {		mesg(M_ERR, "%s: open(): %s", s->fifo_fn, get_err());		cleanup(EXIT_ERR, "alert: unable to contact stormwall");		return;	}	if ( s->stormwall==STORMWALL_WAIT ) {		mesg(M_DEBUG,"alert: ...SUCCESS!");	}}/* close a stormwall socket */void stormwall_close(struct elog_spool *s){	if ( s->fifo_fd<0 )		return;	if ( close(s->fifo_fd) )		mesg(M_WARN, "alert: %s: close(): %s",			s->fifo_fn, get_err());}/* Convert a alert information in to an elog record */static int spool_do_packet(struct elog_spool *s, struct event_alert *ev){	static char decode_buf[4096];	static char sbuf[512];	struct iovec *iov=s->iov;	struct packet *pkt=ev->pkt;	struct elog_dhdr *dh;	char *ptr=decode_buf;	char *ptr_end=decode_buf+sizeof(decode_buf);	size_t tot_len=0;	int i=0;	int j;	/* Construct record header */	s->ph.h.type=ELOG_ALERT;	s->ph.h.prio=ev->a->priority;	s->ph.h.reserved=0;	s->ph.h.ts.tv_sec=pkt->time.tv_sec;	s->ph.h.ts.tv_usec=pkt->time.tv_usec;	/* Construct alert specific bit */	s->ph.sid=ev->a->sid;	s->ph.rev=ev->a->rev;	s->ph.pflags=pkt->flags;	s->ph.decode_len=0;	s->ph.gen_len=strlen(ev->gen->name)+1;	s->ph.alert_len=strlen(ev->a->alert)+1;	s->ph.pkt_len=pkt->len;	s->ph.pkt_caplen=pkt->caplen;	/* Record header vector */	iov[i].iov_base=&s->ph;	iov[i].iov_len=sizeof(s->ph);	tot_len+=iov[i++].iov_len;	/* Construct the decode data */	for(j=0; j<pkt->llen; j++) {		int slen=0, nlen, real;		if ( pkt->layer[j].proto ) {			struct layer *l=&pkt->layer[j];			/* Call plugins to serialise state data */			if ( l->session && l->proto->serialize ) {				slen=l->proto->serialize(pkt, j,					sbuf, sizeof(sbuf));				if ( slen<0 ) {					mesg(M_WARN,						"alert: %s state data too big",						l->proto->name);				}				/* Round to the nearest multiple of 4 */				if ( slen & 0x3 ) slen+=(4-(slen&0x3));			}			real=nlen=strlen(l->proto->name)+1;		}else{			real=nlen=slen=0;		}		/* Round to the nearest multiple of 4 */		if ( nlen & 0x3 ) nlen+=(4-(nlen&0x3));		if ( ptr+nlen+sizeof(*dh) > ptr_end ) {			mesg(M_CRIT,"elog: decode buffer too small!");			return -1;		}		/* Fill in the header */		dh=(struct elog_dhdr *)ptr;		ptr+=sizeof(*dh);		dh->tot_len=(sizeof(*dh)+nlen+slen)>>2;		dh->name_len=nlen>>2;		dh->pkt_ofs=htons(pkt->layer[j].h.raw - pkt->base);		dh->flags=htonl(pkt->layer[j].flags);		/* Then the protocol name  */		if ( real ) {			memcpy(ptr, pkt->layer[j].proto->name, real);			ptr+=real;			/* make sure padding is zeroed */			if ( nlen-real ) {				memset(ptr, 0, nlen-real);				ptr+=nlen-real;			}		}		/* then the session data */		if ( slen ) {			memcpy(ptr, sbuf, slen);			ptr+=slen;		}	}	/* decode data vector */	iov[i].iov_base=decode_buf;	iov[i].iov_len=ptr-decode_buf;	/* fill in/update record header fields */	s->ph.decode_len=(iov[i].iov_len>>2);	tot_len+=iov[i++].iov_len;	/* raw packet data vector */	iov[i].iov_base=pkt->base;	iov[i].iov_len=pkt->caplen;	tot_len+=iov[i++].iov_len;	/* generator string */	iov[i].iov_base=ev->gen->name;	iov[i].iov_len=s->ph.gen_len;	tot_len+=iov[i++].iov_len;	/* Alert string */	iov[i].iov_base=ev->a->alert;	iov[i].iov_len=s->ph.alert_len;	tot_len+=iov[i++].iov_len;	/* Pad to multiples of 4 bytes (ensures	 * aligned access to next header if file	 * is mmap()ed in) */	if ( tot_len & 3 ) {		iov[i].iov_base=(char *)alert_padding;		iov[i].iov_len=(4-(tot_len&3));		tot_len+=iov[i++].iov_len;	}	/* Convert to network byte order  */	s->ph.h.reclen=htonl(tot_len);	s->ph.h.type=htons(s->ph.h.type);	s->ph.h.ts.tv_sec=htonl(s->ph.h.ts.tv_sec);	s->ph.h.ts.tv_usec=htonl(s->ph.h.ts.tv_usec);	s->ph.sid=htonl(s->ph.sid);	s->ph.rev=htonl(s->ph.rev);	s->ph.pflags=htonl(s->ph.pflags);	s->ph.decode_len=htons(s->ph.decode_len);	s->ph.pkt_len=htonl(s->ph.pkt_len);	s->ph.pkt_caplen=htonl(s->ph.pkt_caplen);	s->tot_len=tot_len;	s->io_len=i;	return 0;}/* Unbuffered write to the spool */int spool_write_slow(struct elog_spool *s){	int ret;	/* Actually write it all */	if ( (ret=writev(s->fd, s->iov, s->io_len))==s->tot_len ) {		s->size+=s->tot_len;		return 0;	}	/* Check for errors: a total error is recoverable */	if ( ret<0 ) {		mesg(M_CRIT,"elog: %s: writev(): %s",			s->alert_fn, get_err());		return -1;	}	/* Holy shits! It didn't get written out, maybe we should	 * rotate now to prevent further losses?? */	mesg(M_CRIT, "elog: %u/%u bytes written: your log is corrupt!",		s->tot_len-ret, s->tot_len);	s->size+=ret;	return -1;}/* flush any output buffers, out of line */int spool_flush(struct elog_spool *s){	int len=s->buf_sz-s->buf_len;	int ret;	/* write the buffer */	if ( (ret=write(s->fd, s->buf, len))==len ) {		/* reset the variables */		s->ptr=s->buf;		s->buf_len=s->buf_sz;		s->size+=len;		return 0;	}	if ( ret<0 ) {		mesg(M_CRIT,"elog: %s: write(): %s",			s->alert_fn, get_err());		return -1;	}	mesg(M_CRIT, "elog: %u/%u bytes written: your log is corrupt!",		s->tot_len-ret, s->tot_len);	s->size+=ret;	return -1;}/* Spool writing fast path */static inline int spool_write(struct elog_spool *s){	int i;	/* If this packet can't fit in the remaining	 * buffer space, then flush the buffer */	if ( s->tot_len > s->buf_len ) {		spool_flush(s);		/* If the buffer is flushed, and the packet is		 * still too big, then just write it out as is. */		if ( s->tot_len > s->buf_len )			return spool_write_slow(s);	}	/* common case, append to the buffer */	for (i=0; i<s->io_len; i++) {		memcpy(s->ptr, s->iov[i].iov_base, s->iov[i].iov_len);		s->ptr+=s->iov[i].iov_len;	}	s->buf_len-=s->tot_len;	return 0;}/* Send a packet to the alert spool */int spool_packet(struct elog_spool *s, struct event_alert *ev){	/* Convert to elog format */	if ( spool_do_packet(s, ev)<0 )		return -1;	/* Rotation filenames contain the timestamp	 * and serial number of the first packet in	 * that file */	if ( !s->tv.tv_sec ) {		s->tv.tv_sec=ev->pkt->time.tv_sec;		s->tv.tv_usec=ev->pkt->time.tv_usec;	}	/* Check to see if we exceeded max logfile size or	 * haven't rotated in a while */	if ( (s->max_bytes && (s->size + s->tot_len > s->max_bytes)) ||		(s->max_time && (ev->pkt->time.tv_sec > s->tv.tv_sec + s->max_time)) ) {		spool_rotate(s, 1);	}	return spool_write(s);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -