aboutsummaryrefslogtreecommitdiffstats
path: root/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6
diff options
context:
space:
mode:
Diffstat (limited to 'config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6')
-rw-r--r--config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/Makefile.am17
-rw-r--r--config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/Makefile.in445
-rw-r--r--config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/plugbase.c1544
-rw-r--r--config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/util.c3233
4 files changed, 5239 insertions, 0 deletions
diff --git a/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/Makefile.am b/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/Makefile.am
new file mode 100644
index 00000000..0879c6e3
--- /dev/null
+++ b/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/Makefile.am
@@ -0,0 +1,17 @@
+## $Id
+AUTOMAKE_OPTIONS=foreign no-dependencies
+
+noinst_LIBRARIES = libspo.a
+
+libspo_a_SOURCES = spo_alert_fast.c spo_alert_fast.h \
+spo_alert_full.c spo_alert_full.h \
+spo_alert_syslog.c spo_alert_syslog.h spo_alert_unixsock.c \
+spo_alert_unixsock.h spo_csv.c spo_csv.h spo_database.c spo_database.h \
+spo_log_null.c spo_log_null.h spo_log_tcpdump.c \
+spo_log_tcpdump.h spo_unified.c spo_unified2.c spo_unified.h spo_unified2.h \
+spo_log_ascii.c spo_log_ascii.h spo_alert_sf_socket.h spo_alert_sf_socket.c \
+spo_alert_prelude.c spo_alert_prelude.h spo_alert_arubaaction.c spo_alert_arubaaction.h \
+spo_alert_test.c spo_alert_test.h \
+spo_pf.h spo_pf.c
+
+INCLUDES = @INCLUDES@
diff --git a/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/Makefile.in b/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/Makefile.in
new file mode 100644
index 00000000..3f06cc31
--- /dev/null
+++ b/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/Makefile.in
@@ -0,0 +1,445 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/output-plugins
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libprelude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libspo_a_AR = $(AR) $(ARFLAGS)
+libspo_a_LIBADD =
+am_libspo_a_OBJECTS = spo_alert_fast.$(OBJEXT) \
+ spo_alert_full.$(OBJEXT) spo_alert_syslog.$(OBJEXT) \
+ spo_alert_unixsock.$(OBJEXT) spo_csv.$(OBJEXT) \
+ spo_database.$(OBJEXT) spo_log_null.$(OBJEXT) \
+ spo_log_tcpdump.$(OBJEXT) spo_unified.$(OBJEXT) \
+ spo_unified2.$(OBJEXT) spo_log_ascii.$(OBJEXT) \
+ spo_alert_sf_socket.$(OBJEXT) spo_alert_prelude.$(OBJEXT) \
+ spo_alert_arubaaction.$(OBJEXT) spo_alert_test.$(OBJEXT) \
+ spo_pf.$(OBJEXT)
+libspo_a_OBJECTS = $(am_libspo_a_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libspo_a_SOURCES)
+DIST_SOURCES = $(libspo_a_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_DYNAMIC_EXAMPLES_FALSE = @BUILD_DYNAMIC_EXAMPLES_FALSE@
+BUILD_DYNAMIC_EXAMPLES_TRUE = @BUILD_DYNAMIC_EXAMPLES_TRUE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+HAVE_DYNAMIC_PLUGINS_FALSE = @HAVE_DYNAMIC_PLUGINS_FALSE@
+HAVE_DYNAMIC_PLUGINS_TRUE = @HAVE_DYNAMIC_PLUGINS_TRUE@
+HAVE_SUP_IP6_FALSE = @HAVE_SUP_IP6_FALSE@
+HAVE_SUP_IP6_TRUE = @HAVE_SUP_IP6_TRUE@
+HAVE_TARGET_BASED_FALSE = @HAVE_TARGET_BASED_FALSE@
+HAVE_TARGET_BASED_TRUE = @HAVE_TARGET_BASED_TRUE@
+HAVE_ZLIB_FALSE = @HAVE_ZLIB_FALSE@
+HAVE_ZLIB_TRUE = @HAVE_ZLIB_TRUE@
+INCLUDES = @INCLUDES@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LIBOBJS = @LIBOBJS@
+LIBPRELUDE_CFLAGS = @LIBPRELUDE_CFLAGS@
+LIBPRELUDE_CONFIG = @LIBPRELUDE_CONFIG@
+LIBPRELUDE_CONFIG_PREFIX = @LIBPRELUDE_CONFIG_PREFIX@
+LIBPRELUDE_LDFLAGS = @LIBPRELUDE_LDFLAGS@
+LIBPRELUDE_LIBS = @LIBPRELUDE_LIBS@
+LIBPRELUDE_PREFIX = @LIBPRELUDE_PREFIX@
+LIBPRELUDE_PTHREAD_CFLAGS = @LIBPRELUDE_PTHREAD_CFLAGS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+extra_incl = @extra_incl@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+noinst_LIBRARIES = libspo.a
+libspo_a_SOURCES = spo_alert_fast.c spo_alert_fast.h \
+spo_alert_full.c spo_alert_full.h \
+spo_alert_syslog.c spo_alert_syslog.h spo_alert_unixsock.c \
+spo_alert_unixsock.h spo_csv.c spo_csv.h spo_database.c spo_database.h \
+spo_log_null.c spo_log_null.h spo_log_tcpdump.c \
+spo_log_tcpdump.h spo_unified.c spo_unified2.c spo_unified.h spo_unified2.h \
+spo_log_ascii.c spo_log_ascii.h spo_alert_sf_socket.h spo_alert_sf_socket.c \
+spo_alert_prelude.c spo_alert_prelude.h spo_alert_arubaaction.c spo_alert_arubaaction.h \
+spo_alert_test.c spo_alert_test.h \
+spo_pf.h spo_pf.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/output-plugins/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/output-plugins/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libspo.a: $(libspo_a_OBJECTS) $(libspo_a_DEPENDENCIES)
+ -rm -f libspo.a
+ $(libspo_a_AR) libspo.a $(libspo_a_OBJECTS) $(libspo_a_LIBADD)
+ $(RANLIB) libspo.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+.c.o:
+ $(COMPILE) -c $<
+
+.c.obj:
+ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/plugbase.c b/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/plugbase.c
new file mode 100644
index 00000000..31f381a8
--- /dev/null
+++ b/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/plugbase.c
@@ -0,0 +1,1544 @@
+/* $Id$ */
+/*
+** Copyright (C) 2002-2010 Sourcefire, Inc.
+** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License Version 2 as
+** published by the Free Software Foundation. You may not use, modify or
+** distribute this program under any other version of the GNU General
+** Public License.
+**
+** 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. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifndef WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif /* !WIN32 */
+#include <time.h>
+#include <errno.h>
+
+#include "sf_types.h"
+#include "plugbase.h"
+#include "spo_plugbase.h"
+#include "snort.h"
+#include "debug.h"
+#include "util.h"
+#include "log.h"
+#include "detect.h"
+
+/* built-in preprocessors */
+#include "preprocessors/spp_rpc_decode.h"
+#include "preprocessors/spp_bo.h"
+#include "preprocessors/spp_stream5.h"
+#include "preprocessors/spp_arpspoof.h"
+#include "preprocessors/spp_perfmonitor.h"
+#include "preprocessors/spp_httpinspect.h"
+#include "preprocessors/spp_sfportscan.h"
+#include "preprocessors/spp_frag3.h"
+
+/* built-in detection plugins */
+#include "detection-plugins/sp_pattern_match.h"
+#include "detection-plugins/sp_tcp_flag_check.h"
+#include "detection-plugins/sp_icmp_type_check.h"
+#include "detection-plugins/sp_icmp_code_check.h"
+#include "detection-plugins/sp_ttl_check.h"
+#include "detection-plugins/sp_ip_id_check.h"
+#include "detection-plugins/sp_tcp_ack_check.h"
+#include "detection-plugins/sp_tcp_seq_check.h"
+#include "detection-plugins/sp_dsize_check.h"
+#include "detection-plugins/sp_ipoption_check.h"
+#include "detection-plugins/sp_rpc_check.h"
+#include "detection-plugins/sp_icmp_id_check.h"
+#include "detection-plugins/sp_icmp_seq_check.h"
+#include "detection-plugins/sp_session.h"
+#include "detection-plugins/sp_ip_tos_check.h"
+#include "detection-plugins/sp_ip_fragbits.h"
+#include "detection-plugins/sp_tcp_win_check.h"
+#include "detection-plugins/sp_ip_same_check.h"
+#include "detection-plugins/sp_ip_proto.h"
+#include "detection-plugins/sp_ip_same_check.h"
+#include "detection-plugins/sp_clientserver.h"
+#include "detection-plugins/sp_byte_check.h"
+#include "detection-plugins/sp_byte_jump.h"
+#include "detection-plugins/sp_isdataat.h"
+#include "detection-plugins/sp_pcre.h"
+#include "detection-plugins/sp_flowbits.h"
+#include "detection-plugins/sp_file_data.h"
+#include "detection-plugins/sp_asn1.h"
+#ifdef ENABLE_REACT
+#include "detection-plugins/sp_react.h"
+#endif
+#ifdef ENABLE_RESPOND
+#include "detection-plugins/sp_respond.h"
+#endif
+#include "detection-plugins/sp_ftpbounce.h"
+#include "detection-plugins/sp_urilen_check.h"
+#include "detection-plugins/sp_cvs.h"
+
+/* built-in output plugins */
+#include "output-plugins/spo_alert_syslog.h"
+#include "output-plugins/spo_log_tcpdump.h"
+#include "output-plugins/spo_database.h"
+#include "output-plugins/spo_alert_fast.h"
+#include "output-plugins/spo_alert_full.h"
+#include "output-plugins/spo_alert_unixsock.h"
+#include "output-plugins/spo_csv.h"
+#include "output-plugins/spo_unified.h"
+#include "output-plugins/spo_log_null.h"
+#include "output-plugins/spo_log_ascii.h"
+#include "output-plugins/spo_unified2.h"
+#include "output-plugins/spo_pf.h"
+
+#ifdef ARUBA
+#include "output-plugins/spo_alert_arubaaction.h"
+#endif
+
+#ifdef HAVE_LIBPRELUDE
+#include "output-plugins/spo_alert_prelude.h"
+#endif
+
+#ifdef LINUX
+#include "output-plugins/spo_alert_sf_socket.h"
+#endif
+
+#include "output-plugins/spo_alert_test.h"
+
+extern ListHead *head_tmp;
+extern PreprocConfigFuncNode *preproc_config_funcs;
+extern OutputConfigFuncNode *output_config_funcs;
+extern RuleOptConfigFuncNode *rule_opt_config_funcs;
+extern RuleOptOverrideInitFuncNode *rule_opt_override_init_funcs;
+extern RuleOptParseCleanupNode *rule_opt_parse_cleanup_list;
+extern PreprocSignalFuncNode *preproc_restart_funcs;
+extern PreprocSignalFuncNode *preproc_clean_exit_funcs;
+extern PreprocSignalFuncNode *preproc_shutdown_funcs;
+extern PreprocSignalFuncNode *preproc_reset_funcs;
+extern PreprocSignalFuncNode *preproc_reset_stats_funcs;
+extern PreprocStatsFuncNode *preproc_stats_funcs;
+extern PluginSignalFuncNode *plugin_shutdown_funcs;
+extern PluginSignalFuncNode *plugin_clean_exit_funcs;
+extern PluginSignalFuncNode *plugin_restart_funcs;
+extern OutputFuncNode *AlertList;
+extern OutputFuncNode *LogList;
+
+
+/**************************** Detection Plugin API ****************************/
+/* For translation from enum to char* */
+#ifdef DEBUG
+static const char *optTypeMap[OPT_TYPE_MAX] =
+{
+ "action",
+ "logging",
+ "detection"
+};
+
+#define ENUM2STR(num, map) \
+ ((num < sizeof(map)/sizeof(map[0])) ? map[num] : "undefined")
+#endif
+
+
+void RegisterRuleOptions(void)
+{
+ LogMessage("Initializing Plug-ins!\n");
+
+ SetupPatternMatch();
+ SetupTCPFlagCheck();
+ SetupIcmpTypeCheck();
+ SetupIcmpCodeCheck();
+ SetupTtlCheck();
+ SetupIpIdCheck();
+ SetupTcpAckCheck();
+ SetupTcpSeqCheck();
+ SetupDsizeCheck();
+ SetupIpOptionCheck();
+ SetupRpcCheck();
+ SetupIcmpIdCheck();
+ SetupIcmpSeqCheck();
+ SetupSession();
+ SetupIpTosCheck();
+ SetupFragBits();
+ SetupFragOffset();
+ SetupTcpWinCheck();
+ SetupIpProto();
+ SetupIpSameCheck();
+ SetupClientServer();
+ SetupByteTest();
+ SetupByteJump();
+ SetupIsDataAt();
+ SetupFileData();
+ SetupPcre();
+ SetupFlowBits();
+ SetupAsn1();
+#ifdef ENABLE_REACT
+ SetupReact();
+#endif
+#ifdef ENABLE_RESPOND
+ SetupRespond();
+#endif
+ SetupFTPBounce();
+ SetupUriLenCheck();
+ SetupCvs();
+}
+
+/****************************************************************************
+ *
+ * Function: RegisterRuleOption(char *, void (*func)(), enum OptionType)
+ *
+ * Purpose: Associates a rule option keyword with an option setup/linking
+ * function.
+ *
+ * Arguments: keyword => The option keyword to associate with the option
+ * handler
+ * *func => function pointer to the handler
+ * type => used to determine where keyword is allowed
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void RegisterRuleOption(char *opt_name, RuleOptConfigFunc config_func,
+ RuleOptOverrideInitFunc override_init_func,
+ RuleOptType opt_type,
+ RuleOptOtnHandler otn_handler)
+{
+ RuleOptConfigFuncNode *node;
+
+ DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Registering keyword:func => %s/%s:%p\n",
+ ENUM2STR(opt_type, optTypeMap), opt_name, config_func););
+
+ node = (RuleOptConfigFuncNode *)SnortAlloc(sizeof(RuleOptConfigFuncNode));
+
+ if (rule_opt_config_funcs == NULL)
+ {
+ rule_opt_config_funcs = node;
+ }
+ else
+ {
+ RuleOptConfigFuncNode *tmp = rule_opt_config_funcs;
+ RuleOptConfigFuncNode *last;
+
+ do
+ {
+ if (strcasecmp(tmp->keyword, opt_name) == 0)
+ {
+ free(node);
+ FatalError("Duplicate detection plugin keyword: %s.\n",
+ file_line, opt_name);
+ }
+
+ last = tmp;
+ tmp = tmp->next;
+
+ } while (tmp != NULL);
+
+ last->next = node;
+ }
+
+ node->keyword = SnortStrdup(opt_name);
+ node->type = opt_type;
+ node->func = config_func;
+ node->otn_handler = otn_handler;
+
+ if (override_init_func != NULL)
+ {
+ RuleOptOverrideInitFuncNode *node_override =
+ (RuleOptOverrideInitFuncNode *)SnortAlloc(sizeof(RuleOptOverrideInitFuncNode));
+
+ if (rule_opt_override_init_funcs == NULL)
+ {
+ rule_opt_override_init_funcs = node_override;
+ }
+ else
+ {
+ RuleOptOverrideInitFuncNode *tmp = rule_opt_override_init_funcs;
+ RuleOptOverrideInitFuncNode *last;
+
+ do
+ {
+ if (strcasecmp(tmp->keyword, opt_name) == 0)
+ {
+ free(node_override);
+ FatalError("RegisterRuleOption: Duplicate detection plugin keyword:"
+ " (%s) (%s)!\n", tmp->keyword, opt_name);
+ }
+
+ last = tmp;
+ tmp = tmp->next;
+
+ } while (tmp != NULL);
+
+ last->next = node_override;
+ }
+
+ node_override->keyword = SnortStrdup(opt_name);
+ node_override->type = opt_type;
+ node_override->func = override_init_func;
+ node_override->otn_handler = otn_handler;
+ }
+}
+
+void RegisterOverrideKeyword(char *keyword, char *option, RuleOptOverrideFunc func)
+{
+ RuleOptOverrideInitFuncNode *node = rule_opt_override_init_funcs;
+
+ while (node != NULL)
+ {
+ if (strcasecmp(node->keyword, keyword) == 0)
+ {
+ node->func(keyword, option, func);
+ break;
+ }
+
+ node = node->next;
+ }
+}
+
+/****************************************************************************
+ *
+ * Function: DumpPlugIns()
+ *
+ * Purpose: Prints the keyword->function list
+ *
+ * Arguments: None.
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void DumpRuleOptions(void)
+{
+ RuleOptConfigFuncNode *node;
+
+ node = rule_opt_config_funcs;
+
+ LogMessage("-------------------------------------------------\n");
+ LogMessage(" Keyword | Plugin Registered @\n");
+ LogMessage("-------------------------------------------------\n");
+
+ while (node != NULL)
+ {
+ LogMessage("%-13s: %p\n", node->keyword, node->func);
+ node = node->next;
+ }
+
+ LogMessage("-------------------------------------------------\n");
+ LogMessage("\n");
+}
+
+
+/****************************************************************************
+ *
+ * Function: AddOptFuncToList(int (*func)(), OptTreeNode *)
+ *
+ * Purpose: Links the option detection module to the OTN
+ *
+ * Arguments: (*func)() => function pointer to the detection module
+ * otn => pointer to the current OptTreeNode
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+OptFpList * AddOptFuncToList(RuleOptEvalFunc func, OptTreeNode *otn)
+{
+ OptFpList *ofp = (OptFpList *)SnortAlloc(sizeof(OptFpList));
+
+ DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Adding new rule to list\n"););
+
+ /* if there are no nodes on the function list... */
+ if (otn->opt_func == NULL)
+ {
+ otn->opt_func = ofp;
+ }
+ else
+ {
+ OptFpList *tmp = otn->opt_func;
+
+ /* walk to the end of the list */
+ while (tmp->next != NULL)
+ tmp = tmp->next;
+
+ tmp->next = ofp;
+ }
+
+ DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Set OptTestFunc to %p\n", func););
+
+ ofp->OptTestFunc = func;
+
+ return ofp;
+}
+
+/****************************************************************************
+ *
+ * Function: AddRspFuncToList(int (*func)(), OptTreeNode *)
+ *
+ * Purpose: Adds Response function to OTN
+ *
+ * Arguments: (*func)() => function pointer to the response module
+ * otn => pointer to the current OptTreeNode
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void AddRspFuncToList(ResponseFunc func, OptTreeNode *otn, void *params)
+{
+ RspFpList *rsp = (RspFpList *)SnortAlloc(sizeof(RspFpList));
+
+ DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Adding response to list\n"););
+
+ /* if there are no nodes on the function list... */
+ if (otn->rsp_func == NULL)
+ {
+ otn->rsp_func = rsp;
+ }
+ else
+ {
+ RspFpList *tmp = otn->rsp_func;
+
+ /* walk to the end of the list */
+ while (tmp->next != NULL)
+ tmp = tmp->next;
+
+ tmp->next = rsp;
+ }
+
+ DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Set ResponseFunc to %p\n", func););
+
+ rsp->func = func;
+ rsp->params = params;
+}
+
+void PostConfigInitPlugins(PluginSignalFuncNode *post_config_funcs)
+{
+ while (post_config_funcs != NULL)
+ {
+ post_config_funcs->func(0, post_config_funcs->arg);
+ post_config_funcs = post_config_funcs->next;
+ }
+}
+
+void FreeRuleOptConfigFuncs(RuleOptConfigFuncNode *head)
+{
+
+ while (head != NULL)
+ {
+ RuleOptConfigFuncNode *tmp = head;
+
+ head = head->next;
+
+ if (tmp->keyword != NULL)
+ free(tmp->keyword);
+
+ free(tmp);
+ }
+}
+
+void FreeRuleOptOverrideInitFuncs(RuleOptOverrideInitFuncNode *head)
+{
+
+ while (head != NULL)
+ {
+ RuleOptOverrideInitFuncNode *tmp = head;
+
+ head = head->next;
+
+ if (tmp->keyword != NULL)
+ free(tmp->keyword);
+
+ free(tmp);
+ }
+}
+
+void FreePluginSigFuncs(PluginSignalFuncNode *head)
+{
+ while (head != NULL)
+ {
+ PluginSignalFuncNode *tmp = head;
+
+ head = head->next;
+
+ /* don't free sig->arg, that's free'd by the CleanExit/Restart func */
+ free(tmp);
+ }
+}
+
+
+/************************** Preprocessor Plugin API ***************************/
+static void AddFuncToPreprocSignalList(PreprocSignalFunc, void *,
+ PreprocSignalFuncNode **, uint16_t, uint32_t);
+
+
+void RegisterPreprocessors(void)
+{
+ LogMessage("Initializing Preprocessors!\n");
+
+ SetupARPspoof();
+ SetupFrag3();
+ SetupStream5();
+ SetupRpcDecode();
+ SetupBo();
+ SetupHttpInspect();
+ SetupPerfMonitor();
+ SetupSfPortscan();
+}
+
+/****************************************************************************
+ *
+ * Function: RegisterPreprocessor(char *, void (*)(char *))
+ *
+ * Purpose: Associates a preprocessor statement with its function.
+ *
+ * Arguments: keyword => The option keyword to associate with the
+ * preprocessor
+ * *func => function pointer to the handler
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+#ifndef SNORT_RELOAD
+void RegisterPreprocessor(char *keyword, PreprocConfigFunc func)
+#else
+void RegisterPreprocessor(char *keyword, PreprocConfigFunc func,
+ PreprocReloadFunc rfunc, PreprocReloadSwapFunc sfunc,
+ PreprocReloadSwapFreeFunc ffunc)
+#endif
+{
+ PreprocConfigFuncNode *node =
+ (PreprocConfigFuncNode *)SnortAlloc(sizeof(PreprocConfigFuncNode));
+
+ DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Registering keyword:preproc => %s:%p\n", keyword, func););
+
+ if (preproc_config_funcs == NULL)
+ {
+ preproc_config_funcs = node;
+ }
+ else
+ {
+ PreprocConfigFuncNode *tmp = preproc_config_funcs;
+ PreprocConfigFuncNode *last;
+
+ do
+ {
+ if (strcasecmp(tmp->keyword, keyword) == 0)
+ {
+ free(node);
+ FatalError("Duplicate preprocessor keyword: %s.\n", keyword);
+ }
+
+ last = tmp;
+ tmp = tmp->next;
+
+ } while (tmp != NULL);
+
+ last->next = node;
+ }
+
+ node->keyword = SnortStrdup(keyword);
+ node->config_func = func;
+
+#ifdef SNORT_RELOAD
+ node->reload_func = rfunc;
+ node->reload_swap_func = sfunc;
+ node->reload_swap_free_func = ffunc;
+#endif
+}
+
+PreprocConfigFuncNode * GetPreprocConfig(char *keyword)
+{
+ PreprocConfigFuncNode *head = preproc_config_funcs;
+
+ if (keyword == NULL)
+ return NULL;
+
+ while (head != NULL)
+ {
+ if (strcasecmp(head->keyword, keyword) == 0)
+ return head;
+
+ head = head->next;
+ }
+
+ return NULL;
+}
+
+PreprocConfigFunc GetPreprocConfigFunc(char *keyword)
+{
+ PreprocConfigFuncNode *head = preproc_config_funcs;
+
+ if (keyword == NULL)
+ return NULL;
+
+ while (head != NULL)
+ {
+ if (strcasecmp(head->keyword, keyword) == 0)
+ return head->config_func;
+
+ head = head->next;
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ *
+ * Function: RegisterPreprocStats(char *keyword, void (*func)(int))
+ *
+ * Purpose: Registers a function for printing preprocessor final stats
+ * (or other if it has a use for printing final stats)
+ *
+ * Arguments: keyword => keyword (preprocessor) whose stats will print
+ * func => function pointer to the handler
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void RegisterPreprocStats(char *keyword, PreprocStatsFunc func)
+{
+ PreprocStatsFuncNode *node;
+
+ DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Registering final stats function: "
+ "preproc => %s:%p\n", keyword, func););
+
+ node = (PreprocStatsFuncNode *)SnortAlloc(sizeof(PreprocStatsFuncNode));
+
+ if (preproc_stats_funcs == NULL)
+ {
+ preproc_stats_funcs = node;
+ }
+ else
+ {
+ PreprocStatsFuncNode *tmp = preproc_stats_funcs;
+ PreprocStatsFuncNode *last;
+
+ do
+ {
+ if (strcasecmp(tmp->keyword, keyword) == 0)
+ {
+ free(node);
+ FatalError("Duplicate preprocessor keyword: %s.\n", keyword);
+ }
+
+ last = tmp;
+ tmp = tmp->next;
+
+ } while (tmp != NULL);
+
+ last->next = node;
+ }
+
+ node->keyword = SnortStrdup(keyword);
+ node->func = func;
+}
+
+/****************************************************************************
+ *
+ * Function: DumpPreprocessors()
+ *
+ * Purpose: Prints the keyword->preprocess list
+ *
+ * Arguments: None.
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void DumpPreprocessors(void)
+{
+ PreprocConfigFuncNode *node = preproc_config_funcs;
+
+ LogMessage("-------------------------------------------------\n");
+ LogMessage(" Keyword | Preprocessor @ \n");
+ LogMessage("-------------------------------------------------\n");
+
+ while (node != NULL)
+ {
+ LogMessage("%-13s: %p\n", node->keyword, node->config_func);
+ node = node->next;
+ }
+
+ LogMessage("-------------------------------------------------\n\n");
+}
+
+int IsPreprocEnabled(uint32_t preproc_id)
+{
+ PreprocEvalFuncNode *node;
+ SnortConfig *sc = snort_conf_for_parsing;
+ tSfPolicyId policy_id = getParserPolicy();
+ SnortPolicy *p;
+
+ if (sc == NULL)
+ {
+ FatalError("%s(%d) Snort config for parsing is NULL.\n",
+ __FILE__, __LINE__);
+ }
+
+ p = sc->targeted_policies[policy_id];
+ if (p == NULL)
+ return 0;
+
+ for (node = p->preproc_eval_funcs; node != NULL; node = node->next)
+ {
+ if (node->preproc_id == preproc_id)
+ return 1;
+ }
+
+ return 0;
+}
+
+PreprocEvalFuncNode * AddFuncToPreprocList(PreprocEvalFunc func, uint16_t priority,
+ uint32_t preproc_id, uint32_t proto_mask)
+{
+ PreprocEvalFuncNode *node;
+ SnortConfig *sc = snort_conf_for_parsing;
+ tSfPolicyId policy_id = getParserPolicy();
+ SnortPolicy *p;
+
+ if (sc == NULL)
+ {
+ FatalError("%s(%d) Snort config for parsing is NULL.\n",
+ __FILE__, __LINE__);
+ }
+
+ p = sc->targeted_policies[policy_id];
+ if (p == NULL)
+ return NULL;
+
+ DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
+ "Adding preprocessor function ID %d/bit %d/pri %d to list\n",
+ preproc_id, p->num_preprocs, priority););
+
+ node = (PreprocEvalFuncNode *)SnortAlloc(sizeof(PreprocEvalFuncNode));
+
+ if (p->preproc_eval_funcs == NULL)
+ {
+ p->preproc_eval_funcs = node;
+ }
+ else
+ {
+ PreprocEvalFuncNode *tmp = p->preproc_eval_funcs;
+ PreprocEvalFuncNode *last = NULL;
+
+ do
+ {
+ if (tmp->preproc_id == preproc_id)
+ {
+ free(node);
+ FatalError("Preprocessor already registered with ID %d\n",
+ preproc_id);
+ }
+
+ /* Insert higher priority preprocessors first. Lower priority
+ * number means higher priority */
+ if (priority < tmp->priority)
+ break;
+
+ last = tmp;
+ tmp = tmp->next;
+
+ } while (tmp != NULL);
+
+ /* Priority higher than first item in list */
+ if (last == NULL)
+ {
+ node->next = tmp;
+ p->preproc_eval_funcs = node;
+ }
+ else
+ {
+ node->next = tmp;
+ last->next = node;
+ }
+ }
+
+ node->func = func;
+ node->priority = priority;
+ node->preproc_id = preproc_id;
+ node->preproc_bit = (1 << preproc_id);
+ node->proto_mask = proto_mask;
+
+ p->num_preprocs++;
+ p->preproc_proto_mask |= proto_mask;
+ p->preproc_bit_mask |= node->preproc_bit;
+
+ return node;
+}
+
+void AddFuncToPreprocPostConfigList(PreprocPostConfigFunc func, void *data)
+{
+ PreprocPostConfigFuncNode *node;
+ SnortConfig *sc = snort_conf_for_parsing;
+
+ if (sc == NULL)
+ {
+ FatalError("%s(%d) Snort config for parsing is NULL.\n",
+ __FILE__, __LINE__);
+ }
+
+ node = (PreprocPostConfigFuncNode *)SnortAlloc(sizeof(PreprocPostConfigFuncNode));
+
+ if (sc->preproc_post_config_funcs == NULL)
+ {
+ sc->preproc_post_config_funcs = node;
+ }
+ else
+ {
+ PreprocPostConfigFuncNode *tmp = sc->preproc_post_config_funcs;
+
+ while (tmp->next != NULL)
+ tmp = tmp->next;
+
+ tmp->next = node;
+ }
+
+ node->data = data;
+ node->func = func;
+}
+
+void PostConfigPreprocessors(SnortConfig *sc)
+{
+ PreprocPostConfigFuncNode *list;
+
+ if (sc == NULL)
+ {
+ FatalError("%s(%d) Snort config is NULL.\n",
+ __FILE__, __LINE__);
+ }
+
+ snort_conf_for_parsing = sc;
+
+ list = sc->preproc_post_config_funcs;
+
+ for (; list != NULL; list = list->next)
+ {
+ if (list->func != NULL)
+ list->func(list->data);
+ }
+
+ snort_conf_for_parsing = NULL;
+}
+
+#ifdef SNORT_RELOAD
+void SwapPreprocConfigurations(void)
+{
+ PreprocConfigFuncNode *node = preproc_config_funcs;
+
+ for (; node != NULL; node = node->next)
+ {
+ if (node->reload_swap_func != NULL)
+ node->swap_free_data = node->reload_swap_func();
+ }
+}
+
+void FreeSwappedPreprocConfigurations(void)
+{
+ PreprocConfigFuncNode *node = preproc_config_funcs;
+
+ for (; node != NULL; node = node->next)
+ {
+ if ((node->reload_swap_free_func != NULL) &&
+ (node->swap_free_data != NULL))
+ {
+ node->reload_swap_free_func(node->swap_free_data);
+ node->swap_free_data = NULL;
+ }
+ }
+}
+
+void AddFuncToPreprocReloadVerifyList(PreprocReloadVerifyFunc func)
+{
+ PreprocReloadVerifyFuncNode *node;
+ SnortConfig *sc = snort_conf_for_parsing;
+
+ if (sc == NULL)
+ {
+ FatalError("%s(%d) Snort config for parsing is NULL.\n",
+ __FILE__, __LINE__);
+ }
+
+ node = (PreprocReloadVerifyFuncNode *)SnortAlloc(sizeof(PreprocReloadVerifyFuncNode));
+
+ if (sc->preproc_reload_verify_funcs == NULL)
+ {
+ sc->preproc_reload_verify_funcs = node;
+ }
+ else
+ {
+ PreprocReloadVerifyFuncNode *tmp = sc->preproc_reload_verify_funcs;
+
+ while (tmp->next != NULL)
+ tmp = tmp->next;
+
+ tmp->next = node;
+ }
+
+ node->func = func;
+}
+
+void FreePreprocReloadVerifyFuncList(PreprocReloadVerifyFuncNode *head)
+{
+ while (head != NULL)
+ {
+ PreprocReloadVerifyFuncNode *tmp = head;
+
+ head = head->next;
+ free(tmp);
+ }
+}
+#endif
+
+void AddFuncToConfigCheckList(PreprocCheckConfigFunc func)
+{
+ PreprocCheckConfigFuncNode *node;
+ SnortConfig *sc = snort_conf_for_parsing;
+
+ if (sc == NULL)
+ {
+ FatalError("%s(%d) Snort config for parsing is NULL.\n",
+ __FILE__, __LINE__);
+ }
+
+ node = (PreprocCheckConfigFuncNode *)SnortAlloc(sizeof(PreprocCheckConfigFuncNode));
+
+ if (sc->preproc_config_check_funcs == NULL)
+ {
+ sc->preproc_config_check_funcs = node;
+ }
+ else
+ {
+ PreprocCheckConfigFuncNode *tmp = sc->preproc_config_check_funcs;
+
+ while (tmp->next != NULL)
+ tmp = tmp->next;
+
+ tmp->next = node;
+ }
+
+ node->func = func;
+}
+
+/* functions to aid in cleaning up after plugins */
+void AddFuncToPreprocRestartList(PreprocSignalFunc func, void *arg,
+ uint16_t priority, uint32_t preproc_id)
+{
+ AddFuncToPreprocSignalList(func, arg, &preproc_restart_funcs, priority, preproc_id);
+}
+
+void AddFuncToPreprocCleanExitList(PreprocSignalFunc func, void *arg,
+ uint16_t priority, uint32_t preproc_id)
+{
+ AddFuncToPreprocSignalList(func, arg, &preproc_clean_exit_funcs, priority, preproc_id);
+}
+
+void AddFuncToPreprocShutdownList(PreprocSignalFunc func, void *arg,
+ uint16_t priority, uint32_t preproc_id)
+{
+ AddFuncToPreprocSignalList(func, arg, &preproc_shutdown_funcs, priority, preproc_id);
+}
+
+void AddFuncToPreprocResetList(PreprocSignalFunc func, void *arg,
+ uint16_t priority, uint32_t preproc_id)
+{
+ AddFuncToPreprocSignalList(func, arg, &preproc_reset_funcs, priority, preproc_id);
+}
+
+void AddFuncToPreprocResetStatsList(PreprocSignalFunc func, void *arg,
+ uint16_t priority, uint32_t preproc_id)
+{
+ AddFuncToPreprocSignalList(func, arg, &preproc_reset_stats_funcs, priority, preproc_id);
+}
+
+static void AddFuncToPreprocSignalList(PreprocSignalFunc func, void *arg,
+ PreprocSignalFuncNode **list,
+ uint16_t priority, uint32_t preproc_id)
+{
+ PreprocSignalFuncNode *node;
+
+ if (list == NULL)
+ return;
+
+ node = (PreprocSignalFuncNode *)SnortAlloc(sizeof(PreprocSignalFuncNode));
+
+ if (*list == NULL)
+ {
+ *list = node;
+ }
+ else
+ {
+ PreprocSignalFuncNode *tmp = *list;
+ PreprocSignalFuncNode *last = NULL;
+
+ do
+ {
+ /* Insert higher priority stuff first. Lower priority
+ * number means higher priority */
+ if (priority < tmp->priority)
+ break;
+
+ last = tmp;
+ tmp = tmp->next;
+
+ } while (tmp != NULL);
+
+ /* Priority higher than first item in list */
+ if (last == NULL)
+ {
+ node->next = tmp;
+ *list = node;
+ }
+ else
+ {
+ node->next = tmp;
+ last->next = node;
+ }
+ }
+
+ node->func = func;
+ node->arg = arg;
+ node->preproc_id = preproc_id;
+ node->priority = priority;
+}
+
+void AddFuncToPreprocReassemblyPktList(PreprocReassemblyPktFunc func, uint32_t preproc_id)
+{
+ PreprocReassemblyPktFuncNode *node;
+ SnortConfig *sc = snort_conf_for_parsing;
+ tSfPolicyId policy_id = getParserPolicy();
+ SnortPolicy *p;
+
+ if (sc == NULL)
+ {
+ FatalError("%s(%d) Snort config for parsing is NULL.\n",
+ __FILE__, __LINE__);
+ }
+
+ p = sc->targeted_policies[policy_id];
+ if (p == NULL)
+ return;
+
+ node = (PreprocReassemblyPktFuncNode *)SnortAlloc(sizeof(PreprocReassemblyPktFuncNode));
+
+ if (p->preproc_reassembly_pkt_funcs == NULL)
+ {
+ p->preproc_reassembly_pkt_funcs = node;
+ }
+ else
+ {
+ PreprocReassemblyPktFuncNode *tmp = p->preproc_reassembly_pkt_funcs;
+
+ /* just insert at front of list */
+ p->preproc_reassembly_pkt_funcs = node;
+ node->next = tmp;
+ }
+
+ node->func = func;
+ node->preproc_id = preproc_id;
+}
+
+void FreePreprocConfigFuncs(void)
+{
+ PreprocConfigFuncNode *head = preproc_config_funcs;
+ PreprocConfigFuncNode *tmp;
+
+ while (head != NULL)
+ {
+ tmp = head->next;
+ if (head->keyword != NULL)
+ free(head->keyword);
+ free(head);
+ head = tmp;
+ }
+}
+
+void FreePreprocCheckConfigFuncs(PreprocCheckConfigFuncNode *head)
+{
+ PreprocCheckConfigFuncNode *tmp;
+
+ while (head != NULL)
+ {
+ tmp = head->next;
+ free(head);
+ head = tmp;
+ }
+}
+
+void FreePreprocPostConfigFuncs(PreprocPostConfigFuncNode *head)
+{
+ PreprocPostConfigFuncNode *tmp;
+
+ while (head != NULL)
+ {
+ tmp = head->next;
+ free(head);
+ head = tmp;
+ }
+}
+
+void FreePreprocStatsFuncs(PreprocStatsFuncNode *head)
+{
+ PreprocStatsFuncNode *tmp;
+
+ while (head != NULL)
+ {
+ tmp = head->next;
+ if (head->keyword != NULL)
+ free(head->keyword);
+ free(head);
+ head = tmp;
+ }
+}
+
+void FreePreprocEvalFuncs(PreprocEvalFuncNode *head)
+{
+ PreprocEvalFuncNode *tmp;
+
+ while (head != NULL)
+ {
+ tmp = head->next;
+ //if (head->context)
+ // free(head->context);
+ free(head);
+ head = tmp;
+ }
+}
+
+void FreePreprocReassemblyPktFuncs(PreprocReassemblyPktFuncNode *head)
+{
+ PreprocReassemblyPktFuncNode *tmp;
+
+ while (head != NULL)
+ {
+ tmp = head->next;
+ free(head);
+ head = tmp;
+ }
+}
+
+void FreePreprocSigFuncs(PreprocSignalFuncNode *head)
+{
+ PreprocSignalFuncNode *tmp;
+
+ while (head != NULL)
+ {
+ tmp = head->next;
+ /* don't free sig->arg, that's free'd by the CleanExit/Restart func */
+ free(head);
+ head = tmp;
+ }
+}
+
+void CheckPreprocessorsConfig(SnortConfig *sc)
+{
+ PreprocCheckConfigFuncNode *idx;
+
+ if (sc == NULL)
+ {
+ FatalError("%s(%d) Snort config is NULL.\n",
+ __FILE__, __LINE__);
+ }
+
+ snort_conf_for_parsing = sc;
+
+ idx = sc->preproc_config_check_funcs;
+
+ LogMessage("Verifying Preprocessor Configurations!\n");
+
+ while(idx != NULL)
+ {
+ idx->func();
+ idx = idx->next;
+ }
+
+ snort_conf_for_parsing = NULL;
+}
+
+#ifdef SNORT_RELOAD
+int VerifyReloadedPreprocessors(SnortConfig *sc)
+{
+ PreprocReloadVerifyFuncNode *node;
+
+ if (sc == NULL)
+ {
+ FatalError("%s(%d) Snort config is NULL.\n",
+ __FILE__, __LINE__);
+ }
+
+ snort_conf_for_parsing = sc;
+
+ node = sc->preproc_reload_verify_funcs;
+ while (node != NULL)
+ {
+ if (node->func != NULL)
+ {
+ if (node->func() == -1)
+ return -1;
+ }
+
+ node = node->next;
+ }
+
+ snort_conf_for_parsing = NULL;
+
+ return 0;
+}
+#endif
+
+
+/***************************** Output Plugin API *****************************/
+extern OutputConfigFuncNode *output_config_funcs;
+
+static void AppendOutputFuncList(OutputFunc, void *, OutputFuncNode **);
+
+void RegisterOutputPlugins(void)
+{
+ LogMessage("Initializing Output Plugins!\n");
+
+ AlertSyslogSetup();
+ LogTcpdumpSetup();
+ DatabaseSetup();
+ AlertFastSetup();
+ AlertFullSetup();
+ AlertPfSetup();
+#ifndef WIN32
+ /* Win32 doesn't support AF_UNIX sockets */
+ AlertUnixSockSetup();
+#endif /* !WIN32 */
+ AlertCSVSetup();
+ LogNullSetup();
+ UnifiedSetup();
+ Unified2Setup();
+ LogAsciiSetup();
+
+#ifdef ARUBA
+ AlertArubaActionSetup();
+#endif
+
+#ifdef LINUX
+ /* This uses linux only capabilities */
+ AlertSFSocket_Setup();
+#endif
+
+#ifdef HAVE_LIBPRELUDE
+ AlertPreludeSetup();
+#endif
+
+ AlertTestSetup();
+}
+
+/****************************************************************************
+ *
+ * Function: RegisterOutputPlugin(char *, void (*func)(Packet *, u_char *))
+ *
+ * Purpose: Associates an output statement with its function.
+ *
+ * Arguments: keyword => The output keyword to associate with the
+ * output processor
+ * type => alert or log types
+ * *func => function pointer to the handler
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void RegisterOutputPlugin(char *keyword, int type_flags, OutputConfigFunc func)
+{
+ OutputConfigFuncNode *node = (OutputConfigFuncNode *)SnortAlloc(sizeof(OutputConfigFuncNode));
+
+ DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Registering keyword:output => %s:%p\n",
+ keyword, func););
+
+ if (output_config_funcs == NULL)
+ {
+ output_config_funcs = node;
+ }
+ else
+ {
+ OutputConfigFuncNode *tmp = output_config_funcs;
+ OutputConfigFuncNode *last;
+
+ do
+ {
+ if (strcasecmp(tmp->keyword, keyword) == 0)
+ {
+ free(node);
+ FatalError("Duplicate output keyword: %s\n", keyword);
+ }
+
+ last = tmp;
+ tmp = tmp->next;
+
+ } while (tmp != NULL);
+
+ last->next = node;
+ }
+
+ node->keyword = SnortStrdup(keyword);
+ node->func = func;
+ node->output_type_flags = type_flags;
+}
+
+OutputConfigFunc GetOutputConfigFunc(char *keyword)
+{
+ OutputConfigFuncNode *head = output_config_funcs;
+
+ if (keyword == NULL)
+ return NULL;
+
+ while (head != NULL)
+ {
+ if (strcasecmp(head->keyword, keyword) == 0)
+ return head->func;
+
+ head = head->next;
+ }
+
+ return NULL;
+}
+
+int GetOutputTypeFlags(char *keyword)
+{
+ OutputConfigFuncNode *head = output_config_funcs;
+
+ if (keyword == NULL)
+ return 0;
+
+ while (head != NULL)
+ {
+ if (strcasecmp(head->keyword, keyword) == 0)
+ return head->output_type_flags;
+
+ head = head->next;
+ }
+
+ return 0;
+}
+
+void FreeOutputConfigFuncs(void)
+{
+ OutputConfigFuncNode *head = output_config_funcs;
+ OutputConfigFuncNode *tmp;
+
+ while (head != NULL)
+ {
+ tmp = head->next;
+ if (head->keyword != NULL)
+ free(head->keyword);
+ free(head);
+ head = tmp;
+ }
+}
+
+void FreeOutputList(OutputFuncNode *list)
+{
+ while (list != NULL)
+ {
+ OutputFuncNode *tmp = list;
+
+ list = list->next;
+ free(tmp);
+ }
+}
+
+/****************************************************************************
+ *
+ * Function: DumpOutputPlugins()
+ *
+ * Purpose: Prints the keyword->preprocess list
+ *
+ * Arguments: None.
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void DumpOutputPlugins(void)
+{
+ OutputConfigFuncNode *idx = output_config_funcs;
+
+ LogMessage("-------------------------------------------------\n");
+ LogMessage(" Keyword | Output @ \n");
+ LogMessage("-------------------------------------------------\n");
+ while(idx != NULL)
+ {
+ LogMessage("%-13s: %p\n", idx->keyword, idx->func);
+ idx = idx->next;
+ }
+ LogMessage("-------------------------------------------------\n\n");
+}
+
+void AddFuncToOutputList(OutputFunc func, OutputType type, void *arg)
+{
+ switch (type)
+ {
+ case OUTPUT_TYPE__ALERT:
+ if (head_tmp != NULL)
+ AppendOutputFuncList(func, arg, &head_tmp->AlertList);
+ else
+ AppendOutputFuncList(func, arg, &AlertList);
+
+ break;
+
+ case OUTPUT_TYPE__LOG:
+ if (head_tmp != NULL)
+ AppendOutputFuncList(func, arg, &head_tmp->LogList);
+ else
+ AppendOutputFuncList(func, arg, &LogList);
+
+ break;
+
+ default:
+ /* just to be error-prone */
+ FatalError("Unknown output type: %i. Possible bug, please "
+ "report.\n", type);
+ }
+}
+
+void AppendOutputFuncList(OutputFunc func, void *arg, OutputFuncNode **list)
+{
+ OutputFuncNode *node;
+
+ if (list == NULL)
+ return;
+
+ node = (OutputFuncNode *)SnortAlloc(sizeof(OutputFuncNode));
+
+ if (*list == NULL)
+ {
+ *list = node;
+ }
+ else
+ {
+ OutputFuncNode *tmp = *list;
+
+ while (tmp->next != NULL)
+ tmp = tmp->next;
+
+ tmp->next = node;
+ }
+
+ node->func = func;
+ node->arg = arg;
+}
+
+
+/************************** Miscellaneous Functions **************************/
+
+/* functions to aid in cleaning up after plugins
+ * Used for both rule options and output. Preprocessors have their own */
+void AddFuncToRestartList(PluginSignalFunc func, void *arg)
+{
+ AddFuncToSignalList(func, arg, &plugin_restart_funcs);
+}
+
+void AddFuncToCleanExitList(PluginSignalFunc func, void *arg)
+{
+ AddFuncToSignalList(func, arg, &plugin_clean_exit_funcs);
+}
+
+void AddFuncToShutdownList(PluginSignalFunc func, void *arg)
+{
+ AddFuncToSignalList(func, arg, &plugin_shutdown_funcs);
+}
+
+void AddFuncToPostConfigList(PluginSignalFunc func, void *arg)
+{
+ SnortConfig *sc = snort_conf_for_parsing;
+
+ if (sc == NULL)
+ {
+ FatalError("%s(%d) Snort config for parsing is NULL.\n",
+ __FILE__, __LINE__);
+ }
+
+ AddFuncToSignalList(func, arg, &sc->plugin_post_config_funcs);
+}
+
+void AddFuncToSignalList(PluginSignalFunc func, void *arg, PluginSignalFuncNode **list)
+{
+ PluginSignalFuncNode *node;
+
+ if (list == NULL)
+ return;
+
+ node = (PluginSignalFuncNode *)SnortAlloc(sizeof(PluginSignalFuncNode));
+
+ if (*list == NULL)
+ {
+ *list = node;
+ }
+ else
+ {
+ PluginSignalFuncNode *tmp = *list;
+
+ while (tmp->next != NULL)
+ tmp = tmp->next;
+
+ tmp->next = node;
+ }
+
+ node->func = func;
+ node->arg = arg;
+}
+
+void AddFuncToRuleOptParseCleanupList(RuleOptParseCleanupFunc func)
+{
+ RuleOptParseCleanupNode *node =
+ (RuleOptParseCleanupNode *)SnortAlloc(sizeof(RuleOptParseCleanupNode));
+
+ if (rule_opt_parse_cleanup_list == NULL)
+ {
+ rule_opt_parse_cleanup_list = node;
+ }
+ else
+ {
+ RuleOptParseCleanupNode *tmp = rule_opt_parse_cleanup_list;
+
+ while (tmp->next != NULL)
+ tmp = tmp->next;
+
+ tmp->next = node;
+ }
+
+ node->func = func;
+}
+
+void RuleOptParseCleanup(void)
+{
+ RuleOptParseCleanupNode *list = rule_opt_parse_cleanup_list;
+
+ for (; list != NULL; list = list->next)
+ {
+ if (list->func != NULL)
+ list->func();
+ }
+}
+
+void FreeRuleOptParseCleanupList(RuleOptParseCleanupNode *head)
+{
+ while (head != NULL)
+ {
+ RuleOptParseCleanupNode *tmp = head;
+
+ head = head->next;
+ free(tmp);
+ }
+}
+
+
diff --git a/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/util.c b/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/util.c
new file mode 100644
index 00000000..b2d3b38b
--- /dev/null
+++ b/config/snort-dev/snortsam-package-code/patches/spoink_patch/2.8.6/util.c
@@ -0,0 +1,3233 @@
+/* $Id$ */
+/*
+** Copyright (C) 2002-2010 Sourcefire, Inc.
+** Copyright (C) 2002 Martin Roesch <roesch@sourcefire.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License Version 2 as
+** published by the Free Software Foundation. You may not use, modify or
+** distribute this program under any other version of the GNU General
+** Public License.
+**
+** 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. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+
+#ifndef WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#endif /* !WIN32 */
+
+#include <stdarg.h>
+#include <syslog.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <signal.h>
+#include <unistd.h>
+
+#ifndef WIN32
+#include <grp.h>
+#include <pwd.h>
+#include <netdb.h>
+#include <limits.h>
+#endif /* !WIN32 */
+
+#include <fcntl.h>
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef ZLIB
+#include <zlib.h>
+#endif
+
+#include "snort.h"
+#include "mstring.h"
+#include "debug.h"
+#include "util.h"
+#include "parser.h"
+#include "inline.h"
+#include "build.h"
+#include "plugbase.h"
+#include "sf_types.h"
+#include "sflsq.h"
+#include "ipv6_port.h"
+
+#include "pcre.h"
+
+#include "mpse.h"
+
+#include "ppm.h"
+
+#ifdef TARGET_BASED
+#include "sftarget_reader.h"
+#endif
+
+#ifdef WIN32
+#include "win32/WIN32-Code/name.h"
+#endif
+
+#include "stream5_common.h"
+
+#ifdef PATH_MAX
+#define PATH_MAX_UTIL PATH_MAX
+#else
+#define PATH_MAX_UTIL 1024
+#endif /* PATH_MAX */
+
+extern Stream5Stats s5stats;
+extern int datalink;
+extern pcap_t *pcap_handle;
+extern PreprocStatsFuncNode *preproc_stats_funcs;
+
+static PcapPktStats pkt_stats;
+
+/*
+ * you may need to adjust this on the systems which don't have standard
+ * paths defined
+ */
+#ifndef _PATH_VARRUN
+static char _PATH_VARRUN[STD_BUF];
+#endif
+
+
+#ifdef NAME_MAX
+#define NAME_MAX_UTIL NAME_MAX
+#else
+#define NAME_MAX_UTIL 256
+#endif /* NAME_MAX */
+
+#define FILE_MAX_UTIL (PATH_MAX_UTIL + NAME_MAX_UTIL)
+
+/****************************************************************************
+ *
+ * Function: CalcPct(uint64_t, uint64_t)
+ *
+ * Purpose: Calculate the percentage of a value compared to a total
+ *
+ * Arguments: cnt => the numerator in the equation
+ * total => the denominator in the calculation
+ *
+ * Returns: pct -> the percentage of cnt to value
+ *
+ ****************************************************************************/
+double CalcPct(uint64_t cnt, uint64_t total)
+{
+ double pct = 0.0;
+
+ if (total == 0.0)
+ {
+ pct = (double)cnt;
+ }
+ else
+ {
+ pct = (double)cnt / (double)total;
+ }
+
+ pct *= 100.0;
+
+ return pct;
+}
+
+
+/****************************************************************************
+ *
+ * Function: DisplayBanner()
+ *
+ * Purpose: Show valuable proggie info
+ *
+ * Arguments: None.
+ *
+ * Returns: 0 all the time
+ *
+ ****************************************************************************/
+int DisplayBanner(void)
+{
+ const char * info;
+ const char * pcre_ver;
+#ifdef ZLIB
+ const char * zlib_ver;
+#endif
+
+ info = getenv("HOSTTYPE");
+ if( !info )
+ {
+ info="";
+ }
+
+ pcre_ver = pcre_version();
+#ifdef ZLIB
+ zlib_ver = zlib_version;
+#endif
+
+ LogMessage("\n");
+ LogMessage(" ,,_ -*> Snort! <*-\n");
+ LogMessage(" o\" )~ Version %s%s%s (Build %s) %s %s\n",
+ VERSION,
+#ifdef SUP_IP6
+ " IPv6",
+#else
+ "",
+#endif
+#ifdef GRE
+ " GRE",
+#else
+ "",
+#endif
+ BUILD,
+#ifdef GIDS
+ "inline",
+#else
+ "",
+#endif
+ info);
+ LogMessage(" '''' By Martin Roesch & The Snort Team: http://www.snort.org/snort/snort-team\n");
+ LogMessage(" Copyright (C) 1998-2010 Sourcefire, Inc., et al.\n");
+ LogMessage(" Using PCRE version: %s\n", pcre_ver);
+#ifdef ZLIB
+ LogMessage(" Using ZLIB version: %s\n", zlib_ver);
+#endif
+ LogMessage("\n");
+ LogMessage(" ___ Built Date for Snort on Pfsense 2.0 is May 25 2010.\n");
+ LogMessage(" ___/ f \\ Orion IPS Output Code Copyright (C) 2009-2010 Robert Zelaya.\n");
+ LogMessage("/ p \\___/Sense\n");
+ LogMessage("\\___/ \\\n");
+ LogMessage(" \\___/ Using Snort.org dynamic plugins and Orion IPS source.\n");
+ LogMessage("\n");
+
+ return 0;
+}
+
+
+
+/****************************************************************************
+ *
+ * Function: ts_print(register const struct, char *)
+ *
+ * Purpose: Generate a time stamp and stuff it in a buffer. This one has
+ * millisecond precision. Oh yeah, I ripped this code off from
+ * TCPdump, props to those guys.
+ *
+ * Arguments: timeval => clock struct coming out of libpcap
+ * timebuf => buffer to stuff timestamp into
+ *
+ * Returns: void function
+ *
+ ****************************************************************************/
+void ts_print(register const struct timeval *tvp, char *timebuf)
+{
+ register int s;
+ int localzone;
+ time_t Time;
+ struct timeval tv;
+ struct timezone tz;
+ struct tm *lt; /* place to stick the adjusted clock data */
+
+ /* if null was passed, we use current time */
+ if(!tvp)
+ {
+ /* manual page (for linux) says tz is never used, so.. */
+ bzero((char *) &tz, sizeof(tz));
+ gettimeofday(&tv, &tz);
+ tvp = &tv;
+ }
+
+ localzone = snort_conf->thiszone;
+
+ /*
+ ** If we're doing UTC, then make sure that the timezone is correct.
+ */
+ if (ScOutputUseUtc())
+ localzone = 0;
+
+ s = (tvp->tv_sec + localzone) % 86400;
+ Time = (tvp->tv_sec + localzone) - s;
+
+ lt = gmtime(&Time);
+
+ if (ScOutputIncludeYear())
+ {
+ (void) SnortSnprintf(timebuf, TIMEBUF_SIZE,
+ "%02d/%02d/%02d-%02d:%02d:%02d.%06u ",
+ lt->tm_mon + 1, lt->tm_mday, lt->tm_year - 100,
+ s / 3600, (s % 3600) / 60, s % 60,
+ (u_int) tvp->tv_usec);
+ }
+ else
+ {
+ (void) SnortSnprintf(timebuf, TIMEBUF_SIZE,
+ "%02d/%02d-%02d:%02d:%02d.%06u ", lt->tm_mon + 1,
+ lt->tm_mday, s / 3600, (s % 3600) / 60, s % 60,
+ (u_int) tvp->tv_usec);
+ }
+}
+
+
+
+/****************************************************************************
+ *
+ * Function: gmt2local(time_t)
+ *
+ * Purpose: Figures out how to adjust the current clock reading based on the
+ * timezone you're in. Ripped off from TCPdump.
+ *
+ * Arguments: time_t => offset from GMT
+ *
+ * Returns: offset seconds from GMT
+ *
+ ****************************************************************************/
+int gmt2local(time_t t)
+{
+ register int dt, dir;
+ register struct tm *gmt, *loc;
+ struct tm sgmt;
+
+ if(t == 0)
+ t = time(NULL);
+
+ gmt = &sgmt;
+ *gmt = *gmtime(&t);
+ loc = localtime(&t);
+
+ dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
+ (loc->tm_min - gmt->tm_min) * 60;
+
+ dir = loc->tm_year - gmt->tm_year;
+
+ if(dir == 0)
+ dir = loc->tm_yday - gmt->tm_yday;
+
+ dt += dir * 24 * 60 * 60;
+
+ return(dt);
+}
+
+
+
+
+/****************************************************************************
+ *
+ * Function: copy_argv(u_char **)
+ *
+ * Purpose: Copies a 2D array (like argv) into a flat string. Stolen from
+ * TCPDump.
+ *
+ * Arguments: argv => 2D array to flatten
+ *
+ * Returns: Pointer to the flat string
+ *
+ ****************************************************************************/
+char *copy_argv(char **argv)
+{
+ char **p;
+ u_int len = 0;
+ char *buf;
+ char *src, *dst;
+ //void ftlerr(char *,...);
+
+ p = argv;
+ if(*p == 0)
+ return 0;
+
+ while(*p)
+ len += strlen(*p++) + 1;
+
+ buf = (char *) calloc(1,len);
+
+ if(buf == NULL)
+ {
+ FatalError("calloc() failed: %s\n", strerror(errno));
+ }
+ p = argv;
+ dst = buf;
+
+ while((src = *p++) != NULL)
+ {
+ while((*dst++ = *src++) != '\0');
+ dst[-1] = ' ';
+ }
+
+ dst[-1] = '\0';
+
+ /* Check for an empty string */
+ dst = buf;
+ while (isspace((int)*dst))
+ dst++;
+
+ if (strlen(dst) == 0)
+ {
+ free(buf);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+
+/****************************************************************************
+ *
+ * Function: strip(char *)
+ *
+ * Purpose: Strips a data buffer of CR/LF/TABs. Replaces CR/LF's with
+ * NULL and TABs with spaces.
+ *
+ * Arguments: data => ptr to the data buf to be stripped
+ *
+ * Returns: void
+ *
+ * 3/7/07 - changed to return void - use strlen to get size of string
+ *
+ * Note that this function will turn all '\n' and '\r' into null chars
+ * so, e.g. 'Hello\nWorld\n' => 'Hello\x00World\x00'
+ * note that the string is now just 'Hello' and the length is shortened
+ * by more than just an ending '\n' or '\r'
+ ****************************************************************************/
+void strip(char *data)
+{
+ int size;
+ char *end;
+ char *idx;
+
+ idx = data;
+ end = data + strlen(data);
+ size = end - idx;
+
+ while(idx != end)
+ {
+ if((*idx == '\n') ||
+ (*idx == '\r'))
+ {
+ *idx = 0;
+ size--;
+ }
+ if(*idx == '\t')
+ {
+ *idx = ' ';
+ }
+ idx++;
+ }
+}
+
+/*
+ * Function: ErrorMessage(const char *, ...)
+ *
+ * Purpose: Print a message to stderr.
+ *
+ * Arguments: format => the formatted error string to print out
+ * ... => format commands/fillers
+ *
+ * Returns: void function
+ */
+void ErrorMessage(const char *format,...)
+{
+ char buf[STD_BUF+1];
+ va_list ap;
+
+ if (snort_conf == NULL)
+ return;
+
+ va_start(ap, format);
+
+ if (ScDaemonMode() || ScLogSyslog())
+ {
+ vsnprintf(buf, STD_BUF, format, ap);
+ buf[STD_BUF] = '\0';
+ syslog(LOG_CONS | LOG_DAEMON | LOG_ERR, "%s", buf);
+ }
+ else
+ {
+ vfprintf(stderr, format, ap);
+ }
+ va_end(ap);
+}
+
+/*
+ * Function: LogMessage(const char *, ...)
+ *
+ * Purpose: Print a message to stderr or with logfacility.
+ *
+ * Arguments: format => the formatted error string to print out
+ * ... => format commands/fillers
+ *
+ * Returns: void function
+ */
+void LogMessage(const char *format,...)
+{
+ char buf[STD_BUF+1];
+ va_list ap;
+
+ if (snort_conf == NULL)
+ return;
+
+ if (ScLogQuiet() && !ScDaemonMode() && !ScLogSyslog())
+ return;
+
+ va_start(ap, format);
+
+ if (ScDaemonMode() || ScLogSyslog())
+ {
+ vsnprintf(buf, STD_BUF, format, ap);
+ buf[STD_BUF] = '\0';
+ syslog(LOG_DAEMON | LOG_NOTICE, "%s", buf);
+ }
+ else
+ {
+ vfprintf(stderr, format, ap);
+ }
+
+ va_end(ap);
+}
+
+/*
+ * Function: CreateApplicationEventLogEntry(const char *)
+ *
+ * Purpose: Add an entry to the Win32 "Application" EventLog
+ *
+ * Arguments: szMessage => the formatted error string to print out
+ *
+ * Returns: void function
+ */
+#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
+void CreateApplicationEventLogEntry(const char *msg)
+{
+ HANDLE hEventLog;
+ char* pEventSourceName = "SnortService";
+
+ /* prepare to write to Application log on local host
+ * with Event Source of SnortService
+ */
+ AddEventSource(pEventSourceName);
+ hEventLog = RegisterEventSource(NULL, pEventSourceName);
+ if (hEventLog == NULL)
+ {
+ /* Could not register the event source. */
+ return;
+ }
+
+ if (!ReportEvent(hEventLog, /* event log handle */
+ EVENTLOG_ERROR_TYPE, /* event type */
+ 0, /* category zero */
+ EVMSG_SIMPLE, /* event identifier */
+ NULL, /* no user security identifier */
+ 1, /* one substitution string */
+ 0, /* no data */
+ &msg, /* pointer to array of strings */
+ NULL)) /* pointer to data */
+ {
+ /* Could not report the event. */
+ }
+
+ DeregisterEventSource(hEventLog);
+}
+#endif /* WIN32 && ENABLE_WIN32_SERVICE */
+
+
+/*
+ * Function: FatalError(const char *, ...)
+ *
+ * Purpose: When a fatal error occurs, this function prints the error message
+ * and cleanly shuts down the program
+ *
+ * Arguments: format => the formatted error string to print out
+ * ... => format commands/fillers
+ *
+ * Returns: void function
+ */
+NORETURN void FatalError(const char *format,...)
+{
+ char buf[STD_BUF+1];
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(buf, STD_BUF, format, ap);
+ va_end(ap);
+
+ buf[STD_BUF] = '\0';
+
+ if ((snort_conf != NULL) && (ScDaemonMode() || ScLogSyslog()))
+ {
+ syslog(LOG_CONS | LOG_DAEMON | LOG_ERR, "FATAL ERROR: %s", buf);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: %s", buf);
+ fprintf(stderr,"Fatal Error, Quitting..\n");
+#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE)
+ CreateApplicationEventLogEntry(buf);
+#endif
+ }
+
+ exit(1);
+}
+
+
+/****************************************************************************
+ *
+ * Function: CreatePidFile(char *)
+ *
+ * Purpose: Creates a PID file
+ *
+ * Arguments: Interface opened.
+ *
+ * Returns: void function
+ *
+ ****************************************************************************/
+static FILE *pid_lockfile = NULL;
+static FILE *pid_file = NULL;
+void CreatePidFile(char *intf)
+{
+ struct stat pt;
+ int pid = (int) getpid();
+#ifdef WIN32
+ char dir[STD_BUF + 1];
+#endif
+
+ if (!ScReadMode())
+ {
+ LogMessage("Checking PID path...\n");
+
+ if (strlen(snort_conf->pid_path) != 0)
+ {
+ if((stat(snort_conf->pid_path, &pt) == -1) ||
+ !S_ISDIR(pt.st_mode) || access(snort_conf->pid_path, W_OK) == -1)
+ {
+#ifndef WIN32
+ /* Save this just in case it's reset with LogMessage call */
+ int err = errno;
+
+ LogMessage("WARNING: %s is invalid, trying "
+ "/var/run...\n", snort_conf->pid_path);
+ if (err)
+ {
+ LogMessage("Previous Error, errno=%d, (%s)\n",
+ err, strerror(err) == NULL ? "Unknown error" : strerror(err));
+ }
+#endif
+ memset(snort_conf->pid_path, 0, sizeof(snort_conf->pid_path));
+ }
+ else
+ {
+ LogMessage("PID path stat checked out ok, "
+ "PID path set to %s\n", snort_conf->pid_path);
+ }
+ }
+
+ if (strlen(snort_conf->pid_path) == 0)
+ {
+#ifndef _PATH_VARRUN
+# ifndef WIN32
+ SnortStrncpy(_PATH_VARRUN, "/var/run/", sizeof(_PATH_VARRUN));
+# else
+ if (GetCurrentDirectory(sizeof(dir) - 1, dir))
+ SnortStrncpy(_PATH_VARRUN, dir, sizeof(_PATH_VARRUN));
+# endif /* WIN32 */
+#else
+ LogMessage("PATH_VARRUN is set to %s on this operating "
+ "system\n", _PATH_VARRUN);
+#endif /* _PATH_VARRUN */
+
+ stat(_PATH_VARRUN, &pt);
+
+ if(!S_ISDIR(pt.st_mode) || access(_PATH_VARRUN, W_OK) == -1)
+ {
+ LogMessage("WARNING: _PATH_VARRUN is invalid, trying "
+ "/var/log...\n");
+ SnortStrncpy(snort_conf->pid_path, "/var/log/", sizeof(snort_conf->pid_path));
+ stat(snort_conf->pid_path, &pt);
+
+ if(!S_ISDIR(pt.st_mode) || access(snort_conf->pid_path, W_OK) == -1)
+ {
+ LogMessage("WARNING: %s is invalid, logging Snort "
+ "PID path to log directory (%s)\n", snort_conf->pid_path,
+ snort_conf->log_dir);
+ CheckLogDir();
+ SnortSnprintf(snort_conf->pid_path, sizeof(snort_conf->pid_path),
+ "%s/", snort_conf->log_dir);
+ }
+ }
+ else
+ {
+ LogMessage("PID path stat checked out ok, "
+ "PID path set to %s\n", _PATH_VARRUN);
+ SnortStrncpy(snort_conf->pid_path, _PATH_VARRUN, sizeof(snort_conf->pid_path));
+ }
+ }
+ }
+
+ if(intf == NULL || strlen(snort_conf->pid_path) == 0)
+ {
+ /* snort_conf->pid_path should have some value by now
+ * so let us just be sane. */
+ FatalError("CreatePidFile() failed to lookup interface or pid_path is unknown!\n");
+ }
+
+ SnortSnprintf(snort_conf->pid_filename, sizeof(snort_conf->pid_filename),
+ "%s/snort_%s%s.pid", snort_conf->pid_path, intf, snort_conf->pidfile_suffix);
+
+#ifndef WIN32
+ if (!ScNoLockPidFile())
+ {
+ char pid_lockfilename[STD_BUF+1];
+ int lock_fd;
+
+ /* First, lock the PID file */
+ SnortSnprintf(pid_lockfilename, STD_BUF, "%s.lck", snort_conf->pid_filename);
+ pid_lockfile = fopen(pid_lockfilename, "w");
+
+ if (pid_lockfile)
+ {
+ struct flock lock;
+ lock_fd = fileno(pid_lockfile);
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+
+ if (fcntl(lock_fd, F_SETLK, &lock) == -1)
+ {
+ ClosePidFile();
+ FatalError("Failed to Lock PID File \"%s\" for PID \"%d\"\n", snort_conf->pid_filename, pid);
+ }
+ }
+ }
+#endif
+
+ /* Okay, were able to lock PID file, now open and write PID */
+ pid_file = fopen(snort_conf->pid_filename, "w");
+ if(pid_file)
+ {
+ LogMessage("Writing PID \"%d\" to file \"%s\"\n", pid, snort_conf->pid_filename);
+ fprintf(pid_file, "%d\n", pid);
+ fflush(pid_file);
+ }
+ else
+ {
+ ErrorMessage("Failed to create pid file %s", snort_conf->pid_filename);
+ snort_conf->pid_filename[0] = 0;
+ }
+}
+
+/****************************************************************************
+ *
+ * Function: ClosePidFile(char *)
+ *
+ * Purpose: Releases lock on a PID file
+ *
+ * Arguments: None
+ *
+ * Returns: void function
+ *
+ ****************************************************************************/
+void ClosePidFile(void)
+{
+ if (pid_file)
+ {
+ fclose(pid_file);
+ pid_file = NULL;
+ }
+ if (pid_lockfile)
+ {
+ fclose(pid_lockfile);
+ pid_lockfile = NULL;
+ }
+}
+
+/****************************************************************************
+ *
+ * Function: SetUidGid()
+ *
+ * Purpose: Sets safe UserID and GroupID if needed
+ *
+ * Arguments: none
+ *
+ * Returns: void function
+ *
+ ****************************************************************************/
+void SetUidGid(int user_id, int group_id)
+{
+#ifndef WIN32
+
+ if ((group_id != -1) && (getgid() != (gid_t)group_id))
+ {
+ if (!InlineModeSetPrivsAllowed())
+ {
+ ErrorMessage("Cannot set uid and gid when running Snort in "
+ "inline mode.\n");
+ return;
+ }
+
+ if (setgid(group_id) < 0)
+ FatalError("Cannot set gid: %d\n", group_id);
+
+ DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Set gid to %d\n", group_id););
+ }
+
+ if ((user_id != -1) && (getuid() != (uid_t)user_id))
+ {
+ struct passwd *pw = getpwuid(user_id);
+
+ if (!InlineModeSetPrivsAllowed())
+ {
+ ErrorMessage("Cannot set uid and gid when running Snort in "
+ "inline mode.\n");
+ return;
+ }
+
+ if (pw != NULL)
+ {
+ /* getpwuid and initgroups may use the same static buffers */
+ char *username = SnortStrdup(pw->pw_name);
+
+ if ((getuid() == 0) && (initgroups(username, group_id) < 0))
+ {
+ free(username);
+ FatalError("Can not initgroups(%s,%d)",
+ username, group_id);
+ }
+
+ free(username);
+ }
+
+ /** just to be on a safe side... **/
+ endgrent();
+ endpwent();
+
+ if (setuid(user_id) < 0)
+ FatalError("Can not set uid: %d\n", user_id);
+
+ DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Set uid to %d\n", user_id););
+ }
+#endif /* WIN32 */
+}
+
+#ifdef TIMESTATS
+
+static IntervalStats istats = {0};
+time_t start_time;
+
+void InitTimeStats(void)
+{
+ start_time = time(NULL);
+}
+
+void ResetTimeStats(void)
+{
+ memset(&istats, 0, sizeof(istats));
+}
+
+/* This function prints out stats based on a configurable time
+ * interval. It is an indication on how well snort is */
+/* processing packets, including types, drops, etc */
+void DropStatsPerTimeInterval(void)
+{
+ double per_sec, per_minute, per_hour;
+ uint64_t recv, drop;
+ uint64_t total = 0;
+ uint32_t timestats_interval = ScTimestatsInterval();
+
+#ifdef PCAP_CLOSE
+ if (UpdatePcapPktStats(0) != -1)
+#else
+ if (UpdatePcapPktStats() != -1)
+#endif
+ {
+ recv = GetPcapPktStatsRecv();
+ drop = GetPcapPktStatsDrop();
+
+ istats.recv = recv - istats.recv_total;
+ istats.recv_total = recv;
+
+ istats.drop = drop - istats.drop_total;
+ istats.drop_total = drop;
+
+ /* calculate received packets by type */
+ istats.tcp = pc.tcp - istats.tcp_total;
+ istats.tcp_total = pc.tcp;
+
+ istats.udp = pc.udp - istats.udp_total;
+ istats.udp_total = pc.udp;
+
+ istats.icmp = pc.icmp - istats.icmp_total;
+ istats.icmp_total = pc.icmp;
+
+ istats.arp = pc.arp - istats.arp_total;
+ istats.arp_total = pc.arp;
+
+#ifdef GRE
+ istats.ip4ip4 = pc.ip4ip4 - istats.ip4ip4_total;
+ istats.ip4ip4_total = pc.ip4ip4;
+
+ istats.ip4ip6 = pc.ip4ip6 - istats.ip4ip6_total;
+ istats.ip4ip6_total = pc.ip4ip6;
+
+ istats.ip6ip4 = pc.ip6ip4 - istats.ip6ip4_total;
+ istats.ip6ip4_total = pc.ip6ip4;
+
+ istats.ip6ip6 = pc.ip6ip6 - istats.ip6ip6_total;
+ istats.ip6ip6_total = pc.ip6ip6;
+
+ istats.gre = pc.gre - istats.gre_total;
+ istats.gre_total = pc.gre;
+
+ istats.gre_ip = pc.gre_ip - istats.gre_ip_total;
+ istats.gre_ip_total = pc.gre_ip;
+
+ istats.gre_eth = pc.gre_eth - istats.gre_eth_total;
+ istats.gre_eth_total = pc.gre_eth;
+
+ istats.gre_arp = pc.gre_arp - istats.gre_arp_total;
+ istats.gre_arp_total = pc.gre_arp;
+
+ istats.gre_ipv6 = pc.gre_ipv6 - istats.gre_ipv6_total;
+ istats.gre_ipv6_total = pc.gre_ipv6;
+
+ istats.gre_ipx = pc.gre_ipx - istats.gre_ipx_total;
+ istats.gre_ipx_total = pc.gre_ipx;
+
+ istats.gre_loopback = pc.gre_loopback - istats.gre_loopback_total;
+ istats.gre_loopback_total = pc.gre_loopback;
+
+ istats.gre_vlan = pc.gre_vlan - istats.gre_vlan_total;
+ istats.gre_vlan_total = pc.gre_vlan;
+
+ istats.gre_ppp = pc.gre_ppp - istats.gre_ppp_total;
+ istats.gre_ppp_total = pc.gre_ppp;
+#endif
+
+#ifdef DLT_IEEE802_11 /* if we are tracking wireless, add this to output */
+ istats.wifi_mgmt = pc.wifi_mgmt - istats.wifi_mgmt_total;
+ istats.wifi_mgmt_total = pc.wifi_mgmt;
+
+ istats.wifi_control = pc.wifi_control - istats.wifi_control_total;
+ istats.wifi_control_total = pc.wifi_control;
+
+ istats.wifi_data = pc.wifi_data - istats.wifi_data_total;
+ istats.wifi_data_total = pc.wifi_data;
+#endif
+
+ istats.ipx = pc.ipx - istats.ipx_total;
+ istats.ipx_total = pc.ipx;
+
+ istats.eapol = pc.eapol - istats.eapol_total;
+ istats.eapol_total = pc.eapol;
+
+ istats.ipv6 = pc.ipv6 - istats.ipv6_total;
+ istats.ipv6_total = pc.ipv6;
+
+ istats.ethloopback = pc.ethloopback - istats.ethloopback_total;
+ istats.ethloopback_total = pc.ethloopback;
+
+ istats.other = pc.other - istats.other_total;
+ istats.other_total = pc.other;
+
+ istats.discards = pc.discards - istats.discards_total;
+ istats.discards_total = pc.discards;
+
+ if (pc.frags > 0) /* do we have any fragmented packets being seen? */
+ {
+ istats.frags = pc.frags - istats.frags_total;
+ istats.frags_total = pc.frags;
+
+ istats.frag_trackers = pc.frag_trackers - istats.frag_trackers_total;
+ istats.frag_trackers_total = pc.frag_trackers;
+
+ istats.frag_rebuilt = pc.rebuilt_frags - istats.frag_rebuilt_total;
+ istats.frag_rebuilt_total = pc.rebuilt_frags;
+
+ istats.frag_element = pc.rebuild_element - istats.frag_element_total;
+ istats.frag_element_total = pc.rebuild_element;
+
+ istats.frag_incomp = pc.frag_incomp - istats.frag_incomp_total;
+ istats.frag_incomp_total = pc.frag_incomp;
+
+ istats.frag_timeout = pc.frag_timeout - istats.frag_timeout_total;
+ istats.frag_timeout_total = pc.frag_timeout;
+
+ istats.frag_mem_faults = pc.frag_mem_faults - istats.frag_mem_faults_total;
+ istats.frag_mem_faults_total = pc.frag_mem_faults;
+ }
+
+ if (pc.tcp_stream_pkts > 0) /* do we have TCP stream re-assembly going on? */
+ {
+ istats.tcp_str_packets = pc.tcp_stream_pkts - istats.tcp_str_packets_total;
+ istats.tcp_str_packets_total = pc.tcp_stream_pkts;
+
+ istats.tcp_str_trackers = pc.tcp_streams - istats.tcp_str_trackers_total;
+ istats.tcp_str_trackers_total = pc.tcp_streams;
+
+ istats.tcp_str_flushes = pc.rebuilt_tcp - istats.tcp_str_flushes_total;
+ istats.tcp_str_flushes_total = pc.rebuilt_tcp;
+
+ istats.tcp_str_segs_used = pc.rebuilt_segs - istats.tcp_str_segs_used_total;
+ istats.tcp_str_segs_used_total = pc.rebuilt_segs;
+
+ istats.tcp_str_segs_queued = pc.queued_segs - istats.tcp_str_segs_queued_total;
+ istats.tcp_str_segs_queued_total = pc.queued_segs;
+
+ istats.tcp_str_mem_faults = pc.str_mem_faults - istats.tcp_str_mem_faults_total;
+ istats.tcp_str_mem_faults_total = pc.str_mem_faults;
+ }
+
+ istats.processed = pc.total_processed - istats.processed_total;
+ istats.processed_total = pc.total_processed;
+ total = istats.processed;
+
+ /* prepare packet type per time interval routine */
+ LogMessage("================================================"
+ "===============================\n");
+
+ LogMessage("\n");
+ LogMessage("Statistics Report (last %d seconds)\n", timestats_interval);
+ LogMessage("\n");
+
+ per_sec = (double)istats.recv / (double)timestats_interval;
+
+ LogMessage("Packet Wire Totals:\n");
+ LogMessage("Packets received: " FMTu64("13") "\n", istats.recv);
+
+ if (timestats_interval >= SECONDS_PER_HOUR)
+ {
+ per_hour = (double)(istats.recv * SECONDS_PER_HOUR) / (double)timestats_interval;
+ LogMessage(" per hour: %13.2f\n", per_hour);
+ }
+ if (timestats_interval >= SECONDS_PER_MIN)
+ {
+ per_minute = (double)(istats.recv * SECONDS_PER_MIN) / (double)timestats_interval;
+ LogMessage(" per minute: %13.2f\n", per_minute);
+ }
+ LogMessage(" per second: %13.2f\n", per_sec);
+ LogMessage(" Packets dropped: " FMTu64("13") "\n", istats.drop);
+ LogMessage("\n");
+ LogMessage("Packet Breakdown by Protocol (includes rebuilt packets):\n");
+
+ LogMessage(" TCP: " FMTu64("10") " (%.3f%%)\n",
+ istats.tcp, CalcPct(istats.tcp, total));
+ LogMessage(" UDP: " FMTu64("10") " (%.3f%%)\n",
+ istats.udp, CalcPct(istats.udp, total));
+ LogMessage(" ICMP: " FMTu64("10") " (%.3f%%)\n",
+ istats.icmp, CalcPct(istats.icmp, total));
+ LogMessage(" ARP: " FMTu64("10") " (%.3f%%)\n",
+ istats.arp, CalcPct(istats.arp, total));
+#ifndef NO_NON_ETHER_DECODER
+ LogMessage(" EAPOL: " FMTu64("10") " (%.3f%%)\n",
+ istats.eapol, CalcPct(istats.eapol, total));
+#endif
+ LogMessage(" IPv6: " FMTu64("10") " (%.3f%%)\n",
+ istats.ipv6, CalcPct(istats.ipv6, total));
+ LogMessage(" ETHLOOP: " FMTu64("10") " (%.3f%%)\n",
+ istats.ethloopback, CalcPct(istats.ethloopback, total));
+ LogMessage(" IPX: " FMTu64("10") " (%.3f%%)\n",
+ istats.ipx, CalcPct(istats.ipx, total));
+
+#ifdef GRE
+ LogMessage(" IP4/IP4: " FMTu64("-10") " (%.3f%%)\n",
+ istats.ip4ip4, CalcPct(istats.ip4ip4, total));
+ LogMessage(" IP4/IP6: " FMTu64("-10") " (%.3f%%)\n",
+ istats.ip4ip6, CalcPct(istats.ip4ip6, total));
+ LogMessage(" IP6/IP4: " FMTu64("-10") " (%.3f%%)\n",
+ istats.ip6ip4, CalcPct(istats.ip6ip4, total));
+ LogMessage(" IP6/IP6: " FMTu64("-10") " (%.3f%%)\n",
+ istats.ip6ip6, CalcPct(istats.ip6ip6, total));
+ LogMessage(" GRE: " FMTu64("10") " (%.3f%%)\n",
+ istats.gre, CalcPct(istats.gre, total));
+ LogMessage(" GRE ETH: " FMTu64("-10") " (%.3f%%)\n",
+ istats.gre_eth, CalcPct(istats.gre_eth, total));
+ LogMessage("GRE VLAN: " FMTu64("-10") " (%.3f%%)\n",
+ istats.gre_vlan, CalcPct(istats.gre_vlan, total));
+ LogMessage(" GRE IP: " FMTu64("-10") " (%.3f%%)\n",
+ istats.gre_ip, CalcPct(istats.gre_ip, total));
+ LogMessage("GRE IPv6: " FMTu64("-10") " (%.3f%%)\n",
+ istats.gre_ipv6, CalcPct(istats.gre_ipv6, total));
+ LogMessage("GRE PPTP: " FMTu64("-10") " (%.3f%%)\n",
+ istats.gre_ppp, CalcPct(istats.gre_ppp, total));
+ LogMessage(" GRE ARP: " FMTu64("-10") " (%.3f%%)\n",
+ istats.gre_arp, CalcPct(istats.gre_arp, total));
+ LogMessage(" GRE IPX: " FMTu64("-10") " (%.3f%%)\n",
+ istats.gre_ipx, CalcPct(istats.gre_ipx, total));
+ LogMessage("GRE LOOP: " FMTu64("-10") " (%.3f%%)\n",
+ istats.gre_loopback, CalcPct(istats.gre_loopback, total));
+#endif
+
+ LogMessage(" FRAG: " FMTu64("10") " (%.3f%%)\n",
+ istats.frags, CalcPct(istats.frags, total));
+ LogMessage(" OTHER: " FMTu64("10") " (%.3f%%)\n",
+ istats.other, CalcPct(istats.other, total));
+ LogMessage(" DISCARD: " FMTu64("10") " (%.3f%%)\n",
+ istats.discards, CalcPct(istats.discards, total));
+ LogMessage(" Total: " FMTu64("10") "\n", total);
+
+ LogMessage("\n");
+
+
+ /* handle case where wireless is enabled... */
+
+#ifndef NO_NON_ETHER_DECODER
+#ifdef DLT_IEEE802_11
+ if (datalink == DLT_IEEE802_11)
+ {
+ LogMessage("\n");
+ LogMessage("Wireless Stats:\n\n");
+ LogMessage("Management Packets: " FMTu64("10") " (%.3f%%)\n",
+ istats.wifi_mgmt, CalcPct(istats.wifi_mgmt, total));
+ LogMessage(" Control Packets: " FMTu64("10") " (%.3f%%)\n",
+ istats.wifi_control, CalcPct(istats.wifi_control, total));
+ LogMessage(" Data Packets: " FMTu64("10") " (%.3f%%)\n",
+ istats.wifi_data, CalcPct(istats.wifi_data, total));
+ LogMessage("\n");
+ }
+
+#endif /* if wireless is enabled... */
+#endif // NO_NON_ETHER_DECODER
+
+ /* handle case where we have snort seeing fragmented packets */
+
+ if (pc.frags > 0) /* begin if (pc.frags > 0) */
+ {
+ LogMessage("\n");
+ LogMessage("Fragmentation Stats:\n\n");
+ LogMessage("Fragmented IP Packets: " FMTu64("10") "\n", istats.frags);
+ LogMessage(" Fragment Trackers: " FMTu64("10") "\n", istats.frag_trackers);
+ LogMessage(" Rebuilt IP Packets: " FMTu64("10") "\n", istats.frag_rebuilt);
+ LogMessage(" Frag Elements Used: " FMTu64("10") "\n", istats.frag_element);
+ LogMessage("Discarded(incomplete): " FMTu64("10") "\n", istats.frag_incomp);
+ LogMessage(" Discarded(timeout): " FMTu64("10") "\n", istats.frag_timeout);
+ LogMessage(" Frag2 memory faults: " FMTu64("10") "\n", istats.frag_mem_faults);
+ LogMessage("\n");
+ } /* end if (pc.frags > 0) */
+
+ /* handle TCP stream re-assy stuff here */
+
+ if (pc.tcp_stream_pkts > 0)
+ {
+ LogMessage("\n");
+ LogMessage("TCP Stream Reassembly Stats:\n\n");
+ LogMessage(" TCP Packets Used: " FMTu64("10") "\n", istats.tcp_str_packets);
+ LogMessage(" Stream Trackers: " FMTu64("10") "\n", istats.tcp_str_trackers);
+ LogMessage(" Stream Flushes: " FMTu64("10") "\n", istats.tcp_str_flushes);
+ LogMessage(" Stream Segments Used: " FMTu64("10") "\n", istats.tcp_str_segs_used);
+ LogMessage("Stream Segments Queued: " FMTu64("10") "\n", istats.tcp_str_segs_queued);
+ LogMessage(" Stream4 Memory Faults: " FMTu64("10") "\n", istats.tcp_str_mem_faults);
+ LogMessage("\n");
+ }
+
+ //mpse_print_qinfo();
+
+ } /* end if pcap_stats(ps, &ps) */
+
+ alarm(timestats_interval); /* reset the alarm to go off again */
+}
+
+/* print out stats on how long snort ran */
+void TimeStats(void)
+{
+
+/*
+ * variable definitions for improved statistics handling
+ *
+ * end_time = time which snort finished running (unix epoch)
+ * total_secs = total amount of time snort ran
+ * int_total_secs = used to eliminate casts from this function (temp. var)
+ * days = number of days snort ran
+ * hrs = number of hrs snort ran
+ * mins = number of minutes snort ran
+ * secs = number of seconds snort ran
+ *
+ * ival = temp. variable for integer/modulus math
+ * ppd = packets per day processed
+ * pph = packets per hour processed
+ * ppm = packets per minute processed
+ * pps = packets per second processed
+ *
+ * hflag = used to flag when hrs = zero, but days > 0
+ * mflag = used to flag when min = zero, but hrs > 0
+ *
+ */
+
+ time_t end_time, total_secs;
+ uint32_t days = 0, hrs = 0, mins = 0, secs = 0, tmp = 0;
+ uint64_t pps = 0, ppm = 0, pph = 0, ppd = 0;
+ uint32_t int_total_secs = 0;
+ char hflag = 0, mflag = 0;
+
+
+ end_time = time(NULL); /* grab epoch for end time value (in seconds) */
+ total_secs = end_time - start_time; /* total_secs is how many seconds snort ran for */
+
+ tmp = (uint32_t)total_secs;
+ int_total_secs = tmp; /* used for cast elimination */
+
+ days = tmp / SECONDS_PER_DAY; /* 86400 is number of seconds in a day */
+ tmp = tmp % SECONDS_PER_DAY; /* grab remainder to process hours */
+ hrs = tmp / SECONDS_PER_HOUR; /* 3600 is number of seconds in a(n) hour */
+ tmp = tmp % SECONDS_PER_HOUR; /* grab remainder to process minutes */
+ mins = tmp / SECONDS_PER_MIN; /* 60 is number of seconds in a minute */
+ secs = tmp % SECONDS_PER_MIN; /* grab remainder to process seconds */
+
+ if (total_secs)
+ pps = (pc.total_from_pcap / int_total_secs);
+ else
+ pps = pc.total_from_pcap; /* guard against division by zero */
+
+ /* Use ErrorMessage because this is logged whether
+ * or not logging quietly */
+ ErrorMessage("Snort ran for %u Days %u Hours %u Minutes %u Seconds\n",
+ days, hrs, mins, secs);
+
+ if (days > 0)
+ {
+ ppd = (pc.total_from_pcap / (int_total_secs / SECONDS_PER_DAY));
+ ErrorMessage("Snort Analyzed " STDu64 " Packets Per Day\n", ppd);
+ hflag = 1;
+ }
+
+ if (hrs > 0 || hflag == 1)
+ {
+ pph = (pc.total_from_pcap / (int_total_secs / SECONDS_PER_HOUR));
+ ErrorMessage("Snort Analyzed " STDu64 " Packets Per Hour\n", pph);
+ mflag = 1;
+ }
+
+ if (mins > 0 || mflag == 1)
+ {
+ ppm = (pc.total_from_pcap / (int_total_secs / SECONDS_PER_MIN));
+ ErrorMessage("Snort Analyzed " STDu64 " Packets Per Minute\n", ppm);
+ }
+
+ ErrorMessage("Snort Analyzed " STDu64 " Packets Per Second\n", pps);
+ ErrorMessage("\n");
+}
+#endif /* TIMESTATS */
+
+
+#ifdef PCAP_CLOSE
+int UpdatePcapPktStats(int cacheReturn)
+#else
+int UpdatePcapPktStats(void)
+#endif
+{
+ struct pcap_stat ps;
+ uint32_t recv, drop;
+ static char not_initialized = 1;
+
+#ifdef PCAP_CLOSE
+ static int priorReturn = 0;
+ static int returnWasCached = 0;
+
+ if ( !cacheReturn && returnWasCached )
+ {
+ returnWasCached = 0;
+ return priorReturn;
+ }
+ priorReturn = -1;
+ returnWasCached = cacheReturn;
+#endif
+
+ if (not_initialized)
+ {
+ memset(&pkt_stats, 0, sizeof(PcapPktStats));
+ not_initialized = 0;
+ }
+
+ if ((pcap_handle == NULL) || ScReadMode())
+ return -1;
+
+ if (pcap_stats(pcap_handle, &ps) == -1)
+ {
+ pcap_perror(pcap_handle, "pcap_stats");
+ return -1;
+ }
+
+ recv = (uint32_t)ps.ps_recv;
+ drop = (uint32_t)ps.ps_drop;
+
+#ifdef LINUX_LIBPCAP_DOUBLES_STATS
+ recv /= 2;
+ drop /= 2;
+#endif
+
+#ifdef LIBPCAP_ACCUMULATES
+ /* pcap recv wrapped */
+ if (recv < pkt_stats.wrap_recv)
+ pkt_stats.recv += (uint64_t)UINT32_MAX;
+
+ /* pcap drop wrapped */
+ if (drop < pkt_stats.wrap_drop)
+ pkt_stats.drop += (uint64_t)UINT32_MAX;
+
+ pkt_stats.wrap_recv = recv;
+ pkt_stats.wrap_drop = drop;
+#else
+ pkt_stats.recv += (uint64_t)recv;
+ pkt_stats.drop += (uint64_t)drop;
+#endif /* LIBPCAP_ACCUMULATES */
+
+#ifdef PCAP_CLOSE
+ priorReturn = 0;
+#endif
+ return 0;
+}
+
+uint64_t GetPcapPktStatsRecv(void)
+{
+ return pkt_stats.recv + (uint64_t)pkt_stats.wrap_recv;
+}
+
+uint64_t GetPcapPktStatsDrop(void)
+{
+ return pkt_stats.drop + (uint64_t)pkt_stats.wrap_drop;
+}
+
+
+#ifdef PCAP_CLOSE
+/* exiting should be 0 for if not exiting, 1 if restarting, and 2 if exiting */
+#else
+/* exiting should be 0 for if not exiting and 1 if exiting */
+#endif
+void DropStats(int exiting)
+{
+ PreprocStatsFuncNode *idx;
+ uint64_t total = 0;
+ uint64_t pkts_recv;
+ uint64_t pkts_drop;
+
+ total = pc.total_processed;
+
+#ifdef PPM_MGR
+ PPM_PRINT_SUMMARY(&snort_conf->ppm_cfg);
+#endif
+
+ LogMessage("================================================"
+ "===============================\n");
+
+#ifdef TIMESTATS
+ TimeStats(); /* how long did snort run? */
+#endif
+
+ if (ScReadMode()
+#ifdef GIDS
+ || ScAdapterInlineMode()
+#endif
+ )
+ {
+ LogMessage("Snort processed " STDu64 " packets.\n", total);
+ }
+ else
+ {
+#ifdef PCAP_CLOSE
+ if (exiting < 2 && (pcap_handle == NULL))
+#else
+ if (pcap_handle == NULL)
+#endif
+ {
+ LogMessage("Snort received 0 packets\n");
+ }
+ else
+ {
+#ifdef PCAP_CLOSE
+ if (UpdatePcapPktStats(0) != -1)
+#else
+ if (UpdatePcapPktStats() != -1)
+#endif
+ {
+ pkts_recv = GetPcapPktStatsRecv();
+ pkts_drop = GetPcapPktStatsDrop();
+
+ LogMessage("Packet Wire Totals:\n");
+ LogMessage(" Received: " FMTu64("12") "\n", pkts_recv);
+ LogMessage(" Analyzed: " FMTu64("12") " (%.3f%%)\n", pc.total_from_pcap,
+ CalcPct(pc.total_from_pcap, pkts_recv));
+ LogMessage(" Dropped: " FMTu64("12") " (%.3f%%)\n", pkts_drop,
+ CalcPct(pkts_drop, pkts_recv));
+ LogMessage("Outstanding: " FMTu64("12") " (%.3f%%)\n",
+ pkts_recv - pkts_drop - pc.total_from_pcap,
+ CalcPct((pkts_recv - pkts_drop - pc.total_from_pcap), pkts_recv));
+ }
+ else
+ {
+ LogMessage("Unable to calculate percentages for stats\n");
+ LogMessage("Total number of packets Analyzed: " FMTu64("12") "\n", pc.total_from_pcap);
+ }
+ }
+ }
+
+ LogMessage("================================================"
+ "===============================\n");
+
+ LogMessage("Breakdown by protocol (includes rebuilt packets):\n");
+
+ LogMessage(" ETH: " FMTu64("-10") " (%.3f%%)\n",
+ pc.eth, CalcPct(pc.eth, total));
+ LogMessage(" ETHdisc: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ethdisc, CalcPct(pc.ethdisc, total));
+#ifdef GIDS
+#ifndef IPFW
+ LogMessage(" IPTables: " FMTu64("-10") " (%.3f%%)\n",
+ pc.iptables, CalcPct(pc.iptables, total));
+#else
+ LogMessage(" IPFW: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ipfw, CalcPct(pc.ipfw, total));
+#endif /* IPFW */
+#endif /* GIDS */
+ LogMessage(" VLAN: " FMTu64("-10") " (%.3f%%)\n",
+ pc.vlan, CalcPct(pc.vlan, total));
+
+ if (pc.nested_vlan != 0)
+ LogMessage("Nested VLAN: " FMTu64("-10") " (%.3f%%)\n",
+ pc.nested_vlan, CalcPct(pc.nested_vlan, total));
+
+ LogMessage(" IPV6: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ipv6, CalcPct(pc.ipv6, total));
+ LogMessage(" IP6 EXT: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ip6ext, CalcPct(pc.ip6ext, total));
+ LogMessage(" IP6opts: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ipv6opts, CalcPct(pc.ipv6opts, total));
+ LogMessage(" IP6disc: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ipv6disc, CalcPct(pc.ipv6disc, total));
+
+ LogMessage(" IP4: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ip, CalcPct(pc.ip, total));
+ LogMessage(" IP4disc: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ipdisc, CalcPct(pc.ipdisc, total));
+
+ LogMessage(" TCP 6: " FMTu64("-10") " (%.3f%%)\n",
+ pc.tcp6, CalcPct(pc.tcp6, total));
+ LogMessage(" UDP 6: " FMTu64("-10") " (%.3f%%)\n",
+ pc.udp6, CalcPct(pc.udp6, total));
+ LogMessage(" ICMP6: " FMTu64("-10") " (%.3f%%)\n",
+ pc.icmp6, CalcPct(pc.icmp6, total));
+ LogMessage(" ICMP-IP: " FMTu64("-10") " (%.3f%%)\n",
+ pc.embdip, CalcPct(pc.embdip, total));
+
+ LogMessage(" TCP: " FMTu64("-10") " (%.3f%%)\n",
+ pc.tcp, CalcPct(pc.tcp, total));
+ LogMessage(" UDP: " FMTu64("-10") " (%.3f%%)\n",
+ pc.udp, CalcPct(pc.udp, total));
+ LogMessage(" ICMP: " FMTu64("-10") " (%.3f%%)\n",
+ pc.icmp, CalcPct(pc.icmp, total));
+
+ LogMessage(" TCPdisc: " FMTu64("-10") " (%.3f%%)\n",
+ pc.tdisc, CalcPct(pc.tdisc, total));
+ LogMessage(" UDPdisc: " FMTu64("-10") " (%.3f%%)\n",
+ pc.udisc, CalcPct(pc.udisc, total));
+ LogMessage(" ICMPdis: " FMTu64("-10") " (%.3f%%)\n",
+ pc.icmpdisc, CalcPct(pc.icmpdisc, total));
+
+ LogMessage(" FRAG: " FMTu64("-10") " (%.3f%%)\n",
+ pc.frags, CalcPct(pc.frags, total));
+ LogMessage(" FRAG 6: " FMTu64("-10") " (%.3f%%)\n",
+ pc.frag6, CalcPct(pc.frag6, total));
+
+ LogMessage(" ARP: " FMTu64("-10") " (%.3f%%)\n",
+ pc.arp, CalcPct(pc.arp, total));
+#ifndef NO_NON_ETHER_DECODER
+ LogMessage(" EAPOL: " FMTu64("-10") " (%.3f%%)\n",
+ pc.eapol, CalcPct(pc.eapol, total));
+#endif
+ LogMessage(" ETHLOOP: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ethloopback, CalcPct(pc.ethloopback, total));
+ LogMessage(" IPX: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ipx, CalcPct(pc.ipx, total));
+#ifdef GRE
+ LogMessage("IPv4/IPv4: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ip4ip4, CalcPct(pc.ip4ip4, total));
+ LogMessage("IPv4/IPv6: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ip4ip6, CalcPct(pc.ip4ip6, total));
+ LogMessage("IPv6/IPv4: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ip6ip4, CalcPct(pc.ip6ip4, total));
+ LogMessage("IPv6/IPv6: " FMTu64("-10") " (%.3f%%)\n",
+ pc.ip6ip6, CalcPct(pc.ip6ip6, total));
+ LogMessage(" GRE: " FMTu64("-10") " (%.3f%%)\n",
+ pc.gre, CalcPct(pc.gre, total));
+ LogMessage(" GRE ETH: " FMTu64("-10") " (%.3f%%)\n",
+ pc.gre_eth, CalcPct(pc.gre_eth, total));
+ LogMessage(" GRE VLAN: " FMTu64("-10") " (%.3f%%)\n",
+ pc.gre_vlan, CalcPct(pc.gre_vlan, total));
+ LogMessage(" GRE IPv4: " FMTu64("-10") " (%.3f%%)\n",
+ pc.gre_ip, CalcPct(pc.gre_ip, total));
+ LogMessage(" GRE IPv6: " FMTu64("-10") " (%.3f%%)\n",
+ pc.gre_ipv6, CalcPct(pc.gre_ipv6, total));
+ LogMessage("GRE IP6 E: " FMTu64("-10") " (%.3f%%)\n",
+ pc.gre_ipv6ext, CalcPct(pc.gre_ipv6ext, total));
+ LogMessage(" GRE PPTP: " FMTu64("-10") " (%.3f%%)\n",
+ pc.gre_ppp, CalcPct(pc.gre_ppp, total));
+ LogMessage(" GRE ARP: " FMTu64("-10") " (%.3f%%)\n",
+ pc.gre_arp, CalcPct(pc.gre_arp, total));
+ LogMessage(" GRE IPX: " FMTu64("-10") " (%.3f%%)\n",
+ pc.gre_ipx, CalcPct(pc.gre_ipx, total));
+ LogMessage(" GRE LOOP: " FMTu64("-10") " (%.3f%%)\n",
+ pc.gre_loopback, CalcPct(pc.gre_loopback, total));
+#endif /* GRE */
+#ifdef MPLS
+ LogMessage(" MPLS: " FMTu64("-10") " (%.3f%%)\n",
+ pc.mpls, CalcPct(pc.mpls, total));
+#endif
+ LogMessage(" OTHER: " FMTu64("-10") " (%.3f%%)\n",
+ pc.other, CalcPct(pc.other, total));
+ LogMessage(" DISCARD: " FMTu64("-10") " (%.3f%%)\n",
+ pc.discards, CalcPct(pc.discards, total));
+ LogMessage("InvChkSum: " FMTu64("-10") " (%.3f%%)\n",
+ pc.invalid_checksums, CalcPct(pc.invalid_checksums, total));
+
+ LogMessage(" S5 G 1: " FMTu64("-10") " (%.3f%%)\n",
+ pc.s5tcp1, CalcPct(pc.s5tcp1, total));
+ LogMessage(" S5 G 2: " FMTu64("-10") " (%.3f%%)\n",
+ pc.s5tcp2, CalcPct(pc.s5tcp2, total));
+
+ LogMessage(" Total: " FMTu64("-10") "\n", total);
+
+ LogMessage("================================================"
+ "===============================\n");
+
+ LogMessage("Action Stats:\n");
+ LogMessage("ALERTS: " STDu64 "\n", pc.alert_pkts);
+ LogMessage("LOGGED: " STDu64 "\n", pc.log_pkts);
+ LogMessage("PASSED: " STDu64 "\n", pc.pass_pkts);
+
+#ifdef TARGET_BASED
+ if (ScIdsMode() && IsAdaptiveConfigured(getDefaultPolicy(), 0))
+ {
+ LogMessage("================================================"
+ "===============================\n");
+ LogMessage("Attribute Table Stats:\n");
+ LogMessage(" Number Entries: %u\n", SFAT_NumberOfHosts());
+ LogMessage(" Table Reloaded: " STDu64 "\n", pc.attribute_table_reloads);
+ }
+#endif /* TARGET_BASED */
+
+ //mpse_print_qinfo();
+
+#ifndef NO_NON_ETHER_DECODER
+#ifdef DLT_IEEE802_11
+ if(datalink == DLT_IEEE802_11)
+ {
+ LogMessage("================================================"
+ "===============================\n");
+ LogMessage("Wireless Stats:\n");
+ LogMessage("Breakdown by type:\n");
+ LogMessage(" Management Packets: " FMTu64("-10") " (%.3f%%)\n",
+ pc.wifi_mgmt, CalcPct(pc.wifi_mgmt, total));
+ LogMessage(" Control Packets: " FMTu64("-10") " (%.3f%%)\n",
+ pc.wifi_control, CalcPct(pc.wifi_control, total));
+ LogMessage(" Data Packets: " FMTu64("-10") " (%.3f%%)\n",
+ pc.wifi_data, CalcPct(pc.wifi_data, total));
+ }
+#endif /* DLT_IEEE802_11 */
+#endif // NO_NON_ETHER_DECODER
+
+ for (idx = preproc_stats_funcs; idx != NULL; idx = idx->next)
+ {
+ LogMessage("=============================================="
+ "=================================\n");
+
+#ifdef PCAP_CLOSE
+ idx->func(exiting ? 1 : 0);
+#else
+ idx->func(exiting);
+#endif
+ }
+
+ LogMessage("=============================================="
+ "=================================\n");
+
+ return;
+}
+
+/****************************************************************************
+ *
+ * Function: CleanupProtoNames()
+ *
+ * Purpose: Frees the protocol names
+ *
+ * Arguments: None.
+ *
+ * Returns: void function
+ *
+ ****************************************************************************/
+void CleanupProtoNames(void)
+{
+ int i;
+
+ for(i = 0; i < 256; i++)
+ {
+ if( protocol_names[i] != NULL )
+ {
+ free( protocol_names[i] );
+ protocol_names[i] = NULL;
+ }
+ }
+}
+
+/****************************************************************************
+ *
+ * Function: read_infile(char *)
+ *
+ * Purpose: Reads the BPF filters in from a file. Ripped from tcpdump.
+ *
+ * Arguments: fname => the name of the file containing the BPF filters
+ *
+ * Returns: the processed BPF string
+ *
+ ****************************************************************************/
+char *read_infile(char *fname)
+{
+ register int fd, cc;
+ register char *cp, *cmt;
+ struct stat buf;
+
+ fd = open(fname, O_RDONLY);
+
+ if(fd < 0)
+ FatalError("can't open %s: %s\n", fname, pcap_strerror(errno));
+
+ if(fstat(fd, &buf) < 0)
+ FatalError("can't stat %s: %s\n", fname, pcap_strerror(errno));
+
+ cp = (char *)SnortAlloc(((u_int)buf.st_size + 1) * sizeof(char));
+
+ cc = read(fd, cp, (int) buf.st_size);
+
+ if(cc < 0)
+ FatalError("read %s: %s\n", fname, pcap_strerror(errno));
+
+ if(cc != buf.st_size)
+ FatalError("short read %s (%d != %d)\n", fname, cc, (int) buf.st_size);
+
+ cp[(int) buf.st_size] = '\0';
+
+ close(fd);
+
+ /* Treat everything upto the end of the line as a space
+ * so that we can put comments in our BPF filters
+ */
+
+ while((cmt = strchr(cp, '#')) != NULL)
+ {
+ while (*cmt != '\r' && *cmt != '\n' && *cmt != '\0')
+ {
+ *cmt++ = ' ';
+ }
+ }
+
+ /** LogMessage("BPF filter file: %s\n", fname); **/
+
+ return(cp);
+}
+
+
+ /****************************************************************************
+ *
+ * Function: CheckLogDir()
+ *
+ * Purpose: CyberPsychotic sez: basically we only check if logdir exist and
+ * writable, since it might screw the whole thing in the middle. Any
+ * other checks could be performed here as well.
+ *
+ * Arguments: None.
+ *
+ * Returns: void function
+ *
+ ****************************************************************************/
+void CheckLogDir(void)
+{
+ struct stat st;
+
+ if (snort_conf->log_dir == NULL)
+ return;
+
+ if (stat(snort_conf->log_dir, &st) == -1)
+ FatalError("Stat check on log dir failed: %s.\n", strerror(errno));
+
+ if (!S_ISDIR(st.st_mode) || (access(snort_conf->log_dir, W_OK) == -1))
+ {
+ FatalError("Can not get write access to logging directory \"%s\". "
+ "(directory doesn't exist or permissions are set incorrectly "
+ "or it is not a directory at all)\n",
+ snort_conf->log_dir);
+ }
+}
+
+/* Signal handler for child process signaling the parent
+ * that is is ready */
+static int parent_wait = 1;
+static void SigChildReadyHandler(int signal)
+{
+#ifdef DEBUG
+ LogMessage("Received Signal from Child\n");
+#endif
+ parent_wait = 0;
+}
+
+/****************************************************************************
+ *
+ * Function: GoDaemon()
+ *
+ * Purpose: Puts the program into daemon mode, nice and quiet like....
+ *
+ * Arguments: None.
+ *
+ * Returns: void function
+ *
+ ****************************************************************************/
+void GoDaemon(void)
+{
+#ifndef WIN32
+ int exit_val = 0;
+ pid_t fs;
+
+ LogMessage("Initializing daemon mode\n");
+
+ if (ScDaemonRestart())
+ return;
+
+ /* Don't daemonize if we've already daemonized and
+ * received a SIGHUP. */
+ if(getppid() != 1)
+ {
+ /* Register signal handler that parent can trap signal */
+ signal(SIGNAL_SNORT_CHILD_READY, SigChildReadyHandler);
+ if (errno != 0) errno=0;
+
+ /* now fork the child */
+ fs = fork();
+
+ if(fs > 0)
+ {
+ /* Parent */
+
+ /* Don't exit quite yet. Wait for the child
+ * to signal that is there and created the PID
+ * file.
+ */
+ while (parent_wait)
+ {
+ /* Continue waiting until receiving signal from child */
+ int status;
+ if (waitpid(fs, &status, WNOHANG) == fs)
+ {
+ /* If the child is gone, parent should go away, too */
+ if (WIFEXITED(status))
+ {
+ LogMessage("Child exited unexpectedly\n");
+ exit_val = -1;
+ break;
+ }
+
+ if (WIFSIGNALED(status))
+ {
+ LogMessage("Child terminated unexpectedly\n");
+ exit_val = -2;
+ break;
+ }
+ }
+#ifdef DEBUG
+ LogMessage("Parent waiting for child...\n");
+#endif
+
+ sleep(1);
+ }
+
+ LogMessage("Daemon parent exiting\n");
+
+ exit(exit_val); /* parent */
+ }
+
+ if(fs < 0)
+ {
+ /* Daemonizing failed... */
+ perror("fork");
+ exit(1);
+ }
+
+ /* Child */
+ setsid();
+ }
+
+ close(0);
+ close(1);
+ close(2);
+
+#ifdef DEBUG
+ /* redirect stdin/stdout/stderr to a file */
+ open("/tmp/snort.debug", O_CREAT | O_RDWR); /* stdin, fd 0 */
+
+ /* Change ownership to that which we will drop privileges to */
+ if ((snort_conf->user_id != -1) || (snort_conf->group_id != -1))
+ {
+ uid_t user_id = getuid();
+ gid_t group_id = getgid();
+
+ if (snort_conf->user_id != -1)
+ user_id = snort_conf->user_id;
+ if (snort_conf->group_id != -1)
+ group_id = snort_conf->group_id;
+
+ chown("/tmp/snort.debug", user_id, group_id);
+ }
+#else
+ /* redirect stdin/stdout/stderr to /dev/null */
+ (void)open("/dev/null", O_RDWR); /* stdin, fd 0 */
+#endif
+
+ dup(0); /* stdout, fd 0 => fd 1 */
+ dup(0); /* stderr, fd 0 => fd 2 */
+
+ SignalWaitingParent();
+
+#endif /* ! WIN32 */
+}
+
+/* Signal the parent that child is ready */
+void SignalWaitingParent(void)
+{
+#ifndef WIN32
+ pid_t parentpid = getppid();
+#ifdef DEBUG
+ LogMessage("Signaling parent %d from child %d\n", parentpid, getpid());
+#endif
+
+ if (kill(parentpid, SIGNAL_SNORT_CHILD_READY))
+ {
+ LogMessage("Daemon initialized, failed to signal parent pid: %d, failure: %d, %s\n", parentpid, errno, strerror(errno));
+ }
+ else
+ {
+ LogMessage("Daemon initialized, signaled parent pid: %d\n", parentpid);
+ }
+#endif
+}
+
+/* This function has been moved into mstring.c, since that
+* is where the allocation actually occurs. It has been
+* renamed to mSplitFree().
+*
+void FreeToks(char **toks, int num_toks)
+{
+ if (toks)
+ {
+ if (num_toks > 0)
+ {
+ do
+ {
+ num_toks--;
+ free(toks[num_toks]);
+ } while(num_toks);
+ }
+ free(toks);
+ }
+}
+*/
+
+
+/* Self preserving memory allocator */
+void *SPAlloc(unsigned long size, struct _SPMemControl *spmc)
+{
+ void *tmp;
+
+ spmc->mem_usage += size;
+
+ if(spmc->mem_usage > spmc->memcap)
+ {
+ spmc->sp_func(spmc);
+ }
+
+ tmp = (void *) calloc(size, sizeof(char));
+
+ if(tmp == NULL)
+ {
+ FatalError("Unable to allocate memory! (%lu requested, %lu in use)\n",
+ size, spmc->mem_usage);
+ }
+
+ return tmp;
+}
+
+/* Guaranteed to be '\0' terminated even if truncation occurs.
+ *
+ * returns SNORT_SNPRINTF_SUCCESS if successful
+ * returns SNORT_SNPRINTF_TRUNCATION on truncation
+ * returns SNORT_SNPRINTF_ERROR on error
+ */
+int SnortSnprintf(char *buf, size_t buf_size, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ if (buf == NULL || buf_size <= 0 || format == NULL)
+ return SNORT_SNPRINTF_ERROR;
+
+ /* zero first byte in case an error occurs with
+ * vsnprintf, so buffer is null terminated with
+ * zero length */
+ buf[0] = '\0';
+ buf[buf_size - 1] = '\0';
+
+ va_start(ap, format);
+
+ ret = vsnprintf(buf, buf_size, format, ap);
+
+ va_end(ap);
+
+ if (ret < 0)
+ return SNORT_SNPRINTF_ERROR;
+
+ if (buf[buf_size - 1] != '\0' || (size_t)ret >= buf_size)
+ {
+ /* result was truncated */
+ buf[buf_size - 1] = '\0';
+ return SNORT_SNPRINTF_TRUNCATION;
+ }
+
+ return SNORT_SNPRINTF_SUCCESS;
+}
+
+/* Appends to a given string
+ * Guaranteed to be '\0' terminated even if truncation occurs.
+ *
+ * returns SNORT_SNPRINTF_SUCCESS if successful
+ * returns SNORT_SNPRINTF_TRUNCATION on truncation
+ * returns SNORT_SNPRINTF_ERROR on error
+ */
+int SnortSnprintfAppend(char *buf, size_t buf_size, const char *format, ...)
+{
+ int str_len;
+ int ret;
+ va_list ap;
+
+ if (buf == NULL || buf_size <= 0 || format == NULL)
+ return SNORT_SNPRINTF_ERROR;
+
+ str_len = SnortStrnlen(buf, buf_size);
+
+ /* since we've already checked buf and buf_size an error
+ * indicates no null termination, so just start at
+ * beginning of buffer */
+ if (str_len == SNORT_STRNLEN_ERROR)
+ {
+ buf[0] = '\0';
+ str_len = 0;
+ }
+
+ buf[buf_size - 1] = '\0';
+
+ va_start(ap, format);
+
+ ret = vsnprintf(buf + str_len, buf_size - (size_t)str_len, format, ap);
+
+ va_end(ap);
+
+ if (ret < 0)
+ return SNORT_SNPRINTF_ERROR;
+
+ if (buf[buf_size - 1] != '\0' || (size_t)ret >= buf_size)
+ {
+ /* truncation occured */
+ buf[buf_size - 1] = '\0';
+ return SNORT_SNPRINTF_TRUNCATION;
+ }
+
+ return SNORT_SNPRINTF_SUCCESS;
+}
+
+/* Guaranteed to be '\0' terminated even if truncation occurs.
+ *
+ * Arguments: dst - the string to contain the copy
+ * src - the string to copy from
+ * dst_size - the size of the destination buffer
+ * including the null byte.
+ *
+ * returns SNORT_STRNCPY_SUCCESS if successful
+ * returns SNORT_STRNCPY_TRUNCATION on truncation
+ * returns SNORT_STRNCPY_ERROR on error
+ *
+ * Note: Do not set dst[0] = '\0' on error since it's possible that
+ * dst and src are the same pointer - it will at least be null
+ * terminated in any case
+ */
+int SnortStrncpy(char *dst, const char *src, size_t dst_size)
+{
+ char *ret = NULL;
+
+ if (dst == NULL || src == NULL || dst_size <= 0)
+ return SNORT_STRNCPY_ERROR;
+
+ dst[dst_size - 1] = '\0';
+
+ ret = strncpy(dst, src, dst_size);
+
+ /* Not sure if this ever happens but might as
+ * well be on the safe side */
+ if (ret == NULL)
+ return SNORT_STRNCPY_ERROR;
+
+ if (dst[dst_size - 1] != '\0')
+ {
+ /* result was truncated */
+ dst[dst_size - 1] = '\0';
+ return SNORT_STRNCPY_TRUNCATION;
+ }
+
+ return SNORT_STRNCPY_SUCCESS;
+}
+
+char *SnortStrndup(const char *src, size_t dst_size)
+{
+ char *ret = SnortAlloc(dst_size + 1);
+ int ret_val;
+
+ ret_val = SnortStrncpy(ret, src, dst_size + 1);
+
+ if(ret_val == SNORT_STRNCPY_ERROR)
+ {
+ free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+/* Determines whether a buffer is '\0' terminated and returns the
+ * string length if so
+ *
+ * returns the string length if '\0' terminated
+ * returns SNORT_STRNLEN_ERROR if not '\0' terminated
+ */
+int SnortStrnlen(const char *buf, int buf_size)
+{
+ int i = 0;
+
+ if (buf == NULL || buf_size <= 0)
+ return SNORT_STRNLEN_ERROR;
+
+ for (i = 0; i < buf_size; i++)
+ {
+ if (buf[i] == '\0')
+ break;
+ }
+
+ if (i == buf_size)
+ return SNORT_STRNLEN_ERROR;
+
+ return i;
+}
+
+char * SnortStrdup(const char *str)
+{
+ char *copy = NULL;
+
+ if (!str)
+ {
+ FatalError("Unable to duplicate string: NULL!\n");
+ }
+
+ copy = strdup(str);
+
+ if (copy == NULL)
+ {
+ FatalError("Unable to duplicate string: %s!\n", str);
+ }
+
+ return copy;
+}
+
+/*
+ * Find first occurrence of char of accept in s, limited by slen.
+ * A 'safe' version of strpbrk that won't read past end of buffer s
+ * in cases that s is not NULL terminated.
+ *
+ * This code assumes 'accept' is a static string.
+ */
+const char *SnortStrnPbrk(const char *s, int slen, const char *accept)
+{
+ char ch;
+ const char *s_end;
+ if (!s || !*s || !accept || slen == 0)
+ return NULL;
+
+ s_end = s + slen;
+ while (s < s_end)
+ {
+ ch = *s;
+ if (strchr(accept, ch))
+ return s;
+ s++;
+ }
+ return NULL;
+}
+
+/*
+ * Find first occurrence of searchstr in s, limited by slen.
+ * A 'safe' version of strstr that won't read past end of buffer s
+ * in cases that s is not NULL terminated.
+ */
+const char *SnortStrnStr(const char *s, int slen, const char *searchstr)
+{
+ char ch, nc;
+ int len;
+ if (!s || !*s || !searchstr || slen == 0)
+ return NULL;
+
+ if ((ch = *searchstr++) != 0)
+ {
+ len = strlen(searchstr);
+ do
+ {
+ do
+ {
+ if ((nc = *s++) == 0)
+ {
+ return NULL;
+ }
+ slen--;
+ if (slen == 0)
+ return NULL;
+ } while (nc != ch);
+ if (slen - len < 0)
+ return NULL;
+ } while (memcmp(s, searchstr, len) != 0);
+ s--;
+ slen++;
+ }
+ return s;
+}
+
+/*
+ * Find first occurrence of substring in s, ignore case.
+*/
+const char *SnortStrcasestr(const char *s, const char *substr)
+{
+ char ch, nc;
+ int len;
+
+ if (!s || !*s || !substr)
+ return NULL;
+
+ if ((ch = *substr++) != 0)
+ {
+ ch = tolower((char)ch);
+ len = strlen(substr);
+ do
+ {
+ do
+ {
+ if ((nc = *s++) == 0)
+ {
+ return NULL;
+ }
+ } while ((char)tolower((uint8_t)nc) != ch);
+ } while (strncasecmp(s, substr, len) != 0);
+ s--;
+ }
+ return s;
+}
+
+void *SnortAlloc(unsigned long size)
+{
+ void *tmp;
+
+ tmp = (void *) calloc(size, sizeof(char));
+
+ if(tmp == NULL)
+ {
+ FatalError("Unable to allocate memory! (%lu requested)\n", size);
+ }
+
+ return tmp;
+}
+
+void * SnortAlloc2(size_t size, const char *format, ...)
+{
+ void *tmp;
+
+ tmp = (void *)calloc(size, sizeof(char));
+
+ if(tmp == NULL)
+ {
+ va_list ap;
+ char buf[STD_BUF];
+
+ buf[STD_BUF - 1] = '\0';
+
+ va_start(ap, format);
+
+ vsnprintf(buf, STD_BUF - 1, format, ap);
+
+ va_end(ap);
+
+ FatalError("%s", buf);
+ }
+
+ return tmp;
+}
+
+/**
+ * Chroot and adjust the snort_conf->log_dir reference
+ *
+ * @param directory directory to chroot to
+ * @param logstore ptr to snort_conf->log_dir which must be dynamically allocated
+ */
+void SetChroot(char *directory, char **logstore)
+{
+#ifdef WIN32
+ FatalError("SetChroot() should not be called under Win32!\n");
+#else
+ char *absdir;
+ size_t abslen;
+ char *logdir;
+
+ if(!directory || !logstore)
+ {
+ FatalError("Null parameter passed\n");
+ }
+
+ logdir = *logstore;
+
+ if(logdir == NULL || *logdir == '\0')
+ {
+ FatalError("Null log directory\n");
+ }
+
+ DEBUG_WRAP(DebugMessage(DEBUG_INIT,"SetChroot: %s\n",
+ CurrentWorkingDir()););
+
+ logdir = GetAbsolutePath(logdir);
+
+ DEBUG_WRAP(DebugMessage(DEBUG_INIT, "SetChroot: %s\n",
+ CurrentWorkingDir()));
+
+ logdir = SnortStrdup(logdir);
+
+ /* We're going to reset logstore, so free it now */
+ free(*logstore);
+ *logstore = NULL;
+
+ /* change to the directory */
+ if(chdir(directory) != 0)
+ {
+ FatalError("SetChroot: Can not chdir to \"%s\": %s\n", directory,
+ strerror(errno));
+ }
+
+ /* always returns an absolute pathname */
+ absdir = CurrentWorkingDir();
+
+ if(absdir == NULL)
+ {
+ FatalError("NULL Chroot found\n");
+ }
+
+ abslen = strlen(absdir);
+
+ DEBUG_WRAP(DebugMessage(DEBUG_INIT, "ABS: %s %d\n", absdir, abslen););
+
+ /* make the chroot call */
+ if(chroot(absdir) < 0)
+ {
+ FatalError("Can not chroot to \"%s\": absolute: %s: %s\n",
+ directory, absdir, strerror(errno));
+ }
+
+ DEBUG_WRAP(DebugMessage(DEBUG_INIT,"chroot success (%s ->", absdir););
+ DEBUG_WRAP(DebugMessage(DEBUG_INIT,"%s)\n ", CurrentWorkingDir()););
+
+ /* change to "/" in the new directory */
+ if(chdir("/") < 0)
+ {
+ FatalError("Can not chdir to \"/\" after chroot: %s\n",
+ strerror(errno));
+ }
+
+ DEBUG_WRAP(DebugMessage(DEBUG_INIT,"chdir success (%s)\n",
+ CurrentWorkingDir()););
+
+
+ if(strncmp(absdir, logdir, strlen(absdir)))
+ {
+ FatalError("Absdir is not a subset of the logdir");
+ }
+
+ if(abslen >= strlen(logdir))
+ {
+ *logstore = SnortStrdup("/");
+ }
+ else
+ {
+ *logstore = SnortStrdup(logdir + abslen);
+ }
+
+ DEBUG_WRAP(DebugMessage(DEBUG_INIT,"new logdir from %s to %s\n",
+ logdir, *logstore));
+
+ LogMessage("Chroot directory = %s\n", directory);
+
+#if 0
+ /* XXX XXX */
+ /* install the I can't do this signal handler */
+ signal(SIGHUP, SigCantHupHandler);
+#endif
+#endif /* !WIN32 */
+}
+
+
+/**
+ * Return a ptr to the absolute pathname of snort. This memory must
+ * be copied to another region if you wish to save it for later use.
+ */
+char *CurrentWorkingDir(void)
+{
+ static char buf[PATH_MAX_UTIL + 1];
+
+ if(getcwd((char *) buf, PATH_MAX_UTIL) == NULL)
+ {
+ return NULL;
+ }
+
+ buf[PATH_MAX_UTIL] = '\0';
+
+ return (char *) buf;
+}
+
+/**
+ * Given a directory name, return a ptr to a static
+ */
+char *GetAbsolutePath(char *dir)
+{
+ char *savedir, *dirp;
+ static char buf[PATH_MAX_UTIL + 1];
+
+ if(dir == NULL)
+ {
+ return NULL;
+ }
+
+ savedir = strdup(CurrentWorkingDir());
+
+ if(savedir == NULL)
+ {
+ return NULL;
+ }
+
+ if(chdir(dir) < 0)
+ {
+ LogMessage("Can't change to directory: %s\n", dir);
+ free(savedir);
+ return NULL;
+ }
+
+ dirp = CurrentWorkingDir();
+
+ if(dirp == NULL)
+ {
+ LogMessage("Unable to access current directory\n");
+ free(savedir);
+ return NULL;
+ }
+ else
+ {
+ strncpy(buf, dirp, PATH_MAX_UTIL);
+ buf[PATH_MAX_UTIL] = '\0';
+ }
+
+ if(chdir(savedir) < 0)
+ {
+ LogMessage("Can't change back to directory: %s\n", dir);
+ free(savedir);
+ return NULL;
+ }
+
+ free(savedir);
+ return (char *) buf;
+}
+
+
+#ifndef WIN32
+/* very slow sort - do not use at runtime! */
+SF_LIST * SortDirectory(const char *path)
+{
+ SF_LIST *dir_entries;
+ DIR *dir;
+ struct dirent *direntry;
+ int ret = 0;
+
+ if (path == NULL)
+ return NULL;
+
+ dir_entries = sflist_new();
+ if (dir_entries == NULL)
+ {
+ ErrorMessage("Could not allocate new list for directory entries\n");
+ return NULL;
+ }
+
+ dir = opendir(path);
+ if (dir == NULL)
+ {
+ ErrorMessage("Error opening directory: %s: %s\n",
+ path, strerror(errno));
+ sflist_free_all(dir_entries, free);
+ return NULL;
+ }
+
+ /* Reset errno since we'll be checking it unconditionally */
+ errno = 0;
+
+ while ((direntry = readdir(dir)) != NULL)
+ {
+ char *node_entry_name, *dir_entry_name;
+ SF_LNODE *node;
+
+ dir_entry_name = SnortStrdup(direntry->d_name);
+
+ for (node = sflist_first_node(dir_entries);
+ node != NULL;
+ node = sflist_next_node(dir_entries))
+ {
+ node_entry_name = (char *)node->ndata;
+ if (strcmp(dir_entry_name, node_entry_name) < 0)
+ break;
+ }
+
+ if (node == NULL)
+ ret = sflist_add_tail(dir_entries, (NODE_DATA)dir_entry_name);
+ else
+ ret = sflist_add_before(dir_entries, node, (NODE_DATA)dir_entry_name);
+
+ if (ret == -1)
+ {
+ ErrorMessage("Error adding directory entry to list\n");
+ sflist_free_all(dir_entries, free);
+ closedir(dir);
+ return NULL;
+ }
+ }
+
+ if (errno != 0)
+ {
+ ErrorMessage("Error reading directory: %s: %s\n",
+ path, strerror(errno));
+ errno = 0;
+ sflist_free_all(dir_entries, free);
+ closedir(dir);
+ return NULL;
+ }
+
+ closedir(dir);
+
+ return dir_entries;
+}
+
+int GetFilesUnderDir(const char *path, SF_QUEUE *dir_queue, const char *filter)
+{
+ SF_LIST *dir_entries;
+ char *direntry;
+ int ret = 0;
+ int num_files = 0;
+
+ if ((path == NULL) || (dir_queue == NULL))
+ return -1;
+
+ dir_entries = SortDirectory(path);
+ if (dir_entries == NULL)
+ {
+ ErrorMessage("Error sorting entries in directory: %s\n", path);
+ return -1;
+ }
+
+ for (direntry = (char *)sflist_first(dir_entries);
+ direntry != NULL;
+ direntry = (char *)sflist_next(dir_entries))
+ {
+ char path_buf[PATH_MAX];
+ struct stat file_stat;
+
+ /* Don't look at dot files */
+ if (strncmp(".", direntry, 1) == 0)
+ continue;
+
+ ret = SnortSnprintf(path_buf, PATH_MAX, "%s%s%s",
+ path, path[strlen(path) - 1] == '/' ? "" : "/", direntry);
+ if (ret == SNORT_SNPRINTF_TRUNCATION)
+ {
+ ErrorMessage("Error copying file to buffer: Path too long\n");
+ sflist_free_all(dir_entries, free);
+ return -1;
+ }
+ else if (ret != SNORT_SNPRINTF_SUCCESS)
+ {
+ ErrorMessage("Error copying file to buffer\n");
+ sflist_free_all(dir_entries, free);
+ return -1;
+ }
+
+ ret = stat(path_buf, &file_stat);
+ if (ret == -1)
+ {
+ ErrorMessage("Could not stat file: %s: %s\n",
+ path_buf, strerror(errno));
+ sflist_free_all(dir_entries, free);
+ return -1;
+ }
+
+ if (file_stat.st_mode & S_IFDIR)
+ {
+ ret = GetFilesUnderDir(path_buf, dir_queue, filter);
+ if (ret == -1)
+ {
+ sflist_free_all(dir_entries, free);
+ return -1;
+ }
+
+ num_files += ret;
+ }
+ else if (file_stat.st_mode & S_IFREG)
+ {
+ if ((filter == NULL) || (fnmatch(filter, direntry, 0) == 0))
+ {
+ char *file = SnortStrdup(path_buf);
+
+ ret = sfqueue_add(dir_queue, (NODE_DATA)file);
+ if (ret == -1)
+ {
+ ErrorMessage("Could not append item to list: %s\n", file);
+ free(file);
+ sflist_free_all(dir_entries, free);
+ return -1;
+ }
+
+ num_files++;
+ }
+ }
+ }
+
+ sflist_free_all(dir_entries, free);
+
+ return num_files;
+}
+#endif
+
+/****************************************************************************
+ *
+ * Function: GetUniqueName(char * iface)
+ *
+ * Purpose: To return a string that has a high probability of being unique
+ * for a given sensor.
+ *
+ * Arguments: char * iface - The network interface you are sniffing
+ *
+ * Returns: A char * -- its a static char * so you should not free it
+ *
+ ***************************************************************************/
+char *GetUniqueName(char * iface)
+{
+ char * rptr;
+ static char uniq_name[256];
+
+ if (iface == NULL) LogMessage("Interface is NULL. Name may not be unique for the host\n");
+#ifndef WIN32
+ rptr = GetIP(iface);
+ if(rptr == NULL || !strcmp(rptr, "unknown"))
+#endif
+ {
+ SnortSnprintf(uniq_name, 255, "%s:%s\n",GetHostname(),iface);
+ rptr = uniq_name;
+ }
+ if (ScLogVerbose()) LogMessage("Node unique name is: %s\n", rptr);
+ return rptr;
+}
+
+/****************************************************************************
+ *
+ * Function: GetIP(char * iface)
+ *
+ * Purpose: To return a string representing the IP address for an interface
+ *
+ * Arguments: char * iface - The network interface you want to find an IP
+ * address for.
+ *
+ * Returns: A char * -- make sure you call free on this when you are done
+ * with it.
+ *
+ ***************************************************************************/
+char *GetIP(char * iface)
+{
+ struct ifreq ifr;
+ struct sockaddr_in *addr;
+ int s;
+#ifdef SUP_IP6
+ sfip_t ret;
+#endif
+
+ if(iface)
+ {
+ /* Set up a dummy socket just so we can use ioctl to find the
+ ip address of the interface */
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if(s == -1)
+ {
+ FatalError("Problem establishing socket to find IP address for interface: %s\n", iface);
+ }
+
+ SnortStrncpy(ifr.ifr_name, iface, strlen(iface) + 1);
+
+#ifndef WIN32
+ if(ioctl(s, SIOCGIFADDR, &ifr) < 0) return NULL;
+ else
+#endif
+ {
+ addr = (struct sockaddr_in *) &ifr.ifr_broadaddr;
+ }
+ close(s);
+
+#ifdef SUP_IP6
+// XXX-IPv6 uses ioctl to populate a sockaddr_in structure ... but what if the interface only has an IPv6 address?
+ sfip_set_raw(&ret, addr, AF_INET);
+ return SnortStrdup(sfip_ntoa(&ret));
+#else
+ return SnortStrdup(inet_ntoa(addr->sin_addr));
+#endif
+ }
+ else
+ {
+ return "unknown";
+ }
+}
+
+/****************************************************************************
+ *
+ * Function: GetHostname()
+ *
+ * Purpose: To return a string representing the hostname
+ *
+ * Arguments: None
+ *
+ * Returns: A static char * representing the hostname.
+ *
+ ***************************************************************************/
+char *GetHostname(void)
+{
+#ifdef WIN32
+ DWORD bufflen = 256;
+ static char buff[256];
+ GetComputerName(buff, &bufflen);
+ return buff;
+#else
+ char * error = "unknown";
+ if(getenv("HOSTNAME")) return getenv("HOSTNAME");
+ else if(getenv("HOST")) return getenv("HOST");
+ else return error;
+#endif
+}
+
+/****************************************************************************
+ *
+ * Function: GetTimestamp(register const struct timeval *tvp, int tz)
+ *
+ * Purpose: Get an ISO-8601 formatted timestamp for tvp within the tz
+ * timezone.
+ *
+ * Arguments: tvp is a timeval pointer. tz is a timezone.
+ *
+ * Returns: char * -- You must free this char * when you are done with it.
+ *
+ ***************************************************************************/
+char *GetTimestamp(register const struct timeval *tvp, int tz)
+{
+ struct tm *lt; /* localtime */
+ char * buf;
+ int msec;
+
+ buf = (char *)SnortAlloc(SMALLBUFFER * sizeof(char));
+
+ msec = tvp->tv_usec / 1000;
+
+ if (ScOutputUseUtc())
+ {
+ lt = gmtime((time_t *)&tvp->tv_sec);
+ SnortSnprintf(buf, SMALLBUFFER, "%04i-%02i-%02i %02i:%02i:%02i.%03i",
+ 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday,
+ lt->tm_hour, lt->tm_min, lt->tm_sec, msec);
+ }
+ else
+ {
+ lt = localtime((time_t *)&tvp->tv_sec);
+ SnortSnprintf(buf, SMALLBUFFER,
+ "%04i-%02i-%02i %02i:%02i:%02i.%03i+%03i",
+ 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday,
+ lt->tm_hour, lt->tm_min, lt->tm_sec, msec, tz);
+ }
+
+ return buf;
+}
+
+/****************************************************************************
+ *
+ * Function: GetLocalTimezone()
+ *
+ * Purpose: Find the offset from GMT for current host
+ *
+ * Arguments: none
+ *
+ * Returns: int representing the offset from GMT
+ *
+ ***************************************************************************/
+int GetLocalTimezone(void)
+{
+ time_t ut;
+ struct tm * ltm;
+ long seconds_away_from_utc;
+
+ time(&ut);
+ ltm = localtime(&ut);
+
+#if defined(WIN32) || defined(SOLARIS) || defined(AIX) || defined(HPUX)
+ /* localtime() sets the global timezone variable,
+ which is defined in <time.h> */
+ seconds_away_from_utc = timezone;
+#else
+ seconds_away_from_utc = ltm->tm_gmtoff;
+#endif
+
+ return seconds_away_from_utc/3600;
+}
+
+/****************************************************************************
+ *
+ * Function: GetCurrentTimestamp()
+ *
+ * Purpose: Generate an ISO-8601 formatted timestamp for the current time.
+ *
+ * Arguments: none
+ *
+ * Returns: char * -- You must free this char * when you are done with it.
+ *
+ ***************************************************************************/
+char *GetCurrentTimestamp(void)
+{
+ struct tm *lt;
+ struct timezone tz;
+ struct timeval tv;
+ struct timeval *tvp;
+ char * buf;
+ int tzone;
+ int msec;
+
+ buf = (char *)SnortAlloc(SMALLBUFFER * sizeof(char));
+
+ bzero((char *)&tz,sizeof(tz));
+ gettimeofday(&tv,&tz);
+ tvp = &tv;
+
+ msec = tvp->tv_usec/1000;
+
+ if (ScOutputUseUtc())
+ {
+ lt = gmtime((time_t *)&tvp->tv_sec);
+ SnortSnprintf(buf, SMALLBUFFER, "%04i-%02i-%02i %02i:%02i:%02i.%03i",
+ 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday,
+ lt->tm_hour, lt->tm_min, lt->tm_sec, msec);
+ }
+ else
+ {
+ lt = localtime((time_t *)&tvp->tv_sec);
+
+ tzone = GetLocalTimezone();
+
+ SnortSnprintf(buf, SMALLBUFFER,
+ "%04i-%02i-%02i %02i:%02i:%02i.%03i+%03i",
+ 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday,
+ lt->tm_hour, lt->tm_min, lt->tm_sec, msec, tzone);
+ }
+
+ return buf;
+}
+
+/****************************************************************************
+ * Function: base64(char * xdata, int length)
+ *
+ * Purpose: Insert data into the database
+ *
+ * Arguments: xdata => pointer to data to base64 encode
+ * length => how much data to encode
+ *
+ * Make sure you allocate memory for the output before you pass
+ * the output pointer into this function. You should allocate
+ * (1.5 * length) bytes to be safe.
+ *
+ * Returns: data base64 encoded as a char *
+ *
+ ***************************************************************************/
+char * base64(const u_char * xdata, int length)
+{
+ int count, cols, bits, c, char_count;
+ unsigned char alpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* 64 bytes */
+ char * payloadptr;
+ char * output;
+ char_count = 0;
+ bits = 0;
+ cols = 0;
+
+ output = (char *)SnortAlloc( ((unsigned int) (length * 1.5 + 4)) * sizeof(char) );
+
+ payloadptr = output;
+
+ for(count = 0; count < length; count++)
+ {
+ c = xdata[count];
+
+ if(c > 255)
+ {
+ ErrorMessage("plugbase.c->base64(): encountered char > 255 (decimal %d)\n If you see this error message a char is more than one byte on your machine\n This means your base64 results can not be trusted", c);
+ }
+
+ bits += c;
+ char_count++;
+
+ if(char_count == 3)
+ {
+ *output = alpha[bits >> 18]; output++;
+ *output = alpha[(bits >> 12) & 0x3f]; output++;
+ *output = alpha[(bits >> 6) & 0x3f]; output++;
+ *output = alpha[bits & 0x3f]; output++;
+ cols += 4;
+ if(cols == 72)
+ {
+ *output = '\n'; output++;
+ cols = 0;
+ }
+ bits = 0;
+ char_count = 0;
+ }
+ else
+ {
+ bits <<= 8;
+ }
+ }
+
+ if(char_count != 0)
+ {
+ bits <<= 16 - (8 * char_count);
+ *output = alpha[bits >> 18]; output++;
+ *output = alpha[(bits >> 12) & 0x3f]; output++;
+ if(char_count == 1)
+ {
+ *output = '='; output++;
+ *output = '='; output++;
+ }
+ else
+ {
+ *output = alpha[(bits >> 6) & 0x3f];
+ output++; *output = '=';
+ output++;
+ }
+ }
+ *output = '\0';
+ return payloadptr;
+}
+
+/****************************************************************************
+ *
+ * Function: ascii(u_char *xdata, int length)
+ *
+ * Purpose: This function takes takes a buffer "xdata" and its length then
+ * returns a string of only the printable ASCII characters.
+ *
+ * Arguments: xdata is the buffer, length is the length of the buffer in
+ * bytes
+ *
+ * Returns: char * -- You must free this char * when you are done with it.
+ *
+ ***************************************************************************/
+char *ascii(const u_char *xdata, int length)
+{
+ char *d_ptr, *ret_val;
+ int i,count = 0;
+ int size;
+
+ if(xdata == NULL)
+ {
+ return NULL;
+ }
+
+ for(i=0;i<length;i++)
+ {
+ if(xdata[i] == '<')
+ count+=4; /* &lt; */
+ else if(xdata[i] == '&')
+ count+=5; /* &amp; */
+ else if(xdata[i] == '>') /* &gt; */
+ count += 4;
+ }
+
+ size = length + count + 1;
+ ret_val = (char *) calloc(1,size);
+
+ if(ret_val == NULL)
+ {
+ LogMessage("plugbase.c: ascii(): Out of memory, can't log anything!\n");
+ return NULL;
+ }
+
+ d_ptr = ret_val;
+
+ for(i=0;i<length;i++)
+ {
+ if((xdata[i] > 0x1F) && (xdata[i] < 0x7F))
+ {
+ if(xdata[i] == '<')
+ {
+ SnortStrncpy(d_ptr, "&lt;", size - (d_ptr - ret_val));
+ d_ptr+=4;
+ }
+ else if(xdata[i] == '&')
+ {
+ SnortStrncpy(d_ptr, "&amp;", size - (d_ptr - ret_val));
+ d_ptr += 5;
+ }
+ else if(xdata[i] == '>')
+ {
+ SnortStrncpy(d_ptr, "&gt;", size - (d_ptr - ret_val));
+ d_ptr += 4;
+ }
+ else
+ {
+ *d_ptr++ = xdata[i];
+ }
+ }
+ else
+ {
+ *d_ptr++ = '.';
+ }
+ }
+
+ *d_ptr++ = '\0';
+
+ return ret_val;
+}
+
+/****************************************************************************
+ *
+ * Function: hex(u_char *xdata, int length)
+ *
+ * Purpose: This function takes takes a buffer "xdata" and its length then
+ * returns a string of hex with no spaces
+ *
+ * Arguments: xdata is the buffer, length is the length of the buffer in
+ * bytes
+ *
+ * Returns: char * -- You must free this char * when you are done with it.
+ *
+ ***************************************************************************/
+char *hex(const u_char *xdata, int length)
+{
+ int x;
+ char *rval = NULL;
+ char *buf = NULL;
+
+ if (xdata == NULL)
+ return NULL;
+
+ buf = (char *)calloc((length * 2) + 1, sizeof(char));
+
+ if (buf != NULL)
+ {
+ rval = buf;
+
+ for (x = 0; x < length; x++)
+ {
+ SnortSnprintf(buf, 3, "%02X", xdata[x]);
+ buf += 2;
+ }
+
+ rval[length * 2] = '\0';
+ }
+
+ return rval;
+}
+
+
+
+char *fasthex(const u_char *xdata, int length)
+{
+ char conv[] = "0123456789ABCDEF";
+ char *retbuf = NULL;
+ const u_char *index;
+ const u_char *end;
+ char *ridx;
+
+ index = xdata;
+ end = xdata + length;
+ retbuf = (char *)SnortAlloc(((length * 2) + 1) * sizeof(char));
+ ridx = retbuf;
+
+ while(index < end)
+ {
+ *ridx++ = conv[((*index & 0xFF)>>4)];
+ *ridx++ = conv[((*index & 0xFF)&0x0F)];
+ index++;
+ }
+
+ return retbuf;
+}
+
+/*
+ * Fatal Integer Parser
+ * Ascii to Integer conversion with fatal error support
+ */
+long int xatol(const char *s , const char *etext)
+{
+ long int val;
+ char *endptr;
+ char *default_error = "xatol() error\n";
+
+ if (etext == NULL)
+ etext = default_error;
+
+ if (s == NULL)
+ FatalError("%s: String is NULL\n", etext);
+
+ while (isspace((int)*s))
+ s++;
+
+ if (strlen(s) == 0)
+ FatalError("%s: String is empty\n", etext);
+
+
+ /*
+ * strtoul - errors on win32 : ERANGE (VS 6.0)
+ * errors on linux : ERANGE, EINVAL
+ * (for EINVAL, unsupported base which won't happen here)
+ */
+ val = SnortStrtol(s, &endptr, 0);
+
+ if ((errno == ERANGE) || (*endptr != '\0'))
+ FatalError("%s: Invalid integer input: %s\n", etext, s);
+
+ return val;
+}
+
+/*
+ * Fatal Integer Parser
+ * Ascii to Integer conversion with fatal error support
+ */
+unsigned long int xatou(const char *s , const char *etext)
+{
+ unsigned long int val;
+ char *endptr;
+ char *default_error = "xatou() error\n";
+
+ if (etext == NULL)
+ etext = default_error;
+
+ if (s == NULL)
+ FatalError("%s: String is NULL\n", etext);
+
+ while (isspace((int)*s))
+ s++;
+
+ if (strlen(s) == 0)
+ FatalError("%s: String is empty\n", etext);
+
+ if (*s == '-')
+ {
+ FatalError("%s: Invalid unsigned integer - negative sign found, "
+ "input: %s\n", etext, s);
+ }
+
+
+ /*
+ * strtoul - errors on win32 : ERANGE (VS 6.0)
+ * errors on linux : ERANGE, EINVAL
+ */
+ val = SnortStrtoul(s, &endptr, 0);
+
+ if ((errno == ERANGE) || (*endptr != '\0'))
+ FatalError("%s: Invalid integer input: %s\n", etext, s);
+
+ return val;
+}
+
+unsigned long int xatoup(const char *s , const char *etext)
+{
+ unsigned long int val = xatou(s, etext);
+ if ( !val )
+ FatalError("%s: must be > 0\n", etext);
+ return val;
+}
+
+#ifndef SUP_IP6
+char * ObfuscateIpToText(const struct in_addr ip_addr)
+#else
+char * ObfuscateIpToText(sfip_t *ip)
+#endif
+{
+ static char ip_buf1[INET6_ADDRSTRLEN];
+ static char ip_buf2[INET6_ADDRSTRLEN];
+ static int buf_num = 0;
+ int buf_size = INET6_ADDRSTRLEN;
+ char *ip_buf;
+#ifndef SUP_IP6
+ uint32_t ip = ip_addr.s_addr;
+#endif
+
+ if (buf_num)
+ ip_buf = ip_buf2;
+ else
+ ip_buf = ip_buf1;
+
+ buf_num ^= 1;
+ ip_buf[0] = 0;
+
+#ifndef SUP_IP6
+ if (ip == 0)
+ return ip_buf;
+
+ if (snort_conf->obfuscation_net == 0)
+ {
+ /* Fully obfuscate - just use 'x' */
+ SnortSnprintf(ip_buf, buf_size, "xxx.xxx.xxx.xxx");
+ }
+ else
+ {
+ if (snort_conf->homenet != 0)
+ {
+ if ((ip & snort_conf->netmask) == snort_conf->homenet)
+ ip = snort_conf->obfuscation_net | (ip & snort_conf->obfuscation_mask);
+ }
+ else
+ {
+ ip = snort_conf->obfuscation_net | (ip & snort_conf->obfuscation_mask);
+ }
+
+ SnortSnprintf(ip_buf, buf_size, "%s", inet_ntoa(*((struct in_addr *)&ip)));
+ }
+
+#else
+ if (ip == NULL)
+ return ip_buf;
+
+ if (!IS_SET(snort_conf->obfuscation_net))
+ {
+ if (IS_IP6(ip))
+ SnortSnprintf(ip_buf, buf_size, "x:x:x:x::x:x:x:x");
+ else
+ SnortSnprintf(ip_buf, buf_size, "xxx.xxx.xxx.xxx");
+ }
+ else
+ {
+ sfip_t tmp;
+ char *tmp_buf;
+
+ IP_COPY_VALUE(tmp, ip);
+
+ if (IS_SET(snort_conf->homenet))
+ {
+ if (sfip_contains(&snort_conf->homenet, &tmp) == SFIP_CONTAINS)
+ sfip_obfuscate(&snort_conf->obfuscation_net, &tmp);
+ }
+ else
+ {
+ sfip_obfuscate(&snort_conf->obfuscation_net, &tmp);
+ }
+
+ tmp_buf = sfip_to_str(&tmp);
+ SnortSnprintf(ip_buf, buf_size, "%s", tmp_buf);
+ }
+#endif
+
+ return ip_buf;
+}
+
+void PrintPacketData(const uint8_t *data, const uint32_t len)
+{
+ uint32_t i, j;
+ uint32_t total_len = 0;
+ uint8_t hex_buf[16];
+ uint8_t char_buf[16];
+ char *length_chars = " 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\n"
+ "------------------------------------------------------\n";
+
+ LogMessage("%s", length_chars);
+
+ for (i = 0; i <= len; i++)
+ {
+ if ((i%16 == 0) && (i != 0))
+ {
+ LogMessage("%04x ", total_len);
+ total_len += 16;
+
+ for (j = 0; j < 16; j++)
+ {
+ LogMessage("%02x ", hex_buf[j]);
+ if (j == 7)
+ LogMessage(" ");
+ }
+
+ LogMessage(" ");
+
+ for (j = 0; j < 16; j++)
+ {
+ LogMessage("%c", char_buf[j]);
+ if (j == 7)
+ LogMessage(" ");
+ }
+
+ LogMessage("\n");
+ }
+
+ if (i == len)
+ break;
+
+ hex_buf[i%16] = data[i];
+
+ if (isprint((int)data[i]))
+ char_buf[i%16] = data[i];
+ else
+ char_buf[i%16] = '.';
+ }
+
+ if ((i-total_len) > 0)
+ {
+ LogMessage("%04x ", total_len);
+
+ for (j = 0; j < i-total_len; j++)
+ {
+ LogMessage("%02x ", hex_buf[j]);
+ if (j == 7)
+ LogMessage(" ");
+ }
+
+ if (j < 8)
+ LogMessage(" ");
+ LogMessage("%*s", (16-j)*3, "");
+ LogMessage(" ");
+
+ for (j = 0; j < i-total_len; j++)
+ {
+ LogMessage("%c", char_buf[j]);
+ if (j == 7)
+ LogMessage(" ");
+ }
+ }
+
+ LogMessage("\n");
+}
+