mirror of https://github.com/OISF/suricata
Initial add of the files.
parent
1cfa8dd2e5
commit
bab4b62376
@ -0,0 +1,167 @@
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
These are generic installation instructions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, a file
|
||||
`config.cache' that saves the results of its tests to speed up
|
||||
reconfiguring, and a file `config.log' containing compiler output
|
||||
(useful mainly for debugging `configure').
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If at some point `config.cache'
|
||||
contains results you don't want to keep, you may remove or edit it.
|
||||
|
||||
The file `configure.in' is used to create `configure' by a program
|
||||
called `autoconf'. You only need `configure.in' if you want to change
|
||||
it or regenerate `configure' using a newer version of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system. If you're
|
||||
using `csh' on an old version of System V, you might need to type
|
||||
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||
`configure' itself.
|
||||
|
||||
Running `configure' takes a while. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
4. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. You can give `configure'
|
||||
initial values for variables by setting them in the environment. Using
|
||||
a Bourne-compatible shell, you can do that on the command line like
|
||||
this:
|
||||
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
|
||||
|
||||
Or on systems that have the `env' program, you can do it like this:
|
||||
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you must use a version of `make' that
|
||||
supports the `VPATH' variable, such as GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'.
|
||||
|
||||
If you have to use a `make' that does not supports the `VPATH'
|
||||
variable, you have to compile the package for one architecture at a time
|
||||
in the source code directory. After you have installed the package for
|
||||
one architecture, use `make distclean' before reconfiguring for another
|
||||
architecture.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' will install the package's files in
|
||||
`/usr/local/bin', `/usr/local/man', etc. You can specify an
|
||||
installation prefix other than `/usr/local' by giving `configure' the
|
||||
option `--prefix=PATH'.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
give `configure' the option `--exec-prefix=PATH', the package will use
|
||||
PATH as the prefix for installing programs and libraries.
|
||||
Documentation and other data files will still use the regular prefix.
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' can not figure out
|
||||
automatically, but needs to determine by the type of host the package
|
||||
will run on. Usually `configure' can figure that out, but if it prints
|
||||
a message saying it can not guess the host type, give it the
|
||||
`--host=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name with three fields:
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the host type.
|
||||
|
||||
If you are building compiler tools for cross-compiling, you can also
|
||||
use the `--target=TYPE' option to select the type of system they will
|
||||
produce code for and the `--build=TYPE' option to select the type of
|
||||
system on which you are compiling the package.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Operation Controls
|
||||
==================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Use and save the results of the tests in FILE instead of
|
||||
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
|
||||
debugging `configure'.
|
||||
|
||||
`--help'
|
||||
Print a summary of the options to `configure', and exit.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made.
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`--version'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options.
|
||||
|
@ -0,0 +1,5 @@
|
||||
# not a GNU package. You can remove this line, if
|
||||
# have all needed files, that a GNU package needs
|
||||
AUTOMAKE_OPTIONS = foreign 1.4
|
||||
|
||||
SUBDIRS = src
|
@ -0,0 +1,8 @@
|
||||
default: all
|
||||
|
||||
all:
|
||||
aclocal
|
||||
autoheader
|
||||
automake
|
||||
autoconf
|
||||
|
@ -0,0 +1,637 @@
|
||||
# Makefile.in generated by automake 1.10.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008 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@
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
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 = .
|
||||
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in $(srcdir)/config.h.in \
|
||||
$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
|
||||
TODO config.guess config.sub depcomp install-sh ltmain.sh \
|
||||
missing mkinstalldirs
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.in
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
configure.lineno config.status.lineno
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
|
||||
CONFIG_HEADER = config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
|
||||
html-recursive info-recursive install-data-recursive \
|
||||
install-dvi-recursive install-exec-recursive \
|
||||
install-html-recursive install-info-recursive \
|
||||
install-pdf-recursive install-ps-recursive install-recursive \
|
||||
installcheck-recursive installdirs-recursive pdf-recursive \
|
||||
ps-recursive uninstall-recursive
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
am__remove_distdir = \
|
||||
{ test ! -d $(distdir) \
|
||||
|| { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
&& rm -fr $(distdir); }; }
|
||||
DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = --best
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
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@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
ECHO = @ECHO@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
F77 = @F77@
|
||||
FFLAGS = @FFLAGS@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NMEDIT = @NMEDIT@
|
||||
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@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_F77 = @ac_ct_F77@
|
||||
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@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
# not a GNU package. You can remove this line, if
|
||||
# have all needed files, that a GNU package needs
|
||||
AUTOMAKE_OPTIONS = foreign 1.4
|
||||
SUBDIRS = src
|
||||
all: config.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
am--refresh:
|
||||
@:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
|
||||
cd $(srcdir) && $(AUTOMAKE) --foreign \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
|
||||
cd $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
echo ' $(SHELL) ./config.status'; \
|
||||
$(SHELL) ./config.status;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
|
||||
|
||||
config.h: stamp-h1
|
||||
@if test ! -f $@; then \
|
||||
rm -f stamp-h1; \
|
||||
$(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
|
||||
else :; fi
|
||||
|
||||
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
|
||||
@rm -f stamp-h1
|
||||
cd $(top_builddir) && $(SHELL) ./config.status config.h
|
||||
$(srcdir)/config.h.in: $(am__configure_deps)
|
||||
cd $(top_srcdir) && $(AUTOHEADER)
|
||||
rm -f stamp-h1
|
||||
touch $@
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f config.h stamp-h1
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
distclean-libtool:
|
||||
-rm -f libtool
|
||||
|
||||
# This directory's subdirectories are mostly independent; you can cd
|
||||
# into them and run `make' without going through this Makefile.
|
||||
# To change the values of `make' variables: instead of editing Makefiles,
|
||||
# (1) if the variable is set in `config.status', edit `config.status'
|
||||
# (which will cause the Makefiles to be regenerated when you run `make');
|
||||
# (2) otherwise, pass the desired values on the `make' command line.
|
||||
$(RECURSIVE_TARGETS):
|
||||
@failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
dot_seen=yes; \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done; \
|
||||
if test "$$dot_seen" = "no"; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
|
||||
fi; test -z "$$fail"
|
||||
|
||||
$(RECURSIVE_CLEAN_TARGETS):
|
||||
@failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
case "$@" in \
|
||||
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
|
||||
*) list='$(SUBDIRS)' ;; \
|
||||
esac; \
|
||||
rev=''; for subdir in $$list; do \
|
||||
if test "$$subdir" = "."; then :; else \
|
||||
rev="$$subdir $$rev"; \
|
||||
fi; \
|
||||
done; \
|
||||
rev="$$rev ."; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
for subdir in $$rev; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done && test -z "$$fail"
|
||||
tags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
|
||||
done
|
||||
ctags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
|
||||
done
|
||||
|
||||
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; nonemtpy = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
|
||||
include_option=--etags-include; \
|
||||
empty_fix=.; \
|
||||
else \
|
||||
include_option=--include; \
|
||||
empty_fix=; \
|
||||
fi; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test ! -f $$subdir/TAGS || \
|
||||
tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
|
||||
fi; \
|
||||
done; \
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(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; nonempty = 1; } \
|
||||
END { if (nonempty) { 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: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(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; nonempty = 1; } \
|
||||
END { if (nonempty) { 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)
|
||||
$(am__remove_distdir)
|
||||
test -d $(distdir) || mkdir $(distdir)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
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
|
||||
list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test -d "$(distdir)/$$subdir" \
|
||||
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|
||||
|| exit 1; \
|
||||
distdir=`$(am__cd) $(distdir) && pwd`; \
|
||||
top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
|
||||
(cd $$subdir && \
|
||||
$(MAKE) $(AM_MAKEFLAGS) \
|
||||
top_distdir="$$top_distdir" \
|
||||
distdir="$$distdir/$$subdir" \
|
||||
am__remove_distdir=: \
|
||||
am__skip_length_check=: \
|
||||
distdir) \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
|
||||
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|
||||
|| chmod -R a+r $(distdir)
|
||||
dist-gzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-lzma: distdir
|
||||
tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-tarZ: distdir
|
||||
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-shar: distdir
|
||||
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-zip: distdir
|
||||
-rm -f $(distdir).zip
|
||||
zip -rq $(distdir).zip $(distdir)
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist dist-all: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
# This target untars the dist file and tries a VPATH configuration. Then
|
||||
# it guarantees that the distribution is self-contained by making another
|
||||
# tarfile.
|
||||
distcheck: dist
|
||||
case '$(DIST_ARCHIVES)' in \
|
||||
*.tar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
|
||||
*.tar.bz2*) \
|
||||
bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.lzma*) \
|
||||
unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
|
||||
*.tar.Z*) \
|
||||
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
|
||||
*.shar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
|
||||
*.zip*) \
|
||||
unzip $(distdir).zip ;;\
|
||||
esac
|
||||
chmod -R a-w $(distdir); chmod a+w $(distdir)
|
||||
mkdir $(distdir)/_build
|
||||
mkdir $(distdir)/_inst
|
||||
chmod a-w $(distdir)
|
||||
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
|
||||
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
|
||||
&& cd $(distdir)/_build \
|
||||
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
|
||||
$(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) check \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
|
||||
distuninstallcheck \
|
||||
&& chmod -R a-w "$$dc_install_base" \
|
||||
&& ({ \
|
||||
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
|
||||
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
|
||||
} || { rm -rf "$$dc_destdir"; exit 1; }) \
|
||||
&& rm -rf "$$dc_destdir" \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dist \
|
||||
&& rm -rf $(DIST_ARCHIVES) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck
|
||||
$(am__remove_distdir)
|
||||
@(echo "$(distdir) archives ready for distribution: "; \
|
||||
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
|
||||
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
|
||||
distuninstallcheck:
|
||||
@cd $(distuninstallcheck_dir) \
|
||||
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
|
||||
|| { echo "ERROR: files left after uninstall:" ; \
|
||||
if test -n "$(DESTDIR)"; then \
|
||||
echo " (check DESTDIR support)"; \
|
||||
fi ; \
|
||||
$(distuninstallcheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
distcleancheck: distclean
|
||||
@if test '$(srcdir)' = . ; then \
|
||||
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
|
||||
exit 1 ; \
|
||||
fi
|
||||
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left in build directory after distclean:" ; \
|
||||
$(distcleancheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
check-am: all-am
|
||||
check: check-recursive
|
||||
all-am: Makefile config.h
|
||||
installdirs: installdirs-recursive
|
||||
installdirs-am:
|
||||
install: install-recursive
|
||||
install-exec: install-exec-recursive
|
||||
install-data: install-data-recursive
|
||||
uninstall: uninstall-recursive
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-recursive
|
||||
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-recursive
|
||||
|
||||
clean-am: clean-generic clean-libtool mostlyclean-am
|
||||
|
||||
distclean: distclean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic distclean-hdr \
|
||||
distclean-libtool distclean-tags
|
||||
|
||||
dvi: dvi-recursive
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-recursive
|
||||
|
||||
info: info-recursive
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-recursive
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-recursive
|
||||
|
||||
install-info: install-info-recursive
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-recursive
|
||||
|
||||
install-ps: install-ps-recursive
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf $(top_srcdir)/autom4te.cache
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-recursive
|
||||
|
||||
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
|
||||
|
||||
pdf: pdf-recursive
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-recursive
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
|
||||
install-strip
|
||||
|
||||
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
|
||||
all all-am am--refresh check check-am clean clean-generic \
|
||||
clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \
|
||||
dist-gzip dist-lzma dist-shar dist-tarZ dist-zip distcheck \
|
||||
distclean distclean-generic distclean-hdr distclean-libtool \
|
||||
distclean-tags distcleancheck distdir distuninstallcheck dvi \
|
||||
dvi-am html html-am info info-am install install-am \
|
||||
install-data install-data-am install-dvi install-dvi-am \
|
||||
install-exec install-exec-am install-html install-html-am \
|
||||
install-info install-info-am install-man install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs installdirs-am \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-recursive uninstall uninstall-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:
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,32 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int b=0;
|
||||
int c=0;
|
||||
char flag = 0;
|
||||
|
||||
#define PASS_A(a) flag & 0x01 ? c : (flag |= 0x01, c = ntohs(a))
|
||||
|
||||
|
||||
int dosomething(int a) {
|
||||
return a;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int i = 0;
|
||||
int a = 1234;
|
||||
|
||||
//for (i = 0; i < 100000000L; i++) {
|
||||
for (i = 0; i < 10; i++) {
|
||||
printf("PRE : a %d b %d c %d, flag %s\n", a,b,c, flag & 0x01 ? "SET":"NOT SET");
|
||||
|
||||
a = dosomething(PASS_A(a));
|
||||
|
||||
printf("POST: a %d b %d c %d, flag %s\n", a,b,c, flag & 0x01 ? "SET":"NOT SET");
|
||||
|
||||
// a = ntohs(a);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,55 @@
|
||||
/* config.h.in. Generated from configure.in by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,10 @@
|
||||
AC_INIT(configure.in)
|
||||
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
AM_INIT_AUTOMAKE(vips, 0.1)
|
||||
|
||||
AC_LANG_C
|
||||
AC_PROG_CC
|
||||
AM_PROG_LIBTOOL
|
||||
|
||||
AC_OUTPUT(Makefile src/Makefile)
|
@ -0,0 +1,441 @@
|
||||
#! /bin/sh
|
||||
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
# Copyright 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# 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.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
# `libtool' can also be set to `yes' or `no'.
|
||||
|
||||
depfile=${depfile-`echo "$object" | sed 's,\([^/]*\)$,.deps/\1,;s/\.\([^.]*\)$/.P\1/'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
"$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say).
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
|
||||
## The second -e expression handles DOS-style file names with drive letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the `deleted header file' problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" |
|
||||
## Some versions of gcc put a space before the `:'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like `#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
|
||||
tr '
|
||||
' ' ' >> $depfile
|
||||
echo >> $depfile
|
||||
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> $depfile
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. This file always lives in the current directory.
|
||||
# Also, the AIX compiler puts `$object:' at the start of each line;
|
||||
# $object doesn't have directory information.
|
||||
stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'`
|
||||
tmpdepfile="$stripped.u"
|
||||
outname="$stripped.o"
|
||||
if test "$libtool" = yes; then
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
"$@" -M
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form `foo.o: dependent.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
icc)
|
||||
# Must come before tru64.
|
||||
|
||||
# Intel's C compiler understands `-MD -MF file'. However
|
||||
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
|
||||
# will fill foo.d with something like
|
||||
# foo.o: sub/foo.c
|
||||
# foo.o: sub/foo.h
|
||||
# which is wrong. We want:
|
||||
# sub/foo.o: sub/foo.c
|
||||
# sub/foo.o: sub/foo.h
|
||||
# sub/foo.c:
|
||||
# sub/foo.h:
|
||||
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed -e "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
sed -e "s,^[^:]*: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 AIX compiler uses -MD to generate dependencies as a side
|
||||
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in `foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
|
||||
tmpdepfile1="$object.d"
|
||||
tmpdepfile2=`echo "$object" | sed -e 's/.o$/.d/'`
|
||||
if test "$libtool" = yes; then
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
if test -f "$tmpdepfile1"; then
|
||||
tmpdepfile="$tmpdepfile1"
|
||||
else
|
||||
tmpdepfile="$tmpdepfile2"
|
||||
fi
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||
# That's a space and a tab in the [].
|
||||
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the proprocessed file to stdout, regardless of -o,
|
||||
# because we must use -o when running libtool.
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
( IFS=" "
|
||||
case " $* " in
|
||||
*" --mode=compile "*) # this is libtool, let us make it quiet
|
||||
for arg
|
||||
do # cycle over the arguments
|
||||
case "$arg" in
|
||||
"--mode=compile")
|
||||
# insert --quiet before "--mode=compile"
|
||||
set fnord "$@" --quiet
|
||||
shift # fnord
|
||||
;;
|
||||
esac
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # "$arg"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
"$@" $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
# X makedepend
|
||||
(
|
||||
shift
|
||||
cleared=no
|
||||
for arg in "$@"; do
|
||||
case $cleared in no)
|
||||
set ""; shift
|
||||
cleared=yes
|
||||
esac
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift;;
|
||||
-*)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift;;
|
||||
esac
|
||||
done
|
||||
obj_suffix="`echo $object | sed 's/^.*\././'`"
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} 2>/dev/null -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
tail +3 "$tmpdepfile" | tr ' ' '
|
||||
' | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the proprocessed file to stdout, regardless of -o,
|
||||
# because we must use -o when running libtool.
|
||||
( IFS=" "
|
||||
case " $* " in
|
||||
*" --mode=compile "*)
|
||||
for arg
|
||||
do # cycle over the arguments
|
||||
case $arg in
|
||||
"--mode=compile")
|
||||
# insert --quiet before "--mode=compile"
|
||||
set fnord "$@" --quiet
|
||||
shift # fnord
|
||||
;;
|
||||
esac
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # "$arg"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
"$@" -E |
|
||||
sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
|
||||
sed '$ s: \\$::' > "$tmpdepfile"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the proprocessed file to stdout, regardless of -o,
|
||||
# because we must use -o when running libtool.
|
||||
( IFS=" "
|
||||
case " $* " in
|
||||
*" --mode=compile "*)
|
||||
for arg
|
||||
do # cycle over the arguments
|
||||
case $arg in
|
||||
"--mode=compile")
|
||||
# insert --quiet before "--mode=compile"
|
||||
set fnord "$@" --quiet
|
||||
shift # fnord
|
||||
;;
|
||||
esac
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # "$arg"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
"$@" -E |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
|
||||
echo " " >> "$depfile"
|
||||
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
@ -0,0 +1,276 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5 (mit/util/scripts/install.sh).
|
||||
#
|
||||
# Copyright 1991 by the Massachusetts Institute of Technology
|
||||
#
|
||||
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||
# documentation for any purpose is hereby granted without fee, provided that
|
||||
# the above copyright notice appear in all copies and that both that
|
||||
# copyright notice and this permission notice appear in supporting
|
||||
# documentation, and that the name of M.I.T. not be used in advertising or
|
||||
# publicity pertaining to distribution of the software without specific,
|
||||
# written prior permission. M.I.T. makes no representations about the
|
||||
# suitability of this software for any purpose. It is provided "as is"
|
||||
# without express or implied warranty.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch. It can only install one file at a time, a restriction
|
||||
# shared with many OS's install programs.
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
transformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd=$cpprog
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd=$stripprog
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "$0: no input file specified" >&2
|
||||
exit 1
|
||||
else
|
||||
:
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d "$dst" ]; then
|
||||
instcmd=:
|
||||
chmodcmd=""
|
||||
else
|
||||
instcmd=$mkdirprog
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f "$src" ] || [ -d "$src" ]
|
||||
then
|
||||
:
|
||||
else
|
||||
echo "$0: $src does not exist" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "$0: no destination specified" >&2
|
||||
exit 1
|
||||
else
|
||||
:
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d "$dst" ]
|
||||
then
|
||||
dst=$dst/`basename "$src"`
|
||||
else
|
||||
:
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-$defaultIFS}"
|
||||
|
||||
oIFS=$IFS
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS=$oIFS
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp=$pathcomp$1
|
||||
shift
|
||||
|
||||
if [ ! -d "$pathcomp" ] ;
|
||||
then
|
||||
$mkdirprog "$pathcomp"
|
||||
else
|
||||
:
|
||||
fi
|
||||
|
||||
pathcomp=$pathcomp/
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd "$dst" &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename "$dst"`
|
||||
else
|
||||
dstfile=`basename "$dst" $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename "$dst"`
|
||||
else
|
||||
:
|
||||
fi
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
rmtmp=$dstdir/#rm.$$#
|
||||
|
||||
# Trap to clean up temp files at exit.
|
||||
|
||||
trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
|
||||
trap '(exit $?); exit' 1 2 13 15
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd "$src" "$dsttmp" &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
|
||||
|
||||
# Now remove or move aside any old file at destination location. We try this
|
||||
# two ways since rm can't unlink itself on some systems and the destination
|
||||
# file might be busy for other reasons. In this case, the final cleanup
|
||||
# might fail but the new file should still install successfully.
|
||||
|
||||
{
|
||||
if [ -f "$dstdir/$dstfile" ]
|
||||
then
|
||||
$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
|
||||
$doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
|
||||
{
|
||||
echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
|
||||
(exit 1); exit
|
||||
}
|
||||
else
|
||||
:
|
||||
fi
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
|
||||
|
||||
fi &&
|
||||
|
||||
# The final little trick to "correctly" pass the exit status to the exit trap.
|
||||
|
||||
{
|
||||
(exit 0); exit
|
||||
}
|
@ -0,0 +1,336 @@
|
||||
#! /bin/sh
|
||||
# Common stub for a few missing GNU programs while installing.
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2002 Free Software Foundation, Inc.
|
||||
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# 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.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try \`$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
run=:
|
||||
|
||||
# In the cases where this matters, `missing' is being run in the
|
||||
# srcdir already.
|
||||
if test -f configure.ac; then
|
||||
configure_ac=configure.ac
|
||||
else
|
||||
configure_ac=configure.in
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
--run)
|
||||
# Try to run requested program, and just exit if it succeeds.
|
||||
run=
|
||||
shift
|
||||
"$@" && exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# If it does not exist, or fails to run (possibly an outdated version),
|
||||
# try to emulate it.
|
||||
case "$1" in
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
|
||||
error status if there is no known handling for PROGRAM.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
--run try to run the given command, and emulate it if it fails
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal touch file \`aclocal.m4'
|
||||
autoconf touch file \`configure'
|
||||
autoheader touch file \`config.h.in'
|
||||
automake touch all \`Makefile.in' files
|
||||
bison create \`y.tab.[ch]', if possible, from existing .[ch]
|
||||
flex create \`lex.yy.c', if possible, from existing .c
|
||||
help2man touch the output file
|
||||
lex create \`lex.yy.c', if possible, from existing .c
|
||||
makeinfo touch the output file
|
||||
tar try tar, gnutar, gtar, then tar without non-portable flags
|
||||
yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing 0.4 - GNU automake"
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: Unknown \`$1' option"
|
||||
echo 1>&2 "Try \`$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aclocal*)
|
||||
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
|
||||
# We have it, but it failed.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
|
||||
to install the \`Automake' and \`Perl' packages. Grab them from
|
||||
any GNU archive site."
|
||||
touch aclocal.m4
|
||||
;;
|
||||
|
||||
autoconf)
|
||||
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
|
||||
# We have it, but it failed.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified \`${configure_ac}'. You might want to install the
|
||||
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
|
||||
archive site."
|
||||
touch configure
|
||||
;;
|
||||
|
||||
autoheader)
|
||||
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
|
||||
# We have it, but it failed.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified \`acconfig.h' or \`${configure_ac}'. You might want
|
||||
to install the \`Autoconf' and \`GNU m4' packages. Grab them
|
||||
from any GNU archive site."
|
||||
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
|
||||
test -z "$files" && files="config.h"
|
||||
touch_files=
|
||||
for f in $files; do
|
||||
case "$f" in
|
||||
*:*) touch_files="$touch_files "`echo "$f" |
|
||||
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
|
||||
*) touch_files="$touch_files $f.in";;
|
||||
esac
|
||||
done
|
||||
touch $touch_files
|
||||
;;
|
||||
|
||||
automake*)
|
||||
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
|
||||
# We have it, but it failed.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
|
||||
You might want to install the \`Automake' and \`Perl' packages.
|
||||
Grab them from any GNU archive site."
|
||||
find . -type f -name Makefile.am -print |
|
||||
sed 's/\.am$/.in/' |
|
||||
while read f; do touch "$f"; done
|
||||
;;
|
||||
|
||||
autom4te)
|
||||
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
|
||||
# We have it, but it failed.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is needed, and you do not seem to have it handy on your
|
||||
system. You might have modified some files without having the
|
||||
proper tools for further handling them.
|
||||
You can get \`$1Help2man' as part of \`Autoconf' from any GNU
|
||||
archive site."
|
||||
|
||||
file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
|
||||
test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
|
||||
if test -f "$file"; then
|
||||
touch $file
|
||||
else
|
||||
test -z "$file" || exec >$file
|
||||
echo "#! /bin/sh"
|
||||
echo "# Created by GNU Automake missing as a replacement of"
|
||||
echo "# $ $@"
|
||||
echo "exit 0"
|
||||
chmod +x $file
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
bison|yacc)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified a \`.y' file. You may need the \`Bison' package
|
||||
in order for those modifications to take effect. You can get
|
||||
\`Bison' from any GNU archive site."
|
||||
rm -f y.tab.c y.tab.h
|
||||
if [ $# -ne 1 ]; then
|
||||
eval LASTARG="\${$#}"
|
||||
case "$LASTARG" in
|
||||
*.y)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
|
||||
if [ -f "$SRCFILE" ]; then
|
||||
cp "$SRCFILE" y.tab.c
|
||||
fi
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
|
||||
if [ -f "$SRCFILE" ]; then
|
||||
cp "$SRCFILE" y.tab.h
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [ ! -f y.tab.h ]; then
|
||||
echo >y.tab.h
|
||||
fi
|
||||
if [ ! -f y.tab.c ]; then
|
||||
echo 'main() { return 0; }' >y.tab.c
|
||||
fi
|
||||
;;
|
||||
|
||||
lex|flex)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified a \`.l' file. You may need the \`Flex' package
|
||||
in order for those modifications to take effect. You can get
|
||||
\`Flex' from any GNU archive site."
|
||||
rm -f lex.yy.c
|
||||
if [ $# -ne 1 ]; then
|
||||
eval LASTARG="\${$#}"
|
||||
case "$LASTARG" in
|
||||
*.l)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
|
||||
if [ -f "$SRCFILE" ]; then
|
||||
cp "$SRCFILE" lex.yy.c
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [ ! -f lex.yy.c ]; then
|
||||
echo 'main() { return 0; }' >lex.yy.c
|
||||
fi
|
||||
;;
|
||||
|
||||
help2man)
|
||||
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
|
||||
# We have it, but it failed.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified a dependency of a manual page. You may need the
|
||||
\`Help2man' package in order for those modifications to take
|
||||
effect. You can get \`Help2man' from any GNU archive site."
|
||||
|
||||
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
|
||||
if test -z "$file"; then
|
||||
file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
|
||||
fi
|
||||
if [ -f "$file" ]; then
|
||||
touch $file
|
||||
else
|
||||
test -z "$file" || exec >$file
|
||||
echo ".ab help2man is required to generate this page"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
makeinfo)
|
||||
if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
|
||||
# We have makeinfo, but it failed.
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is missing on your system. You should only need it if
|
||||
you modified a \`.texi' or \`.texinfo' file, or any other file
|
||||
indirectly affecting the aspect of the manual. The spurious
|
||||
call might also be the consequence of using a buggy \`make' (AIX,
|
||||
DU, IRIX). You might want to install the \`Texinfo' package or
|
||||
the \`GNU make' package. Grab either from any GNU archive site."
|
||||
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
|
||||
if test -z "$file"; then
|
||||
file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
|
||||
file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
|
||||
fi
|
||||
touch $file
|
||||
;;
|
||||
|
||||
tar)
|
||||
shift
|
||||
if test -n "$run"; then
|
||||
echo 1>&2 "ERROR: \`tar' requires --run"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We have already tried tar in the generic part.
|
||||
# Look for gnutar/gtar before invocation to avoid ugly error
|
||||
# messages.
|
||||
if (gnutar --version > /dev/null 2>&1); then
|
||||
gnutar "$@" && exit 0
|
||||
fi
|
||||
if (gtar --version > /dev/null 2>&1); then
|
||||
gtar "$@" && exit 0
|
||||
fi
|
||||
firstarg="$1"
|
||||
if shift; then
|
||||
case "$firstarg" in
|
||||
*o*)
|
||||
firstarg=`echo "$firstarg" | sed s/o//`
|
||||
tar "$firstarg" "$@" && exit 0
|
||||
;;
|
||||
esac
|
||||
case "$firstarg" in
|
||||
*h*)
|
||||
firstarg=`echo "$firstarg" | sed s/h//`
|
||||
tar "$firstarg" "$@" && exit 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: I can't seem to be able to run \`tar' with the given arguments.
|
||||
You may want to install GNU tar or Free paxutils, or check the
|
||||
command line arguments."
|
||||
exit 1
|
||||
;;
|
||||
|
||||
*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is needed, and you do not seem to have it handy on your
|
||||
system. You might have modified some files without having the
|
||||
proper tools for further handling them. Check the \`README' file,
|
||||
it often tells you about the needed prerequirements for installing
|
||||
this package. You may also peek at any GNU archive site, in case
|
||||
some other package would contain this missing \`$1' program."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
@ -0,0 +1,111 @@
|
||||
#! /bin/sh
|
||||
# mkinstalldirs --- make directory hierarchy
|
||||
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
|
||||
# Created: 1993-05-16
|
||||
# Public domain
|
||||
|
||||
errstatus=0
|
||||
dirmode=""
|
||||
|
||||
usage="\
|
||||
Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..."
|
||||
|
||||
# process command line arguments
|
||||
while test $# -gt 0 ; do
|
||||
case $1 in
|
||||
-h | --help | --h*) # -h for help
|
||||
echo "$usage" 1>&2
|
||||
exit 0
|
||||
;;
|
||||
-m) # -m PERM arg
|
||||
shift
|
||||
test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
|
||||
dirmode=$1
|
||||
shift
|
||||
;;
|
||||
--) # stop option processing
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*) # unknown option
|
||||
echo "$usage" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
*) # first non-opt arg
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
for file
|
||||
do
|
||||
if test -d "$file"; then
|
||||
shift
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
case $# in
|
||||
0) exit 0 ;;
|
||||
esac
|
||||
|
||||
case $dirmode in
|
||||
'')
|
||||
if mkdir -p -- . 2>/dev/null; then
|
||||
echo "mkdir -p -- $*"
|
||||
exec mkdir -p -- "$@"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if mkdir -m "$dirmode" -p -- . 2>/dev/null; then
|
||||
echo "mkdir -m $dirmode -p -- $*"
|
||||
exec mkdir -m "$dirmode" -p -- "$@"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
for file
|
||||
do
|
||||
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
|
||||
shift
|
||||
|
||||
pathcomp=
|
||||
for d
|
||||
do
|
||||
pathcomp="$pathcomp$d"
|
||||
case $pathcomp in
|
||||
-*) pathcomp=./$pathcomp ;;
|
||||
esac
|
||||
|
||||
if test ! -d "$pathcomp"; then
|
||||
echo "mkdir $pathcomp"
|
||||
|
||||
mkdir "$pathcomp" || lasterr=$?
|
||||
|
||||
if test ! -d "$pathcomp"; then
|
||||
errstatus=$lasterr
|
||||
else
|
||||
if test ! -z "$dirmode"; then
|
||||
echo "chmod $dirmode $pathcomp"
|
||||
lasterr=""
|
||||
chmod "$dirmode" "$pathcomp" || lasterr=$?
|
||||
|
||||
if test ! -z "$lasterr"; then
|
||||
errstatus=$lasterr
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
pathcomp="$pathcomp/"
|
||||
done
|
||||
done
|
||||
|
||||
exit $errstatus
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# End:
|
||||
# mkinstalldirs ends here
|
@ -0,0 +1,67 @@
|
||||
bin_PROGRAMS = vips
|
||||
vips_SOURCES = vips.c vips.h \
|
||||
config.c config.h \
|
||||
packet-queue.c packet-queue.h \
|
||||
threads.c threads.h \
|
||||
source-nfq.c source-nfq.h \
|
||||
decode.c decode.h \
|
||||
decode-ipv4.c decode-ipv4.h \
|
||||
decode-ipv6.c decode-ipv6.h \
|
||||
decode-icmpv4.c decode-icmpv4.h \
|
||||
decode-icmpv6.c decode-icmpv6.h \
|
||||
decode-tcp.c decode-tcp.h \
|
||||
decode-http.c decode-http.h \
|
||||
flow.c flow.h \
|
||||
flow-queue.c flow-queue.h \
|
||||
flow-hash.c flow-hash.h \
|
||||
flow-util.c flow-util.h \
|
||||
flow-var.c flow-var.h \
|
||||
host.c host.h \
|
||||
detect.c detect.h \
|
||||
detect-mpm.c detect-mpm.h \
|
||||
detect-content.c detect-content.h \
|
||||
detect-uricontent.c detect-uricontent.h \
|
||||
detect-flowvar.c detect-flowvar.h \
|
||||
detect-pcre.c detect-pcre.h \
|
||||
detect-depth.c detect-depth.h \
|
||||
detect-nocase.c detect-nocase.h \
|
||||
detect-recursive.c detect-recursive.h \
|
||||
detect-rawbytes.c detect-rawbytes.h \
|
||||
detect-within.c detect-within.h \
|
||||
detect-distance.c detect-distance.h \
|
||||
detect-offset.c detect-offset.h \
|
||||
detect-sid.c detect-sid.h \
|
||||
detect-rev.c detect-rev.h \
|
||||
detect-classtype.c detect-classtype.h \
|
||||
detect-reference.c detect-reference.h \
|
||||
detect-threshold.c detect-threshold.h \
|
||||
detect-metadata.c detect-metadata.h \
|
||||
detect-msg.c detect-msg.h \
|
||||
detect-flow.c detect-flow.h \
|
||||
detect-dsize.c detect-dsize.h \
|
||||
detect-address.c detect-address.h \
|
||||
util-mpm-trie.c util-mpm-trie.h \
|
||||
util-mpm.c util-mpm.h \
|
||||
util-binsearch.c util-binsearch.h \
|
||||
util-mpm-wumanber.c util-mpm-wumanber.h \
|
||||
util-cidr.c util-cidr.h \
|
||||
util-unittest.c util-unittest.h \
|
||||
tm-modules.c tm-modules.h \
|
||||
tm-queues.c tm-queues.h \
|
||||
tm-queuehandlers.c tm-queuehandlers.h \
|
||||
tm-threads.c tm-threads.h \
|
||||
tmqh-simple.c tmqh-simple.h \
|
||||
tmqh-nfq.c tmqh-nfq.h \
|
||||
tmqh-packetpool.c tmqh-packetpool.h \
|
||||
alert-fastlog.c alert-fastlog.h \
|
||||
alert-unified-log.c alert-unified-log.h \
|
||||
alert-unified-alert.c alert-unified-alert.h
|
||||
|
||||
# set the include path found by configure
|
||||
INCLUDES= $(all_includes)
|
||||
|
||||
# the library search path.
|
||||
vips_LDFLAGS = $(all_libraries)
|
||||
vips_LDADD = -lnetfilter_queue -lpthread -lpcre
|
||||
vips_CFLAGS = -Wall -fno-strict-aliasing
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,174 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
/* alert fastlog
|
||||
*
|
||||
* Logs alerts in a line based text format compatible to Snort's
|
||||
* alert_fast format.
|
||||
*
|
||||
* TODO
|
||||
* - Print the protocol as a string
|
||||
* - Support classifications
|
||||
* - Support priorities
|
||||
* - Support more than just IPv4/IPv4 TCP/UDP.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vips.h"
|
||||
#include "debug.h"
|
||||
#include "detect.h"
|
||||
#include "flow.h"
|
||||
|
||||
#include "threadvars.h"
|
||||
#include "tm-modules.h"
|
||||
|
||||
#include "util-unittest.h"
|
||||
|
||||
int AlertFastlog (ThreadVars *, Packet *, void *);
|
||||
int AlertFastlogIPv4(ThreadVars *, Packet *, void *);
|
||||
int AlertFastlogIPv6(ThreadVars *, Packet *, void *);
|
||||
int AlertFastlogThreadInit(ThreadVars *, void **);
|
||||
int AlertFastlogThreadDeinit(ThreadVars *, void *);
|
||||
|
||||
void TmModuleAlertFastlogRegister (void) {
|
||||
tmm_modules[TMM_ALERTFASTLOG].name = "AlertFastlog";
|
||||
tmm_modules[TMM_ALERTFASTLOG].Init = AlertFastlogThreadInit;
|
||||
tmm_modules[TMM_ALERTFASTLOG].Func = AlertFastlog;
|
||||
tmm_modules[TMM_ALERTFASTLOG].Deinit = AlertFastlogThreadDeinit;
|
||||
}
|
||||
|
||||
void TmModuleAlertFastlogIPv4Register (void) {
|
||||
tmm_modules[TMM_ALERTFASTLOG4].name = "AlertFastlogIPv4";
|
||||
tmm_modules[TMM_ALERTFASTLOG4].Init = AlertFastlogThreadInit;
|
||||
tmm_modules[TMM_ALERTFASTLOG4].Func = AlertFastlogIPv4;
|
||||
tmm_modules[TMM_ALERTFASTLOG4].Deinit = AlertFastlogThreadDeinit;
|
||||
}
|
||||
|
||||
void TmModuleAlertFastlogIPv6Register (void) {
|
||||
tmm_modules[TMM_ALERTFASTLOG6].name = "AlertFastlogIPv6";
|
||||
tmm_modules[TMM_ALERTFASTLOG6].Init = AlertFastlogThreadInit;
|
||||
tmm_modules[TMM_ALERTFASTLOG6].Func = AlertFastlogIPv6;
|
||||
tmm_modules[TMM_ALERTFASTLOG6].Deinit = AlertFastlogThreadDeinit;
|
||||
}
|
||||
|
||||
typedef struct _AlertFastlogThread {
|
||||
FILE *fp;
|
||||
} AlertFastlogThread;
|
||||
|
||||
static void CreateTimeString (const struct timeval *ts, char *str, size_t size) {
|
||||
time_t time = ts->tv_sec;
|
||||
struct tm *t = gmtime(&time);
|
||||
u_int32_t sec = ts->tv_sec % 86400;
|
||||
|
||||
snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u",
|
||||
t->tm_mon + 1, t->tm_mday, t->tm_year - 100,
|
||||
sec / 3600, (sec % 3600) / 60, sec % 60,
|
||||
(u_int32_t) ts->tv_usec);
|
||||
}
|
||||
|
||||
int AlertFastlogIPv4(ThreadVars *tv, Packet *p, void *data)
|
||||
{
|
||||
AlertFastlogThread *aft = (AlertFastlogThread *)data;
|
||||
int i;
|
||||
char timebuf[64];
|
||||
|
||||
if (p->alerts.cnt == 0)
|
||||
return 0;
|
||||
|
||||
CreateTimeString(&p->ts, timebuf, sizeof(timebuf));
|
||||
|
||||
for (i = 0; i < p->alerts.cnt; i++) {
|
||||
PacketAlert *pa = &p->alerts.alerts[i];
|
||||
char srcip[16], dstip[16];
|
||||
|
||||
inet_ntop(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip));
|
||||
inet_ntop(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip));
|
||||
|
||||
fprintf(aft->fp, "%s [**] [%u:%u:%u] %s [**] [Classification: fixme] [Priority: 1] {%u} %s:%u -> %s:%u\n",
|
||||
timebuf, pa->gid, pa->sid, pa->rev, pa->msg, IPV4_GET_IPPROTO(p), srcip, p->sp, dstip, p->dp);
|
||||
fflush(aft->fp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertFastlogIPv6(ThreadVars *tv, Packet *p, void *data)
|
||||
{
|
||||
AlertFastlogThread *aft = (AlertFastlogThread *)data;
|
||||
int i;
|
||||
char timebuf[64];
|
||||
|
||||
if (p->alerts.cnt == 0)
|
||||
return 0;
|
||||
|
||||
CreateTimeString(&p->ts, timebuf, sizeof(timebuf));
|
||||
|
||||
for (i = 0; i < p->alerts.cnt; i++) {
|
||||
PacketAlert *pa = &p->alerts.alerts[i];
|
||||
char srcip[46], dstip[46];
|
||||
|
||||
inet_ntop(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip));
|
||||
inet_ntop(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip));
|
||||
|
||||
fprintf(aft->fp, "%s [**] [%u:%u:%u] %s [**] [Classification: fixme] [Priority: 1] {%u} %s:%u -> %s:%u\n",
|
||||
timebuf, pa->gid, pa->sid, pa->rev, pa->msg, IPV6_GET_L4PROTO(p), srcip, p->sp, dstip, p->dp);
|
||||
fflush(aft->fp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertFastlog (ThreadVars *tv, Packet *p, void *data)
|
||||
{
|
||||
if (PKT_IS_IPV4(p)) {
|
||||
return(AlertFastlogIPv4(tv, p, data));
|
||||
} else if (PKT_IS_IPV6(p)) {
|
||||
return(AlertFastlogIPv6(tv, p, data));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertFastlogThreadInit(ThreadVars *t, void **data)
|
||||
{
|
||||
AlertFastlogThread *aft = malloc(sizeof(AlertFastlogThread));
|
||||
if (aft == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memset(aft, 0, sizeof(AlertFastlogThread));
|
||||
|
||||
/* XXX */
|
||||
aft->fp = fopen("/var/log/eips/fast.log", "w");
|
||||
if (aft->fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*data = (void *)aft;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertFastlogThreadDeinit(ThreadVars *t, void *data)
|
||||
{
|
||||
AlertFastlogThread *aft = (AlertFastlogThread *)data;
|
||||
if (aft == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (aft->fp != NULL)
|
||||
fclose(aft->fp);
|
||||
|
||||
/* clear memory */
|
||||
memset(aft, 0, sizeof(AlertFastlogThread));
|
||||
|
||||
free(aft);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __ALERT_FASTLOG_H__
|
||||
#define __ALERT_FASTLOG_H__
|
||||
|
||||
void TmModuleAlertFastlogRegister (void);
|
||||
void TmModuleAlertFastlogIPv4Register (void);
|
||||
void TmModuleAlertFastlogIPv6Register (void);
|
||||
|
||||
#endif /* __ALERT_FASTLOG_H__ */
|
||||
|
@ -0,0 +1,251 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
/* alert unified
|
||||
*
|
||||
* Logs alerts in a format compatible to Snort's unified1 format, so it should
|
||||
* be readable by Barnyard.
|
||||
*
|
||||
* TODO
|
||||
* - inspect error messages for threadsafety
|
||||
* - inspect gettimeofday for threadsafely
|
||||
* - implement configuration
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vips.h"
|
||||
#include "debug.h"
|
||||
#include "detect.h"
|
||||
#include "flow.h"
|
||||
|
||||
#include "threadvars.h"
|
||||
#include "tm-modules.h"
|
||||
|
||||
#include "util-unittest.h"
|
||||
|
||||
int AlertUnifiedAlert (ThreadVars *, Packet *, void *);
|
||||
int AlertUnifiedAlertThreadInit(ThreadVars *, void **);
|
||||
int AlertUnifiedAlertThreadDeinit(ThreadVars *, void *);
|
||||
|
||||
void TmModuleAlertUnifiedAlertRegister (void) {
|
||||
tmm_modules[TMM_ALERTUNIFIEDALERT].name = "AlertUnifiedAlert";
|
||||
tmm_modules[TMM_ALERTUNIFIEDALERT].Init = AlertUnifiedAlertThreadInit;
|
||||
tmm_modules[TMM_ALERTUNIFIEDALERT].Func = AlertUnifiedAlert;
|
||||
tmm_modules[TMM_ALERTUNIFIEDALERT].Deinit = AlertUnifiedAlertThreadDeinit;
|
||||
}
|
||||
|
||||
typedef struct _AlertUnifiedAlertThread {
|
||||
FILE *fp;
|
||||
u_int32_t size_limit;
|
||||
u_int32_t size_current;
|
||||
} AlertUnifiedAlertThread;
|
||||
|
||||
#define ALERTUNIFIEDALERT_ALERTMAGIC 0xDEAD4137 /* taken from Snort */
|
||||
#define ALERTUNIFIEDALERT_VERMAJOR 1 /* taken from Snort */
|
||||
#define ALERTUNIFIEDALERT_VERMINOR 81 /* taken from Snort */
|
||||
|
||||
typedef struct _AlertUnifiedAlertFileHeader {
|
||||
u_int32_t magic;
|
||||
u_int32_t ver_major;
|
||||
u_int32_t ver_minor;
|
||||
u_int32_t timezone;
|
||||
} AlertUnifiedAlertFileHeader;
|
||||
|
||||
typedef struct _AlertUnifiedAlertPacketHeader {
|
||||
/* Snort's 'Event' structure */
|
||||
u_int32_t sig_gen;
|
||||
u_int32_t sig_sid;
|
||||
u_int32_t sig_rev;
|
||||
u_int32_t sig_class;
|
||||
u_int32_t sig_prio;
|
||||
u_int32_t pad1; /* Snort's event_id */
|
||||
u_int32_t pad2; /* Snort's event_reference */
|
||||
u_int32_t tv_sec1; /* from Snort's struct pcap_timeval in Event */
|
||||
u_int32_t tv_usec1; /* from Snort's struct pcap_timeval in Event */
|
||||
|
||||
u_int32_t tv_sec2; /* from Snort's struct pcap_timeval */
|
||||
u_int32_t tv_usec2; /* from Snort's struct pcap_timeval */
|
||||
|
||||
u_int32_t src_ip;
|
||||
u_int32_t dst_ip;
|
||||
u_int16_t sp;
|
||||
u_int16_t dp;
|
||||
u_int32_t protocol;
|
||||
u_int32_t flags;
|
||||
} AlertUnifiedAlertPacketHeader;
|
||||
|
||||
int AlertUnifiedAlertCreateFile(ThreadVars *t, AlertUnifiedAlertThread *aun) {
|
||||
char filename[2048]; /* XXX some sane default? */
|
||||
int ret;
|
||||
|
||||
/* get the time so we can have a filename with seconds since epoch
|
||||
* in it. XXX review if we can take this info from somewhere else.
|
||||
* This is used both during init and runtime, so it must be thread
|
||||
* safe. */
|
||||
struct timeval ts;
|
||||
memset (&ts, 0, sizeof(struct timeval));
|
||||
gettimeofday(&ts, NULL);
|
||||
|
||||
/* create the filename to use */
|
||||
snprintf(filename, sizeof(filename), "%s/%s.%u", "/var/log/eips", "unified.alert", (u_int32_t)ts.tv_sec);
|
||||
|
||||
/* XXX filename & location */
|
||||
aun->fp = fopen(filename, "wb");
|
||||
if (aun->fp == NULL) {
|
||||
printf("Error: fopen failed: %s\n", strerror(errno)); /* XXX errno threadsafety? */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* write the fileheader to the file so the reader can recognize it */
|
||||
AlertUnifiedAlertFileHeader hdr;
|
||||
hdr.magic = ALERTUNIFIEDALERT_ALERTMAGIC;
|
||||
hdr.ver_major = ALERTUNIFIEDALERT_VERMAJOR;
|
||||
hdr.ver_minor = ALERTUNIFIEDALERT_VERMINOR;
|
||||
hdr.timezone = 0; /* XXX */
|
||||
|
||||
ret = fwrite(&hdr, sizeof(hdr), 1, aun->fp);
|
||||
if (ret != 1) {
|
||||
printf("Error: fwrite failed: ret = %d, %s\n", ret, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
fflush(aun->fp);
|
||||
|
||||
aun->size_current = sizeof(hdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertUnifiedAlertCloseFile(ThreadVars *t, AlertUnifiedAlertThread *aun) {
|
||||
if (aun->fp != NULL)
|
||||
fclose(aun->fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertUnifiedAlertRotateFile(ThreadVars *t, AlertUnifiedAlertThread *aun) {
|
||||
if (AlertUnifiedAlertCloseFile(t,aun) < 0) {
|
||||
printf("Error: AlertUnifiedAlertCloseFile failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (AlertUnifiedAlertCreateFile(t, aun) < 0) {
|
||||
printf("Error: AlertUnifiedCreateFile failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertUnifiedAlert (ThreadVars *tv, Packet *p, void *data)
|
||||
{
|
||||
AlertUnifiedAlertThread *aun = (AlertUnifiedAlertThread *)data;
|
||||
AlertUnifiedAlertPacketHeader hdr;
|
||||
int ret;
|
||||
u_int8_t ethh_offset = 0;
|
||||
|
||||
/* the unified1 format only supports IPv4. */
|
||||
if (p->alerts.cnt == 0 || !PKT_IS_IPV4(p))
|
||||
return 0;
|
||||
|
||||
/* if we have no ethernet header (e.g. when using nfq), we have to create
|
||||
* one ourselves. */
|
||||
if (p->ethh == NULL) {
|
||||
ethh_offset = sizeof(EthernetHdr);
|
||||
}
|
||||
|
||||
/* check and enforce the filesize limit */
|
||||
if ((aun->size_current + sizeof(hdr)) > aun->size_limit) {
|
||||
if (AlertUnifiedAlertRotateFile(tv,aun) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* XXX which one to add to this alert? Lets see how Snort solves this.
|
||||
* For now just take last alert. */
|
||||
PacketAlert *pa = &p->alerts.alerts[p->alerts.cnt-1];
|
||||
|
||||
/* fill the hdr structure */
|
||||
hdr.sig_gen = pa->gid;
|
||||
hdr.sig_sid = pa->sid;
|
||||
hdr.sig_rev = pa->rev;
|
||||
hdr.sig_class = pa->class;
|
||||
hdr.sig_prio = pa->prio;
|
||||
hdr.pad1 = 0;
|
||||
hdr.pad2 = 0;
|
||||
hdr.tv_sec1 = hdr.tv_sec2 = p->ts.tv_sec;
|
||||
hdr.tv_usec1 = hdr.tv_usec2 = p->ts.tv_usec;
|
||||
hdr.src_ip = GET_IPV4_SRC_ADDR_U32(p);
|
||||
hdr.dst_ip = GET_IPV4_DST_ADDR_U32(p);
|
||||
hdr.sp = p->sp;
|
||||
hdr.dp = p->dp;
|
||||
hdr.protocol = IPV4_GET_RAW_IPPROTO(p->ip4h);
|
||||
hdr.flags = 0;
|
||||
|
||||
/* write and flush so it's written immediately */
|
||||
ret = fwrite(&hdr, sizeof(hdr), 1, aun->fp);
|
||||
if (ret != 1) {
|
||||
printf("Error: fwrite failed: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
/* force writing to disk so barnyard will not read half
|
||||
* written records and choke. */
|
||||
fflush(aun->fp);
|
||||
|
||||
aun->size_current += sizeof(hdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertUnifiedAlertThreadInit(ThreadVars *t, void **data)
|
||||
{
|
||||
AlertUnifiedAlertThread *aun = malloc(sizeof(AlertUnifiedAlertThread));
|
||||
if (aun == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memset(aun, 0, sizeof(AlertUnifiedAlertThread));
|
||||
|
||||
aun->fp = NULL;
|
||||
|
||||
int ret = AlertUnifiedAlertCreateFile(t, aun);
|
||||
if (ret != 0) {
|
||||
printf("Error: AlertUnifiedCreateFile failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* XXX make configurable */
|
||||
aun->size_limit = 10 * 1024 * 1024;
|
||||
|
||||
*data = (void *)aun;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertUnifiedAlertThreadDeinit(ThreadVars *t, void *data)
|
||||
{
|
||||
AlertUnifiedAlertThread *aun = (AlertUnifiedAlertThread *)data;
|
||||
if (aun == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AlertUnifiedAlertCloseFile(t, aun) < 0)
|
||||
goto error;
|
||||
|
||||
/* clear memory */
|
||||
memset(aun, 0, sizeof(AlertUnifiedAlertThread));
|
||||
free(aun);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
/* clear memory */
|
||||
if (aun != NULL) {
|
||||
memset(aun, 0, sizeof(AlertUnifiedAlertThread));
|
||||
free(aun);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __ALERT_UNIFIED_ALERT_H__
|
||||
#define __ALERT_UNIFIED_ALERT_H__
|
||||
|
||||
void TmModuleAlertUnifiedAlertRegister (void);
|
||||
|
||||
#endif /* __ALERT_UNIFIED_ALERT_H__ */
|
||||
|
@ -0,0 +1,266 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
/* alert unified
|
||||
*
|
||||
* Logs alerts in a format compatible to Snort's unified1 format, so it should
|
||||
* be readable by Barnyard.
|
||||
*
|
||||
* TODO
|
||||
* - inspect error messages for threadsafety
|
||||
* - inspect gettimeofday for threadsafely
|
||||
* - implement configuration
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vips.h"
|
||||
#include "debug.h"
|
||||
#include "detect.h"
|
||||
#include "flow.h"
|
||||
|
||||
#include "threadvars.h"
|
||||
#include "tm-modules.h"
|
||||
|
||||
#include "util-unittest.h"
|
||||
|
||||
int AlertUnifiedLog (ThreadVars *, Packet *, void *);
|
||||
int AlertUnifiedLogThreadInit(ThreadVars *, void **);
|
||||
int AlertUnifiedLogThreadDeinit(ThreadVars *, void *);
|
||||
|
||||
void TmModuleAlertUnifiedLogRegister (void) {
|
||||
tmm_modules[TMM_ALERTUNIFIEDLOG].name = "AlertUnifiedLog";
|
||||
tmm_modules[TMM_ALERTUNIFIEDLOG].Init = AlertUnifiedLogThreadInit;
|
||||
tmm_modules[TMM_ALERTUNIFIEDLOG].Func = AlertUnifiedLog;
|
||||
tmm_modules[TMM_ALERTUNIFIEDLOG].Deinit = AlertUnifiedLogThreadDeinit;
|
||||
}
|
||||
|
||||
typedef struct _AlertUnifiedLogThread {
|
||||
FILE *fp;
|
||||
u_int32_t size_limit;
|
||||
u_int32_t size_current;
|
||||
} AlertUnifiedLogThread;
|
||||
|
||||
#define ALERTUNIFIEDLOG_LOGMAGIC 0xDEAD1080 /* taken from Snort */
|
||||
#define ALERTUNIFIEDLOG_VERMAJOR 1 /* taken from Snort */
|
||||
#define ALERTUNIFIEDLOG_VERMINOR 2 /* taken from Snort */
|
||||
|
||||
typedef struct _AlertUnifiedLogFileHeader {
|
||||
u_int32_t magic;
|
||||
u_int16_t ver_major;
|
||||
u_int16_t ver_minor;
|
||||
u_int32_t timezone;
|
||||
u_int32_t pad1; /* Snort has something called sigfigs, dunno what it is. I do know it's always 0. */
|
||||
u_int32_t snaplen;
|
||||
u_int32_t linktype;
|
||||
} AlertUnifiedLogFileHeader;
|
||||
|
||||
typedef struct _AlertUnifiedLogPacketHeader {
|
||||
/* Snort's 'Event' structure */
|
||||
u_int32_t sig_gen;
|
||||
u_int32_t sig_sid;
|
||||
u_int32_t sig_rev;
|
||||
u_int32_t sig_class;
|
||||
u_int32_t sig_prio;
|
||||
u_int32_t pad1; /* Snort's event_id */
|
||||
u_int32_t pad2; /* Snort's event_reference */
|
||||
u_int32_t tv_sec1; /* from Snort's struct pcap_timeval */
|
||||
u_int32_t tv_usec1; /* from Snort's struct pcap_timeval */
|
||||
|
||||
/* 32 bit unsigned flags */
|
||||
u_int32_t pktflags;
|
||||
|
||||
/* Snort's 'SnortPktHeader' structure */
|
||||
u_int32_t tv_sec2; /* from Snort's struct pcap_timeval */
|
||||
u_int32_t tv_usec2; /* from Snort's struct pcap_timeval */
|
||||
u_int32_t caplen;
|
||||
u_int32_t pktlen;
|
||||
} AlertUnifiedLogPacketHeader;
|
||||
|
||||
int AlertUnifiedLogCreateFile(ThreadVars *t, AlertUnifiedLogThread *aun) {
|
||||
char filename[2048]; /* XXX some sane default? */
|
||||
int ret;
|
||||
|
||||
/* get the time so we can have a filename with seconds since epoch
|
||||
* in it. XXX review if we can take this info from somewhere else.
|
||||
* This is used both during init and runtime, so it must be thread
|
||||
* safe. */
|
||||
struct timeval ts;
|
||||
memset (&ts, 0, sizeof(struct timeval));
|
||||
gettimeofday(&ts, NULL);
|
||||
|
||||
/* create the filename to use */
|
||||
snprintf(filename, sizeof(filename), "%s/%s.%u", "/var/log/eips", "unified.log", (u_int32_t)ts.tv_sec);
|
||||
|
||||
/* XXX filename & location */
|
||||
aun->fp = fopen(filename, "wb");
|
||||
if (aun->fp == NULL) {
|
||||
printf("Error: fopen failed: %s\n", strerror(errno)); /* XXX errno threadsafety? */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* write the fileheader to the file so the reader can recognize it */
|
||||
AlertUnifiedLogFileHeader hdr;
|
||||
hdr.magic = ALERTUNIFIEDLOG_LOGMAGIC;
|
||||
hdr.ver_major = ALERTUNIFIEDLOG_VERMAJOR;
|
||||
hdr.ver_minor = ALERTUNIFIEDLOG_VERMINOR;
|
||||
hdr.timezone = 0; /* XXX */
|
||||
hdr.pad1 = 0; /* XXX */
|
||||
hdr.snaplen = 65536; /* XXX */
|
||||
hdr.linktype = DLT_EN10MB; /* XXX */
|
||||
|
||||
ret = fwrite(&hdr, sizeof(hdr), 1, aun->fp);
|
||||
if (ret != 1) {
|
||||
printf("Error: fwrite failed: ret = %d, %s\n", ret, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
aun->size_current = sizeof(hdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertUnifiedLogCloseFile(ThreadVars *t, AlertUnifiedLogThread *aun) {
|
||||
if (aun->fp != NULL)
|
||||
fclose(aun->fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertUnifiedLogRotateFile(ThreadVars *t, AlertUnifiedLogThread *aun) {
|
||||
if (AlertUnifiedLogCloseFile(t,aun) < 0) {
|
||||
printf("Error: AlertUnifiedLogCloseFile failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (AlertUnifiedLogCreateFile(t, aun) < 0) {
|
||||
printf("Error: AlertUnifiedCreateFile failed\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertUnifiedLog (ThreadVars *tv, Packet *p, void *data)
|
||||
{
|
||||
AlertUnifiedLogThread *aun = (AlertUnifiedLogThread *)data;
|
||||
AlertUnifiedLogPacketHeader hdr;
|
||||
int ret;
|
||||
u_int8_t ethh_offset = 0;
|
||||
u_int8_t buf[80000];
|
||||
u_int32_t buflen = 0;
|
||||
|
||||
/* the unified1 format only supports IPv4. */
|
||||
if (p->alerts.cnt == 0 || !PKT_IS_IPV4(p))
|
||||
return 0;
|
||||
|
||||
/* if we have no ethernet header (e.g. when using nfq), we have to create
|
||||
* one ourselves. */
|
||||
if (p->ethh == NULL) {
|
||||
ethh_offset = sizeof(EthernetHdr);
|
||||
}
|
||||
|
||||
/* check and enforce the filesize limit */
|
||||
if ((aun->size_current + sizeof(hdr) + p->pktlen + ethh_offset) > aun->size_limit) {
|
||||
if (AlertUnifiedLogRotateFile(tv,aun) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* XXX which one to add to this alert? Lets see how Snort solves this.
|
||||
* For now just take last alert. */
|
||||
PacketAlert *pa = &p->alerts.alerts[p->alerts.cnt-1];
|
||||
|
||||
/* fill the hdr structure */
|
||||
hdr.sig_gen = pa->gid;
|
||||
hdr.sig_sid = pa->sid;
|
||||
hdr.sig_rev = pa->rev;
|
||||
hdr.sig_class = pa->class;
|
||||
hdr.sig_prio = pa->prio;
|
||||
hdr.pad1 = 0;
|
||||
hdr.pad2 = 0;
|
||||
hdr.tv_sec1 = hdr.tv_sec2 = p->ts.tv_sec;
|
||||
hdr.tv_usec1 = hdr.tv_usec2 = p->ts.tv_usec;
|
||||
hdr.pktflags = 0; /* XXX */
|
||||
hdr.pktlen = hdr.caplen = p->pktlen + ethh_offset;
|
||||
|
||||
memcpy(buf,&hdr,sizeof(hdr));
|
||||
buflen = sizeof(hdr);
|
||||
|
||||
if (p->ethh == NULL) {
|
||||
EthernetHdr ethh;
|
||||
memset(ðh, 0, sizeof(EthernetHdr));
|
||||
ethh.eth_type = htons(ETHERNET_TYPE_IP);
|
||||
|
||||
memcpy(buf+buflen,ðh,sizeof(ethh));
|
||||
buflen += sizeof(ethh);
|
||||
}
|
||||
|
||||
memcpy(buf+buflen,&p->pkt,p->pktlen);
|
||||
buflen += p->pktlen;
|
||||
|
||||
/* write and flush so it's written immediately */
|
||||
ret = fwrite(buf, buflen, 1, aun->fp);
|
||||
if (ret != 1) {
|
||||
printf("Error: fwrite failed: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
/* force writing to disk so barnyard will not read half
|
||||
* written records and choke. */
|
||||
fflush(aun->fp);
|
||||
|
||||
aun->size_current += buflen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertUnifiedLogThreadInit(ThreadVars *t, void **data)
|
||||
{
|
||||
AlertUnifiedLogThread *aun = malloc(sizeof(AlertUnifiedLogThread));
|
||||
if (aun == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memset(aun, 0, sizeof(AlertUnifiedLogThread));
|
||||
|
||||
aun->fp = NULL;
|
||||
|
||||
int ret = AlertUnifiedLogCreateFile(t, aun);
|
||||
if (ret != 0) {
|
||||
printf("Error: AlertUnifiedCreateFile failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* XXX make configurable */
|
||||
aun->size_limit = 1 * 1024 * 1024;
|
||||
|
||||
*data = (void *)aun;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AlertUnifiedLogThreadDeinit(ThreadVars *t, void *data)
|
||||
{
|
||||
AlertUnifiedLogThread *aun = (AlertUnifiedLogThread *)data;
|
||||
if (aun == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (AlertUnifiedLogCloseFile(t, aun) < 0)
|
||||
goto error;
|
||||
|
||||
/* clear memory */
|
||||
memset(aun, 0, sizeof(AlertUnifiedLogThread));
|
||||
free(aun);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
/* clear memory */
|
||||
if (aun != NULL) {
|
||||
memset(aun, 0, sizeof(AlertUnifiedLogThread));
|
||||
free(aun);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __ALERT_UNIFIED_LOG_H__
|
||||
#define __ALERT_UNIFIED_LOG_H__
|
||||
|
||||
void TmModuleAlertUnifiedLogRegister (void);
|
||||
|
||||
#endif /* __ALERT_UNIFIED_LOG_H__ */
|
||||
|
@ -0,0 +1,79 @@
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <pcre.h>
|
||||
|
||||
#include "vips.h"
|
||||
|
||||
static pcre *config_pcre = NULL;
|
||||
static pcre_extra *config_pcre_extra = NULL;
|
||||
|
||||
#define CONFIG_PCRE "^\\s*([a-z]+)\\s*(.*)$"
|
||||
|
||||
|
||||
|
||||
int LoadConfig ( void ) {
|
||||
char line[8192] = "";
|
||||
char *regexstr = CONFIG_PCRE;
|
||||
const char *eb;
|
||||
int eo;
|
||||
int opts = 0;
|
||||
int ret = 0;
|
||||
#define MAX_SUBSTRINGS 30
|
||||
int ov[MAX_SUBSTRINGS];
|
||||
|
||||
FILE *fp = fopen("vips.conf", "r");
|
||||
if (fp == NULL) printf("ERROR: fopen failed %s\n", strerror(errno));
|
||||
|
||||
|
||||
//opts |= PCRE_UNGREEDY;
|
||||
config_pcre = pcre_compile(regexstr, opts, &eb, &eo, NULL);
|
||||
if(config_pcre == NULL)
|
||||
{
|
||||
printf("pcre compile of \"%s\" failed at offset %d: %s\n", regexstr, eo, eb);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config_pcre_extra = pcre_study(config_pcre, 0, &eb);
|
||||
if(eb != NULL)
|
||||
{
|
||||
printf("pcre study failed: %s\n", eb);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
while (fgets(line,sizeof(line),fp) != NULL) {
|
||||
//printf("LoadConfig: %s", line);
|
||||
|
||||
ret = pcre_exec(config_pcre, config_pcre_extra, line, strlen(line), 0, 0, ov, MAX_SUBSTRINGS);
|
||||
if (ret != 3) {
|
||||
//printf("pcre_exec failed: ret %d, optstr \"%s\"\n", ret, line);
|
||||
continue;
|
||||
}
|
||||
//printf("LoadConfig: pcre_exec returned %d\n", ret);
|
||||
|
||||
const char *all, *name, *value;
|
||||
pcre_get_substring(line, ov, MAX_SUBSTRINGS, 0, &all);
|
||||
pcre_get_substring(line, ov, MAX_SUBSTRINGS, 1, &name);
|
||||
pcre_get_substring(line, ov, MAX_SUBSTRINGS, 2, &value);
|
||||
|
||||
printf("LoadConfig: name \"%s\" value \"%s\"\n", name, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define DEBUGPRINT(format, args...) \
|
||||
printf("[%s:%d](%s) " format "\n", __FILE__, __LINE__, __FUNCTION__, ## args)
|
||||
|
||||
#else
|
||||
|
||||
#define DEBUGPRINT(format, args...)
|
||||
|
||||
#endif /* DEBUG */
|
||||
#endif /* __DEBUG_H__ */
|
||||
|
@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
#ifndef __DECODE_ETHERNET_H__
|
||||
#define __DECODE_ETHERNET_H__
|
||||
|
||||
/* Ethernet types -- taken from Snort and Libdnet */
|
||||
#define ETHERNET_TYPE_PUP 0x0200 /* PUP protocol */
|
||||
#define ETHERNET_TYPE_IP 0x0800
|
||||
#define ETHERNET_TYPE_ARP 0x0806
|
||||
#define ETHERNET_TYPE_REVARP 0x8035
|
||||
#define ETHERNET_TYPE_EAPOL 0x888e
|
||||
#define ETHERNET_TYPE_IPV6 0x86dd
|
||||
#define ETHERNET_TYPE_IPX 0x8137
|
||||
#define ETHERNET_TYPE_PPPoE_DISC 0x8863 /* discovery stage */
|
||||
#define ETHERNET_TYPE_PPPoE_SESS 0x8864 /* session stage */
|
||||
#define ETHERNET_TYPE_8021Q 0x8100
|
||||
#define ETHERNET_TYPE_LOOP 0x9000
|
||||
|
||||
typedef struct _EthernetHdr {
|
||||
u_int8_t eth_dst[6];
|
||||
u_int8_t eth_src[6];
|
||||
u_int16_t eth_type;
|
||||
} EthernetHdr;
|
||||
|
||||
#endif /* __DECODE_ETHERNET_H__ */
|
||||
|
@ -0,0 +1,35 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __DECODE_EVENTS_H__
|
||||
#define __DECODE_EVENTS_H__
|
||||
|
||||
enum {
|
||||
/* IPV4 EVENTS */
|
||||
IPV4_PKT_TOO_SMALL = 1, /* pkt smaller than minimum header size */
|
||||
IPV4_HLEN_TOO_SMALL,
|
||||
IPV4_IPLEN_SMALLER_THAN_HLEN,
|
||||
|
||||
/* IPV6 EVENTS */
|
||||
IPV6_PKT_TOO_SMALL,
|
||||
IPV6_TRUNC_EXTHDR,
|
||||
IPV6_EXTHDR_DUPL_FH,
|
||||
IPV6_EXTHDR_DUPL_RH,
|
||||
IPV6_EXTHDR_DUPL_HH,
|
||||
IPV6_EXTHDR_DUPL_DH,
|
||||
IPV6_EXTHDR_DUPL_AH,
|
||||
IPV6_EXTHDR_DUPL_EH,
|
||||
|
||||
IPV6_EXTHDR_INVALID_OPTLEN, /* the optlen in an hop or dst hdr is invalid. */
|
||||
|
||||
/* TCP EVENTS */
|
||||
TCP_PKT_TOO_SMALL,
|
||||
TCP_HLEN_TOO_SMALL,
|
||||
TCP_INVALID_OPTLEN,
|
||||
|
||||
/* TCP OPTIONS */
|
||||
TCP_OPT_INVALID_LEN,
|
||||
TCP_OPT_DUPLICATE, /* option length isn't right */
|
||||
|
||||
};
|
||||
|
||||
#endif /* __DECODE_EVENTS_H__ */
|
@ -0,0 +1,56 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#include "decode.h"
|
||||
#include "decode-http.h"
|
||||
#include "decode-events.h"
|
||||
|
||||
#define HTTP_HEADER_LEN 10
|
||||
#define HTTP_BANNER "HTTP"
|
||||
#define HTTP_GET "GET"
|
||||
#define HTTP_POST "POST"
|
||||
|
||||
void DecodeHTTP(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
int i, u = 0;
|
||||
char uri[2048];
|
||||
char code[4];
|
||||
|
||||
if (len < HTTP_HEADER_LEN)
|
||||
return;
|
||||
|
||||
if (memcmp(pkt, HTTP_GET, 3) == 0) {
|
||||
for (u = 0, i = 4; i < len && pkt[i] != ' ' && u < sizeof(uri); i++) {
|
||||
uri[u] = pkt[i];
|
||||
u++;
|
||||
}
|
||||
uri[u] = '\0';
|
||||
#ifdef DEBUG
|
||||
printf("HTTP GET %s\n", uri);
|
||||
#endif
|
||||
|
||||
} else if (memcmp(pkt, HTTP_POST, 4) == 0) {
|
||||
for (u = 0, i = 5; i < len && pkt[i] != ' ' && u < sizeof(uri); i++) {
|
||||
uri[u] = pkt[i];
|
||||
u++;
|
||||
}
|
||||
uri[u] = '\0';
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("HTTP POST %s\n", uri);
|
||||
#endif
|
||||
}
|
||||
if (memcmp(pkt, HTTP_BANNER, 4) == 0) {
|
||||
for (u = 0, i = 9; i < len && pkt[i] != ' ' && u < sizeof(code); i++) {
|
||||
code[u] = pkt[i];
|
||||
u++;
|
||||
}
|
||||
code[u] = '\0';
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("HTTP reply code %s\n", code);
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __DECODE_HTTP_H__
|
||||
#define __DECODE_HTTP_H__
|
||||
|
||||
#endif /* __DECODE_HTTP_H__ */
|
||||
|
@ -0,0 +1,20 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#include "decode.h"
|
||||
#include "decode-icmpv4.h"
|
||||
|
||||
void DecodeICMPV4(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len )
|
||||
{
|
||||
p->icmpv4h = (ICMPV4Hdr *)pkt;
|
||||
|
||||
if (len < ICMPV4_HEADER_LEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("ICMPV4 TYPE %u CODE %u\n", p->icmpv4h->type, p->icmpv4h->code);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __DECODE_ICMPV4_H__
|
||||
#define __DECODE_ICMPV4_H__
|
||||
|
||||
#define ICMPV4_HEADER_LEN 4
|
||||
|
||||
/* ICMPv4 header structure */
|
||||
typedef struct _ICMPV4Hdr
|
||||
{
|
||||
u_int8_t type;
|
||||
u_int8_t code;
|
||||
u_int16_t csum;
|
||||
|
||||
/* XXX incomplete */
|
||||
} ICMPV4Hdr;
|
||||
|
||||
#endif /* __DECODE_ICMPV4_H__ */
|
||||
|
@ -0,0 +1,20 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#include "decode.h"
|
||||
#include "decode-icmpv6.h"
|
||||
|
||||
void DecodeICMPV6(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
p->icmpv6h = (ICMPV6Hdr *)pkt;
|
||||
|
||||
if (len < ICMPV6_HEADER_LEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("ICMPV6 TYPE %u CODE %u\n", p->icmpv6h->type, p->icmpv6h->code);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __DECODE_ICMPV6_H__
|
||||
#define __DECODE_ICMPV6_H__
|
||||
|
||||
#define ICMPV6_HEADER_LEN 8
|
||||
|
||||
typedef struct _ICMPV6Hdr
|
||||
{
|
||||
u_int8_t type;
|
||||
u_int8_t code;
|
||||
u_int16_t csum;
|
||||
|
||||
/* XXX incomplete */
|
||||
} ICMPV6Hdr;
|
||||
|
||||
#endif /* __DECODE_ICMPV6_H__ */
|
||||
|
@ -0,0 +1,109 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#include "vips.h"
|
||||
#include "packet-queue.h"
|
||||
#include "decode.h"
|
||||
#include "decode-ipv4.h"
|
||||
#include "decode-events.h"
|
||||
|
||||
/* XXX */
|
||||
static int DecodeIPV4Options(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
printf("*pkt %u\n", *pkt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DecodeIPV4Packet(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("DecodeIPV4Packet\n");
|
||||
#endif
|
||||
p->ip4h = (IPV4Hdr *)pkt;
|
||||
|
||||
if (len < IPV4_HEADER_LEN) {
|
||||
DECODER_SET_EVENT(p,IPV4_PKT_TOO_SMALL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (IPV4_GET_HLEN(p) < IPV4_HEADER_LEN) {
|
||||
DECODER_SET_EVENT(p,IPV4_HLEN_TOO_SMALL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (IPV4_GET_IPLEN(p) < IPV4_GET_HLEN(p)) {
|
||||
DECODER_SET_EVENT(p,IPV4_IPLEN_SMALLER_THAN_HLEN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* save the options len */
|
||||
p->ip4vars.ip_opts_len = IPV4_GET_HLEN(p) - IPV4_HEADER_LEN;
|
||||
if (p->ip4vars.ip_opts_len > 0) {
|
||||
DecodeIPV4Options(t, p, pkt + IPV4_GET_HLEN(p), p->ip4vars.ip_opts_len);
|
||||
}
|
||||
|
||||
/* set the address struct */
|
||||
SET_IPV4_SRC_ADDR(p,&p->src);
|
||||
SET_IPV4_DST_ADDR(p,&p->dst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DecodeIPV4(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* reset the decoder cache flags */
|
||||
IPV4_CACHE_INIT(p);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("DecodeIPV4\n");
|
||||
#endif
|
||||
|
||||
/* do the actual decoding */
|
||||
ret = DecodeIPV4Packet (t, p, pkt, len);
|
||||
if (ret < 0) {
|
||||
#ifdef DEBUG
|
||||
printf("DecodeIPV4 failed!\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* do hdr test, process hdr rules */
|
||||
|
||||
#ifdef DEBUG
|
||||
/* debug print */
|
||||
char s[16], d[16];
|
||||
inet_ntop(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), s, sizeof(s));
|
||||
inet_ntop(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), d, sizeof(d));
|
||||
printf("IPV4 %s->%s PROTO: %u OFFSET: %u RF: %u DF: %u MF: %u ID: %u\n", s,d,
|
||||
IPV4_GET_IPPROTO(p), IPV4_GET_IPOFFSET(p), IPV4_GET_RF(p),
|
||||
IPV4_GET_DF(p), IPV4_GET_MF(p), IPV4_GET_IPID(p));
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* check what next decoder to invoke */
|
||||
switch (IPV4_GET_IPPROTO(p)) {
|
||||
case IPPROTO_TCP:
|
||||
return(DecodeTCP(t, p, pkt + IPV4_GET_HLEN(p), len - IPV4_GET_HLEN(p)));
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
//printf("DecodeIPV4: next layer is UDP\n");
|
||||
break;
|
||||
case IPPROTO_ICMP:
|
||||
//printf("DecodeIPV4: next layer is ICMP\n");
|
||||
return(DecodeICMPV4(t, p, pkt + IPV4_GET_HLEN(p), len - IPV4_GET_HLEN(p)));
|
||||
break;
|
||||
case IPPROTO_IPV6:
|
||||
//printf("DecodeIPV4: next layer is IPV6\n");
|
||||
//printf("DecodeIPV4: we are p %p\n", p);
|
||||
|
||||
/* spawn off tunnel packet */
|
||||
SetupTunnelPkt(t, p, pkt + IPV4_GET_HLEN(p), len - IPV4_GET_HLEN(p), IPV4_GET_IPPROTO(p));
|
||||
/* this is now a tunnel packet */
|
||||
SET_TUNNEL_PKT(p);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,146 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __DECODE_IPV4_H__
|
||||
#define __DECODE_IPV4_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pcap.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#define IPV4_HEADER_LEN 20
|
||||
#define IPV4_OPTMAX 40
|
||||
#define IPV4_MAXPACKET_LEN 65535 /* maximum packet size */
|
||||
|
||||
#define IPV4_OPT_EOL 0x00
|
||||
#define IPV4_OPT_NOP 0x01
|
||||
#define IPV4_OPT_RR 0x07
|
||||
#define IPV4_OPT_RTRALT 0x94
|
||||
#define IPV4_OPT_TS 0x44
|
||||
#define IPV4_OPT_SECURITY 0x82
|
||||
#define IPV4_OPT_LSRR 0x83
|
||||
|
||||
typedef struct _IPV4Hdr
|
||||
{
|
||||
u_int8_t ip_verhl; /* version & header length */
|
||||
u_int8_t ip_tos;
|
||||
u_int16_t ip_len; /* length */
|
||||
u_int16_t ip_id; /* id */
|
||||
u_int16_t ip_off; /* frag offset */
|
||||
u_int8_t ip_ttl;
|
||||
u_int8_t ip_proto; /* protocol (tcp, udp, etc) */
|
||||
u_int16_t ip_csum; /* checksum */
|
||||
struct in_addr ip_src;
|
||||
struct in_addr ip_dst;
|
||||
} IPV4Hdr;
|
||||
|
||||
#define IPV4_GET_RAW_VER(ip4h) (((ip4h)->ip_verhl & 0xf0) >> 4)
|
||||
#define IPV4_GET_RAW_HLEN(ip4h) ((ip4h)->ip_verhl & 0x0f)
|
||||
#define IPV4_GET_RAW_IPTOS(ip4h) ((ip4h)->ip_tos)
|
||||
#define IPV4_GET_RAW_IPLEN(ip4h) ((ip4h)->ip_len)
|
||||
#define IPV4_GET_RAW_IPID(ip4h) ((ip4h)->ip_id)
|
||||
#define IPV4_GET_RAW_IPOFFSET(ip4h) ((ip4h)->ip_off)
|
||||
#define IPV4_GET_RAW_IPTTL(ip4h) ((ip4h)->ip_ttl)
|
||||
#define IPV4_GET_RAW_IPPROTO(ip4h) ((ip4h)->ip_proto)
|
||||
|
||||
/* we need to change them as well as get them */
|
||||
#define IPV4_SET_RAW_VER(ip4h, value) ((ip4h)->ip_verhl = (((ip4h)->ip_verhl & 0x0f) | (value << 4)))
|
||||
#define IPV4_SET_RAW_HLEN(ip4h, value) ((ip4h)->ip_verhl = (((ip4h)->ip_verhl & 0xf0) | (value & 0x0f)))
|
||||
#define IPV4_SET_RAW_IPTOS(ip4h, value) ((ip4h)->ip_tos = value)
|
||||
#define IPV4_SET_RAW_IPLEN(ip4h, value) ((ip4h)->ip_len = value)
|
||||
#define IPV4_SET_RAW_IPPROTO(ip4h, value) ((ip4h)->ip_proto = value)
|
||||
|
||||
/* this is enough since noone will access the cache without first
|
||||
* checking the flags */
|
||||
#define IPV4_CACHE_INIT(p) (p)->ip4c.flags = 0
|
||||
|
||||
/* ONLY call these functions after making sure that:
|
||||
* 1. p->ip4h is set
|
||||
* 2. p->ip4h is valid (len is correct)
|
||||
* 3. cache is initialized
|
||||
*/
|
||||
#define IPV4_GET_VER(p) \
|
||||
((p)->ip4c.flags & IPV4_CACHE_VER ? \
|
||||
(p)->ip4c.ver : ((p)->ip4c.flags |= IPV4_CACHE_VER, (p)->ip4c.ver = IPV4_GET_RAW_VER((p)->ip4h)))
|
||||
#define IPV4_GET_HLEN(p) \
|
||||
((p)->ip4c.flags & IPV4_CACHE_HLEN ? \
|
||||
(p)->ip4c.hl : ((p)->ip4c.flags |= IPV4_CACHE_HLEN, (p)->ip4c.hl = IPV4_GET_RAW_HLEN((p)->ip4h) << 2))
|
||||
#define IPV4_GET_IPTOS(p) \
|
||||
IPV4_GET_RAW_IPTOS(p)
|
||||
#define IPV4_GET_IPLEN(p) \
|
||||
(p)->ip4c.flags & IPV4_CACHE_IPLEN ? \
|
||||
(p)->ip4c.ip_len : ((p)->ip4c.flags |= IPV4_CACHE_IPLEN, (p)->ip4c.ip_len = ntohs(IPV4_GET_RAW_IPLEN((p)->ip4h)))
|
||||
#define IPV4_GET_IPID(p) \
|
||||
(p)->ip4c.flags & IPV4_CACHE_IPID ? \
|
||||
(p)->ip4c.ip_id : ((p)->ip4c.flags |= IPV4_CACHE_IPID, (p)->ip4c.ip_id = ntohs(IPV4_GET_RAW_IPID((p)->ip4h)))
|
||||
/* _IPV4_GET_IPOFFSET: get the content of the offset header field in host order */
|
||||
#define _IPV4_GET_IPOFFSET(p) \
|
||||
((p)->ip4c.flags & IPV4_CACHE__IPOFF ? \
|
||||
(p)->ip4c._ip_off : ((p)->ip4c.flags |= IPV4_CACHE__IPOFF, (p)->ip4c._ip_off = ntohs(IPV4_GET_RAW_IPOFFSET((p)->ip4h))))
|
||||
/* IPV4_GET_IPOFFSET: get the final offset */
|
||||
#define IPV4_GET_IPOFFSET(p) \
|
||||
((p)->ip4c.flags & IPV4_CACHE_IPOFF ? \
|
||||
(p)->ip4c.ip_off : ((p)->ip4c.flags |= IPV4_CACHE_IPOFF, (p)->ip4c.ip_off = _IPV4_GET_IPOFFSET(p) & 0x1fff))
|
||||
/* IPV4_GET_RF: get the RF flag. Use _IPV4_GET_IPOFFSET to save a ntohs call. */
|
||||
#define IPV4_GET_RF(p) \
|
||||
((p)->ip4c.flags & IPV4_CACHE_RF ? \
|
||||
(p)->ip4c.rf : ((p)->ip4c.flags |= IPV4_CACHE_RF, (p)->ip4c.rf = (u_int8_t)((_IPV4_GET_IPOFFSET((p)) & 0x8000) >> 15)))
|
||||
/* IPV4_GET_DF: get the DF flag. Use _IPV4_GET_IPOFFSET to save a ntohs call. */
|
||||
#define IPV4_GET_DF(p) \
|
||||
((p)->ip4c.flags & IPV4_CACHE_DF ? \
|
||||
(p)->ip4c.df : ((p)->ip4c.flags |= IPV4_CACHE_DF, (p)->ip4c.df = (u_int8_t)((_IPV4_GET_IPOFFSET((p)) & 0x4000) >> 14)))
|
||||
/* IPV4_GET_MF: get the MF flag. Use _IPV4_GET_IPOFFSET to save a ntohs call. */
|
||||
#define IPV4_GET_MF(p) \
|
||||
((p)->ip4c.flags & IPV4_CACHE_MF ? \
|
||||
(p)->ip4c.mf : ((p)->ip4c.flags |= IPV4_CACHE_MF, (p)->ip4c.mf = (u_int8_t)((_IPV4_GET_IPOFFSET((p)) & 0x2000) >> 13)))
|
||||
#define IPV4_GET_IPTTL(p) \
|
||||
IPV4_GET_RAW_IPTTL(p)
|
||||
#define IPV4_GET_IPPROTO(p) \
|
||||
(p)->ip4c.flags & IPV4_CACHE_IPPROTO ? \
|
||||
(p)->ip4c.ip_proto : ((p)->ip4c.flags |= IPV4_CACHE_IPPROTO, (p)->ip4c.ip_proto = IPV4_GET_RAW_IPPROTO((p)->ip4h))
|
||||
|
||||
#define IPV4_CACHE_VER 0x0001 /* 1 */
|
||||
#define IPV4_CACHE_HLEN 0x0002 /* 2 */
|
||||
#define IPV4_CACHE_IPTOS 0x0004 /* 4 */
|
||||
#define IPV4_CACHE_IPLEN 0x0008 /* 8 */
|
||||
#define IPV4_CACHE_IPID 0x0010 /* 16 */
|
||||
#define IPV4_CACHE_IPOFF 0x0020 /* 32 */
|
||||
#define IPV4_CACHE__IPOFF 0x0040 /* 64 */
|
||||
#define IPV4_CACHE_RF 0x0080 /* 128*/
|
||||
#define IPV4_CACHE_DF 0x0100 /* 256 */
|
||||
#define IPV4_CACHE_MF 0x0200 /* 512 */
|
||||
#define IPV4_CACHE_IPTTL 0x0400 /* 1024*/
|
||||
#define IPV4_CACHE_IPPROTO 0x0800 /* 2048 */
|
||||
|
||||
/* decoder cache */
|
||||
typedef struct _IPV4Cache
|
||||
{
|
||||
u_int16_t flags;
|
||||
|
||||
u_int8_t ver;
|
||||
u_int8_t hl;
|
||||
u_int8_t ip_tos; /* type of service */
|
||||
u_int16_t ip_len; /* datagram length */
|
||||
u_int16_t ip_id; /* identification */
|
||||
u_int16_t ip_off; /* fragment offset */
|
||||
u_int16_t _ip_off; /* fragment offset - full field value, host order*/
|
||||
u_int8_t rf;
|
||||
u_int8_t df;
|
||||
u_int8_t mf;
|
||||
u_int8_t ip_ttl; /* time to live field */
|
||||
u_int8_t ip_proto; /* datagram protocol */
|
||||
u_int16_t ip_csum; /* checksum */
|
||||
u_int32_t ip_src_u32; /* source IP */
|
||||
u_int32_t ip_dst_u32; /* dest IP */
|
||||
|
||||
} IPV4Cache;
|
||||
|
||||
/* helper structure with parsed ipv4 info */
|
||||
typedef struct _IPV4Vars
|
||||
{
|
||||
u_int8_t ip_opts_len;
|
||||
} IPV4Vars;
|
||||
|
||||
#endif /* __DECODE_IPV4_H__ */
|
||||
|
@ -0,0 +1,423 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#include "decode.h"
|
||||
#include "decode-ipv6.h"
|
||||
#include "decode-icmpv6.h"
|
||||
#include "decode-events.h"
|
||||
|
||||
#define IPV6_EXTHDRS ip6eh.ip6_exthdrs
|
||||
#define IPV6_EH_CNT ip6eh.ip6_exthdrs_cnt
|
||||
|
||||
static void
|
||||
DecodeIPV6ExtHdrs(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
u_int8_t *orig_pkt = pkt;
|
||||
u_int8_t nh;
|
||||
u_int8_t hdrextlen;
|
||||
u_int16_t plen;
|
||||
char dstopts = 0;
|
||||
char exthdr_fh_done = 0;
|
||||
|
||||
nh = IPV6_GET_NH(p);
|
||||
plen = len;
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (plen < 2) /* minimal needed in a hdr */
|
||||
return;
|
||||
|
||||
switch(nh)
|
||||
{
|
||||
case IPPROTO_TCP:
|
||||
IPV6_SET_L4PROTO(p,nh);
|
||||
DecodeTCP(t, p, pkt, plen);
|
||||
return;
|
||||
|
||||
case IPPROTO_UDP:
|
||||
IPV6_SET_L4PROTO(p,nh);
|
||||
//DecodeUDP(t, p, pkt, plen);
|
||||
return;
|
||||
|
||||
case IPPROTO_ICMPV6:
|
||||
IPV6_SET_L4PROTO(p,nh);
|
||||
DecodeICMPV6(t, p, pkt, plen);
|
||||
return;
|
||||
|
||||
case IPPROTO_ROUTING:
|
||||
hdrextlen = (*(pkt+1) + 1) << 3; /* 8 octet units */
|
||||
if (hdrextlen > plen) {
|
||||
DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->IPV6_EH_CNT < IPV6_MAX_OPT)
|
||||
{
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2;
|
||||
p->IPV6_EH_CNT++;
|
||||
}
|
||||
|
||||
if (IPV6_EXTHDR_ISSET_RH(p)) {
|
||||
DECODER_SET_EVENT(p, IPV6_EXTHDR_DUPL_RH);
|
||||
/* skip past this extension so we can continue parsing the rest
|
||||
* of the packet */
|
||||
nh = *pkt;
|
||||
pkt += hdrextlen;
|
||||
plen -= hdrextlen;
|
||||
break;
|
||||
}
|
||||
|
||||
IPV6_EXTHDR_SET_RH(p, pkt);
|
||||
IPV6_EXTHDR_RH(p)->ip6rh_len = hdrextlen;
|
||||
/* XXX move into own function and load on demand */
|
||||
if (IPV6_EXTHDR_RH(p)->ip6rh_type == 0) {
|
||||
u_int8_t i;
|
||||
|
||||
u_int8_t n = IPV6_EXTHDR_RH(p)->ip6rh_len / 2;
|
||||
|
||||
/* because we devide the header len by 2 (as rfc 2460 tells us to)
|
||||
* we devide the result by 8 and not 16 as the header fields are
|
||||
* sized */
|
||||
for (i = 0; i < (n/8) && i < sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr)/sizeof(struct in6_addr); ++i) {
|
||||
/* the address header fields are 16 bytes in size */
|
||||
/* XXX do this without memcpy since it's expensive */
|
||||
memcpy(&IPV6_EXTHDR_RH(p)->ip6rh0_addr[i], pkt+(i*16)+8, sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr[i]));
|
||||
}
|
||||
IPV6_EXTHDR_RH(p)->ip6rh0_num_addrs = i;
|
||||
}
|
||||
|
||||
nh = *pkt;
|
||||
pkt += hdrextlen;
|
||||
plen -= hdrextlen;
|
||||
break;
|
||||
|
||||
case IPPROTO_HOPOPTS:
|
||||
case IPPROTO_DSTOPTS:
|
||||
{
|
||||
IPV6OptHAO *hao = NULL;
|
||||
IPV6OptRA *ra = NULL;
|
||||
IPV6OptJumbo *jumbo = NULL;
|
||||
u_int8_t optslen = 0;
|
||||
|
||||
hdrextlen = (*(pkt+1) + 1) << 3;
|
||||
if (hdrextlen > plen) {
|
||||
DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->IPV6_EH_CNT < IPV6_MAX_OPT)
|
||||
{
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2;
|
||||
p->IPV6_EH_CNT++;
|
||||
}
|
||||
|
||||
u_int8_t *ptr = pkt + 2; /* +2 to go past nxthdr and len */
|
||||
|
||||
/* point the pointers to right structures
|
||||
* in Packet. */
|
||||
if (nh == IPPROTO_HOPOPTS) {
|
||||
if (IPV6_EXTHDR_ISSET_HH(p)) {
|
||||
DECODER_SET_EVENT(p, IPV6_EXTHDR_DUPL_HH);
|
||||
/* skip past this extension so we can continue parsing the rest
|
||||
* of the packet */
|
||||
nh = *pkt;
|
||||
pkt += hdrextlen;
|
||||
plen -= hdrextlen;
|
||||
break;
|
||||
}
|
||||
|
||||
IPV6_EXTHDR_SET_HH(p, pkt);
|
||||
hao = &IPV6_EXTHDR_HH_HAO(p);
|
||||
ra = &IPV6_EXTHDR_HH_RA(p);
|
||||
jumbo = &IPV6_EXTHDR_HH_JUMBO(p);
|
||||
|
||||
optslen = ((IPV6_EXTHDR_HH(p)->ip6hh_len+1)<<3)-2;
|
||||
}
|
||||
else if (nh == IPPROTO_DSTOPTS)
|
||||
{
|
||||
if (dstopts == 0) {
|
||||
IPV6_EXTHDR_SET_DH1(p, pkt);
|
||||
hao = &IPV6_EXTHDR_DH1_HAO(p);
|
||||
ra = &IPV6_EXTHDR_DH1_RA(p);
|
||||
jumbo = &IPV6_EXTHDR_DH2_JUMBO(p);
|
||||
optslen = ((IPV6_EXTHDR_DH1(p)->ip6dh_len+1)<<3)-2;
|
||||
dstopts = 1;
|
||||
} else if (dstopts == 1) {
|
||||
IPV6_EXTHDR_SET_DH2(p, pkt);
|
||||
hao = &IPV6_EXTHDR_DH2_HAO(p);
|
||||
ra = &IPV6_EXTHDR_DH2_RA(p);
|
||||
jumbo = &IPV6_EXTHDR_DH2_JUMBO(p);
|
||||
optslen = ((IPV6_EXTHDR_DH2(p)->ip6dh_len+1)<<3)-2;
|
||||
dstopts = 2;
|
||||
} else {
|
||||
DECODER_SET_EVENT(p, IPV6_EXTHDR_DUPL_DH);
|
||||
/* skip past this extension so we can continue parsing the rest
|
||||
* of the packet */
|
||||
nh = *pkt;
|
||||
pkt += hdrextlen;
|
||||
plen -= hdrextlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optslen > plen) {
|
||||
/* since the packet is long enough (we checked
|
||||
* plen against hdrlen, the optlen must be malformed. */
|
||||
DECODER_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
|
||||
/* skip past this extension so we can continue parsing the rest
|
||||
* of the packet */
|
||||
nh = *pkt;
|
||||
pkt += hdrextlen;
|
||||
plen -= hdrextlen;
|
||||
break;
|
||||
}
|
||||
/* XXX move into own function to loaded on demand */
|
||||
u_int16_t offset = 0;
|
||||
while(offset < optslen)
|
||||
{
|
||||
if (*ptr == IPV6OPT_PADN) /* PadN */
|
||||
{
|
||||
//printf("PadN option\n");
|
||||
}
|
||||
else if (*ptr == IPV6OPT_RA) /* RA */
|
||||
{
|
||||
ra->ip6ra_type = *(ptr);
|
||||
ra->ip6ra_len = *(ptr + 1);
|
||||
memcpy(&ra->ip6ra_value, (ptr + 2), sizeof(ra->ip6ra_value));
|
||||
ra->ip6ra_value = ntohs(ra->ip6ra_value);
|
||||
//printf("RA option: type %u len %u value %u\n",
|
||||
// ra->ip6ra_type, ra->ip6ra_len, ra->ip6ra_value);
|
||||
}
|
||||
else if (*ptr == IPV6OPT_JUMBO) /* Jumbo */
|
||||
{
|
||||
jumbo->ip6j_type = *(ptr);
|
||||
jumbo->ip6j_len = *(ptr+1);
|
||||
memcpy(&jumbo->ip6j_payload_len, (ptr+2), sizeof(jumbo->ip6j_payload_len));
|
||||
jumbo->ip6j_payload_len = ntohl(jumbo->ip6j_payload_len);
|
||||
//printf("Jumbo option: type %u len %u payload len %u\n",
|
||||
// jumbo->ip6j_type, jumbo->ip6j_len, jumbo->ip6j_payload_len);
|
||||
}
|
||||
else if (*ptr == IPV6OPT_HAO) /* HAO */
|
||||
{
|
||||
hao->ip6hao_type = *(ptr);
|
||||
hao->ip6hao_len = *(ptr+1);
|
||||
memcpy(&hao->ip6hao_hoa, (ptr+2), sizeof(hao->ip6hao_hoa));
|
||||
//printf("HAO option: type %u len %u ",
|
||||
// hao->ip6hao_type, hao->ip6hao_len);
|
||||
//char addr_buf[46];
|
||||
//inet_ntop(AF_INET6, (char *)&(hao->ip6hao_hoa),
|
||||
// addr_buf,sizeof(addr_buf));
|
||||
//printf("home addr %s\n", addr_buf);
|
||||
}
|
||||
u_int16_t len = (*(ptr + 1) + 2);
|
||||
ptr += len; /* +2 for opt type and opt len fields */
|
||||
offset += len;
|
||||
}
|
||||
|
||||
nh = *pkt;
|
||||
pkt += hdrextlen;
|
||||
plen -= hdrextlen;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPPROTO_FRAGMENT:
|
||||
/* store the offset of this extension into the packet
|
||||
* past the ipv6 header. We use it in defrag for creating
|
||||
* a defragmented packet without the frag header */
|
||||
if (exthdr_fh_done == 0) {
|
||||
p->ip6eh.fh_offset = pkt - orig_pkt;
|
||||
exthdr_fh_done = 1;
|
||||
}
|
||||
|
||||
hdrextlen = sizeof(IPV6FragHdr);
|
||||
if (hdrextlen > plen) {
|
||||
DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR);
|
||||
return;
|
||||
}
|
||||
|
||||
if(p->IPV6_EH_CNT<IPV6_MAX_OPT)
|
||||
{
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2;
|
||||
p->IPV6_EH_CNT++;
|
||||
}
|
||||
|
||||
if (IPV6_EXTHDR_ISSET_FH(p)) {
|
||||
DECODER_SET_EVENT(p, IPV6_EXTHDR_DUPL_FH);
|
||||
nh = *pkt;
|
||||
pkt += hdrextlen;
|
||||
plen -= hdrextlen;
|
||||
break;
|
||||
}
|
||||
|
||||
/* set the header ptr first */
|
||||
IPV6_EXTHDR_SET_FH(p, pkt);
|
||||
|
||||
nh = *pkt;
|
||||
pkt += hdrextlen;
|
||||
plen -= hdrextlen;
|
||||
break;
|
||||
|
||||
case IPPROTO_ESP:
|
||||
{
|
||||
hdrextlen = sizeof(IPV6EspHdr);
|
||||
if (hdrextlen > plen) {
|
||||
DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR);
|
||||
return;
|
||||
}
|
||||
|
||||
if(p->IPV6_EH_CNT<IPV6_MAX_OPT)
|
||||
{
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = IPPROTO_NONE;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2;
|
||||
p->IPV6_EH_CNT++;
|
||||
}
|
||||
|
||||
if (IPV6_EXTHDR_ISSET_EH(p)) {
|
||||
DECODER_SET_EVENT(p, IPV6_EXTHDR_DUPL_EH);
|
||||
return;
|
||||
}
|
||||
|
||||
IPV6_EXTHDR_SET_EH(p, pkt);
|
||||
|
||||
nh = IPPROTO_NONE;
|
||||
pkt += hdrextlen;
|
||||
plen -= hdrextlen;
|
||||
break;
|
||||
}
|
||||
case IPPROTO_AH:
|
||||
{
|
||||
hdrextlen = (*(pkt+1) + 1) << 3;
|
||||
if (hdrextlen > plen) {
|
||||
DECODER_SET_EVENT(p, IPV6_TRUNC_EXTHDR);
|
||||
return;
|
||||
}
|
||||
|
||||
if(p->IPV6_EH_CNT<IPV6_MAX_OPT)
|
||||
{
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen;
|
||||
p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2;
|
||||
p->IPV6_EH_CNT++;
|
||||
}
|
||||
|
||||
if (IPV6_EXTHDR_ISSET_AH(p)) {
|
||||
DECODER_SET_EVENT(p, IPV6_EXTHDR_DUPL_AH);
|
||||
nh = *pkt;
|
||||
pkt += hdrextlen;
|
||||
plen -= hdrextlen;
|
||||
break;
|
||||
}
|
||||
|
||||
IPV6_EXTHDR_SET_AH(p, pkt);
|
||||
|
||||
nh = *pkt;
|
||||
pkt += hdrextlen;
|
||||
plen -= hdrextlen;
|
||||
break;
|
||||
}
|
||||
case IPPROTO_NONE:
|
||||
IPV6_SET_L4PROTO(p,nh);
|
||||
return;
|
||||
|
||||
default:
|
||||
IPV6_SET_L4PROTO(p,nh);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int DecodeIPV6Packet (ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
p->ip6h = (IPV6Hdr *)pkt;
|
||||
|
||||
if (len < IPV6_HEADER_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SET_IPV6_SRC_ADDR(p,&p->src);
|
||||
SET_IPV6_DST_ADDR(p,&p->dst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DecodeIPV6(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
IPV6_CACHE_INIT(p);
|
||||
|
||||
/* do the actual decoding */
|
||||
ret = DecodeIPV6Packet (t, p, pkt, len);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
/* now process the L4 Layer */
|
||||
switch(IPV6_GET_L4PROTO(p)) {
|
||||
case IPPROTO_TCP:
|
||||
return(DecodeTCP(t, p, pkt + IPV6_HEADER_LEN, len - IPV6_HEADER_LEN));
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
//return(DecodeUDP(p, pkt + IPV6_HEADER_LEN, len - IPV6_HEADER_LEN));
|
||||
break;
|
||||
case IPPROTO_ICMPV6:
|
||||
return(DecodeICMPV6(t, p, pkt + IPV6_HEADER_LEN, len - IPV6_HEADER_LEN));
|
||||
break;
|
||||
case IPPROTO_FRAGMENT:
|
||||
case IPPROTO_HOPOPTS:
|
||||
case IPPROTO_ROUTING:
|
||||
case IPPROTO_NONE:
|
||||
case IPPROTO_DSTOPTS:
|
||||
case IPPROTO_AH:
|
||||
case IPPROTO_ESP:
|
||||
DecodeIPV6ExtHdrs(t, p, pkt + IPV6_HEADER_LEN, len - IPV6_HEADER_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* debug print */
|
||||
char s[46], d[46];
|
||||
inet_ntop(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), s, sizeof(s));
|
||||
inet_ntop(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), d, sizeof(d));
|
||||
printf("IPV6 %s->%s - CLASS: %u FLOW: %u NH: %u PLEN: %u HLIM: %u\n", s,d,
|
||||
IPV6_GET_CLASS(p), IPV6_GET_FLOW(p), IPV6_GET_NH(p), IPV6_GET_PLEN(p),
|
||||
IPV6_GET_HLIM(p));
|
||||
|
||||
if (IPV6_EXTHDR_ISSET_FH(p)) {
|
||||
printf("IPV6 FRAG - HDRLEN: %u NH: %u OFFSET: %u ID: %u\n",
|
||||
IPV6_EXTHDR_GET_FH_HDRLEN(p), IPV6_EXTHDR_GET_FH_NH(p),
|
||||
IPV6_EXTHDR_GET_FH_OFFSET(p), IPV6_EXTHDR_GET_FH_ID(p));
|
||||
}
|
||||
if (IPV6_EXTHDR_ISSET_RH(p)) {
|
||||
printf("IPV6 ROUTE - HDRLEN: %u NH: %u TYPE: %u\n",
|
||||
IPV6_EXTHDR_GET_RH_HDRLEN(p), IPV6_EXTHDR_GET_RH_NH(p),
|
||||
IPV6_EXTHDR_GET_RH_TYPE(p));
|
||||
}
|
||||
if (IPV6_EXTHDR_ISSET_HH(p)) {
|
||||
printf("IPV6 HOPOPT - HDRLEN: %u NH: %u\n",
|
||||
IPV6_EXTHDR_GET_HH_HDRLEN(p), IPV6_EXTHDR_GET_HH_NH(p));
|
||||
}
|
||||
if (IPV6_EXTHDR_ISSET_DH1(p)) {
|
||||
printf("IPV6 DSTOPT1 - HDRLEN: %u NH: %u\n",
|
||||
IPV6_EXTHDR_GET_DH1_HDRLEN(p), IPV6_EXTHDR_GET_DH1_NH(p));
|
||||
}
|
||||
if (IPV6_EXTHDR_ISSET_DH2(p)) {
|
||||
printf("IPV6 DSTOPT2 - HDRLEN: %u NH: %u\n",
|
||||
IPV6_EXTHDR_GET_DH2_HDRLEN(p), IPV6_EXTHDR_GET_DH2_NH(p));
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,313 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __DECODE_IPV6_H__
|
||||
#define __DECODE_IPV6_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pcap.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#define IPV6_HEADER_LEN 40
|
||||
#define IPV6_MAXPACKET 65535 /* maximum packet size */
|
||||
#define IPV6_MAX_OPT 40
|
||||
|
||||
typedef struct _IPV6Hdr
|
||||
{
|
||||
union {
|
||||
struct _ip6_un1 {
|
||||
u_int32_t ip6_un1_flow; /* 20 bits of flow-ID */
|
||||
u_int16_t ip6_un1_plen; /* payload length */
|
||||
u_int8_t ip6_un1_nxt; /* next header */
|
||||
u_int8_t ip6_un1_hlim; /* hop limit */
|
||||
} ip6_un1;
|
||||
u_int8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */
|
||||
} ip6_hdrun;
|
||||
|
||||
u_int32_t ip6_src[4];
|
||||
u_int32_t ip6_dst[4];
|
||||
} IPV6Hdr;
|
||||
|
||||
#define s_ip6_vfc ip6_hdrun.ip6_un2_vfc
|
||||
#define s_ip6_flow ip6_hdrun.ip6_un1.ip6_un1_flow
|
||||
#define s_ip6_plen ip6_hdrun.ip6_un1.ip6_un1_plen
|
||||
#define s_ip6_nxt ip6_hdrun.ip6_un1.ip6_un1_nxt
|
||||
#define s_ip6_hlim ip6_hdrun.ip6_un1.ip6_un1_hlim
|
||||
|
||||
#define IPV6_GET_RAW_VER(ip6h) (((ip6h)->s_ip6_vfc & 0xf0) >> 4)
|
||||
#define IPV6_GET_RAW_CLASS(ip6h) ((ntohl((ip6h)->s_ip6_flow) & 0x0FF00000) >> 20)
|
||||
#define IPV6_GET_RAW_FLOW(ip6h) (ntohl((ip6h)->s_ip6_flow) & 0x000FFFFF)
|
||||
#define IPV6_GET_RAW_NH(ip6h) ((ip6h)->s_ip6_nxt)
|
||||
#define IPV6_GET_RAW_PLEN(ip6h) (ntohs((ip6h)->s_ip6_plen))
|
||||
#define IPV6_GET_RAW_HLIM(ip6h) ((ip6h)->s_ip6_hlim)
|
||||
|
||||
#define IPV6_SET_RAW_VER(ip6h, value) ((ip6h)->s_ip6_vfc = (((ip6h)->s_ip6_vfc & 0x0f) | (value << 4)))
|
||||
|
||||
#define IPV6_SET_L4PROTO(p,proto) (p)->ip6vars.l4proto = proto
|
||||
|
||||
/* this is enough since noone will access the cache without first
|
||||
* checking the flags */
|
||||
#define IPV6_CACHE_INIT(p) (p)->ip6c.flags = 0
|
||||
|
||||
/* ONLY call these functions after making sure that:
|
||||
* 1. p->ip6h is set
|
||||
* 2. p->ip6h is valid (len is correct)
|
||||
* 3. cache is initialized
|
||||
*/
|
||||
#define IPV6_GET_VER(p) \
|
||||
((p)->ip6c.flags & IPV6_CACHE_VER ? \
|
||||
(p)->ip6c.ver : ((p)->ip6c.flags |= IPV6_CACHE_VER, (p)->ip6c.ver = IPV6_GET_RAW_VER((p)->ip6h)))
|
||||
#define IPV6_GET_CLASS(p) \
|
||||
((p)->ip6c.flags & IPV6_CACHE_CLASS ? \
|
||||
(p)->ip6c.cl : ((p)->ip6c.flags |= IPV6_CACHE_CLASS, (p)->ip6c.cl = IPV6_GET_RAW_CLASS((p)->ip6h)))
|
||||
#define IPV6_GET_FLOW(p) \
|
||||
(p)->ip6c.flags & IPV6_CACHE_FLOW ? \
|
||||
(p)->ip6c.flow : ((p)->ip6c.flags |= IPV6_CACHE_FLOW, (p)->ip6c.flow = IPV6_GET_RAW_FLOW((p)->ip6h))
|
||||
#define IPV6_GET_NH(p) \
|
||||
IPV6_GET_RAW_NH((p)->ip6h)
|
||||
#define IPV6_GET_PLEN(p) \
|
||||
(p)->ip6c.flags & IPV6_CACHE_PLEN ? \
|
||||
(p)->ip6c.plen : ((p)->ip6c.flags |= IPV6_CACHE_PLEN, (p)->ip6c.plen = IPV6_GET_RAW_PLEN((p)->ip6h))
|
||||
#define IPV6_GET_HLIM(p) \
|
||||
IPV6_GET_RAW_HLIM((p)->ip6h)
|
||||
/* XXX */
|
||||
#define IPV6_GET_L4PROTO(p) \
|
||||
(p)->ip6vars.l4proto
|
||||
|
||||
#define IPV6_CACHE_VER 0x0001 /* 1 */
|
||||
#define IPV6_CACHE_CLASS 0x0002 /* 2 */
|
||||
#define IPV6_CACHE_FLOW 0x0004 /* 4 */
|
||||
#define IPV6_CACHE_NH 0x0008 /* 8 */
|
||||
#define IPV6_CACHE_PLEN 0x0010 /* 16 */
|
||||
#define IPV6_CACHE_HLIM 0x0020 /* 32 */
|
||||
|
||||
/* decoder cache */
|
||||
typedef struct _IPV6Cache
|
||||
{
|
||||
u_int16_t flags;
|
||||
u_int8_t ver;
|
||||
u_int8_t cl;
|
||||
u_int8_t flow;
|
||||
u_int8_t nh;
|
||||
u_int16_t plen;
|
||||
u_int8_t hlim;
|
||||
} IPV6Cache;
|
||||
|
||||
/* helper structure with parsed ipv6 info */
|
||||
typedef struct _IPV6Vars
|
||||
{
|
||||
u_int8_t ip_opts_len;
|
||||
u_int8_t l4proto; /* the proto after the extension headers
|
||||
* store while decoding so we don't have
|
||||
* to loop through the exthdrs all the time */
|
||||
} IPV6Vars;
|
||||
|
||||
/* Fragment header */
|
||||
typedef struct _IPV6FragHdr
|
||||
{
|
||||
u_int8_t ip6fh_nxt; /* next header */
|
||||
u_int8_t ip6fh_reserved; /* reserved field */
|
||||
u_int16_t ip6fh_offlg; /* offset, reserved, and flag */
|
||||
u_int32_t ip6fh_ident; /* identification */
|
||||
} IPV6FragHdr;
|
||||
|
||||
#define IPV6_EXTHDR_GET_RAW_FH_NH(p) ((p)->ip6eh.ip6fh->ip6fh_nxt)
|
||||
#define IPV6_EXTHDR_GET_RAW_FH_HDRLEN(p) sizeof(IPV6FragHdr)
|
||||
#define IPV6_EXTHDR_GET_RAW_FH_OFFSET(p) (ntohs((p)->ip6eh.ip6fh->ip6fh_offlg) & 0xFFF8)
|
||||
#define IPV6_EXTHDR_GET_RAW_FH_FLAG(p) (ntohs((p)->ip6eh.ip6fh->ip6fh_offlg) & 0x0001)
|
||||
#define IPV6_EXTHDR_GET_RAW_FH_ID(p) (ntohl((p)->ip6eh.ip6fh->ip6fh_ident))
|
||||
|
||||
#define IPV6_EXTHDR_GET_FH_NH(p) IPV6_EXTHDR_GET_RAW_FH_NH((p))
|
||||
#define IPV6_EXTHDR_GET_FH_HDRLEN(p) IPV6_EXTHDR_GET_RAW_FH_HDRLEN((p))
|
||||
#define IPV6_EXTHDR_GET_FH_OFFSET(p) IPV6_EXTHDR_GET_RAW_FH_OFFSET((p))
|
||||
#define IPV6_EXTHDR_GET_FH_FLAG(p) IPV6_EXTHDR_GET_RAW_FH_FLAG((p))
|
||||
#define IPV6_EXTHDR_GET_FH_ID(p) IPV6_EXTHDR_GET_RAW_FH_ID((p))
|
||||
|
||||
/* rfc 1826 */
|
||||
typedef struct _IPV6AuthHdr
|
||||
{
|
||||
u_int8_t ip6ah_nxt; /* next header */
|
||||
u_int8_t ip6ah_len; /* header length in units of 8 bytes, not
|
||||
including first 8 bytes. */
|
||||
u_int16_t ip6ah_reserved; /* reserved for future use */
|
||||
u_int32_t ip6ah_spi; /* SECURITY PARAMETERS INDEX (SPI) */
|
||||
u_int32_t ip6ah_seq; /* sequence number */
|
||||
} IPV6AuthHdr;
|
||||
|
||||
typedef struct _IPV6EspHdr
|
||||
{
|
||||
u_int32_t ip6esph_spi; /* SECURITY PARAMETERS INDEX (SPI) */
|
||||
u_int32_t ip6esph_seq; /* sequence number */
|
||||
} IPV6EspHdr;
|
||||
|
||||
typedef struct _IPV6RouteHdr
|
||||
{
|
||||
u_int8_t ip6rh_nxt; /* next header */
|
||||
u_int8_t ip6rh_len; /* header length in units of 8 bytes, not
|
||||
including first 8 bytes. */
|
||||
u_int8_t ip6rh_type; /* routing type */
|
||||
u_int8_t ip6rh_segsleft; /* segments left */
|
||||
struct in6_addr ip6rh0_addr[23]; /* type 0 addresses */
|
||||
u_int8_t ip6rh0_num_addrs; /* number of actual addresses in the
|
||||
array/packet. The array is guarranteed
|
||||
to be filled up to this number. */
|
||||
} IPV6RouteHdr;
|
||||
|
||||
#define IPV6_EXTHDR_GET_RAW_RH_NH(p) ((p)->ip6eh.ip6rh->ip6rh_nxt)
|
||||
#define IPV6_EXTHDR_GET_RAW_RH_HDRLEN(p) ((p)->ip6eh.ip6rh->ip6rh_len)
|
||||
#define IPV6_EXTHDR_GET_RAW_RH_TYPE(p) (ntohs((p)->ip6eh.ip6rh->ip6rh_type))
|
||||
/* XXX */
|
||||
|
||||
#define IPV6_EXTHDR_GET_RH_NH(p) IPV6_EXTHDR_GET_RAW_RH_NH((p))
|
||||
#define IPV6_EXTHDR_GET_RH_HDRLEN(p) IPV6_EXTHDR_GET_RAW_RH_HDRLEN((p))
|
||||
#define IPV6_EXTHDR_GET_RH_TYPE(p) IPV6_EXTHDR_GET_RAW_RH_TYPE((p))
|
||||
/* XXX */
|
||||
|
||||
|
||||
/* Hop-by-Hop header and Destination Options header use options that are
|
||||
* defined here. */
|
||||
|
||||
#define IPV6OPT_PADN 0x01
|
||||
#define IPV6OPT_RA 0x05
|
||||
#define IPV6OPT_JUMBO 0xC2
|
||||
#define IPV6OPT_HAO 0xC9
|
||||
|
||||
/* Home Address Option */
|
||||
typedef struct _IPV6OptHAO
|
||||
{
|
||||
u_int8_t ip6hao_type; /* Option type */
|
||||
u_int8_t ip6hao_len; /* Option Data len (excludes type and len) */
|
||||
struct in6_addr ip6hao_hoa; /* Home address. */
|
||||
} IPV6OptHAO;
|
||||
|
||||
/* Router Alert Option */
|
||||
typedef struct _IPV6OptRA
|
||||
{
|
||||
u_int8_t ip6ra_type; /* Option type */
|
||||
u_int8_t ip6ra_len; /* Option Data len (excludes type and len) */
|
||||
u_int16_t ip6ra_value; /* Router Alert value */
|
||||
} IPV6OptRA;
|
||||
|
||||
/* Jumbo Option */
|
||||
typedef struct _IPV6OptJumbo
|
||||
{
|
||||
u_int8_t ip6j_type; /* Option type */
|
||||
u_int8_t ip6j_len; /* Option Data len (excludes type and len) */
|
||||
u_int32_t ip6j_payload_len; /* Jumbo Payload Length */
|
||||
} IPV6OptJumbo;
|
||||
|
||||
typedef struct _IPV6HopOptsHdr
|
||||
{
|
||||
u_int8_t ip6hh_nxt; /* next header */
|
||||
u_int8_t ip6hh_len; /* header length in units of 8 bytes, not
|
||||
including first 8 bytes. */
|
||||
} IPV6HopOptsHdr;
|
||||
|
||||
#define IPV6_EXTHDR_GET_RAW_HH_NH(p) ((p)->ip6eh.ip6hh->ip6hh_nxt)
|
||||
#define IPV6_EXTHDR_GET_RAW_HH_HDRLEN(p) ((p)->ip6eh.ip6hh->ip6hh_len)
|
||||
/* XXX */
|
||||
|
||||
#define IPV6_EXTHDR_GET_HH_NH(p) IPV6_EXTHDR_GET_RAW_HH_NH((p))
|
||||
#define IPV6_EXTHDR_GET_HH_HDRLEN(p) IPV6_EXTHDR_GET_RAW_HH_HDRLEN((p))
|
||||
/* XXX */
|
||||
|
||||
typedef struct _IPV6DstOptsHdr
|
||||
{
|
||||
u_int8_t ip6dh_nxt; /* next header */
|
||||
u_int8_t ip6dh_len; /* header length in units of 8 bytes, not
|
||||
including first 8 bytes. */
|
||||
} IPV6DstOptsHdr;
|
||||
|
||||
#define IPV6_EXTHDR_GET_RAW_DH1_NH(p) ((p)->ip6eh.ip6dh1->ip6dh_nxt)
|
||||
#define IPV6_EXTHDR_GET_RAW_DH1_HDRLEN(p) ((p)->ip6eh.ip6dh1->ip6dh_len)
|
||||
/* XXX */
|
||||
|
||||
#define IPV6_EXTHDR_GET_DH1_NH(p) IPV6_EXTHDR_GET_RAW_DH1_NH((p))
|
||||
#define IPV6_EXTHDR_GET_DH1_HDRLEN(p) IPV6_EXTHDR_GET_RAW_DH1_HDRLEN((p))
|
||||
/* XXX */
|
||||
|
||||
#define IPV6_EXTHDR_GET_RAW_DH2_NH(p) ((p)->ip6eh.ip6dh2->ip6dh_nxt)
|
||||
#define IPV6_EXTHDR_GET_RAW_DH2_HDRLEN(p) ((p)->ip6eh.ip6dh2->ip6dh_len)
|
||||
/* XXX */
|
||||
|
||||
#define IPV6_EXTHDR_GET_DH2_NH(p) IPV6_EXTHDR_GET_RAW_DH2_NH((p))
|
||||
#define IPV6_EXTHDR_GET_DH2_HDRLEN(p) IPV6_EXTHDR_GET_RAW_DH2_HDRLEN((p))
|
||||
/* XXX */
|
||||
|
||||
typedef struct _IPV6GenOptHdr
|
||||
{
|
||||
u_int8_t type;
|
||||
u_int8_t next;
|
||||
u_int8_t len;
|
||||
u_int8_t *data;
|
||||
} IPV6GenOptHdr;
|
||||
|
||||
typedef struct _IPV6ExtHdrs
|
||||
{
|
||||
IPV6FragHdr *ip6fh;
|
||||
/* In fh_offset we store the offset of this extension into the packet past
|
||||
* the ipv6 header. We use it in defrag for creating a defragmented packet
|
||||
* without the frag header */
|
||||
u_int16_t fh_offset;
|
||||
|
||||
IPV6RouteHdr *ip6rh;
|
||||
IPV6AuthHdr *ip6ah;
|
||||
IPV6EspHdr *ip6eh;
|
||||
IPV6DstOptsHdr *ip6dh1;
|
||||
IPV6DstOptsHdr *ip6dh2;
|
||||
IPV6HopOptsHdr *ip6hh;
|
||||
|
||||
/* Hop-By-Hop options */
|
||||
IPV6OptHAO ip6hh_opt_hao;
|
||||
IPV6OptRA ip6hh_opt_ra;
|
||||
IPV6OptJumbo ip6hh_opt_jumbo;
|
||||
/* Dest Options 1 */
|
||||
IPV6OptHAO ip6dh1_opt_hao;
|
||||
IPV6OptRA ip6dh1_opt_ra;
|
||||
IPV6OptJumbo ip6dh1_opt_jumbo;
|
||||
/* Dest Options 2 */
|
||||
IPV6OptHAO ip6dh2_opt_hao;
|
||||
IPV6OptRA ip6dh2_opt_ra;
|
||||
IPV6OptJumbo ip6dh2_opt_jumbo;
|
||||
|
||||
IPV6GenOptHdr ip6_exthdrs[IPV6_MAX_OPT];
|
||||
u_int8_t ip6_exthdrs_cnt;
|
||||
|
||||
} IPV6ExtHdrs;
|
||||
|
||||
#define IPV6_EXTHDR_FH(p) (p)->ip6eh.ip6fh
|
||||
#define IPV6_EXTHDR_RH(p) (p)->ip6eh.ip6rh
|
||||
#define IPV6_EXTHDR_AH(p) (p)->ip6eh.ip6ah
|
||||
#define IPV6_EXTHDR_EH(p) (p)->ip6eh.ip6eh
|
||||
#define IPV6_EXTHDR_DH1(p) (p)->ip6eh.ip6dh1
|
||||
#define IPV6_EXTHDR_DH2(p) (p)->ip6eh.ip6dh2
|
||||
#define IPV6_EXTHDR_HH(p) (p)->ip6eh.ip6hh
|
||||
|
||||
#define IPV6_EXTHDR_HH_HAO(p) (p)->ip6eh.ip6hh_opt_hao
|
||||
#define IPV6_EXTHDR_DH1_HAO(p) (p)->ip6eh.ip6dh1_opt_hao
|
||||
#define IPV6_EXTHDR_DH2_HAO(p) (p)->ip6eh.ip6dh2_opt_hao
|
||||
#define IPV6_EXTHDR_HH_RA(p) (p)->ip6eh.ip6hh_opt_ra
|
||||
#define IPV6_EXTHDR_DH1_RA(p) (p)->ip6eh.ip6dh1_opt_ra
|
||||
#define IPV6_EXTHDR_DH2_RA(p) (p)->ip6eh.ip6dh2_opt_ra
|
||||
#define IPV6_EXTHDR_HH_JUMBO(p) (p)->ip6eh.ip6hh_opt_jumbo
|
||||
#define IPV6_EXTHDR_DH1_JUMBO(p) (p)->ip6eh.ip6dh1_opt_jumbo
|
||||
#define IPV6_EXTHDR_DH2_JUMBO(p) (p)->ip6eh.ip6dh2_opt_jumbo
|
||||
|
||||
#define IPV6_EXTHDR_SET_FH(p,pkt) IPV6_EXTHDR_FH((p)) = (IPV6FragHdr *)pkt
|
||||
#define IPV6_EXTHDR_ISSET_FH(p) (IPV6_EXTHDR_FH((p)) != NULL)
|
||||
#define IPV6_EXTHDR_SET_RH(p,pkt) IPV6_EXTHDR_RH((p)) = (IPV6RouteHdr *)pkt
|
||||
#define IPV6_EXTHDR_ISSET_RH(p) (IPV6_EXTHDR_RH((p)) != NULL)
|
||||
#define IPV6_EXTHDR_SET_AH(p,pkt) IPV6_EXTHDR_AH((p)) = (IPV6AuthHdr *)pkt
|
||||
#define IPV6_EXTHDR_ISSET_AH(p) (IPV6_EXTHDR_AH((p)) != NULL)
|
||||
#define IPV6_EXTHDR_SET_EH(p,pkt) IPV6_EXTHDR_EH((p)) = (IPV6EspHdr *)pkt
|
||||
#define IPV6_EXTHDR_ISSET_EH(p) (IPV6_EXTHDR_EH((p)) != NULL)
|
||||
#define IPV6_EXTHDR_SET_DH1(p,pkt) IPV6_EXTHDR_DH1((p)) = (IPV6DstOptsHdr *)pkt
|
||||
#define IPV6_EXTHDR_ISSET_DH1(p) (IPV6_EXTHDR_DH1((p)) != NULL)
|
||||
#define IPV6_EXTHDR_SET_DH2(p,pkt) IPV6_EXTHDR_DH2((p)) = (IPV6DstOptsHdr *)pkt
|
||||
#define IPV6_EXTHDR_ISSET_DH2(p) (IPV6_EXTHDR_DH2((p)) != NULL)
|
||||
#define IPV6_EXTHDR_SET_HH(p,pkt) IPV6_EXTHDR_HH((p)) = (IPV6HopOptsHdr *)pkt
|
||||
#define IPV6_EXTHDR_ISSET_HH(p) (IPV6_EXTHDR_HH((p)) != NULL)
|
||||
|
||||
#endif /* __DECODE_IPV6_H__ */
|
||||
|
@ -0,0 +1,155 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#include "decode.h"
|
||||
#include "decode-tcp.h"
|
||||
#include "decode-events.h"
|
||||
|
||||
#include "flow.h"
|
||||
|
||||
static int DecodeTCPOptions(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
u_int16_t plen = len;
|
||||
while (plen)
|
||||
{
|
||||
/* single byte options */
|
||||
if (*pkt == TCP_OPT_EOL) {
|
||||
break;
|
||||
} else if (*pkt == TCP_OPT_NOP) {
|
||||
pkt++;
|
||||
plen--;
|
||||
|
||||
/* multibyte options */
|
||||
} else {
|
||||
if (plen < 2) {
|
||||
break;
|
||||
}
|
||||
|
||||
p->TCP_OPTS[p->TCP_OPTS_CNT].type = *pkt;
|
||||
p->TCP_OPTS[p->TCP_OPTS_CNT].len = *(pkt+1);
|
||||
if (plen > 2)
|
||||
p->TCP_OPTS[p->TCP_OPTS_CNT].data = (pkt+2);
|
||||
else
|
||||
p->TCP_OPTS[p->TCP_OPTS_CNT].data = NULL;
|
||||
|
||||
/* we already know that the total options len is valid,
|
||||
* so here the len of the specific option must be bad.
|
||||
* Also check for invalid lengths 0 and 1. */
|
||||
if (p->TCP_OPTS[p->TCP_OPTS_CNT].len > plen ||
|
||||
p->TCP_OPTS[p->TCP_OPTS_CNT].len < 2) {
|
||||
DECODER_SET_EVENT(p,TCP_OPT_INVALID_LEN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we are parsing the most commonly used opts to prevent
|
||||
* us from having to walk the opts list for these all the
|
||||
* time. */
|
||||
switch (p->TCP_OPTS[p->TCP_OPTS_CNT].type) {
|
||||
case TCP_OPT_WS:
|
||||
if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_WS_LEN) {
|
||||
DECODER_SET_EVENT(p,TCP_OPT_INVALID_LEN);
|
||||
} else {
|
||||
if (p->tcpvars.ws != NULL) {
|
||||
DECODER_SET_EVENT(p,TCP_OPT_DUPLICATE);
|
||||
} else {
|
||||
p->tcpvars.ws = &p->TCP_OPTS[p->TCP_OPTS_CNT];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TCP_OPT_MSS:
|
||||
if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_MSS_LEN) {
|
||||
DECODER_SET_EVENT(p,TCP_OPT_INVALID_LEN);
|
||||
} else {
|
||||
if (p->tcpvars.mss != NULL) {
|
||||
DECODER_SET_EVENT(p,TCP_OPT_DUPLICATE);
|
||||
} else {
|
||||
p->tcpvars.mss = &p->TCP_OPTS[p->TCP_OPTS_CNT];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TCP_OPT_SACKOK:
|
||||
if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_SACKOK_LEN) {
|
||||
DECODER_SET_EVENT(p,TCP_OPT_INVALID_LEN);
|
||||
} else {
|
||||
if (p->tcpvars.sackok != NULL) {
|
||||
DECODER_SET_EVENT(p,TCP_OPT_DUPLICATE);
|
||||
} else {
|
||||
p->tcpvars.sackok = &p->TCP_OPTS[p->TCP_OPTS_CNT];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TCP_OPT_TS:
|
||||
if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_TS_LEN) {
|
||||
DECODER_SET_EVENT(p,TCP_OPT_INVALID_LEN);
|
||||
} else {
|
||||
if (p->tcpvars.ts != NULL) {
|
||||
DECODER_SET_EVENT(p,TCP_OPT_DUPLICATE);
|
||||
} else {
|
||||
p->tcpvars.ts = &p->TCP_OPTS[p->TCP_OPTS_CNT];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
pkt += p->TCP_OPTS[p->TCP_OPTS_CNT].len;
|
||||
plen -= (p->TCP_OPTS[p->TCP_OPTS_CNT].len);
|
||||
p->TCP_OPTS_CNT++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DecodeTCPPacket(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
p->tcph = (TCPHdr *)pkt;
|
||||
|
||||
if (len < TCP_HEADER_LEN) {
|
||||
DECODER_SET_EVENT(p, TCP_PKT_TOO_SMALL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->tcpvars.hlen = TCP_GET_HLEN(p);
|
||||
if (len < p->tcpvars.hlen) {
|
||||
DECODER_SET_EVENT(p, TCP_HLEN_TOO_SMALL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SET_TCP_SRC_PORT(p,&p->sp);
|
||||
SET_TCP_DST_PORT(p,&p->dp);
|
||||
|
||||
p->tcpvars.tcp_opt_len = p->tcpvars.hlen - TCP_HEADER_LEN;
|
||||
if (p->tcpvars.tcp_opt_len > TCP_OPTLENMAX) {
|
||||
DECODER_SET_EVENT(p, TCP_INVALID_OPTLEN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p->tcpvars.tcp_opt_len > 0) {
|
||||
DecodeTCPOptions(t, p, pkt + TCP_HEADER_LEN, p->tcpvars.tcp_opt_len);
|
||||
}
|
||||
|
||||
p->tcp_payload = pkt + p->tcpvars.hlen;
|
||||
p->tcp_payload_len = len - p->tcpvars.hlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DecodeTCP(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
if (DecodeTCPPacket(t, p,pkt,len) < 0)
|
||||
return;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("TCP sp: %u -> dp: %u - HLEN: %u LEN: %u %s%s%s%s\n",
|
||||
GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), p->tcpvars.hlen, len,
|
||||
p->tcpvars.sackok ? "SACKOK " : "",
|
||||
p->tcpvars.ws ? "WS " : "",
|
||||
p->tcpvars.ts ? "TS " : "",
|
||||
p->tcpvars.mss ? "MSS " : "");
|
||||
#endif
|
||||
|
||||
/* Flow is an integral part of us */
|
||||
FlowHandlePacket(t, p);
|
||||
|
||||
DecodeHTTP(t, p, pkt + p->tcpvars.hlen, len - p->tcpvars.hlen);
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,100 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __DECODE_TCP_H__
|
||||
#define __DECODE_TCP_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pcap.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#define TCP_HEADER_LEN 20
|
||||
#define TCP_OPTLENMAX 40
|
||||
#define TCP_OPTMAX 20 /* every opt is at least 2 bytes
|
||||
* (type + len), except EOL and NOP */
|
||||
|
||||
#define TH_FIN 0x01
|
||||
#define TH_SYN 0x02
|
||||
#define TH_RST 0x04
|
||||
#define TH_PUSH 0x08
|
||||
#define TH_ACK 0x10
|
||||
#define TH_URG 0x20
|
||||
#define TH_RES2 0x40
|
||||
#define TH_RES1 0x80
|
||||
|
||||
/* tcp option codes */
|
||||
#define TCP_OPT_EOL 0x00
|
||||
#define TCP_OPT_NOP 0x01
|
||||
#define TCP_OPT_MSS 0x02
|
||||
#define TCP_OPT_WS 0x03
|
||||
#define TCP_OPT_SACKOK 0x04
|
||||
#define TCP_OPT_SACK 0x05
|
||||
#define TCP_OPT_TS 0x08
|
||||
|
||||
#define TCP_OPT_SACKOK_LEN 2
|
||||
#define TCP_OPT_WS_LEN 3
|
||||
#define TCP_OPT_TS_LEN 10
|
||||
#define TCP_OPT_MSS_LEN 4
|
||||
|
||||
#define TCP_OPTS tcpvars.tcp_opts
|
||||
#define TCP_OPTS_CNT tcpvars.tcp_opt_cnt
|
||||
|
||||
#define TCP_GET_RAW_OFFSET(tcph) (((tcph)->th_offx2 & 0xf0) >> 4)
|
||||
#define TCP_GET_RAW_X2(tcph) ((tcph)->th_offx2 & 0x0f)
|
||||
#define TCP_GET_RAW_SRC_PORT(tcph) ntohs((tcph)->th_sport)
|
||||
#define TCP_GET_RAW_DST_PORT(tcph) ntohs((tcph)->th_dport)
|
||||
|
||||
#define TCP_SET_RAW_TCP_OFFSET(tcph, value) ((tcph)->th_offx2 = (unsigned char)(((tcph)->th_offx2 & 0x0f) | (value << 4)))
|
||||
#define TCP_SET_RAW_TCP_X2(tcph, value) ((tcph)->th_offx2 = (unsigned char)(((tcph)->th_offx2 & 0xf0) | (value & 0x0f)))
|
||||
|
||||
#define TCP_GET_OFFSET(p) TCP_GET_RAW_OFFSET(p->tcph)
|
||||
#define TCP_GET_HLEN(p) TCP_GET_OFFSET(p) << 2
|
||||
#define TCP_GET_SRC_PORT(p) TCP_GET_RAW_SRC_PORT(p->tcph)
|
||||
#define TCP_GET_DST_PORT(p) TCP_GET_RAW_DST_PORT(p->tcph)
|
||||
|
||||
typedef struct _TCPOpt {
|
||||
u_int8_t type;
|
||||
u_int8_t len;
|
||||
u_int8_t *data;
|
||||
} TCPOpt;
|
||||
|
||||
typedef struct _TCPHdr
|
||||
{
|
||||
u_int16_t th_sport; /* source port */
|
||||
u_int16_t th_dport; /* destination port */
|
||||
u_int32_t th_seq; /* sequence number */
|
||||
u_int32_t th_ack; /* acknowledgement number */
|
||||
u_int8_t th_offx2; /* offset and reserved */
|
||||
u_int8_t th_flags; /* pkt flags */
|
||||
u_int16_t th_win; /* pkt window */
|
||||
u_int16_t th_sum; /* checksum */
|
||||
u_int16_t th_urp; /* urgent pointer */
|
||||
} TCPHdr;
|
||||
|
||||
typedef struct _TCPVars
|
||||
{
|
||||
u_int8_t hlen;
|
||||
|
||||
u_int8_t tcp_opt_len;
|
||||
TCPOpt tcp_opts[TCP_OPTMAX];
|
||||
u_int8_t tcp_opt_cnt;
|
||||
|
||||
/* ptrs to commonly used and needed opts */
|
||||
TCPOpt *sackok;
|
||||
TCPOpt *ws;
|
||||
TCPOpt *ts;
|
||||
TCPOpt *mss;
|
||||
} TCPVars;
|
||||
|
||||
#define CLEAR_TCP_PACKET(p) { \
|
||||
(p)->tcph = NULL; \
|
||||
(p)->tcpvars.tcp_opt_cnt = 0; \
|
||||
(p)->tcpvars.sackok = NULL; \
|
||||
(p)->tcpvars.ts = NULL; \
|
||||
(p)->tcpvars.ws = NULL; \
|
||||
(p)->tcpvars.mss = NULL; \
|
||||
}
|
||||
|
||||
#endif /* __DECODE_TCP_H__ */
|
||||
|
@ -0,0 +1,21 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
/* Decode the raw packet */
|
||||
|
||||
#include "decode.h"
|
||||
|
||||
void DecodeTunnel(ThreadVars *t, Packet *p, u_int8_t *pkt, u_int16_t len)
|
||||
{
|
||||
switch (p->tunnel_proto) {
|
||||
case IPPROTO_IP:
|
||||
return(DecodeIPV4(t, p, pkt, len));
|
||||
break;
|
||||
case IPPROTO_IPV6:
|
||||
return(DecodeIPV6(t, p, pkt, len));
|
||||
break;
|
||||
default:
|
||||
printf("FIXME: DecodeTunnel: protocol %u not supported.\n", p->tunnel_proto);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,319 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __DECODE_H__
|
||||
#define __DECODE_H__
|
||||
|
||||
//#define IPQ
|
||||
#define NFQ
|
||||
//#define IPFW
|
||||
//#define PCAP
|
||||
|
||||
//#define DEBUG
|
||||
#define DBG_PERF
|
||||
//#define DBG_THREADS
|
||||
#define COUNTERS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "threadvars.h"
|
||||
|
||||
#ifdef NFQ
|
||||
#include "source-nfq.h"
|
||||
#endif /* NFQ */
|
||||
|
||||
#include "decode-ethernet.h"
|
||||
#include "decode-ipv4.h"
|
||||
#include "decode-ipv6.h"
|
||||
#include "decode-icmpv4.h"
|
||||
#include "decode-icmpv6.h"
|
||||
#include "decode-tcp.h"
|
||||
#include "decode-http.h"
|
||||
|
||||
/* Address */
|
||||
typedef struct _Address
|
||||
{
|
||||
char family;
|
||||
union {
|
||||
u_int32_t address_un_data32[4]; /* type-specific field */
|
||||
u_int16_t address_un_data16[8]; /* type-specific field */
|
||||
u_int8_t address_un_data8[16]; /* type-specific field */
|
||||
} address;
|
||||
} Address;
|
||||
|
||||
#define addr_data32 address.address_un_data32
|
||||
#define addr_data16 address.address_un_data16
|
||||
#define addr_data8 address.address_un_data8
|
||||
|
||||
/* Set the IPv4 addressesinto the Addrs of the Packet.
|
||||
* Make sure p->ip4h is initialized and validated.
|
||||
*
|
||||
* We set the rest of the struct to 0 so we can
|
||||
* prevent using memset. */
|
||||
#define SET_IPV4_SRC_ADDR(p,a) { \
|
||||
(a)->family = AF_INET; \
|
||||
(a)->addr_data32[0] = (u_int32_t)(p)->ip4h->ip_src.s_addr; \
|
||||
(a)->addr_data32[1] = 0; \
|
||||
(a)->addr_data32[2] = 0; \
|
||||
(a)->addr_data32[3] = 0; \
|
||||
}
|
||||
#define SET_IPV4_DST_ADDR(p,a) { \
|
||||
(a)->family = AF_INET; \
|
||||
(a)->addr_data32[0] = (u_int32_t)(p)->ip4h->ip_dst.s_addr; \
|
||||
(a)->addr_data32[1] = 0; \
|
||||
(a)->addr_data32[2] = 0; \
|
||||
(a)->addr_data32[3] = 0; \
|
||||
}
|
||||
/* Set the IPv6 addressesinto the Addrs of the Packet.
|
||||
* Make sure p->ip6h is initialized and validated. */
|
||||
#define SET_IPV6_SRC_ADDR(p,a) { \
|
||||
(a)->family = AF_INET6; \
|
||||
(a)->addr_data32[0] = (p)->ip6h->ip6_src[0]; \
|
||||
(a)->addr_data32[1] = (p)->ip6h->ip6_src[1]; \
|
||||
(a)->addr_data32[2] = (p)->ip6h->ip6_src[2]; \
|
||||
(a)->addr_data32[3] = (p)->ip6h->ip6_src[3]; \
|
||||
}
|
||||
#define SET_IPV6_DST_ADDR(p,a) { \
|
||||
(a)->family = AF_INET6; \
|
||||
(a)->addr_data32[0] = (p)->ip6h->ip6_dst[0]; \
|
||||
(a)->addr_data32[1] = (p)->ip6h->ip6_dst[1]; \
|
||||
(a)->addr_data32[2] = (p)->ip6h->ip6_dst[2]; \
|
||||
(a)->addr_data32[3] = (p)->ip6h->ip6_dst[3]; \
|
||||
}
|
||||
/* Set the TCP ports into the Ports of the Packet.
|
||||
* Make sure p->tcph is initialized and validated. */
|
||||
#define SET_TCP_SRC_PORT(pkt,prt) { \
|
||||
SET_PORT(TCP_GET_SRC_PORT((pkt)), *prt); \
|
||||
}
|
||||
#define SET_TCP_DST_PORT(pkt,prt) { \
|
||||
SET_PORT(TCP_GET_DST_PORT((pkt)), *prt); \
|
||||
}
|
||||
|
||||
#define GET_IPV4_SRC_ADDR_U32(p) ((p)->src.addr_data32[0])
|
||||
#define GET_IPV4_DST_ADDR_U32(p) ((p)->dst.addr_data32[0])
|
||||
#define GET_IPV4_SRC_ADDR_PTR(p) ((p)->src.addr_data32)
|
||||
#define GET_IPV4_DST_ADDR_PTR(p) ((p)->dst.addr_data32)
|
||||
|
||||
#define GET_IPV6_SRC_ADDR(p) ((p)->src.addr_data32)
|
||||
#define GET_IPV6_DST_ADDR(p) ((p)->dst.addr_data32)
|
||||
#define GET_TCP_SRC_PORT(p) ((p)->sp)
|
||||
#define GET_TCP_DST_PORT(p) ((p)->dp)
|
||||
|
||||
/* Port is just a u_int16_t */
|
||||
typedef u_int16_t Port;
|
||||
#define SET_PORT(v, p) ((p) = (v))
|
||||
|
||||
#define CMP_ADDR(a1,a2) \
|
||||
(((a1)->addr_data32[3] == (a2)->addr_data32[3] && \
|
||||
(a1)->addr_data32[2] == (a2)->addr_data32[2] && \
|
||||
(a1)->addr_data32[1] == (a2)->addr_data32[1] && \
|
||||
(a1)->addr_data32[0] == (a2)->addr_data32[0]))
|
||||
#define CMP_PORT(p1,p2) \
|
||||
((p1 == p2))
|
||||
|
||||
#define PKT_IS_IPV4(p) (((p)->ip4h != NULL))
|
||||
#define PKT_IS_IPV6(p) (((p)->ip6h != NULL))
|
||||
|
||||
/* structure to store the sids/gids/etc the detection engine
|
||||
* found in this packet */
|
||||
typedef struct _PacketAlert {
|
||||
u_int8_t gid;
|
||||
u_int32_t sid;
|
||||
u_int8_t rev;
|
||||
u_int8_t class;
|
||||
u_int8_t prio;
|
||||
char *msg;
|
||||
} PacketAlert;
|
||||
|
||||
#define PACKET_ALERT_MAX 256
|
||||
|
||||
typedef struct _PacketAlerts {
|
||||
u_int16_t cnt;
|
||||
PacketAlert alerts[PACKET_ALERT_MAX];
|
||||
} PacketAlerts;
|
||||
|
||||
#define HTTP_URI_MAXCNT 8
|
||||
#define HTTP_URI_MAXLEN 1024
|
||||
|
||||
typedef struct _HttpUri {
|
||||
/* the raw uri for the packet as set by pcre */
|
||||
u_int8_t *raw[HTTP_URI_MAXCNT];
|
||||
u_int16_t raw_size[HTTP_URI_MAXCNT];
|
||||
|
||||
/* normalized uri */
|
||||
u_int8_t norm[HTTP_URI_MAXCNT][HTTP_URI_MAXLEN];
|
||||
u_int16_t norm_size[HTTP_URI_MAXCNT];
|
||||
|
||||
u_int8_t cnt;
|
||||
} HttpUri;
|
||||
|
||||
typedef struct _Packet
|
||||
{
|
||||
/* Addresses, Ports and protocol
|
||||
* these are on top so we can use
|
||||
* the Packet as a hash key */
|
||||
Address src;
|
||||
Address dst;
|
||||
Port sp;
|
||||
Port dp;
|
||||
u_int8_t proto;
|
||||
|
||||
struct timeval ts;
|
||||
|
||||
/* program flow */
|
||||
int pickup_q_id;
|
||||
int verdict_q_id;
|
||||
|
||||
/* ready to set verdict counter, only set in root */
|
||||
u_int8_t rtv_cnt;
|
||||
/* tunnel packet ref count */
|
||||
u_int8_t tpr_cnt;
|
||||
pthread_mutex_t mutex_rtv_cnt;
|
||||
|
||||
/* tunnel XXX convert to bitfield*/
|
||||
int tunnel_pkt;
|
||||
|
||||
/* nfq stuff */
|
||||
#ifdef NFQ
|
||||
NFQPacketVars nfq_v;
|
||||
#endif /* NFQ */
|
||||
|
||||
/* tunnel stuff */
|
||||
u_int8_t tunnel_proto;
|
||||
|
||||
/* storage */
|
||||
u_int8_t pkt[65536];
|
||||
u_int16_t pktlen;
|
||||
|
||||
/* flow */
|
||||
struct _Flow *flow;
|
||||
u_int8_t flowflags;
|
||||
|
||||
/* header pointers */
|
||||
EthernetHdr *ethh;
|
||||
|
||||
IPV4Hdr *ip4h;
|
||||
IPV4Vars ip4vars;
|
||||
IPV4Cache ip4c;
|
||||
|
||||
IPV6Hdr *ip6h;
|
||||
IPV6Vars ip6vars;
|
||||
IPV6Cache ip6c;
|
||||
IPV6ExtHdrs ip6eh;
|
||||
|
||||
ICMPV4Hdr *icmpv4h;
|
||||
ICMPV6Hdr *icmpv6h;
|
||||
|
||||
TCPHdr *tcph;
|
||||
TCPVars tcpvars;
|
||||
u_int8_t *tcp_payload;
|
||||
u_int16_t tcp_payload_len;
|
||||
|
||||
/* decoder events: review how many events we have */
|
||||
u_int8_t events[65535/8];
|
||||
|
||||
HttpUri http_uri;
|
||||
|
||||
PacketAlerts alerts;
|
||||
|
||||
/* IPS action to take */
|
||||
int action;
|
||||
|
||||
/* double linked list ptrs */
|
||||
struct _Packet *next;
|
||||
struct _Packet *prev;
|
||||
|
||||
/* tunnel/encapsulation handling */
|
||||
struct _Packet *root; /* in case of tunnel this is a ptr
|
||||
* to the 'real' packet, the one we
|
||||
* need to set the verdict on --
|
||||
* It should always point to the lowest
|
||||
* packet in a encapsulated packet */
|
||||
|
||||
} Packet;
|
||||
|
||||
/* clear key vars so we don't need to call the expensive
|
||||
* memset or bzero
|
||||
*/
|
||||
#define CLEAR_PACKET(p) { \
|
||||
if ((p)->tcph != NULL) { \
|
||||
CLEAR_TCP_PACKET((p)); \
|
||||
} \
|
||||
(p)->ethh = NULL; \
|
||||
(p)->ip4h = NULL; \
|
||||
(p)->ip6h = NULL; \
|
||||
(p)->action = 0; \
|
||||
(p)->pktlen = 0; \
|
||||
(p)->tunnel_pkt = 0; \
|
||||
(p)->rtv_cnt = 0; \
|
||||
(p)->tpr_cnt = 0; \
|
||||
(p)->root = NULL; \
|
||||
(p)->proto = 0; \
|
||||
(p)->sp = 0; \
|
||||
(p)->dp = 0; \
|
||||
(p)->flow = NULL; \
|
||||
(p)->flowflags = 0; \
|
||||
(p)->alerts.cnt = 0; \
|
||||
(p)->http_uri.cnt = 0; \
|
||||
}
|
||||
|
||||
#define ACTION_ACCEPT 0
|
||||
#define ACTION_DROP 1
|
||||
#define ACTION_REJECT 2
|
||||
|
||||
/* macro's for setting the action
|
||||
* handle the case of a root packet
|
||||
* for tunnels */
|
||||
#define ACCEPT_PACKET(p) ((p)->root ? ((p)->root->action = ACTION_ACCEPT) : ((p)->action = ACTION_ACCEPT))
|
||||
#define DROP_PACKET(p) ((p)->root ? ((p)->root->action = ACTION_DROP) : ((p)->action = ACTION_DROP))
|
||||
#define REJECT_PACKET(p) ((p)->root ? ((p)->root->action = ACTION_REJECT) : ((p)->action = ACTION_REJECT))
|
||||
|
||||
#define INCR_PKT_RTV(p) \
|
||||
{ \
|
||||
mutex_lock((p)->root ? &(p)->root->mutex_rtv_cnt : &(p)->mutex_rtv_cnt); \
|
||||
((p)->root ? (p)->root->rtv_cnt++ : (p)->rtv_cnt++); \
|
||||
mutex_unlock((p)->root ? &(p)->root->mutex_rtv_cnt : &(p)->mutex_rtv_cnt); \
|
||||
}
|
||||
|
||||
#define INCR_PKT_TPR(p) \
|
||||
{ \
|
||||
mutex_lock((p)->root ? &(p)->root->mutex_rtv_cnt : &(p)->mutex_rtv_cnt); \
|
||||
((p)->root ? (p)->root->tpr_cnt++ : (p)->tpr_cnt++); \
|
||||
mutex_unlock((p)->root ? &(p)->root->mutex_rtv_cnt : &(p)->mutex_rtv_cnt); \
|
||||
}
|
||||
|
||||
#define PKT_RTV(p) ((p)->root ? (p)->root->rtv_cnt : (p)->rtv_cnt)
|
||||
#define PKT_TPR(p) ((p)->root ? (p)->root->tpr_cnt : (p)->tpr_cnt)
|
||||
|
||||
#define IS_TUNNEL_ROOT_PKT(p) (((p)->root == NULL && (p)->tunnel_pkt == 1))
|
||||
#define IS_TUNNEL_PKT(p) (((p)->tunnel_pkt == 1))
|
||||
#define SET_TUNNEL_PKT(p) ((p)->tunnel_pkt = 1)
|
||||
#define IS_IPV4_PKT(p) ((p)->ip4h ? 1 : 0)
|
||||
#define IS_IPV6_PKT(p) ((p)->ip6h ? 1 : 0)
|
||||
|
||||
|
||||
/* decoder functions */
|
||||
void DecodeTunnel(ThreadVars *, Packet *, u_int8_t *, u_int16_t);
|
||||
void DecodeIPV4(ThreadVars *, Packet *, u_int8_t *, u_int16_t);
|
||||
void DecodeIPV6(ThreadVars *, Packet *, u_int8_t *, u_int16_t);
|
||||
void DecodeICMPV4(ThreadVars *, Packet *, u_int8_t *, u_int16_t);
|
||||
void DecodeICMPV6(ThreadVars *, Packet *, u_int8_t *, u_int16_t);
|
||||
void DecodeTCP(ThreadVars *, Packet *, u_int8_t *, u_int16_t);
|
||||
void DecodeHTTP(ThreadVars *, Packet *, u_int8_t *, u_int16_t);
|
||||
|
||||
Packet *SetupPkt (void);
|
||||
void SetupTunnelPkt(ThreadVars *, Packet *, u_int8_t *, u_int16_t, u_int8_t);
|
||||
|
||||
#define DECODER_SET_EVENT(p, e) ((p)->events[(e/8)] |= (1<<(e%8)))
|
||||
#define DECODER_ISSET_EVENT(p, e) ((p)->events[(e/8)] & (1<<(e%8)))
|
||||
|
||||
#endif /* __DECODE_H__ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_ADDRESS_H__
|
||||
#define __DETECT_ADDRESS_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectAddressRegister (void);
|
||||
|
||||
#endif /* __DETECT_ADDRESS_H__ */
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* CLASSTYPE part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
int DetectClasstypeSetup (Signature *s, SigMatch *m, char *str);
|
||||
|
||||
void DetectClasstypeRegister (void) {
|
||||
sigmatch_table[DETECT_CLASSTYPE].name = "classtype";
|
||||
sigmatch_table[DETECT_CLASSTYPE].Match = NULL;
|
||||
sigmatch_table[DETECT_CLASSTYPE].Setup = DetectClasstypeSetup;
|
||||
sigmatch_table[DETECT_CLASSTYPE].Free = NULL;
|
||||
sigmatch_table[DETECT_CLASSTYPE].RegisterTests = NULL;
|
||||
}
|
||||
|
||||
int DetectClasstypeSetup (Signature *s, SigMatch *m, char *rawstr)
|
||||
{
|
||||
char *str = rawstr;
|
||||
char dubbed = 0;
|
||||
|
||||
/* strip "'s */
|
||||
if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') {
|
||||
str = strdup(rawstr+1);
|
||||
str[strlen(rawstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
/* XXX */
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_CLASSTYPE_H__
|
||||
#define __DETECT_CLASSTYPE_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectClasstypeRegister (void);
|
||||
|
||||
#endif /* __DETECT_CLASSTYPE_H__ */
|
||||
|
@ -0,0 +1,381 @@
|
||||
/* Simple content match part of the detection engine.
|
||||
*
|
||||
* Copyright (C) 2008 by Victor Julien <victor@inliniac.net> */
|
||||
|
||||
/* This is a very important part of the detection engine, and certainly one
|
||||
* of the most complex parts. String searching is complex and expensive,
|
||||
* and thus worth optimizing. The way that is done here is by only running
|
||||
* the pattern matcher once for every packet. In this search, all search words,
|
||||
* the 'content' matches, are looked for. All results, of all the search words
|
||||
* are stored in a array of lists. The array is an array of MpmMatchBucket's,
|
||||
* that can be entered through the DetectContentData id field. There, it finds
|
||||
* the bucket containing a list of 0, 1, or more matches of that content match.
|
||||
* The list contains MpmMatch items, that contain an offset field. This field
|
||||
* is the possition of the last character in the match.
|
||||
*
|
||||
* 03/22/2008 -- VJ:
|
||||
* Recursive capture runs do something special to the depth and offset: the
|
||||
* settings are only considered for the initial match. For the next matches,
|
||||
* they are not. The reason is that this way we can still anchor the first
|
||||
* match to a specific part of the payload, while the rest can be handled
|
||||
* by content and pcre matches.
|
||||
*
|
||||
* TODO: add a 'recursive depth' to limit the depth to do the recursion on...
|
||||
*
|
||||
* XXX more later....
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "detect-content.h"
|
||||
#include "detect-uricontent.h"
|
||||
|
||||
#include "detect-mpm.h"
|
||||
#include "util-mpm.h"
|
||||
|
||||
#include "flow.h"
|
||||
#include "flow-var.h"
|
||||
#include "detect-flow.h"
|
||||
|
||||
#include "threads.h"
|
||||
|
||||
int DetectContentMatch (ThreadVars *, PatternMatcherThread *, Packet *, Signature *, SigMatch *);
|
||||
int DetectContentSetup (Signature *, SigMatch *, char *);
|
||||
|
||||
u_int8_t nocasetable[256];
|
||||
#define _nc(c) nocasetable[(c)]
|
||||
|
||||
void DetectContentRegister (void) {
|
||||
sigmatch_table[DETECT_CONTENT].name = "content";
|
||||
sigmatch_table[DETECT_CONTENT].Match = DetectContentMatch;
|
||||
sigmatch_table[DETECT_CONTENT].Setup = DetectContentSetup;
|
||||
sigmatch_table[DETECT_CONTENT].Free = NULL;
|
||||
sigmatch_table[DETECT_CONTENT].RegisterTests = NULL;
|
||||
|
||||
/* create table for O(1) case conversion lookup */
|
||||
u_int8_t c = 0;
|
||||
for ( ; c < 255; c++) {
|
||||
if ( c >= 'a' && c <= 'z')
|
||||
nocasetable[c] = (c - ('a' - 'A'));
|
||||
else if (c >= 'A' && c <= 'Z')
|
||||
nocasetable[c] = (c + ('a' - 'A'));
|
||||
else
|
||||
nocasetable[c] = c;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
for (c = 0; c < 255; c++) {
|
||||
if (isprint(nocasetable[c]))
|
||||
printf("nocasetable[%c]: %c\n", c, nocasetable[c]);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
|
||||
static inline int
|
||||
TestOffsetDepth(MpmMatch *m, DetectContentData *co, u_int16_t pktoff) {
|
||||
if (m->offset >= pktoff) {
|
||||
if (co->offset == 0 ||
|
||||
(co->offset && m->offset >= co->offset)) {
|
||||
if (co->depth == 0 ||
|
||||
(co->depth && (m->offset+co->content_len) <= co->depth))
|
||||
{
|
||||
//printf("TestOffsetDepth: depth %u, offset %u, m->offset %u, return 1\n",
|
||||
// co->depth, co->offset, m->offset);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf("TestOffsetDepth: depth %u, offset %u, m->offset %u, return 0\n",
|
||||
// co->depth, co->offset, m->offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is called recursively (if nescessary) to be able
|
||||
* to determite whether or not a chain of content matches connected
|
||||
* with 'within' and 'distance' options fully matches. The reason it
|
||||
* was done like this is to make sure we can handle partial matches
|
||||
* that turn out to fail being followed by full matches later in the
|
||||
* packet. This adds some runtime complexity however. */
|
||||
static inline int
|
||||
TestWithinDistanceOffsetDepth(ThreadVars *t, PatternMatcherThread *pmt, MpmMatch *m, SigMatch *nsm, u_int16_t pktoff)
|
||||
{
|
||||
//printf("test_nextsigmatch m:%p, nsm:%p\n", m,nsm);
|
||||
if (nsm == NULL)
|
||||
return 1;
|
||||
|
||||
DetectContentData *co = (DetectContentData *)nsm->ctx;
|
||||
MpmMatch *nm = pmt->mpm_ctx[pmt->mpm_instance].match[co->id].top;
|
||||
|
||||
for (; nm; nm = nm->next) {
|
||||
//printf("TestWithinDistanceOffsetDepth: nm->offset %u, m->offset %u\n", nm->offset, m->offset);
|
||||
if (nm->offset >= pktoff) {
|
||||
if ((co->within == 0 || (co->within &&
|
||||
(nm->offset > m->offset) &&
|
||||
((nm->offset - m->offset + co->content_len) <= co->within))))
|
||||
{
|
||||
//printf("TestWithinDistanceOffsetDepth: MATCH: %u <= WITHIN(%u), "
|
||||
// "nm->offset %u, m->offset %u\n", nm->offset - m->offset + co->content_len,
|
||||
// co->within, nm->offset, m->offset);
|
||||
|
||||
if (co->distance == 0 || (co->distance &&
|
||||
(nm->offset > m->offset) &&
|
||||
((nm->offset - m->offset) >= co->distance)))
|
||||
{
|
||||
//printf("TestWithinDistanceOffsetDepth: MATCH: %u >= DISTANCE(%u), "
|
||||
// "nm->offset %u, m->offset %u\n", nm->offset - m->offset,
|
||||
// co->distance, nm->offset, m->offset);
|
||||
if (TestOffsetDepth(nm, co, pktoff) == 1) {
|
||||
return TestWithinDistanceOffsetDepth(t, pmt, nm, nsm->next, pktoff);
|
||||
}
|
||||
} else {
|
||||
//printf("TestWithinDistanceOffsetDepth: NO MATCH: %u >= DISTANCE(%u), "
|
||||
// "nm->offset %u, m->offset %u\n", nm->offset - m->offset,
|
||||
// co->distance, nm->offset, m->offset);
|
||||
}
|
||||
} else {
|
||||
//printf("TestWithinDistanceOffsetDepth: NO MATCH: %u <= WITHIN(%u), "
|
||||
// "nm->offset %u, m->offset %u\n", nm->offset - m->offset + co->content_len,
|
||||
// co->within, nm->offset, m->offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
DoDetectContent(ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Signature *s, SigMatch *sm, DetectContentData *co)
|
||||
{
|
||||
int ret = 0;
|
||||
char match = 0;
|
||||
|
||||
/* Get the top match, we already know we have one. */
|
||||
MpmMatch *m = pmt->mpm_ctx[pmt->mpm_instance].match[co->id].top;
|
||||
|
||||
/* if we have within or distance coming up next, check this match
|
||||
* for distance and/or within and check the rest of this match
|
||||
* chain as well. */
|
||||
if ((co->flags & DETECT_CONTENT_WITHIN_NEXT ||
|
||||
co->flags & DETECT_CONTENT_DISTANCE_NEXT) &&
|
||||
pmt->de_checking_distancewithin == 0)
|
||||
{
|
||||
/* indicate to the detection engine the next sigmatch(es)
|
||||
* are part of this match chain */
|
||||
pmt->de_checking_distancewithin = 1;
|
||||
|
||||
for (; m != NULL; m = m->next) {
|
||||
/* first check our match for offset and depth */
|
||||
if (TestOffsetDepth(m, co, pmt->pkt_off) == 1) {
|
||||
ret = TestWithinDistanceOffsetDepth(t, pmt, m, sm->next, pmt->pkt_off);
|
||||
if (ret == 1) {
|
||||
/* update pkt ptrs, content doesn't use this,
|
||||
* but pcre does */
|
||||
pmt->pkt_ptr = p->tcp_payload + m->offset;
|
||||
pmt->pkt_off = m->offset;
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Okay, this is complicated... on the first match of a match chain,
|
||||
* we do the whole match of that chain (a chain here means a number
|
||||
* of consecutive content matches that relate to each other with
|
||||
* 'within and/or 'distance options'). But we still get to the next
|
||||
* sigmatches. We have already inspected this sigmatch, even for
|
||||
* offset and depth. Since the fact that we get there means we have
|
||||
* had a match, we return match here too.
|
||||
*/
|
||||
} else if (co->flags & DETECT_CONTENT_WITHIN ||
|
||||
co->flags & DETECT_CONTENT_DISTANCE)
|
||||
{
|
||||
pmt->de_checking_distancewithin = 0;
|
||||
match = 1;
|
||||
/* Getting here means we are not in checking an within/distance chain.
|
||||
* This means we can just inspect this content match on it's own. So
|
||||
* Let's see if at least one of the matches within the offset and depth
|
||||
* settings. If so, return a match.
|
||||
*/
|
||||
} else {
|
||||
/* when in recursive capture mode don't check depth and offset
|
||||
* after the first match */
|
||||
if (s->flags & SIG_FLAG_RECURSIVE && pmt->pkt_cnt) {
|
||||
for (; m != NULL; m = m->next) {
|
||||
if (m->offset >= pmt->pkt_off) {
|
||||
/* update pkt ptrs, content doesn't use this,
|
||||
* but pcre does */
|
||||
pmt->pkt_ptr = p->tcp_payload + m->offset;
|
||||
pmt->pkt_off = m->offset;
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (; m != NULL; m = m->next) {
|
||||
ret = TestOffsetDepth(m,co, pmt->pkt_off);
|
||||
if (ret == 1) {
|
||||
/* update pkt ptrs, content doesn't use this,
|
||||
* but pcre does */
|
||||
pmt->pkt_ptr = p->tcp_payload + m->offset;
|
||||
pmt->pkt_off = m->offset;
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* returns 0: no match
|
||||
* 1: match
|
||||
* -1: error
|
||||
*/
|
||||
|
||||
int DetectContentMatch (ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Signature *s, SigMatch *m)
|
||||
{
|
||||
u_int32_t len = 0;
|
||||
|
||||
if (p->tcp_payload_len == 0)
|
||||
return 0;
|
||||
|
||||
DetectContentData *co = (DetectContentData *)m->ctx;
|
||||
|
||||
/* see if we had a match */
|
||||
len = pmt->mpm_ctx[pmt->mpm_instance].match[co->id].len;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("content \'%s\' matched %u time(s) at offsets: ", co->content, len);
|
||||
|
||||
MpmMatch *tmpm = NULL;
|
||||
for (tmpm = pmt->mpm_ctx[pmt->mpm_instance].match[co->id].top; tmpm != NULL; tmpm = tmpm->next) {
|
||||
printf("%u ", tmpm->offset);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
return DoDetectContent(t, pmt, p, s, m, co);
|
||||
}
|
||||
|
||||
int DetectContentSetup (Signature *s, SigMatch *m, char *contentstr)
|
||||
{
|
||||
DetectContentData *cd = NULL;
|
||||
SigMatch *sm = NULL;
|
||||
char *str = contentstr;
|
||||
char dubbed = 0;
|
||||
u_int16_t len;
|
||||
|
||||
if (contentstr[0] == '\"' && contentstr[strlen(contentstr)-1] == '\"') {
|
||||
str = strdup(contentstr+1);
|
||||
str[strlen(contentstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
len = strlen(str);
|
||||
if (len == 0)
|
||||
return -1;
|
||||
|
||||
cd = malloc(sizeof(DetectContentData));
|
||||
if (cd == NULL) {
|
||||
printf("DetectContentSetup malloc failed\n");
|
||||
goto error;
|
||||
}
|
||||
memset(cd,0,sizeof(DetectContentData));
|
||||
|
||||
//printf("DetectContentSetup: \"%s\", len %u\n", str, len);
|
||||
char converted = 0;
|
||||
|
||||
{
|
||||
u_int16_t i, x;
|
||||
u_int8_t bin = 0, binstr[3] = "", binpos = 0;
|
||||
for (i = 0, x = 0; i < len; i++) {
|
||||
// printf("str[%02u]: %c\n", i, str[i]);
|
||||
if (str[i] == '|') {
|
||||
if (bin) {
|
||||
bin = 0;
|
||||
} else {
|
||||
bin = 1;
|
||||
}
|
||||
} else {
|
||||
if (bin) {
|
||||
if (isdigit(str[i]) ||
|
||||
str[i] == 'A' || str[i] == 'a' ||
|
||||
str[i] == 'B' || str[i] == 'b' ||
|
||||
str[i] == 'C' || str[i] == 'c' ||
|
||||
str[i] == 'D' || str[i] == 'd' ||
|
||||
str[i] == 'E' || str[i] == 'e' ||
|
||||
str[i] == 'F' || str[i] == 'f') {
|
||||
// printf("part of binary: %c\n", str[i]);
|
||||
|
||||
binstr[binpos] = (char)str[i];
|
||||
binpos++;
|
||||
|
||||
if (binpos == 2) {
|
||||
u_int8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF;
|
||||
#ifdef DEBUG
|
||||
printf("Binstr %X\n", c);
|
||||
#endif
|
||||
binpos = 0;
|
||||
str[x] = c;
|
||||
x++;
|
||||
converted = 1;
|
||||
}
|
||||
} else if (str[i] == ' ') {
|
||||
// printf("space as part of binary string\n");
|
||||
}
|
||||
} else {
|
||||
str[x] = str[i];
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
for (i = 0; i < x; i++) {
|
||||
if (isprint(str[i])) printf("%c", str[i]);
|
||||
else printf("\\x%02u", str[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
if (converted) {
|
||||
len = x;
|
||||
}
|
||||
}
|
||||
|
||||
cd->content = malloc(len);
|
||||
if (cd->content == NULL)
|
||||
return -1;
|
||||
|
||||
memcpy(cd->content, str, len);
|
||||
cd->content_len = len;
|
||||
cd->depth = 0;
|
||||
cd->offset = 0;
|
||||
cd->within = 0;
|
||||
cd->distance = 0;
|
||||
cd->flags = 0;
|
||||
|
||||
/* Okay so far so good, lets get this into a SigMatch
|
||||
* and put it in the Signature. */
|
||||
sm = SigMatchAlloc();
|
||||
if (sm == NULL)
|
||||
goto error;
|
||||
|
||||
sm->type = DETECT_CONTENT;
|
||||
sm->ctx = (void *)cd;
|
||||
|
||||
SigMatchAppend(s,m,sm);
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (dubbed) free(str);
|
||||
if (cd) free(cd);
|
||||
if (sm) free(sm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
#ifndef __DETECT_CONTENT_H__
|
||||
#define __DETECT_CONTENT_H__
|
||||
|
||||
#define DETECT_CONTENT_NOCASE 0x01
|
||||
#define DETECT_CONTENT_DISTANCE 0x02
|
||||
#define DETECT_CONTENT_WITHIN 0x04
|
||||
|
||||
#define DETECT_CONTENT_DISTANCE_NEXT 0x08
|
||||
#define DETECT_CONTENT_WITHIN_NEXT 0x10
|
||||
|
||||
#define DETECT_CONTENT_RAWBYTES 0x20
|
||||
|
||||
|
||||
typedef struct _DetectContentData {
|
||||
u_int8_t *content;
|
||||
u_int8_t content_len;
|
||||
u_int32_t id;
|
||||
|
||||
u_int16_t depth;
|
||||
u_int16_t offset;
|
||||
int32_t distance;
|
||||
int32_t within;
|
||||
u_int8_t flags;
|
||||
} DetectContentData;
|
||||
|
||||
/* prototypes */
|
||||
void DetectContentRegister (void);
|
||||
|
||||
#endif /* __DETECT_CONTENT_H__ */
|
||||
|
@ -0,0 +1,55 @@
|
||||
/* DEPTH part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
#include <pcre.h>
|
||||
#include "detect-content.h"
|
||||
#include "detect-pcre.h"
|
||||
|
||||
int DetectDepthSetup (Signature *s, SigMatch *m, char *depthstr);
|
||||
|
||||
void DetectDepthRegister (void) {
|
||||
sigmatch_table[DETECT_DEPTH].name = "depth";
|
||||
sigmatch_table[DETECT_DEPTH].Match = NULL;
|
||||
sigmatch_table[DETECT_DEPTH].Setup = DetectDepthSetup;
|
||||
sigmatch_table[DETECT_DEPTH].Free = NULL;
|
||||
sigmatch_table[DETECT_DEPTH].RegisterTests = NULL;
|
||||
}
|
||||
|
||||
int DetectDepthSetup (Signature *s, SigMatch *m, char *depthstr)
|
||||
{
|
||||
char *str = depthstr;
|
||||
char dubbed = 0;
|
||||
|
||||
//printf("DetectDepthSetup: s->match:%p,m:%p,depthstr:\'%s\'\n", s->match, m, depthstr);
|
||||
|
||||
/* strip "'s */
|
||||
if (depthstr[0] == '\"' && depthstr[strlen(depthstr)-1] == '\"') {
|
||||
str = strdup(depthstr+1);
|
||||
str[strlen(depthstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
SigMatch *pm = m;
|
||||
if (pm != NULL) {
|
||||
if (pm->type == DETECT_PCRE) {
|
||||
DetectPcreData *pe = (DetectPcreData *)pm->ctx;
|
||||
pe->depth = (u_int32_t)atoi(str);
|
||||
//printf("DetectDepthSetup: set depth %u for previous pcre\n", pe->depth);
|
||||
} else if (pm->type == DETECT_CONTENT) {
|
||||
DetectContentData *cd = (DetectContentData *)pm->ctx;
|
||||
cd->depth = (u_int32_t)atoi(str);
|
||||
//printf("DetectDepthSetup: set depth %u for previous content\n", cd->depth);
|
||||
} else {
|
||||
printf("DetectDepthSetup: Unknown previous keyword!\n");
|
||||
}
|
||||
} else {
|
||||
printf("DetectDepthSetup: No previous match!\n");
|
||||
}
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_DEPTH_H__
|
||||
#define __DETECT_DEPTH_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectDepthRegister (void);
|
||||
|
||||
#endif /* __DETECT_DEPTH_H__ */
|
||||
|
@ -0,0 +1,86 @@
|
||||
/* DISTANCE part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
#include <pcre.h>
|
||||
#include "detect-content.h"
|
||||
#include "detect-uricontent.h"
|
||||
#include "detect-pcre.h"
|
||||
|
||||
int DetectDistanceSetup (Signature *s, SigMatch *m, char *distancestr);
|
||||
|
||||
void DetectDistanceRegister (void) {
|
||||
sigmatch_table[DETECT_DISTANCE].name = "distance";
|
||||
sigmatch_table[DETECT_DISTANCE].Match = NULL;
|
||||
sigmatch_table[DETECT_DISTANCE].Setup = DetectDistanceSetup;
|
||||
sigmatch_table[DETECT_DISTANCE].Free = NULL;
|
||||
sigmatch_table[DETECT_DISTANCE].RegisterTests = NULL;
|
||||
}
|
||||
|
||||
int DetectDistanceSetup (Signature *s, SigMatch *m, char *distancestr)
|
||||
{
|
||||
char *str = distancestr;
|
||||
char dubbed = 0;
|
||||
|
||||
//printf("DetectDistanceSetup: s->match:%p,m:%p,distancestr:\'%s\'\n", s->match, m, distancestr);
|
||||
|
||||
/* strip "'s */
|
||||
if (distancestr[0] == '\"' && distancestr[strlen(distancestr)-1] == '\"') {
|
||||
str = strdup(distancestr+1);
|
||||
str[strlen(distancestr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
SigMatch *pm = m;
|
||||
if (pm != NULL) {
|
||||
if (pm->type == DETECT_PCRE) {
|
||||
DetectPcreData *pe = (DetectPcreData *)pm->ctx;
|
||||
|
||||
pe->distance = strtol(str, NULL, 10);
|
||||
pe->flags |= DETECT_PCRE_DISTANCE;
|
||||
|
||||
//printf("DetectDistanceSetup: set distance %d for previous pcre\n", pe->distance);
|
||||
} else if (pm->type == DETECT_CONTENT) {
|
||||
DetectContentData *cd = (DetectContentData *)pm->ctx;
|
||||
|
||||
cd->distance = strtol(str, NULL, 10);
|
||||
cd->flags |= DETECT_CONTENT_DISTANCE;
|
||||
|
||||
//printf("DetectDistanceSetup: set distance %d for previous content\n", cd->distance);
|
||||
} else if (pm->type == DETECT_URICONTENT) {
|
||||
DetectUricontentData *cd = (DetectUricontentData *)pm->ctx;
|
||||
|
||||
cd->distance = strtol(str, NULL, 10);
|
||||
cd->flags |= DETECT_URICONTENT_DISTANCE;
|
||||
|
||||
//printf("DetectDistanceSetup: set distance %d for previous content\n", cd->distance);
|
||||
} else {
|
||||
printf("DetectDistanceSetup: Unknown previous keyword!\n");
|
||||
}
|
||||
} else {
|
||||
printf("DetectDistanceSetup: No previous match!\n");
|
||||
}
|
||||
pm = m->prev;
|
||||
if (pm != NULL) {
|
||||
if (pm->type == DETECT_PCRE) {
|
||||
DetectPcreData *pe = (DetectPcreData *)pm->ctx;
|
||||
pe->flags |= DETECT_PCRE_DISTANCE_NEXT;
|
||||
} else if (pm->type == DETECT_CONTENT) {
|
||||
DetectContentData *cd = (DetectContentData *)pm->ctx;
|
||||
cd->flags |= DETECT_CONTENT_DISTANCE_NEXT;
|
||||
} else if (pm->type == DETECT_URICONTENT) {
|
||||
DetectUricontentData *cd = (DetectUricontentData *)pm->ctx;
|
||||
cd->flags |= DETECT_URICONTENT_DISTANCE_NEXT;
|
||||
} else {
|
||||
printf("DetectDistanceSetup: Unknown previous-previous keyword!\n");
|
||||
}
|
||||
} else {
|
||||
printf("DetectDistanceSetup: No previous-previous match!\n");
|
||||
}
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_DISTANCE_H__
|
||||
#define __DETECT_DISTANCE_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectDistanceRegister (void);
|
||||
|
||||
#endif /* __DETECT_DISTANCE_H__ */
|
||||
|
@ -0,0 +1,425 @@
|
||||
/* DSIZE part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
#include "util-unittest.h"
|
||||
|
||||
#include <pcre.h>
|
||||
|
||||
#define PARSE_REGEX "^(?:\\\")?(<|>)?([0-9]+)(?:(<>)([0-9]+))?(?:\\\")?$"
|
||||
static pcre *parse_regex;
|
||||
static pcre_extra *parse_regex_study;
|
||||
|
||||
#define LT 0
|
||||
#define EQ 1
|
||||
#define GT 2
|
||||
#define RA 3
|
||||
|
||||
typedef struct _DetectDsizeData {
|
||||
u_int16_t dsize;
|
||||
u_int16_t dsize2;
|
||||
u_int8_t mode;
|
||||
} DetectDsizeData;
|
||||
|
||||
int DetectDsizeMatch (ThreadVars *, PatternMatcherThread *, Packet *, Signature *, SigMatch *);
|
||||
int DetectDsizeSetup (Signature *s, SigMatch *m, char *str);
|
||||
void DsizeRegisterTests(void);
|
||||
|
||||
void DetectDsizeRegister (void) {
|
||||
sigmatch_table[DETECT_DSIZE].name = "dsize";
|
||||
sigmatch_table[DETECT_DSIZE].Match = DetectDsizeMatch;
|
||||
sigmatch_table[DETECT_DSIZE].Setup = DetectDsizeSetup;
|
||||
sigmatch_table[DETECT_DSIZE].Free = NULL;
|
||||
sigmatch_table[DETECT_DSIZE].RegisterTests = DsizeRegisterTests;
|
||||
|
||||
const char *eb;
|
||||
int eo;
|
||||
int opts = 0;
|
||||
|
||||
parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL);
|
||||
if(parse_regex == NULL)
|
||||
{
|
||||
printf("pcre compile of \"%s\" failed at offset %d: %s\n", PARSE_REGEX, eo, eb);
|
||||
goto error;
|
||||
}
|
||||
|
||||
parse_regex_study = pcre_study(parse_regex, 0, &eb);
|
||||
if(eb != NULL)
|
||||
{
|
||||
printf("pcre study failed: %s\n", eb);
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
/* XXX */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns 0: no match
|
||||
* 1: match
|
||||
* -1: error
|
||||
*/
|
||||
|
||||
int DetectDsizeMatch (ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Signature *s, SigMatch *m)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
DetectDsizeData *dd = (DetectDsizeData *)m->ctx;
|
||||
|
||||
if (dd->mode == EQ && dd->dsize == p->tcp_payload_len)
|
||||
ret = 1;
|
||||
else if (dd->mode == LT && p->tcp_payload_len < dd->dsize)
|
||||
ret = 1;
|
||||
else if (dd->mode == GT && p->tcp_payload_len > dd->dsize)
|
||||
ret = 1;
|
||||
else if (dd->mode == RA && p->tcp_payload_len > dd->dsize && p->tcp_payload_len < dd->dsize2)
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DetectDsizeData *DetectDsizeParse (char *rawstr)
|
||||
{
|
||||
DetectDsizeData *dd = NULL;
|
||||
char *value1 = NULL, *value2 = NULL,
|
||||
*mode = NULL, *range = NULL;
|
||||
#define MAX_SUBSTRINGS 30
|
||||
int ret = 0, res = 0;
|
||||
int ov[MAX_SUBSTRINGS];
|
||||
|
||||
ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS);
|
||||
if (ret < 3 || ret > 5) {
|
||||
//printf("DetectDsizeSetup: parse error, ret %d\n", ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
const char *str_ptr;
|
||||
|
||||
res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectDsizeSetup: pcre_get_substring failed\n");
|
||||
goto error;
|
||||
}
|
||||
mode = (char *)str_ptr;
|
||||
//printf("mode \"%s\"\n", mode);
|
||||
|
||||
res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectDsizeSetup: pcre_get_substring failed\n");
|
||||
goto error;
|
||||
}
|
||||
value1 = (char *)str_ptr;
|
||||
//printf("value1 \"%s\"\n", value1);
|
||||
|
||||
res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, &str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectDsizeSetup: pcre_get_substring failed\n");
|
||||
goto error;
|
||||
}
|
||||
range = (char *)str_ptr;
|
||||
//printf("range \"%s\"\n", range);
|
||||
|
||||
res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, &str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectDsizeSetup: pcre_get_substring failed\n");
|
||||
goto error;
|
||||
}
|
||||
value2 = (char *)str_ptr;
|
||||
//printf("value2 \"%s\"\n", value2);
|
||||
|
||||
dd = malloc(sizeof(DetectDsizeData));
|
||||
if (dd == NULL) {
|
||||
printf("DetectDsizeSetup malloc failed\n");
|
||||
goto error;
|
||||
}
|
||||
dd->dsize = 0;
|
||||
dd->dsize2 = 0;
|
||||
|
||||
if (mode[0] == '<') dd->mode = LT;
|
||||
else if (mode[0] == '>') dd->mode = GT;
|
||||
else dd->mode = EQ;
|
||||
|
||||
if (strcmp("<>", range) == 0) {
|
||||
if (strlen(mode) != 0)
|
||||
goto error;
|
||||
|
||||
dd->mode = RA;
|
||||
}
|
||||
|
||||
/* set the value */
|
||||
dd->dsize = (u_int16_t)atoi(value1);
|
||||
if (strlen(value2) > 0) {
|
||||
if (dd->mode != RA)
|
||||
goto error;
|
||||
|
||||
dd->dsize2 = (u_int16_t)atoi(value2);
|
||||
|
||||
if (dd->dsize2 <= dd->dsize)
|
||||
goto error;
|
||||
}
|
||||
|
||||
free(value1);
|
||||
free(value2);
|
||||
free(mode);
|
||||
free(range);
|
||||
return dd;
|
||||
|
||||
error:
|
||||
if (dd) free(dd);
|
||||
if (value1) free(value1);
|
||||
if (value2) free(value2);
|
||||
if (mode) free(mode);
|
||||
if (range) free(range);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int DetectDsizeSetup (Signature *s, SigMatch *m, char *rawstr)
|
||||
{
|
||||
DetectDsizeData *dd = NULL;
|
||||
SigMatch *sm = NULL;
|
||||
|
||||
//printf("DetectDsizeSetup: \'%s\'\n", rawstr);
|
||||
|
||||
dd = DetectDsizeParse(rawstr);
|
||||
if (dd == NULL) goto error;
|
||||
|
||||
/* Okay so far so good, lets get this into a SigMatch
|
||||
* and put it in the Signature. */
|
||||
sm = SigMatchAlloc();
|
||||
if (sm == NULL)
|
||||
goto error;
|
||||
|
||||
sm->type = DETECT_DSIZE;
|
||||
sm->ctx = (void *)dd;
|
||||
|
||||
SigMatchAppend(s,m,sm);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (dd) free(dd);
|
||||
if (sm) free(sm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void DetectDsizeFree(DetectDsizeData *dd) {
|
||||
free(dd);
|
||||
}
|
||||
|
||||
/*
|
||||
* ONLY TESTS BELOW THIS COMMENT
|
||||
*/
|
||||
|
||||
int DsizeTestParse01 (void) {
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("1");
|
||||
if (dd) {
|
||||
DetectDsizeFree(dd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DsizeTestParse02 (void) {
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse(">10");
|
||||
if (dd) {
|
||||
DetectDsizeFree(dd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DsizeTestParse03 (void) {
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("<100");
|
||||
if (dd) {
|
||||
DetectDsizeFree(dd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DsizeTestParse04 (void) {
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("1<>2");
|
||||
if (dd) {
|
||||
DetectDsizeFree(dd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DsizeTestParse05 (void) {
|
||||
int result = 0;
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("1");
|
||||
if (dd) {
|
||||
if (dd->dsize == 1)
|
||||
result = 1;
|
||||
|
||||
DetectDsizeFree(dd);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int DsizeTestParse06 (void) {
|
||||
int result = 0;
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse(">10");
|
||||
if (dd) {
|
||||
if (dd->dsize == 10 && dd->mode == GT)
|
||||
result = 1;
|
||||
|
||||
DetectDsizeFree(dd);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int DsizeTestParse07 (void) {
|
||||
int result = 0;
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("<100");
|
||||
if (dd) {
|
||||
if (dd->dsize == 100 && dd->mode == LT)
|
||||
result = 1;
|
||||
|
||||
DetectDsizeFree(dd);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int DsizeTestParse08 (void) {
|
||||
int result = 0;
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("1<>2");
|
||||
if (dd) {
|
||||
if (dd->dsize == 1 && dd->dsize2 == 2 && dd->mode == RA)
|
||||
result = 1;
|
||||
|
||||
DetectDsizeFree(dd);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int DsizeTestParse09 (void) {
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("A");
|
||||
if (dd) {
|
||||
DetectDsizeFree(dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DsizeTestParse10 (void) {
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse(">10<>10");
|
||||
if (dd) {
|
||||
DetectDsizeFree(dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DsizeTestParse11 (void) {
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("<>10");
|
||||
if (dd) {
|
||||
DetectDsizeFree(dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DsizeTestParse12 (void) {
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("1<>");
|
||||
if (dd) {
|
||||
DetectDsizeFree(dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DsizeTestParse13 (void) {
|
||||
int result = 0;
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("1");
|
||||
if (dd) {
|
||||
if (dd->dsize2 == 0)
|
||||
result = 1;
|
||||
|
||||
DetectDsizeFree(dd);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int DsizeTestParse14 (void) {
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("");
|
||||
if (dd) {
|
||||
DetectDsizeFree(dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DsizeTestParse15 (void) {
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse(" ");
|
||||
if (dd) {
|
||||
DetectDsizeFree(dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DsizeTestParse16 (void) {
|
||||
DetectDsizeData *dd = NULL;
|
||||
dd = DetectDsizeParse("2<>1");
|
||||
if (dd) {
|
||||
DetectDsizeFree(dd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DsizeRegisterTests(void) {
|
||||
UtRegisterTest("DsizeTestParse01", DsizeTestParse01, 1);
|
||||
UtRegisterTest("DsizeTestParse02", DsizeTestParse02, 1);
|
||||
UtRegisterTest("DsizeTestParse03", DsizeTestParse03, 1);
|
||||
UtRegisterTest("DsizeTestParse04", DsizeTestParse04, 1);
|
||||
UtRegisterTest("DsizeTestParse05", DsizeTestParse05, 1);
|
||||
UtRegisterTest("DsizeTestParse06", DsizeTestParse06, 1);
|
||||
UtRegisterTest("DsizeTestParse07", DsizeTestParse07, 1);
|
||||
UtRegisterTest("DsizeTestParse08", DsizeTestParse08, 1);
|
||||
UtRegisterTest("DsizeTestParse09", DsizeTestParse09, 1);
|
||||
UtRegisterTest("DsizeTestParse10", DsizeTestParse10, 1);
|
||||
UtRegisterTest("DsizeTestParse11", DsizeTestParse11, 1);
|
||||
UtRegisterTest("DsizeTestParse12", DsizeTestParse12, 1);
|
||||
UtRegisterTest("DsizeTestParse13", DsizeTestParse13, 1);
|
||||
UtRegisterTest("DsizeTestParse14", DsizeTestParse14, 1);
|
||||
UtRegisterTest("DsizeTestParse15", DsizeTestParse15, 1);
|
||||
UtRegisterTest("DsizeTestParse16", DsizeTestParse16, 1);
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_DSIZE_H__
|
||||
#define __DETECT_DSIZE_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectDsizeRegister (void);
|
||||
|
||||
#endif /* __DETECT_DSIZE_H__ */
|
||||
|
@ -0,0 +1,166 @@
|
||||
/* FLOW part of the detection engine. */
|
||||
|
||||
#include <pcre.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
|
||||
#include "flow.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
#include "detect-flow.h"
|
||||
|
||||
#define PARSE_REGEX "([A-z_]+)(?:,([A-z_]+))?"
|
||||
static pcre *parse_regex;
|
||||
static pcre_extra *parse_regex_study;
|
||||
|
||||
int DetectFlowMatch (ThreadVars *, PatternMatcherThread *, Packet *, Signature *, SigMatch *);
|
||||
int DetectFlowSetup (Signature *, SigMatch *, char *);
|
||||
|
||||
void DetectFlowRegister (void) {
|
||||
sigmatch_table[DETECT_FLOW].name = "flow";
|
||||
sigmatch_table[DETECT_FLOW].Match = DetectFlowMatch;
|
||||
sigmatch_table[DETECT_FLOW].Setup = DetectFlowSetup;
|
||||
sigmatch_table[DETECT_FLOW].Free = NULL;
|
||||
sigmatch_table[DETECT_FLOW].RegisterTests = NULL;
|
||||
|
||||
const char *eb;
|
||||
int eo;
|
||||
int opts = 0;
|
||||
|
||||
parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL);
|
||||
if(parse_regex == NULL)
|
||||
{
|
||||
printf("pcre compile of \"%s\" failed at offset %d: %s\n", PARSE_REGEX, eo, eb);
|
||||
goto error;
|
||||
}
|
||||
|
||||
parse_regex_study = pcre_study(parse_regex, 0, &eb);
|
||||
if(eb != NULL)
|
||||
{
|
||||
printf("pcre study failed: %s\n", eb);
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
/* XXX */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns 0: no match
|
||||
* 1: match
|
||||
* -1: error
|
||||
*/
|
||||
|
||||
int DetectFlowMatch (ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Signature *s, SigMatch *m)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
DetectFlowData *fd = (DetectFlowData *)m->ctx;
|
||||
|
||||
if (fd->flags & FLOW_PKT_TOSERVER && p->flowflags & FLOW_PKT_TOSERVER) {
|
||||
ret = 1;
|
||||
}
|
||||
else if (fd->flags & FLOW_PKT_TOCLIENT && p->flowflags & FLOW_PKT_TOCLIENT) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
//printf("DetectFlowMatch: returning %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DetectFlowSetup (Signature *s, SigMatch *m, char *flowstr)
|
||||
{
|
||||
DetectFlowData *fd = NULL;
|
||||
SigMatch *sm = NULL;
|
||||
char *state = NULL, *dir = NULL, *stream = NULL;
|
||||
#define MAX_SUBSTRINGS 30
|
||||
int ret = 0, res = 0;
|
||||
int ov[MAX_SUBSTRINGS];
|
||||
|
||||
//printf("DetectFlowSetup: \'%s\'\n", flowstr);
|
||||
|
||||
ret = pcre_exec(parse_regex, parse_regex_study, flowstr, strlen(flowstr), 0, 0, ov, MAX_SUBSTRINGS);
|
||||
if (ret > 1) {
|
||||
const char *str_ptr;
|
||||
res = pcre_get_substring((char *)flowstr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectFlowSetup: pcre_get_substring failed\n");
|
||||
return -1;
|
||||
}
|
||||
state = (char *)str_ptr;
|
||||
|
||||
if (ret > 2) {
|
||||
res = pcre_get_substring((char *)flowstr, ov, MAX_SUBSTRINGS, 2, &str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectFlowSetup: pcre_get_substring failed\n");
|
||||
return -1;
|
||||
}
|
||||
dir = (char *)str_ptr;
|
||||
}
|
||||
if (ret > 3) {
|
||||
res = pcre_get_substring((char *)flowstr, ov, MAX_SUBSTRINGS, 3, &str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectFlowSetup: pcre_get_substring failed\n");
|
||||
return -1;
|
||||
}
|
||||
stream = (char *)str_ptr;
|
||||
}
|
||||
}
|
||||
//printf("ret %d state \'%s\', dir \'%s\', stream '%s'\n", ret, state, dir, stream);
|
||||
|
||||
fd = malloc(sizeof(DetectFlowData));
|
||||
if (fd == NULL) {
|
||||
printf("DetectFlowSetup malloc failed\n");
|
||||
goto error;
|
||||
}
|
||||
fd->flags = 0;
|
||||
|
||||
/* inspect our options and set the flags */
|
||||
if (state) {
|
||||
if (strcmp(state,"established") == 0) fd->flags |= FLOW_PKT_ESTABLISHED;
|
||||
if (strcmp(state,"stateless") == 0) fd->flags |= FLOW_PKT_STATELESS;
|
||||
if (strcmp(state,"to_client") == 0) fd->flags |= FLOW_PKT_TOCLIENT;
|
||||
if (strcmp(state,"to_server") == 0) fd->flags |= FLOW_PKT_TOSERVER;
|
||||
if (strcmp(state,"from_server") == 0) fd->flags |= FLOW_PKT_TOCLIENT;
|
||||
if (strcmp(state,"from_client") == 0) fd->flags |= FLOW_PKT_TOSERVER;
|
||||
}
|
||||
if (dir) {
|
||||
if (strcmp(dir,"established") == 0) fd->flags |= FLOW_PKT_ESTABLISHED;
|
||||
if (strcmp(dir,"stateless") == 0) fd->flags |= FLOW_PKT_STATELESS;
|
||||
if (strcmp(dir,"to_client") == 0) fd->flags |= FLOW_PKT_TOCLIENT;
|
||||
if (strcmp(dir,"to_server") == 0) fd->flags |= FLOW_PKT_TOSERVER;
|
||||
if (strcmp(dir,"from_server") == 0) fd->flags |= FLOW_PKT_TOCLIENT;
|
||||
if (strcmp(dir,"from_client") == 0) fd->flags |= FLOW_PKT_TOSERVER;
|
||||
}
|
||||
if (stream) {
|
||||
if (strcmp(stream,"established") == 0) fd->flags |= FLOW_PKT_ESTABLISHED;
|
||||
if (strcmp(stream,"stateless") == 0) fd->flags |= FLOW_PKT_STATELESS;
|
||||
if (strcmp(stream,"to_client") == 0) fd->flags |= FLOW_PKT_TOCLIENT;
|
||||
if (strcmp(stream,"to_server") == 0) fd->flags |= FLOW_PKT_TOSERVER;
|
||||
if (strcmp(stream,"from_server") == 0) fd->flags |= FLOW_PKT_TOCLIENT;
|
||||
if (strcmp(stream,"from_client") == 0) fd->flags |= FLOW_PKT_TOSERVER;
|
||||
}
|
||||
|
||||
/* Okay so far so good, lets get this into a SigMatch
|
||||
* and put it in the Signature. */
|
||||
sm = SigMatchAlloc();
|
||||
if (sm == NULL)
|
||||
goto error;
|
||||
|
||||
sm->type = DETECT_FLOW;
|
||||
sm->ctx = (void *)fd;
|
||||
|
||||
SigMatchAppend(s,m,sm);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (fd) free(fd);
|
||||
if (sm) free(sm);
|
||||
return -1;
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
#ifndef __DETECT_FLOW_H__
|
||||
#define __DETECT_FLOW_H__
|
||||
|
||||
typedef struct _DetectFlowData {
|
||||
u_int8_t flags;
|
||||
} DetectFlowData;
|
||||
|
||||
/* prototypes */
|
||||
void DetectFlowRegister (void);
|
||||
|
||||
#endif /* __DETECT_FLOW_H__ */
|
||||
|
@ -0,0 +1,216 @@
|
||||
/* Simple flowvar content match part of the detection engine.
|
||||
*
|
||||
* Copyright (C) 2008 by Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <pcre.h>
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "threads.h"
|
||||
#include "flow.h"
|
||||
#include "flow-var.h"
|
||||
#include "detect-flowvar.h"
|
||||
#include "util-binsearch.h"
|
||||
|
||||
#define PARSE_REGEX "(.*),(.*)"
|
||||
static pcre *parse_regex;
|
||||
static pcre_extra *parse_regex_study;
|
||||
|
||||
int DetectFlowvarMatch (ThreadVars *, PatternMatcherThread *, Packet *, Signature *, SigMatch *);
|
||||
int DetectFlowvarSetup (Signature *, SigMatch *, char *);
|
||||
|
||||
void DetectFlowvarRegister (void) {
|
||||
sigmatch_table[DETECT_FLOWVAR].name = "flowvar";
|
||||
sigmatch_table[DETECT_FLOWVAR].Match = DetectFlowvarMatch;
|
||||
sigmatch_table[DETECT_FLOWVAR].Setup = DetectFlowvarSetup;
|
||||
sigmatch_table[DETECT_FLOWVAR].Free = NULL;
|
||||
sigmatch_table[DETECT_FLOWVAR].RegisterTests = NULL;
|
||||
|
||||
const char *eb;
|
||||
int eo;
|
||||
int opts = 0;
|
||||
|
||||
parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL);
|
||||
if(parse_regex == NULL)
|
||||
{
|
||||
printf("pcre compile of \"%s\" failed at offset %d: %s\n", PARSE_REGEX, eo, eb);
|
||||
goto error;
|
||||
}
|
||||
|
||||
parse_regex_study = pcre_study(parse_regex, 0, &eb);
|
||||
if(eb != NULL)
|
||||
{
|
||||
printf("pcre study failed: %s\n", eb);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns 0: no match
|
||||
* 1: match
|
||||
* -1: error
|
||||
*/
|
||||
|
||||
int DetectFlowvarMatch (ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Signature *s, SigMatch *m)
|
||||
{
|
||||
int ret = 0;
|
||||
DetectFlowvarData *fd = (DetectFlowvarData *)m->ctx;
|
||||
|
||||
/* we need a lock */
|
||||
mutex_lock(&p->flow->m);
|
||||
|
||||
FlowVar *fv = FlowVarGet(p->flow, fd->name);
|
||||
if (fv != NULL) {
|
||||
u_int8_t *ptr = BinSearch(fv->value, fv->value_len, fd->content, fd->content_len);
|
||||
if (ptr != NULL)
|
||||
ret = 1;
|
||||
}
|
||||
mutex_unlock(&p->flow->m);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DetectFlowvarSetup (Signature *s, SigMatch *m, char *rawstr)
|
||||
{
|
||||
DetectFlowvarData *cd = NULL;
|
||||
SigMatch *sm = NULL;
|
||||
char *str = rawstr;
|
||||
char dubbed = 0;
|
||||
u_int16_t len;
|
||||
char *varname = NULL, *varcontent = NULL;
|
||||
#define MAX_SUBSTRINGS 30
|
||||
int ret = 0, res = 0;
|
||||
int ov[MAX_SUBSTRINGS];
|
||||
|
||||
ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS);
|
||||
if (ret > 1) {
|
||||
const char *str_ptr;
|
||||
res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectPcreSetup: pcre_get_substring failed\n");
|
||||
return -1;
|
||||
}
|
||||
varname = (char *)str_ptr;
|
||||
|
||||
if (ret > 2) {
|
||||
res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectPcreSetup: pcre_get_substring failed\n");
|
||||
return -1;
|
||||
}
|
||||
varcontent = (char *)str_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
printf("DetectFlowvarSetup: varname %s, varcontent %s\n", varname, varcontent);
|
||||
|
||||
if (varcontent[0] == '\"' && varcontent[strlen(varcontent)-1] == '\"') {
|
||||
str = strdup(varcontent+1);
|
||||
str[strlen(varcontent)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
len = strlen(str);
|
||||
if (len == 0)
|
||||
return -1;
|
||||
|
||||
cd = malloc(sizeof(DetectFlowvarData));
|
||||
if (cd == NULL) {
|
||||
printf("DetectFlowvarSetup malloc failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
char converted = 0;
|
||||
|
||||
{
|
||||
u_int16_t i, x;
|
||||
u_int8_t bin = 0, binstr[3] = "", binpos = 0;
|
||||
for (i = 0, x = 0; i < len; i++) {
|
||||
// printf("str[%02u]: %c\n", i, str[i]);
|
||||
if (str[i] == '|') {
|
||||
if (bin) {
|
||||
bin = 0;
|
||||
} else {
|
||||
bin = 1;
|
||||
}
|
||||
} else {
|
||||
if (bin) {
|
||||
if (isdigit(str[i]) ||
|
||||
str[i] == 'A' || str[i] == 'a' ||
|
||||
str[i] == 'B' || str[i] == 'b' ||
|
||||
str[i] == 'C' || str[i] == 'c' ||
|
||||
str[i] == 'D' || str[i] == 'd' ||
|
||||
str[i] == 'E' || str[i] == 'e' ||
|
||||
str[i] == 'F' || str[i] == 'f') {
|
||||
// printf("part of binary: %c\n", str[i]);
|
||||
|
||||
binstr[binpos] = (char)str[i];
|
||||
binpos++;
|
||||
|
||||
if (binpos == 2) {
|
||||
u_int8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF;
|
||||
#ifdef DEBUG
|
||||
printf("Binstr %X\n", c);
|
||||
#endif
|
||||
binpos = 0;
|
||||
str[x] = c;
|
||||
x++;
|
||||
converted = 1;
|
||||
}
|
||||
} else if (str[i] == ' ') {
|
||||
// printf("space as part of binary string\n");
|
||||
}
|
||||
} else {
|
||||
str[x] = str[i];
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
//#ifdef DEBUG
|
||||
for (i = 0; i < x; i++) {
|
||||
if (isprint(str[i])) printf("%c", str[i]);
|
||||
else printf("\\x%02u", str[i]);
|
||||
}
|
||||
printf("\n");
|
||||
//#endif
|
||||
|
||||
if (converted)
|
||||
len = x;
|
||||
}
|
||||
|
||||
cd->content = malloc(len);
|
||||
if (cd->content == NULL)
|
||||
return -1;
|
||||
|
||||
cd->name = strdup(varname);
|
||||
memcpy(cd->content, str, len);
|
||||
cd->content_len = len;
|
||||
cd->flags = 0;
|
||||
|
||||
/* Okay so far so good, lets get this into a SigMatch
|
||||
* and put it in the Signature. */
|
||||
sm = SigMatchAlloc();
|
||||
if (sm == NULL)
|
||||
goto error;
|
||||
|
||||
sm->type = DETECT_FLOWVAR;
|
||||
sm->ctx = (void *)cd;
|
||||
|
||||
SigMatchAppend(s,m,sm);
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (dubbed) free(str);
|
||||
if (cd) free(cd);
|
||||
if (sm) free(sm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
#ifndef __DETECT_FLOWVAR_H__
|
||||
#define __DETECT_FLOWVAR_H__
|
||||
|
||||
#define DETECT_CONTENT_NOCASE 0x01
|
||||
|
||||
typedef struct _DetectFlowvarData {
|
||||
char *name;
|
||||
u_int8_t *content;
|
||||
u_int8_t content_len;
|
||||
u_int8_t flags;
|
||||
} DetectFlowvarData;
|
||||
|
||||
/* prototypes */
|
||||
void DetectFlowvarRegister (void);
|
||||
|
||||
#endif /* __DETECT_FLOWVAR_H__ */
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* METADATA part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
int DetectMetadataSetup (Signature *s, SigMatch *m, char *str);
|
||||
|
||||
void DetectMetadataRegister (void) {
|
||||
sigmatch_table[DETECT_METADATA].name = "metadata";
|
||||
sigmatch_table[DETECT_METADATA].Match = NULL;
|
||||
sigmatch_table[DETECT_METADATA].Setup = DetectMetadataSetup;
|
||||
sigmatch_table[DETECT_METADATA].Free = NULL;
|
||||
sigmatch_table[DETECT_METADATA].RegisterTests = NULL;
|
||||
}
|
||||
|
||||
int DetectMetadataSetup (Signature *s, SigMatch *m, char *rawstr)
|
||||
{
|
||||
char *str = rawstr;
|
||||
char dubbed = 0;
|
||||
|
||||
/* strip "'s */
|
||||
if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') {
|
||||
str = strdup(rawstr+1);
|
||||
str[strlen(rawstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
/* XXX */
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_METADATA_H__
|
||||
#define __DETECT_METADATA_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectMetadataRegister (void);
|
||||
|
||||
#endif /* __DETECT_METADATA_H__ */
|
||||
|
@ -0,0 +1,218 @@
|
||||
/* Multi pattern matcher */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
|
||||
#include "detect-mpm.h"
|
||||
#include "util-mpm.h"
|
||||
|
||||
#include "flow.h"
|
||||
#include "flow-var.h"
|
||||
#include "detect-flow.h"
|
||||
|
||||
#include "detect-content.h"
|
||||
#include "detect-uricontent.h"
|
||||
|
||||
MpmCtx mpm_ctx[MPM_INSTANCE_MAX];
|
||||
|
||||
u_int32_t PacketPatternMatch(ThreadVars *t, PatternMatcherThread *pmt, Packet *p) {
|
||||
u_int32_t ret;
|
||||
|
||||
ret = mpm_ctx[pmt->mpm_instance].Search(&mpm_ctx[pmt->mpm_instance], &pmt->mpm_ctx[pmt->mpm_instance], p->tcp_payload, p->tcp_payload_len);
|
||||
|
||||
//printf("PacketPatternMatch: ret %u\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* cleans up the mpm instance after a match */
|
||||
void PacketPatternCleanup(ThreadVars *t, PatternMatcherThread *pmt, u_int8_t instance) {
|
||||
if (mpm_ctx[pmt->mpm_instance].Cleanup != NULL) {
|
||||
mpm_ctx[pmt->mpm_instance].Cleanup(&pmt->mpm_ctx[instance]);
|
||||
}
|
||||
}
|
||||
|
||||
void PatternMatchDestroy(void) {
|
||||
u_int8_t instance;
|
||||
|
||||
/* intialize contexes */
|
||||
for (instance = 0; instance < MPM_INSTANCE_MAX; instance++) {
|
||||
mpm_ctx[instance].DestroyCtx(&mpm_ctx[instance]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* TODO
|
||||
* - determine if a content match can set the 'single' flag
|
||||
*
|
||||
*
|
||||
*/
|
||||
void PatternMatchPrepare(Signature *rootsig)
|
||||
{
|
||||
Signature *s;
|
||||
u_int8_t instance = 0;
|
||||
|
||||
u_int32_t id = 0;
|
||||
u_int32_t depth = 0;
|
||||
u_int32_t offset = 0;
|
||||
u_int32_t within = 0;
|
||||
u_int32_t distance = 0;
|
||||
u_int32_t keywords = 0;
|
||||
|
||||
u_int32_t uri_id = 0;
|
||||
u_int32_t uri_depth = 0;
|
||||
u_int32_t uri_offset = 0;
|
||||
u_int32_t uri_within = 0;
|
||||
u_int32_t uri_distance = 0;
|
||||
u_int32_t uri_keywords = 0;
|
||||
|
||||
/* intialize contexes */
|
||||
for (instance = 0; instance < MPM_INSTANCE_MAX; instance++) {
|
||||
MpmInitCtx(&mpm_ctx[instance], MPM_WUMANBER);
|
||||
}
|
||||
|
||||
for (s = rootsig; s != NULL; s = s->next) {
|
||||
instance = MPM_INSTANCE_BOTH;
|
||||
|
||||
SigMatch *sm;
|
||||
for (sm = s->match; sm != NULL; sm = sm->next) {
|
||||
if (sm->type == DETECT_FLOW) {
|
||||
DetectFlowData *fd = (DetectFlowData *)sm->ctx;
|
||||
if (fd->flags & FLOW_PKT_TOSERVER)
|
||||
instance = MPM_INSTANCE_TOSERVER;
|
||||
else if (fd->flags & FLOW_PKT_TOCLIENT)
|
||||
instance = MPM_INSTANCE_TOCLIENT;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
//printf("Add sig %u to instance %u\n", s->id, instance);
|
||||
|
||||
for (sm = s->match; sm != NULL; sm = sm->next) {
|
||||
if (sm->type == DETECT_CONTENT) {
|
||||
DetectContentData *cd = (DetectContentData *)sm->ctx;
|
||||
|
||||
if (cd->depth) depth++;
|
||||
if (cd->offset) offset++;
|
||||
if (cd->within) within++;
|
||||
if (cd->distance) distance++;
|
||||
|
||||
if (instance == MPM_INSTANCE_BOTH) { /* no flow setting in rule */
|
||||
if (cd->flags & DETECT_CONTENT_NOCASE) {
|
||||
mpm_ctx[MPM_INSTANCE_TOSERVER].AddPatternNocase(&mpm_ctx[MPM_INSTANCE_TOSERVER], cd->content, cd->content_len, id);
|
||||
mpm_ctx[MPM_INSTANCE_TOCLIENT].AddPatternNocase(&mpm_ctx[MPM_INSTANCE_TOCLIENT], cd->content, cd->content_len, id);
|
||||
} else {
|
||||
mpm_ctx[MPM_INSTANCE_TOSERVER].AddPattern(&mpm_ctx[MPM_INSTANCE_TOSERVER], cd->content, cd->content_len, id);
|
||||
mpm_ctx[MPM_INSTANCE_TOCLIENT].AddPattern(&mpm_ctx[MPM_INSTANCE_TOCLIENT], cd->content, cd->content_len, id);
|
||||
}
|
||||
} else {
|
||||
if (cd->flags & DETECT_CONTENT_NOCASE) {
|
||||
mpm_ctx[instance].AddPatternNocase(&mpm_ctx[instance], cd->content, cd->content_len, id);
|
||||
} else {
|
||||
mpm_ctx[instance].AddPattern(&mpm_ctx[instance], cd->content, cd->content_len, id);
|
||||
}
|
||||
}
|
||||
|
||||
cd->id = id;
|
||||
|
||||
id++;
|
||||
keywords++;
|
||||
} else if (sm->type == DETECT_URICONTENT) {
|
||||
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
|
||||
|
||||
if (ud->depth) uri_depth++;
|
||||
if (ud->offset) uri_offset++;
|
||||
if (ud->within) uri_within++;
|
||||
if (ud->distance) uri_distance++;
|
||||
|
||||
if (instance == MPM_INSTANCE_BOTH) { /* no flow setting in rule */
|
||||
if (ud->flags & DETECT_URICONTENT_NOCASE) {
|
||||
mpm_ctx[MPM_INSTANCE_TOSERVER + MPM_INSTANCE_URIOFFSET].AddPatternNocase(&mpm_ctx[MPM_INSTANCE_TOSERVER + MPM_INSTANCE_URIOFFSET], ud->uricontent, ud->uricontent_len, uri_id);
|
||||
mpm_ctx[MPM_INSTANCE_TOCLIENT + MPM_INSTANCE_URIOFFSET].AddPatternNocase(&mpm_ctx[MPM_INSTANCE_TOCLIENT + MPM_INSTANCE_URIOFFSET], ud->uricontent, ud->uricontent_len, uri_id);
|
||||
} else {
|
||||
mpm_ctx[MPM_INSTANCE_TOSERVER + MPM_INSTANCE_URIOFFSET].AddPattern(&mpm_ctx[MPM_INSTANCE_TOSERVER + MPM_INSTANCE_URIOFFSET], ud->uricontent, ud->uricontent_len, uri_id);
|
||||
mpm_ctx[MPM_INSTANCE_TOCLIENT + MPM_INSTANCE_URIOFFSET].AddPattern(&mpm_ctx[MPM_INSTANCE_TOCLIENT + MPM_INSTANCE_URIOFFSET], ud->uricontent, ud->uricontent_len, uri_id);
|
||||
}
|
||||
} else {
|
||||
if (ud->flags & DETECT_URICONTENT_NOCASE) {
|
||||
mpm_ctx[instance + MPM_INSTANCE_URIOFFSET].AddPatternNocase(&mpm_ctx[instance + MPM_INSTANCE_URIOFFSET], ud->uricontent, ud->uricontent_len, uri_id);
|
||||
} else {
|
||||
mpm_ctx[instance + MPM_INSTANCE_URIOFFSET].AddPattern(&mpm_ctx[instance + MPM_INSTANCE_URIOFFSET], ud->uricontent, ud->uricontent_len, uri_id);
|
||||
}
|
||||
}
|
||||
|
||||
ud->id = uri_id;
|
||||
|
||||
uri_id++;
|
||||
uri_keywords++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (instance = 0; instance < MPM_INSTANCE_MAX; instance++) {
|
||||
if (mpm_ctx[instance].Prepare != NULL) {
|
||||
mpm_ctx[instance].Prepare(&mpm_ctx[instance]);
|
||||
}
|
||||
}
|
||||
|
||||
//printf("Printing info...\n");
|
||||
//for (instance = 0; instance < MPM_INSTANCE_MAX; instance++) {
|
||||
// mpm_ctx[instance].PrintCtx(&mpm_ctx[instance]);
|
||||
//}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (instance = 0; instance < MPM_INSTANCE_MAX; instance++) {
|
||||
printf("Case sensitive:\n");
|
||||
MpmPrintTree(&mpm_ctx[instance].root);
|
||||
printf("Case INsensitive:\n");
|
||||
MpmPrintTree(&mpm_ctx[instance].nocase_root);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
|
||||
int PatternMatcherThreadInit(ThreadVars *t, void **data) {
|
||||
u_int8_t mpm_instance = 0;
|
||||
|
||||
PatternMatcherThread *pmt = malloc(sizeof(PatternMatcherThread));
|
||||
if (pmt == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memset(pmt, 0, sizeof(PatternMatcherThread));
|
||||
|
||||
/* intialize contexes */
|
||||
for (mpm_instance = 0; mpm_instance < MPM_INSTANCE_MAX; mpm_instance++) {
|
||||
mpm_ctx[mpm_instance].InitThreadCtx(&mpm_ctx[mpm_instance], &pmt->mpm_ctx[mpm_instance]);
|
||||
}
|
||||
|
||||
*data = (void *)pmt;
|
||||
//printf("PatternMatcherThreadInit: data %p pmt %p\n", *data, pmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PatternMatcherThreadDeinit(ThreadVars *t, void *data) {
|
||||
PatternMatcherThread *pmt = (PatternMatcherThread *)data;
|
||||
u_int8_t instance;
|
||||
|
||||
/* intialize contexes */
|
||||
for (instance = 0; instance < MPM_INSTANCE_MAX; instance++) {
|
||||
mpm_ctx[instance].DestroyThreadCtx(&mpm_ctx[instance], &pmt->mpm_ctx[instance]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void PatternMatcherThreadInfo(ThreadVars *t, PatternMatcherThread *pmt) {
|
||||
u_int8_t mpm_instance = 0;
|
||||
|
||||
/* intialize contexes */
|
||||
for (mpm_instance = 0; mpm_instance < MPM_INSTANCE_MAX; mpm_instance++) {
|
||||
mpm_ctx[mpm_instance].PrintThreadCtx(&pmt->mpm_ctx[mpm_instance]);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
#ifndef __DETECT_MPM_H__
|
||||
#define __DETECT_MPM_H__
|
||||
|
||||
u_int32_t PacketPatternMatch(ThreadVars *, PatternMatcherThread *, Packet *);
|
||||
int PacketPatternScan(ThreadVars *t, Packet *p, u_int8_t mpm_instance);
|
||||
void PacketPatternCleanup(ThreadVars *, PatternMatcherThread *, u_int8_t);
|
||||
void PatternMatchPrepare(Signature *);
|
||||
void PatternMatcherThreadInfo(ThreadVars *, PatternMatcherThread *);
|
||||
void PatternMatchDestroy(void);
|
||||
|
||||
int PatternMatcherThreadInit(ThreadVars *, void **);
|
||||
int PatternMatcherThreadDeinit(ThreadVars *, void *);
|
||||
|
||||
#endif /* __DETECT_MPM_H__ */
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* MSG part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
int DetectMsgSetup (Signature *s, SigMatch *m, char *msgstr);
|
||||
|
||||
void DetectMsgRegister (void) {
|
||||
sigmatch_table[DETECT_MSG].name = "msg";
|
||||
sigmatch_table[DETECT_MSG].Match = NULL;
|
||||
sigmatch_table[DETECT_MSG].Setup = DetectMsgSetup;
|
||||
sigmatch_table[DETECT_MSG].Free = NULL;
|
||||
sigmatch_table[DETECT_MSG].RegisterTests = NULL;
|
||||
}
|
||||
|
||||
int DetectMsgSetup (Signature *s, SigMatch *m, char *msgstr)
|
||||
{
|
||||
char *str = msgstr;
|
||||
char dubbed = 0;
|
||||
|
||||
/* strip "'s */
|
||||
if (msgstr[0] == '\"' && msgstr[strlen(msgstr)-1] == '\"') {
|
||||
str = strdup(msgstr+1);
|
||||
str[strlen(msgstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
s->msg = strdup(str);
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_MSG_H__
|
||||
#define __DETECT_MSG_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectMsgRegister (void);
|
||||
|
||||
#endif /* __DETECT_MSG_H__ */
|
||||
|
@ -0,0 +1,58 @@
|
||||
/* NOCASE part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
#include <pcre.h>
|
||||
#include "detect-content.h"
|
||||
#include "detect-uricontent.h"
|
||||
#include "detect-pcre.h"
|
||||
|
||||
int DetectNocaseSetup (Signature *s, SigMatch *m, char *depthstr);
|
||||
|
||||
void DetectNocaseRegister (void) {
|
||||
sigmatch_table[DETECT_NOCASE].name = "nocase";
|
||||
sigmatch_table[DETECT_NOCASE].Match = NULL;
|
||||
sigmatch_table[DETECT_NOCASE].Setup = DetectNocaseSetup;
|
||||
sigmatch_table[DETECT_NOCASE].Free = NULL;
|
||||
sigmatch_table[DETECT_NOCASE].RegisterTests = NULL;
|
||||
|
||||
sigmatch_table[DETECT_NOCASE].flags |= SIGMATCH_NOOPT;
|
||||
}
|
||||
|
||||
int DetectNocaseSetup (Signature *s, SigMatch *m, char *nullstr)
|
||||
{
|
||||
//printf("DetectNocaseSetup: s->match:%p,m:%p\n", s->match, m);
|
||||
|
||||
if (nullstr != NULL) {
|
||||
printf("DetectNocaseSetup: nocase has no value\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SigMatch *pm = m;
|
||||
if (pm != NULL) {
|
||||
#if 0
|
||||
if (pm->type == DETECT_PCRE) {
|
||||
DetectPcreData *pe = (DetectPcreData *)pm->ctx;
|
||||
printf("DetectNocaseSetup: set depth %u for previous pcre\n", pe->depth);
|
||||
} else
|
||||
#endif
|
||||
if (pm->type == DETECT_CONTENT) {
|
||||
DetectContentData *cd = (DetectContentData *)pm->ctx;
|
||||
//printf("DetectNocaseSetup: set nocase for previous content\n");
|
||||
cd->flags |= DETECT_CONTENT_NOCASE;
|
||||
} else if (pm->type == DETECT_URICONTENT) {
|
||||
DetectUricontentData *cd = (DetectUricontentData *)pm->ctx;
|
||||
//printf("DetectNocaseSetup: set nocase for previous content\n");
|
||||
cd->flags |= DETECT_URICONTENT_NOCASE;
|
||||
} else {
|
||||
printf("DetectNocaseSetup: Unknown previous keyword!\n");
|
||||
}
|
||||
} else {
|
||||
printf("DetectNocaseSetup: No previous match!\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_NOCASE_H__
|
||||
#define __DETECT_NOCASE_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectNocaseRegister (void);
|
||||
|
||||
#endif /* __DETECT_NOCASE_H__ */
|
||||
|
@ -0,0 +1,55 @@
|
||||
/* OFFSET part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
#include <pcre.h>
|
||||
#include "detect-content.h"
|
||||
#include "detect-pcre.h"
|
||||
|
||||
int DetectOffsetSetup (Signature *s, SigMatch *m, char *offsetstr);
|
||||
|
||||
void DetectOffsetRegister (void) {
|
||||
sigmatch_table[DETECT_OFFSET].name = "offset";
|
||||
sigmatch_table[DETECT_OFFSET].Match = NULL;
|
||||
sigmatch_table[DETECT_OFFSET].Setup = DetectOffsetSetup;
|
||||
sigmatch_table[DETECT_OFFSET].Free = NULL;
|
||||
sigmatch_table[DETECT_OFFSET].RegisterTests = NULL;
|
||||
}
|
||||
|
||||
int DetectOffsetSetup (Signature *s, SigMatch *m, char *offsetstr)
|
||||
{
|
||||
char *str = offsetstr;
|
||||
char dubbed = 0;
|
||||
|
||||
//printf("DetectOffsetSetup: s->match:%p,m:%p,offsetstr:\'%s\'\n", s->match, m, offsetstr);
|
||||
|
||||
/* strip "'s */
|
||||
if (offsetstr[0] == '\"' && offsetstr[strlen(offsetstr)-1] == '\"') {
|
||||
str = strdup(offsetstr+1);
|
||||
str[strlen(offsetstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
SigMatch *pm = m;
|
||||
if (pm != NULL) {
|
||||
if (pm->type == DETECT_PCRE) {
|
||||
//DetectPcreData *pe = (DetectPcreData *)pm->ctx;
|
||||
//pe->offset = (u_int32_t)atoi(str); /* XXX */
|
||||
//printf("DetectOffsetSetup: set offset %u for previous pcre\n", pe->offset);
|
||||
} else if (pm->type == DETECT_CONTENT) {
|
||||
DetectContentData *cd = (DetectContentData *)pm->ctx;
|
||||
cd->offset = (u_int32_t)atoi(str); /* XXX */
|
||||
//printf("DetectOffsetSetup: set offset %u for previous content\n", cd->offset);
|
||||
} else {
|
||||
printf("DetectOffsetSetup: Unknown previous keyword!\n");
|
||||
}
|
||||
} else {
|
||||
printf("DetectOffsetSetup: No previous match!\n");
|
||||
}
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_OFFSET_H__
|
||||
#define __DETECT_OFFSET_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectOffsetRegister (void);
|
||||
|
||||
#endif /* __DETECT_OFFSET_H__ */
|
||||
|
@ -0,0 +1,281 @@
|
||||
/* PCRE part of the detection engine. */
|
||||
|
||||
#include <pcre.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
#include "detect-pcre.h"
|
||||
|
||||
#include "detect-mpm.h"
|
||||
|
||||
#define PARSE_CAPTURE_REGEX "\\(\\?\\<([A-z0-9_]+)\\>"
|
||||
#define PARSE_REGEX "(?<!\\\\)/(.*)(?<!\\\\)/([A-z]*)"
|
||||
static pcre *parse_regex;
|
||||
static pcre_extra *parse_regex_study;
|
||||
static pcre *parse_capture_regex;
|
||||
static pcre_extra *parse_capture_regex_study;
|
||||
|
||||
int DetectPcreMatch (ThreadVars *, PatternMatcherThread *, Packet *, Signature *, SigMatch *);
|
||||
int DetectPcreSetup (Signature *, SigMatch *, char *);
|
||||
|
||||
void DetectPcreRegister (void) {
|
||||
sigmatch_table[DETECT_PCRE].name = "pcre";
|
||||
sigmatch_table[DETECT_PCRE].Match = DetectPcreMatch;
|
||||
sigmatch_table[DETECT_PCRE].Setup = DetectPcreSetup;
|
||||
sigmatch_table[DETECT_PCRE].Free = NULL;
|
||||
sigmatch_table[DETECT_PCRE].RegisterTests = NULL;
|
||||
|
||||
const char *eb;
|
||||
int eo;
|
||||
int opts = 0;
|
||||
|
||||
parse_regex = pcre_compile(PARSE_REGEX, opts, &eb, &eo, NULL);
|
||||
if(parse_regex == NULL)
|
||||
{
|
||||
printf("pcre compile of \"%s\" failed at offset %d: %s\n", PARSE_REGEX, eo, eb);
|
||||
goto error;
|
||||
}
|
||||
|
||||
parse_regex_study = pcre_study(parse_regex, 0, &eb);
|
||||
if(eb != NULL)
|
||||
{
|
||||
printf("pcre study failed: %s\n", eb);
|
||||
goto error;
|
||||
}
|
||||
|
||||
parse_capture_regex = pcre_compile(PARSE_CAPTURE_REGEX, opts, &eb, &eo, NULL);
|
||||
if(parse_capture_regex == NULL)
|
||||
{
|
||||
printf("pcre compile of \"%s\" failed at offset %d: %s\n", PARSE_CAPTURE_REGEX, eo, eb);
|
||||
goto error;
|
||||
}
|
||||
|
||||
parse_capture_regex_study = pcre_study(parse_capture_regex, 0, &eb);
|
||||
if(eb != NULL)
|
||||
{
|
||||
printf("pcre study failed: %s\n", eb);
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
|
||||
error:
|
||||
/* XXX */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns 0: no match
|
||||
* 1: match
|
||||
* -1: error
|
||||
*/
|
||||
|
||||
int DetectPcreMatch (ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Signature *s, SigMatch *m)
|
||||
{
|
||||
#define MAX_SUBSTRINGS 30
|
||||
int ret = 0;
|
||||
int ov[MAX_SUBSTRINGS];
|
||||
u_int8_t *ptr = NULL;
|
||||
u_int16_t len = 0;
|
||||
|
||||
if (p->tcp_payload_len == 0)
|
||||
return 0;
|
||||
|
||||
//printf("DetectPcre: pre match: t->pkt_ptr %p t->pkt_off %u\n", t->pkt_ptr, t->pkt_off);
|
||||
|
||||
DetectPcreData *pe = (DetectPcreData *)m->ctx;
|
||||
if (s->flags & SIG_FLAG_RECURSIVE) {
|
||||
ptr = pmt->pkt_ptr ? pmt->pkt_ptr : p->tcp_payload;
|
||||
len = p->tcp_payload_len - pmt->pkt_off;
|
||||
} else if (pe->flags & DETECT_PCRE_RELATIVE) {
|
||||
ptr = pmt->pkt_ptr;
|
||||
len = p->tcp_payload_len - pmt->pkt_off;
|
||||
if (ptr == NULL || len == 0)
|
||||
return 0;
|
||||
} else {
|
||||
ptr = p->tcp_payload;
|
||||
len = p->tcp_payload_len;
|
||||
}
|
||||
|
||||
//printf("DetectPcre: ptr %p, len %u\n", ptr, len);
|
||||
|
||||
ret = pcre_exec(pe->re, pe->sd, (char *)ptr, len, 0, 0, ov, MAX_SUBSTRINGS);
|
||||
if (ret >= 0) {
|
||||
if (ret > 1 && pe->capname != NULL) {
|
||||
const char *str_ptr;
|
||||
ret = pcre_get_substring((char *)ptr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
|
||||
if (ret) {
|
||||
if (strcmp(pe->capname,"http_uri") == 0) {
|
||||
if (pmt->de_scanned_httpuri == 1)
|
||||
PacketPatternCleanup(t, pmt, pmt->mpm_instance+MPM_INSTANCE_URIOFFSET);
|
||||
|
||||
pmt->de_have_httpuri = 1;
|
||||
pmt->de_scanned_httpuri = 0;
|
||||
|
||||
p->http_uri.raw[pmt->pkt_cnt] = (u_int8_t *)str_ptr;
|
||||
p->http_uri.raw_size[pmt->pkt_cnt] = ret;
|
||||
p->http_uri.cnt = pmt->pkt_cnt;
|
||||
} else {
|
||||
FlowVarAdd(p->flow, pe->capname, (u_int8_t *)str_ptr, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* update ptrs for pcre RELATIVE */
|
||||
pmt->pkt_ptr = ptr+ov[1];
|
||||
pmt->pkt_off = (ptr+ov[1]) - p->tcp_payload;
|
||||
//printf("DetectPcre: post match: t->pkt_ptr %p t->pkt_off %u\n", t->pkt_ptr, t->pkt_off);
|
||||
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
//printf("DetectPcreMatch: ret %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DetectPcreSetup (Signature *s, SigMatch *m, char *regexstr)
|
||||
{
|
||||
const char *eb;
|
||||
int eo;
|
||||
int opts = 0;
|
||||
DetectPcreData *pd = NULL;
|
||||
SigMatch *sm = NULL;
|
||||
char *re = NULL, *op = NULL;
|
||||
char dubbed = 0;
|
||||
#define MAX_SUBSTRINGS 30
|
||||
int ret = 0, res = 0;
|
||||
int ov[MAX_SUBSTRINGS];
|
||||
const char *capture_str_ptr = NULL;
|
||||
|
||||
//printf("DetectPcreSetup: \'%s\'\n", regexstr);
|
||||
|
||||
ret = pcre_exec(parse_capture_regex, parse_capture_regex_study, regexstr, strlen(regexstr), 0, 0, ov, MAX_SUBSTRINGS);
|
||||
if (ret > 1) {
|
||||
res = pcre_get_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, &capture_str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectPcreSetup: pcre_get_substring failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
//printf("DetectPcreSetup: \'%s\'\n", capture_str_ptr ? capture_str_ptr : "NULL");
|
||||
|
||||
ret = pcre_exec(parse_regex, parse_regex_study, regexstr, strlen(regexstr), 0, 0, ov, MAX_SUBSTRINGS);
|
||||
if (ret > 1) {
|
||||
const char *str_ptr;
|
||||
res = pcre_get_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectPcreSetup: pcre_get_substring failed\n");
|
||||
return -1;
|
||||
}
|
||||
re = (char *)str_ptr;
|
||||
|
||||
if (ret > 2) {
|
||||
res = pcre_get_substring((char *)regexstr, ov, MAX_SUBSTRINGS, 2, &str_ptr);
|
||||
if (res < 0) {
|
||||
printf("DetectPcreSetup: pcre_get_substring failed\n");
|
||||
return -1;
|
||||
}
|
||||
op = (char *)str_ptr;
|
||||
}
|
||||
}
|
||||
//printf("ret %d re \'%s\', op \'%s\'\n", ret, re, op);
|
||||
|
||||
pd = malloc(sizeof(DetectPcreData));
|
||||
if (pd == NULL) {
|
||||
printf("DetectPcreSetup malloc failed\n");
|
||||
goto error;
|
||||
}
|
||||
memset(pd, 0, sizeof(DetectPcreData));
|
||||
|
||||
pd->depth = 0;
|
||||
pd->flags = 0;
|
||||
|
||||
if (capture_str_ptr != NULL) {
|
||||
pd->capname = strdup((char *)capture_str_ptr);
|
||||
}
|
||||
//printf("DetectPcreSetup: pd->capname %s\n", pd->capname ? pd->capname : "NULL");
|
||||
|
||||
while (*op) {
|
||||
DEBUGPRINT("DetectPcreSetup: regex option %c", *op);
|
||||
|
||||
switch (*op) {
|
||||
case 'A':
|
||||
opts |= PCRE_ANCHORED;
|
||||
break;
|
||||
case 'E':
|
||||
opts |= PCRE_DOLLAR_ENDONLY;
|
||||
break;
|
||||
case 'G':
|
||||
opts |= PCRE_UNGREEDY;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
opts |= PCRE_CASELESS;
|
||||
break;
|
||||
case 'm':
|
||||
opts |= PCRE_MULTILINE;
|
||||
break;
|
||||
case 's':
|
||||
opts |= PCRE_DOTALL;
|
||||
break;
|
||||
case 'x':
|
||||
opts |= PCRE_EXTENDED;
|
||||
break;
|
||||
|
||||
case 'B': /* snort's option */
|
||||
pd->flags |= DETECT_PCRE_RAWBYTES;
|
||||
break;
|
||||
case 'R': /* snort's option */
|
||||
pd->flags |= DETECT_PCRE_RELATIVE;
|
||||
break;
|
||||
case 'U': /* snort's option */
|
||||
pd->flags |= DETECT_PCRE_URI;
|
||||
break;
|
||||
default:
|
||||
printf("DetectPcreSetup: unknown regex modifier '%c'\n", *op);
|
||||
break;
|
||||
}
|
||||
op++;
|
||||
}
|
||||
|
||||
//printf("DetectPcreSetup: \"%s\"\n", re);
|
||||
|
||||
pd->re = pcre_compile(re, opts, &eb, &eo, NULL);
|
||||
if(pd->re == NULL)
|
||||
{
|
||||
printf("pcre compile of \"%s\" failed at offset %d: %s\n", regexstr, eo, eb);
|
||||
goto error;
|
||||
}
|
||||
|
||||
pd->sd = pcre_study(pd->re, 0, &eb);
|
||||
if(eb != NULL)
|
||||
{
|
||||
printf("pcre study failed : %s\n", eb);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Okay so far so good, lets get this into a SigMatch
|
||||
* and put it in the Signature. */
|
||||
sm = SigMatchAlloc();
|
||||
if (sm == NULL)
|
||||
goto error;
|
||||
|
||||
sm->type = DETECT_PCRE;
|
||||
sm->ctx = (void *)pd;
|
||||
|
||||
SigMatchAppend(s,m,sm);
|
||||
|
||||
if (dubbed) free(re);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (dubbed) free(re);
|
||||
if (pd) free(pd);
|
||||
if (sm) free(sm);
|
||||
return -1;
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
#ifndef __DETECT_PCRE_H__
|
||||
#define __DETECT_PCRE_H__
|
||||
|
||||
#define DETECT_PCRE_DISTANCE 0x01
|
||||
#define DETECT_PCRE_WITHIN 0x02
|
||||
#define DETECT_PCRE_RELATIVE 0x04
|
||||
|
||||
#define DETECT_PCRE_DISTANCE_NEXT 0x08
|
||||
#define DETECT_PCRE_WITHIN_NEXT 0x10
|
||||
|
||||
#define DETECT_PCRE_RAWBYTES 0x20
|
||||
#define DETECT_PCRE_URI 0x40
|
||||
|
||||
typedef struct _DetectPcreData {
|
||||
/* pcre options */
|
||||
pcre *re;
|
||||
pcre_extra *sd;
|
||||
int opts;
|
||||
|
||||
/* match position vars */
|
||||
u_int16_t depth;
|
||||
u_int16_t offset;
|
||||
int32_t within;
|
||||
int32_t distance;
|
||||
|
||||
u_int8_t flags;
|
||||
|
||||
char *capname;
|
||||
} DetectPcreData;
|
||||
|
||||
/* prototypes */
|
||||
void DetectPcreRegister (void);
|
||||
|
||||
#endif /* __DETECT_PCRE_H__ */
|
||||
|
@ -0,0 +1,53 @@
|
||||
/* RAWBYTES part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
#include <pcre.h>
|
||||
#include "detect-content.h"
|
||||
#include "detect-pcre.h"
|
||||
|
||||
int DetectRawbytesSetup (Signature *s, SigMatch *m, char *depthstr);
|
||||
|
||||
void DetectRawbytesRegister (void) {
|
||||
sigmatch_table[DETECT_RAWBYTES].name = "rawbytes";
|
||||
sigmatch_table[DETECT_RAWBYTES].Match = NULL;
|
||||
sigmatch_table[DETECT_RAWBYTES].Setup = DetectRawbytesSetup;
|
||||
sigmatch_table[DETECT_RAWBYTES].Free = NULL;
|
||||
sigmatch_table[DETECT_RAWBYTES].RegisterTests = NULL;
|
||||
|
||||
sigmatch_table[DETECT_RAWBYTES].flags |= SIGMATCH_NOOPT;
|
||||
}
|
||||
|
||||
int DetectRawbytesSetup (Signature *s, SigMatch *m, char *nullstr)
|
||||
{
|
||||
//printf("DetectRawbytesSetup: s->match:%p,m:%p\n", s->match, m);
|
||||
|
||||
if (nullstr != NULL) {
|
||||
printf("DetectRawbytesSetup: nocase has no value\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SigMatch *pm = m;
|
||||
if (pm != NULL) {
|
||||
#if 0
|
||||
if (pm->type == DETECT_PCRE) {
|
||||
DetectPcreData *pe = (DetectPcreData *)pm->ctx;
|
||||
printf("DetectRawbytesSetup: set depth %u for previous pcre\n", pe->depth);
|
||||
} else
|
||||
#endif
|
||||
if (pm->type == DETECT_CONTENT) {
|
||||
DetectContentData *cd = (DetectContentData *)pm->ctx;
|
||||
//printf("DetectRawbytesSetup: set nocase for previous content\n");
|
||||
cd->flags |= DETECT_CONTENT_RAWBYTES;
|
||||
} else {
|
||||
printf("DetectRawbytesSetup: Unknown previous keyword!\n");
|
||||
}
|
||||
} else {
|
||||
printf("DetectRawbytesSetup: No previous match!\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_RAWBYTES_H__
|
||||
#define __DETECT_RAWBYTES_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectRawbytesRegister (void);
|
||||
|
||||
#endif /* __DETECT_RAWBYTES_H__ */
|
||||
|
@ -0,0 +1,39 @@
|
||||
/* RECURSIVE part of the detection engine.
|
||||
*
|
||||
* Used to capture variables recursively in a payload,
|
||||
* used for example to extract http_uri for uricontent.
|
||||
*
|
||||
* Note: non Snort compatible. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
#include <pcre.h>
|
||||
|
||||
int DetectRecursiveSetup (Signature *s, SigMatch *m, char *depthstr);
|
||||
|
||||
void DetectRecursiveRegister (void) {
|
||||
sigmatch_table[DETECT_RECURSIVE].name = "recursive";
|
||||
sigmatch_table[DETECT_RECURSIVE].Match = NULL;
|
||||
sigmatch_table[DETECT_RECURSIVE].Setup = DetectRecursiveSetup;
|
||||
sigmatch_table[DETECT_RECURSIVE].Free = NULL;
|
||||
sigmatch_table[DETECT_RECURSIVE].RegisterTests = NULL;
|
||||
|
||||
sigmatch_table[DETECT_RECURSIVE].flags |= SIGMATCH_NOOPT;
|
||||
}
|
||||
|
||||
int DetectRecursiveSetup (Signature *s, SigMatch *m, char *nullstr)
|
||||
{
|
||||
//printf("DetectRecursiveSetup: s->match:%p,m:%p\n", s->match, m);
|
||||
|
||||
if (nullstr != NULL) {
|
||||
printf("DetectRecursiveSetup: recursive has no value\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->flags |= SIG_FLAG_RECURSIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_RECURSIVE_H__
|
||||
#define __DETECT_RECURSIVE_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectRecursiveRegister (void);
|
||||
|
||||
#endif /* __DETECT_RECURSIVE_H__ */
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* REFERENCE part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
int DetectReferenceSetup (Signature *s, SigMatch *m, char *str);
|
||||
|
||||
void DetectReferenceRegister (void) {
|
||||
sigmatch_table[DETECT_REFERENCE].name = "reference";
|
||||
sigmatch_table[DETECT_REFERENCE].Match = NULL;
|
||||
sigmatch_table[DETECT_REFERENCE].Setup = DetectReferenceSetup;
|
||||
sigmatch_table[DETECT_REFERENCE].Free = NULL;
|
||||
sigmatch_table[DETECT_REFERENCE].RegisterTests = NULL;
|
||||
}
|
||||
|
||||
int DetectReferenceSetup (Signature *s, SigMatch *m, char *rawstr)
|
||||
{
|
||||
char *str = rawstr;
|
||||
char dubbed = 0;
|
||||
|
||||
/* strip "'s */
|
||||
if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') {
|
||||
str = strdup(rawstr+1);
|
||||
str[strlen(rawstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
/* XXX */
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_REFERENCE_H__
|
||||
#define __DETECT_REFERENCE_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectReferenceRegister (void);
|
||||
|
||||
#endif /* __DETECT_REFERENCE_H__ */
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* REV part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
int DetectRevSetup (Signature *s, SigMatch *m, char *str);
|
||||
|
||||
void DetectRevRegister (void) {
|
||||
sigmatch_table[DETECT_REV].name = "rev";
|
||||
sigmatch_table[DETECT_REV].Match = NULL;
|
||||
sigmatch_table[DETECT_REV].Setup = DetectRevSetup;
|
||||
sigmatch_table[DETECT_REV].Free = NULL;
|
||||
sigmatch_table[DETECT_REV].RegisterTests = NULL;
|
||||
}
|
||||
|
||||
int DetectRevSetup (Signature *s, SigMatch *m, char *rawstr)
|
||||
{
|
||||
char *str = rawstr;
|
||||
char dubbed = 0;
|
||||
|
||||
/* strip "'s */
|
||||
if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') {
|
||||
str = strdup(rawstr+1);
|
||||
str[strlen(rawstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
s->rev = (u_int8_t)atoi(str);
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_REV_H__
|
||||
#define __DETECT_REV_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectRevRegister (void);
|
||||
|
||||
#endif /* __DETECT_REV_H__ */
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* SID part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
int DetectSidSetup (Signature *s, SigMatch *m, char *sidstr);
|
||||
|
||||
void DetectSidRegister (void) {
|
||||
sigmatch_table[DETECT_SID].name = "sid";
|
||||
sigmatch_table[DETECT_SID].Match = NULL;
|
||||
sigmatch_table[DETECT_SID].Setup = DetectSidSetup;
|
||||
sigmatch_table[DETECT_SID].Free = NULL;
|
||||
sigmatch_table[DETECT_SID].RegisterTests = NULL;
|
||||
}
|
||||
|
||||
int DetectSidSetup (Signature *s, SigMatch *m, char *sidstr)
|
||||
{
|
||||
char *str = sidstr;
|
||||
char dubbed = 0;
|
||||
|
||||
/* strip "'s */
|
||||
if (sidstr[0] == '\"' && sidstr[strlen(sidstr)-1] == '\"') {
|
||||
str = strdup(sidstr+1);
|
||||
str[strlen(sidstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
s->id = (u_int32_t)atoi(str);
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_SID_H__
|
||||
#define __DETECT_SID_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectSidRegister (void);
|
||||
|
||||
#endif /* __DETECT_SID_H__ */
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* THRESHOLD part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
int DetectThresholdSetup (Signature *s, SigMatch *m, char *str);
|
||||
|
||||
void DetectThresholdRegister (void) {
|
||||
sigmatch_table[DETECT_THRESHOLD].name = "threshold";
|
||||
sigmatch_table[DETECT_THRESHOLD].Match = NULL;
|
||||
sigmatch_table[DETECT_THRESHOLD].Setup = DetectThresholdSetup;
|
||||
sigmatch_table[DETECT_THRESHOLD].Free = NULL;
|
||||
sigmatch_table[DETECT_THRESHOLD].RegisterTests = NULL;
|
||||
}
|
||||
|
||||
int DetectThresholdSetup (Signature *s, SigMatch *m, char *rawstr)
|
||||
{
|
||||
char *str = rawstr;
|
||||
char dubbed = 0;
|
||||
|
||||
/* strip "'s */
|
||||
if (rawstr[0] == '\"' && rawstr[strlen(rawstr)-1] == '\"') {
|
||||
str = strdup(rawstr+1);
|
||||
str[strlen(rawstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
/* XXX */
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_THRESHOLD_H__
|
||||
#define __DETECT_THRESHOLD_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectThresholdRegister (void);
|
||||
|
||||
#endif /* __DETECT_THRESHOLD_H__ */
|
||||
|
@ -0,0 +1,421 @@
|
||||
/* Simple uricontent match part of the detection engine.
|
||||
*
|
||||
* Copyright (C) 2008 by Victor Julien <victor@inliniac.net> */
|
||||
|
||||
/* This is a very important part of the detection engine, and certainly one
|
||||
* of the most complex parts. String searching is complex and expensive,
|
||||
* and thus worth optimizing. The way that is done here is by only running
|
||||
* the pattern matcher once for every packet. In this search, all search words,
|
||||
* the 'content' matches, are looked for. All results, of all the search words
|
||||
* are stored in a array of lists. The array is an array of MpmMatchBucket's,
|
||||
* that can be entered through the DetectContentData id field. There, it finds
|
||||
* the bucket containing a list of 0, 1, or more matches of that content match.
|
||||
* The list contains MpmMatch items, that contain an offset field. This field
|
||||
* is the possition of the last character in the match.
|
||||
*
|
||||
* XXX more later....
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "detect-uricontent.h"
|
||||
#include "detect-mpm.h"
|
||||
#include "flow.h"
|
||||
#include "detect-flow.h"
|
||||
#include "flow-var.h"
|
||||
#include "threads.h"
|
||||
#include "util-mpm.h"
|
||||
|
||||
#include "util-unittest.h"
|
||||
|
||||
MpmCtx mpm_ctx[MPM_INSTANCE_MAX];
|
||||
|
||||
int DetectUricontentMatch (ThreadVars *, PatternMatcherThread *, Packet *, Signature *, SigMatch *);
|
||||
int DetectUricontentSetup (Signature *, SigMatch *, char *);
|
||||
void HttpUriRegisterTests(void);
|
||||
|
||||
u_int8_t nocasetable[256];
|
||||
#define _nc(c) nocasetable[(c)]
|
||||
|
||||
void DetectUricontentRegister (void) {
|
||||
sigmatch_table[DETECT_URICONTENT].name = "uricontent";
|
||||
sigmatch_table[DETECT_URICONTENT].Match = DetectUricontentMatch;
|
||||
sigmatch_table[DETECT_URICONTENT].Setup = DetectUricontentSetup;
|
||||
sigmatch_table[DETECT_URICONTENT].Free = NULL;
|
||||
sigmatch_table[DETECT_URICONTENT].RegisterTests = HttpUriRegisterTests;
|
||||
|
||||
/* create table for O(1) case conversion lookup */
|
||||
u_int8_t c = 0;
|
||||
for ( ; c < 255; c++) {
|
||||
if ( c >= 'a' && c <= 'z')
|
||||
nocasetable[c] = (c - ('a' - 'A'));
|
||||
else if (c >= 'A' && c <= 'Z')
|
||||
nocasetable[c] = (c + ('a' - 'A'));
|
||||
else
|
||||
nocasetable[c] = c;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
for (c = 0; c < 255; c++) {
|
||||
if (isprint(nocasetable[c]))
|
||||
printf("nocasetable[%c]: %c\n", c, nocasetable[c]);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
|
||||
/* Normalize http buffer
|
||||
*
|
||||
* Returns 0: on ok
|
||||
* 1: normalized with events occurred.
|
||||
*
|
||||
* What we normalize:
|
||||
* - ../ becomes
|
||||
* example: /one/../two/ becomes /two/
|
||||
* - // becomes /
|
||||
* example: /one//two/ becomes /one/two/
|
||||
* - '%20' becomes ' '
|
||||
* example: '/one/%20/two/' becomes '/one/ /two/'
|
||||
*/
|
||||
static inline int
|
||||
HttpUriNormalize(u_int8_t *raw, u_int16_t rawlen, u_int8_t *norm, u_int16_t *normlen) {
|
||||
u_int16_t i,x;
|
||||
for (i = 0, x = 0; i < rawlen; i++) {
|
||||
/* check for ../ */
|
||||
/* check for // */
|
||||
|
||||
norm[x] = raw[i];
|
||||
x++;
|
||||
}
|
||||
*normlen = x;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
TestOffsetDepth(MpmMatch *m, DetectUricontentData *co) {
|
||||
if (co->offset == 0 ||
|
||||
(co->offset && ((m->offset+1) - co->uricontent_len) >= co->offset)) {
|
||||
if (co->depth == 0 ||
|
||||
(co->depth && (m->offset+1) <= co->depth))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is called recursively (if nescessary) to be able
|
||||
* to determite whether or not a chain of content matches connected
|
||||
* with 'within' and 'distance' options fully matches. The reason it
|
||||
* was done like this is to make sure we can handle partial matches
|
||||
* that turn out to fail being followed by full matches later in the
|
||||
* packet. This adds some runtime complexity however. */
|
||||
static inline int
|
||||
TestWithinDistanceOffsetDepth(ThreadVars *t, PatternMatcherThread *pmt, MpmMatch *m, SigMatch *nsm)
|
||||
{
|
||||
//printf("test_nextsigmatch m:%p, nsm:%p\n", m,nsm);
|
||||
if (nsm == NULL)
|
||||
return 1;
|
||||
|
||||
DetectUricontentData *co = (DetectUricontentData *)nsm->ctx;
|
||||
MpmMatch *nm = pmt->mpm_ctx[pmt->mpm_instance + MPM_INSTANCE_URIOFFSET].match[co->id].top;
|
||||
|
||||
for (; nm; nm = nm->next) {
|
||||
//printf("test_nextsigmatch: (nm->offset+1) %u, (m->offset+1) %u\n", (nm->offset+1), (m->offset+1));
|
||||
|
||||
if ((co->within == 0 || (co->within &&
|
||||
((nm->offset+1) > (m->offset+1)) &&
|
||||
((nm->offset+1) - (m->offset+1) <= co->within))))
|
||||
{
|
||||
//printf("test_nextsigmatch: WITHIN (nm->offset+1) %u, (m->offset+1) %u\n", (nm->offset+1), (m->offset+1));
|
||||
|
||||
if (co->distance == 0 || (co->distance &&
|
||||
((nm->offset+1) > (m->offset+1)) &&
|
||||
((nm->offset+1) - (m->offset+1) >= co->distance)))
|
||||
{
|
||||
if (TestOffsetDepth(nm, co) == 1) {
|
||||
//printf("test_nextsigmatch: DISTANCE (nm->offset+1) %u, (m->offset+1) %u\n", (nm->offset+1), (m->offset+1));
|
||||
return TestWithinDistanceOffsetDepth(t, pmt, nm, nsm->next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
DoDetectUricontent(ThreadVars *t, PatternMatcherThread *pmt, Packet *p, SigMatch *sm, DetectUricontentData *co)
|
||||
{
|
||||
int ret = 0;
|
||||
char match = 0;
|
||||
|
||||
/* Get the top match, we already know we have one. */
|
||||
MpmMatch *m = pmt->mpm_ctx[pmt->mpm_instance + MPM_INSTANCE_URIOFFSET].match[co->id].top;
|
||||
|
||||
/* if we have within or distance coming up next, check this match
|
||||
* for distance and/or within and check the rest of this match
|
||||
* chain as well. */
|
||||
if ((co->flags & DETECT_URICONTENT_WITHIN_NEXT ||
|
||||
co->flags & DETECT_URICONTENT_DISTANCE_NEXT) &&
|
||||
pmt->de_checking_distancewithin == 0)
|
||||
{
|
||||
/* indicate to the detection engine the next sigmatch(es)
|
||||
* are part of this match chain */
|
||||
pmt->de_checking_distancewithin = 1;
|
||||
|
||||
for (; m != NULL; m = m->next) {
|
||||
/* first check our match for offset and depth */
|
||||
if (TestOffsetDepth(m, co) == 1) {
|
||||
ret = TestWithinDistanceOffsetDepth(t, pmt, m, sm->next);
|
||||
if (ret == 1) {
|
||||
/* update pkt ptrs, content doesn't use this,
|
||||
* but pcre does */
|
||||
pmt->pkt_ptr = p->tcp_payload + m->offset;
|
||||
pmt->pkt_off = m->offset;
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Okay, this is complicated... on the first match of a match chain,
|
||||
* we do the whole match of that chain (a chain here means a number
|
||||
* of consecutive content matches that relate to each other with
|
||||
* 'within and/or 'distance options'). But we still get to the next
|
||||
* sigmatches. We have already inspected this sigmatch, even for
|
||||
* offset and depth. Since the fact that we get there means we have
|
||||
* had a match, we return match here too.
|
||||
*/
|
||||
} else if (co->flags & DETECT_URICONTENT_WITHIN ||
|
||||
co->flags & DETECT_URICONTENT_DISTANCE)
|
||||
{
|
||||
pmt->de_checking_distancewithin = 0;
|
||||
match = 1;
|
||||
/* Getting here means we are not in checking an within/distance chain.
|
||||
* This means we can just inspect this content match on it's own. So
|
||||
* Let's see if at least one of the matches within the offset and depth
|
||||
* settings. If so, return a match.
|
||||
*/
|
||||
} else {
|
||||
for (; m != NULL; m = m->next) {
|
||||
ret = TestOffsetDepth(m,co);
|
||||
if (ret == 1) {
|
||||
/* update pkt ptrs, content doesn't use this,
|
||||
* but pcre does */
|
||||
pmt->pkt_ptr = p->tcp_payload + m->offset;
|
||||
pmt->pkt_off = m->offset;
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* returns 0: no match
|
||||
* 1: match
|
||||
* -1: error
|
||||
*/
|
||||
|
||||
int DetectUricontentMatch (ThreadVars *t, PatternMatcherThread *pmt, Packet *p, Signature *s, SigMatch *m)
|
||||
{
|
||||
u_int32_t len = 0;
|
||||
u_int32_t ret = 0;
|
||||
u_int8_t instance = pmt->mpm_instance + MPM_INSTANCE_URIOFFSET;
|
||||
//printf("instance %u\n", instance);
|
||||
|
||||
//printf("scanning uricontent have %u scan %u\n", t->de_have_httpuri, t->de_scanned_httpuri);
|
||||
|
||||
if (pmt->de_have_httpuri == 1 && pmt->de_scanned_httpuri == 0) {
|
||||
/* Scan http uri now */
|
||||
//printf("DetectUricontentMatch: going to scan uri buffer(s)\n");
|
||||
|
||||
/* scan all buffers we have */
|
||||
u_int8_t i;
|
||||
for (i = 0; i <= p->http_uri.cnt; i++) {
|
||||
//printf("p->http_uri.raw_size[%u] %u, %p, %s\n", i, p->http_uri.raw_size[i], p->http_uri.raw[i], p->http_uri.raw[i]);
|
||||
|
||||
ret += mpm_ctx[instance].Search(&mpm_ctx[instance], &pmt->mpm_ctx[instance], p->http_uri.raw[i], p->http_uri.raw_size[i]);
|
||||
//printf("DetectUricontentMatch: ret %u\n", ret);
|
||||
}
|
||||
pmt->de_scanned_httpuri = 1;
|
||||
|
||||
//printf("DetectUricontentMatch: final ret %u\n", ret);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DetectUricontentData *co = (DetectUricontentData *)m->ctx;
|
||||
|
||||
/* see if we had a match */
|
||||
len = pmt->mpm_ctx[instance].match[co->id].len;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("uricontent \'%s\' matched %u time(s) at offsets: ", co->uricontent, len);
|
||||
|
||||
MpmMatch *tmpm = NULL;
|
||||
for (tmpm = pmt->mpm_ctx[mpm_instance].match[co->id].top; tmpm != NULL; tmpm = tmpm->next) {
|
||||
printf("%u ", tmpm->offset);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
return DoDetectUricontent(t, pmt, p, m, co);
|
||||
}
|
||||
|
||||
int DetectUricontentSetup (Signature *s, SigMatch *m, char *contentstr)
|
||||
{
|
||||
DetectUricontentData *cd = NULL;
|
||||
SigMatch *sm = NULL;
|
||||
char *str = contentstr;
|
||||
char dubbed = 0;
|
||||
u_int16_t len = 0;
|
||||
|
||||
if (contentstr[0] == '\"' && contentstr[strlen(contentstr)-1] == '\"') {
|
||||
str = strdup(contentstr+1);
|
||||
str[strlen(contentstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
len = strlen(str);
|
||||
if (len == 0)
|
||||
return -1;
|
||||
|
||||
cd = malloc(sizeof(DetectUricontentData));
|
||||
if (cd == NULL) {
|
||||
printf("DetectContentSetup malloc failed\n");
|
||||
goto error;
|
||||
}
|
||||
memset(cd,0,sizeof(DetectUricontentData));
|
||||
|
||||
//printf("DetectUricontentSetup: \"%s\", len %u\n", str, len);
|
||||
char converted = 0;
|
||||
|
||||
{
|
||||
u_int16_t i, x;
|
||||
u_int8_t bin = 0, binstr[3] = "", binpos = 0;
|
||||
for (i = 0, x = 0; i < len; i++) {
|
||||
//printf("str[%02u]: %c\n", i, str[i]);
|
||||
if (str[i] == '|') {
|
||||
if (bin) {
|
||||
bin = 0;
|
||||
} else {
|
||||
bin = 1;
|
||||
}
|
||||
} else {
|
||||
if (bin) {
|
||||
if (isdigit(str[i]) ||
|
||||
str[i] == 'A' || str[i] == 'a' ||
|
||||
str[i] == 'B' || str[i] == 'b' ||
|
||||
str[i] == 'C' || str[i] == 'c' ||
|
||||
str[i] == 'D' || str[i] == 'd' ||
|
||||
str[i] == 'E' || str[i] == 'e' ||
|
||||
str[i] == 'F' || str[i] == 'f') {
|
||||
// printf("part of binary: %c\n", str[i]);
|
||||
|
||||
binstr[binpos] = (char)str[i];
|
||||
binpos++;
|
||||
|
||||
if (binpos == 2) {
|
||||
u_int8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF;
|
||||
#ifdef DEBUG
|
||||
printf("Binstr %X\n", c);
|
||||
#endif
|
||||
binpos = 0;
|
||||
str[x] = c;
|
||||
x++;
|
||||
converted = 1;
|
||||
}
|
||||
} else if (str[i] == ' ') {
|
||||
// printf("space as part of binary string\n");
|
||||
}
|
||||
} else {
|
||||
str[x] = str[i];
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
for (i = 0; i < x; i++) {
|
||||
if (isprint(str[i])) printf("%c", str[i]);
|
||||
else printf("\\x%02u", str[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
if (converted)
|
||||
len = x;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("DetectUricontentSetup: len %u\n", len);
|
||||
#endif
|
||||
|
||||
cd->uricontent = malloc(len);
|
||||
if (cd->uricontent == NULL)
|
||||
return -1;
|
||||
|
||||
memcpy(cd->uricontent, str, len);
|
||||
cd->uricontent_len = len;
|
||||
cd->depth = 0;
|
||||
cd->offset = 0;
|
||||
cd->within = 0;
|
||||
cd->distance = 0;
|
||||
cd->flags = 0;
|
||||
|
||||
/* Okay so far so good, lets get this into a SigMatch
|
||||
* and put it in the Signature. */
|
||||
sm = SigMatchAlloc();
|
||||
if (sm == NULL)
|
||||
goto error;
|
||||
|
||||
sm->type = DETECT_URICONTENT;
|
||||
sm->ctx = (void *)cd;
|
||||
|
||||
SigMatchAppend(s,m,sm);
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (dubbed) free(str);
|
||||
if (cd) free(cd);
|
||||
if (sm) free(sm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* TESTS
|
||||
*/
|
||||
|
||||
int HttpUriTest01 (void) {
|
||||
u_int8_t *raw = (u_int8_t *)"/one/../two/";
|
||||
u_int16_t rawlen = strlen((char *)raw);
|
||||
u_int8_t *norm = (u_int8_t *)"/two/";
|
||||
u_int16_t normlen = strlen((char *)norm);
|
||||
int result = 0, r = 0;
|
||||
|
||||
u_int8_t buf[1024];
|
||||
u_int16_t buflen = 0;
|
||||
|
||||
r = HttpUriNormalize(raw, rawlen, buf, &buflen);
|
||||
|
||||
if (buflen == normlen && memcmp(norm, buf, normlen) == 0)
|
||||
result = 1;
|
||||
|
||||
//printf("HttpUriTest01: buflen %u, %s\n", buflen, buf);
|
||||
|
||||
//end:
|
||||
return result;
|
||||
}
|
||||
|
||||
void HttpUriRegisterTests(void) {
|
||||
UtRegisterTest("HttpUriTest01", HttpUriTest01, 1);
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
#ifndef __DETECT_URICONTENT_H__
|
||||
#define __DETECT_URICONTENT_H__
|
||||
|
||||
#define DETECT_URICONTENT_NOCASE 0x01
|
||||
#define DETECT_URICONTENT_DISTANCE 0x02
|
||||
#define DETECT_URICONTENT_WITHIN 0x04
|
||||
|
||||
#define DETECT_URICONTENT_DISTANCE_NEXT 0x08
|
||||
#define DETECT_URICONTENT_WITHIN_NEXT 0x10
|
||||
|
||||
#define DETECT_URICONTENT_RAWBYTES 0x20
|
||||
|
||||
typedef struct _DetectUricontentData {
|
||||
u_int8_t *uricontent;
|
||||
u_int8_t uricontent_len;
|
||||
u_int32_t id;
|
||||
|
||||
u_int16_t depth;
|
||||
u_int16_t offset;
|
||||
int32_t distance;
|
||||
int32_t within;
|
||||
u_int8_t flags;
|
||||
} DetectUricontentData;
|
||||
|
||||
/* prototypes */
|
||||
void DetectUricontentRegister (void);
|
||||
|
||||
#endif /* __DETECT_URICONTENT_H__ */
|
||||
|
@ -0,0 +1,86 @@
|
||||
/* WITHIN part of the detection engine. */
|
||||
|
||||
#include "decode.h"
|
||||
#include "detect.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
#include <pcre.h>
|
||||
#include "detect-content.h"
|
||||
#include "detect-uricontent.h"
|
||||
#include "detect-pcre.h"
|
||||
|
||||
int DetectWithinSetup (Signature *s, SigMatch *m, char *withinstr);
|
||||
|
||||
void DetectWithinRegister (void) {
|
||||
sigmatch_table[DETECT_WITHIN].name = "within";
|
||||
sigmatch_table[DETECT_WITHIN].Match = NULL;
|
||||
sigmatch_table[DETECT_WITHIN].Setup = DetectWithinSetup;
|
||||
sigmatch_table[DETECT_WITHIN].Free = NULL;
|
||||
sigmatch_table[DETECT_WITHIN].RegisterTests = NULL;
|
||||
}
|
||||
|
||||
int DetectWithinSetup (Signature *s, SigMatch *m, char *withinstr)
|
||||
{
|
||||
char *str = withinstr;
|
||||
char dubbed = 0;
|
||||
|
||||
//printf("DetectWithinSetup: s->match:%p,m:%p,withinstr:\'%s\'\n", s->match, m, withinstr);
|
||||
|
||||
/* strip "'s */
|
||||
if (withinstr[0] == '\"' && withinstr[strlen(withinstr)-1] == '\"') {
|
||||
str = strdup(withinstr+1);
|
||||
str[strlen(withinstr)-2] = '\0';
|
||||
dubbed = 1;
|
||||
}
|
||||
|
||||
SigMatch *pm = m;
|
||||
if (pm != NULL) {
|
||||
if (pm->type == DETECT_PCRE) {
|
||||
DetectPcreData *pe = (DetectPcreData *)pm->ctx;
|
||||
|
||||
pe->within = strtol(str, NULL, 10);
|
||||
pe->flags |= DETECT_PCRE_WITHIN;
|
||||
|
||||
//printf("DetectWithinSetup: set within %d for previous pcre\n", pe->within);
|
||||
} else if (pm->type == DETECT_CONTENT) {
|
||||
DetectContentData *cd = (DetectContentData *)pm->ctx;
|
||||
|
||||
cd->within = strtol(str, NULL, 10);
|
||||
cd->flags |= DETECT_CONTENT_WITHIN;
|
||||
|
||||
//printf("DetectWithinSetup: set within %d for previous content\n", cd->within);
|
||||
} else if (pm->type == DETECT_URICONTENT) {
|
||||
DetectUricontentData *ud = (DetectUricontentData *)pm->ctx;
|
||||
|
||||
ud->within = strtol(str, NULL, 10);
|
||||
ud->flags |= DETECT_URICONTENT_WITHIN;
|
||||
|
||||
//printf("DetectWithinSetup: set within %d for previous content\n", cd->within);
|
||||
} else {
|
||||
printf("DetectWithinSetup: Unknown previous keyword!\n");
|
||||
}
|
||||
} else {
|
||||
printf("DetectWithinSetup: No previous match!\n");
|
||||
}
|
||||
pm = m->prev;
|
||||
if (pm != NULL) {
|
||||
if (pm->type == DETECT_PCRE) {
|
||||
DetectPcreData *pe = (DetectPcreData *)pm->ctx;
|
||||
pe->flags |= DETECT_PCRE_WITHIN_NEXT;
|
||||
} else if (pm->type == DETECT_CONTENT) {
|
||||
DetectContentData *cd = (DetectContentData *)pm->ctx;
|
||||
cd->flags |= DETECT_CONTENT_WITHIN_NEXT;
|
||||
} else if (pm->type == DETECT_URICONTENT) {
|
||||
DetectUricontentData *ud = (DetectUricontentData *)pm->ctx;
|
||||
ud->flags |= DETECT_URICONTENT_WITHIN_NEXT;
|
||||
} else {
|
||||
printf("DetectWithinSetup: Unknown previous-previous keyword!\n");
|
||||
}
|
||||
} else {
|
||||
printf("DetectWithinSetup: No previous-previous match!\n");
|
||||
}
|
||||
|
||||
if (dubbed) free(str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#ifndef __DETECT_WITHIN_H__
|
||||
#define __DETECT_WITHIN_H__
|
||||
|
||||
/* prototypes */
|
||||
void DetectWithinRegister (void);
|
||||
|
||||
#endif /* __DETECT_WITHIN_H__ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,106 @@
|
||||
#ifndef __DETECT_H__
|
||||
#define __DETECT_H__
|
||||
|
||||
#define SIG_FLAG_RECURSIVE 0x01
|
||||
#define SIG_FLAG_SP_ANY 0x02
|
||||
#define SIG_FLAG_DP_ANY 0x04
|
||||
|
||||
typedef struct _PatternMatcherThread {
|
||||
/* detection engine variables */
|
||||
u_int8_t *pkt_ptr; /* ptr to the current position in the pkt */
|
||||
u_int16_t pkt_off;
|
||||
u_int8_t pkt_cnt;
|
||||
|
||||
/* multipattern matcher ctx */
|
||||
MpmThreadCtx mpm_ctx[MPM_INSTANCE_MAX];
|
||||
char de_checking_distancewithin;
|
||||
|
||||
/* http_uri stuff for uricontent */
|
||||
char de_have_httpuri;
|
||||
char de_scanned_httpuri;
|
||||
|
||||
/* instance of the mpm */
|
||||
u_int8_t mpm_instance;
|
||||
} PatternMatcherThread;
|
||||
|
||||
/* for now typedef them to known types, we will implement
|
||||
* our types later... */
|
||||
typedef Port SigPort;
|
||||
typedef Address SigAddress;
|
||||
|
||||
typedef struct _Signature {
|
||||
u_int32_t id;
|
||||
u_int8_t rev;
|
||||
char *msg;
|
||||
u_int8_t flags;
|
||||
|
||||
SigAddress src, dst;
|
||||
SigPort sp, dp;
|
||||
|
||||
struct _SigMatch *match;
|
||||
struct _Signature *next;
|
||||
} Signature;
|
||||
|
||||
typedef struct _SigMatch {
|
||||
u_int8_t type;
|
||||
void *ctx;
|
||||
struct _SigMatch *prev;
|
||||
struct _SigMatch *next;
|
||||
} SigMatch;
|
||||
|
||||
typedef struct SigTableElmt {
|
||||
char *name;
|
||||
u_int8_t cost; /* 0 hardly any, 255 very expensive */
|
||||
int (*Match)(ThreadVars *, PatternMatcherThread *, Packet *, Signature *, SigMatch *);
|
||||
int (*Setup)(Signature *, SigMatch *, char *);
|
||||
int (*Free)(SigMatch *);
|
||||
void (*RegisterTests)(void);
|
||||
u_int8_t flags;
|
||||
} SigTableElmt;
|
||||
|
||||
#define SIGMATCH_NOOPT 0x01
|
||||
|
||||
void SigLoadSignatures (void);
|
||||
void SigTableSetup(void);
|
||||
|
||||
enum {
|
||||
DETECT_SID,
|
||||
DETECT_REV,
|
||||
DETECT_CLASSTYPE,
|
||||
DETECT_THRESHOLD,
|
||||
DETECT_METADATA,
|
||||
DETECT_REFERENCE,
|
||||
DETECT_MSG,
|
||||
DETECT_CONTENT,
|
||||
DETECT_URICONTENT,
|
||||
DETECT_PCRE,
|
||||
DETECT_DEPTH,
|
||||
DETECT_DISTANCE,
|
||||
DETECT_WITHIN,
|
||||
DETECT_OFFSET,
|
||||
DETECT_NOCASE,
|
||||
DETECT_RECURSIVE,
|
||||
DETECT_RAWBYTES,
|
||||
DETECT_FLOW,
|
||||
DETECT_DSIZE,
|
||||
DETECT_FLOWVAR,
|
||||
DETECT_ADDRESS,
|
||||
|
||||
/* make sure this stays last */
|
||||
DETECT_TBLSIZE,
|
||||
};
|
||||
|
||||
/* Table with all SigMatch registrations */
|
||||
SigTableElmt sigmatch_table[DETECT_TBLSIZE];
|
||||
|
||||
/* detection api */
|
||||
SigMatch *SigMatchAlloc(void);
|
||||
void SigMatchAppend(Signature *, SigMatch *, SigMatch *);
|
||||
void SigCleanSignatures(void);
|
||||
|
||||
void SigTableRegisterTests(void);
|
||||
void SigRegisterTests(void);
|
||||
void TmModuleDetectRegister (void);
|
||||
|
||||
#endif /* __DETECT_H__ */
|
||||
|
@ -0,0 +1,163 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#include "threads.h"
|
||||
#include "decode.h"
|
||||
#include "debug.h"
|
||||
#include "flow.h"
|
||||
|
||||
#include "flow-hash.h"
|
||||
#include "flow-util.h"
|
||||
#include "flow-private.h"
|
||||
|
||||
u_int32_t FlowGetKey(Packet *p) {
|
||||
FlowKey *k = (FlowKey *)p;
|
||||
u_int32_t key;
|
||||
|
||||
if (p->ip4h != NULL)
|
||||
key = (flow_config.hash_rand + k->sp + k->dp + \
|
||||
k->src.addr_data32[0] + k->dst.addr_data32[0]) % flow_config.hash_size;
|
||||
else if (p->ip6h != NULL)
|
||||
key = (flow_config.hash_rand + k->sp + k->dp + \
|
||||
k->src.addr_data32[0] + k->src.addr_data32[1] + \
|
||||
k->src.addr_data32[2] + k->src.addr_data32[3] + \
|
||||
k->dst.addr_data32[0] + k->dst.addr_data32[1] + \
|
||||
k->dst.addr_data32[2] + k->dst.addr_data32[3]) % flow_config.hash_size;
|
||||
else
|
||||
key = 0;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/* Since two or more flows can have the same hash key, we need to compare
|
||||
* the flow with the current flow key. */
|
||||
#define CMP_FLOW(f1,f2) \
|
||||
((CMP_ADDR(&(f1)->src, &(f2)->src) && \
|
||||
CMP_ADDR(&(f1)->dst, &(f2)->dst) && \
|
||||
CMP_PORT((f1)->sp, (f2)->sp) && CMP_PORT((f1)->dp, (f2)->dp)) || \
|
||||
(CMP_ADDR(&(f1)->src, &(f2)->dst) && \
|
||||
CMP_ADDR(&(f1)->dst, &(f2)->src) && \
|
||||
CMP_PORT((f1)->sp, (f2)->dp) && CMP_PORT((f1)->dp, (f2)->sp)))
|
||||
|
||||
/* FlowGetFlowFromHash
|
||||
*
|
||||
* Hash retrieval function for flows. Looks up the hash bucket containing the
|
||||
* flow pointer. Then compares the packet with the found flow to see if it is
|
||||
* the flow we need. If it isn't, walk the list until the right flow is found.
|
||||
*
|
||||
* If the flow is not found or the bucket was emtpy, a new flow is taken from
|
||||
* the queue. FlowDequeue() will alloc new flows as long as we stay within our
|
||||
* memcap limit.
|
||||
*
|
||||
* returns a *LOCKED* flow or NULL
|
||||
*/
|
||||
Flow *FlowGetFlowFromHash (Packet *p)
|
||||
{
|
||||
Flow *f = NULL;
|
||||
|
||||
/* get the key to our bucket */
|
||||
u_int32_t key = FlowGetKey(p);
|
||||
/* get our hash bucket and lock it */
|
||||
FlowBucket *fb = &flow_hash[key];
|
||||
mutex_lock(&fb->m);
|
||||
|
||||
DEBUGPRINT("FlowGetFlowFromHash: fb %p fb->f %p", fb, fb->f);
|
||||
|
||||
/* see if the bucket already has a flow */
|
||||
if (fb->f == NULL) {
|
||||
/* no, so get one */
|
||||
f = fb->f = FlowDequeue(&flow_spare_q);
|
||||
if (f == NULL) {
|
||||
flow_flags |= FLOW_EMERGENCY;
|
||||
|
||||
f = fb->f = FlowAlloc();
|
||||
if (f == NULL) {
|
||||
mutex_unlock(&fb->m);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* these are protected by the bucket lock */
|
||||
f->hnext = NULL;
|
||||
f->hprev = NULL;
|
||||
|
||||
/* got one, now lock, initialize and return */
|
||||
mutex_lock(&f->m);
|
||||
FlowInit(f,p);
|
||||
FlowRequeue(f, NULL, &flow_new_q);
|
||||
f->flags |= FLOW_NEW_LIST;
|
||||
f->fb = fb;
|
||||
|
||||
mutex_unlock(&fb->m);
|
||||
return f;
|
||||
}
|
||||
|
||||
/* ok, we have a flow in the bucket. Let's find out if it is our flow */
|
||||
f = fb->f;
|
||||
/* lock the 'root' flow */
|
||||
mutex_lock(&f->m);
|
||||
|
||||
/* see if this is the flow we are looking for */
|
||||
if (CMP_FLOW(f, p) == 0) {
|
||||
Flow *pf = NULL; /* previous flow */
|
||||
mutex_unlock(&f->m);
|
||||
|
||||
while (f) {
|
||||
pf = f; /* pf is not locked at this point */
|
||||
f = f->hnext;
|
||||
|
||||
if (f == NULL) {
|
||||
/* get us a new one and put it and the list tail */
|
||||
f = pf->hnext = FlowDequeue(&flow_spare_q);
|
||||
if (f == NULL) {
|
||||
flow_flags |= FLOW_EMERGENCY;
|
||||
|
||||
f = fb->f = FlowAlloc();
|
||||
if (f == NULL) {
|
||||
mutex_unlock(&fb->m);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
f->hnext = NULL;
|
||||
f->hprev = pf;
|
||||
|
||||
/* lock, initialize and return */
|
||||
mutex_lock(&f->m);
|
||||
FlowInit(f,p);
|
||||
FlowRequeue(f, NULL, &flow_new_q);
|
||||
|
||||
f->flags |= FLOW_NEW_LIST;
|
||||
f->fb = fb;
|
||||
|
||||
mutex_unlock(&fb->m);
|
||||
return f;
|
||||
}
|
||||
|
||||
mutex_lock(&f->m);
|
||||
|
||||
if (CMP_FLOW(f, p) != 0) {
|
||||
/* we found our flow, lets put it on top of the
|
||||
* hash list -- this rewards active flows */
|
||||
if (f->hnext) f->hnext->hprev = f->hprev;
|
||||
if (f->hprev) f->hprev->hnext = f->hnext;
|
||||
|
||||
f->hnext = fb->f;
|
||||
f->hprev = NULL;
|
||||
fb->f->hprev = f;
|
||||
fb->f = f;
|
||||
|
||||
/* found our flow */
|
||||
mutex_unlock(&fb->m);
|
||||
return f;
|
||||
}
|
||||
|
||||
/* not found, try the next... */
|
||||
mutex_unlock(&f->m);
|
||||
}
|
||||
}
|
||||
|
||||
/* The 'root' flow was our flow, return it.
|
||||
* It's already locked. */
|
||||
mutex_unlock(&fb->m);
|
||||
return f;
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __FLOW_HASH_H__
|
||||
#define __FLOW_HASH_H__
|
||||
|
||||
/* flow hash bucket -- the hash is basically an array of these buckets.
|
||||
* Each bucket contains a flow or list of flows. All these flows have
|
||||
* the same hashkey (the hash is a chained hash). When doing modifications
|
||||
* to the list, the entire bucket is locked. */
|
||||
typedef struct _FlowBucket {
|
||||
Flow *f;
|
||||
pthread_mutex_t m;
|
||||
} FlowBucket;
|
||||
|
||||
/* prototypes */
|
||||
|
||||
Flow *FlowGetFlowFromHash(Packet *);
|
||||
|
||||
#endif /* __FLOW_HASH_H__ */
|
||||
|
@ -0,0 +1,37 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __FLOW_PRIVATE_H__
|
||||
#define __FLOW_PRIVATE_H__
|
||||
|
||||
#include "flow-hash.h"
|
||||
#include "flow-queue.h"
|
||||
|
||||
/* per flow flags */
|
||||
#define FLOW_TO_SRC_SEEN 0x01
|
||||
#define FLOW_TO_DST_SEEN 0x02
|
||||
#define FLOW_NEW_LIST 0x04
|
||||
#define FLOW_EST_LIST 0x08
|
||||
|
||||
/* global flow flags */
|
||||
#define FLOW_EMERGENCY 0x01
|
||||
|
||||
/*
|
||||
* Variables
|
||||
*/
|
||||
|
||||
FlowQueue flow_spare_q; /* Spare flow's. Prealloced flows in here */
|
||||
FlowQueue flow_new_q; /* Flows in the unreplied state live here */
|
||||
FlowQueue flow_est_q; /* All other flows live here, the top holds the
|
||||
* last recently used (lru) flow, so we can remove
|
||||
* that in case of memory problems and check it for
|
||||
* timeouts. */
|
||||
FlowBucket *flow_hash;
|
||||
FlowConfig flow_config;
|
||||
|
||||
u_int8_t flow_flags;
|
||||
|
||||
u_int32_t flow_memuse;
|
||||
pthread_mutex_t flow_memuse_mutex;
|
||||
|
||||
#endif /* __FLOW_PRIVATE_H__ */
|
||||
|
@ -0,0 +1,100 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#include "threads.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "flow-queue.h"
|
||||
#include "flow-util.h"
|
||||
|
||||
void FlowEnqueue (FlowQueue *q, Flow *f) {
|
||||
/* more packets in queue */
|
||||
if (q->top != NULL) {
|
||||
f->lnext = q->top;
|
||||
q->top->lprev = f;
|
||||
q->top = f;
|
||||
/* only packet */
|
||||
} else {
|
||||
q->top = f;
|
||||
q->bot = f;
|
||||
}
|
||||
q->len++;
|
||||
#ifdef DBG_PERF
|
||||
if (q->len > q->dbg_maxlen)
|
||||
q->dbg_maxlen = q->len;
|
||||
#endif /* DBG_PERF */
|
||||
}
|
||||
|
||||
Flow *FlowDequeue (FlowQueue *q) {
|
||||
mutex_lock(&q->mutex_q);
|
||||
|
||||
Flow *f = q->bot;
|
||||
if (f == NULL) {
|
||||
mutex_unlock(&q->mutex_q);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* more packets in queue */
|
||||
if (q->bot->lprev != NULL) {
|
||||
q->bot = q->bot->lprev;
|
||||
q->bot->lnext = NULL;
|
||||
/* just the one we remove, so now empty */
|
||||
} else {
|
||||
q->top = NULL;
|
||||
q->bot = NULL;
|
||||
}
|
||||
|
||||
q->len--;
|
||||
|
||||
f->lnext = NULL;
|
||||
f->lprev = NULL;
|
||||
|
||||
mutex_unlock(&q->mutex_q);
|
||||
return f;
|
||||
}
|
||||
|
||||
void FlowRequeue(Flow *f, FlowQueue *srcq, FlowQueue *dstq)
|
||||
{
|
||||
if (srcq != NULL)
|
||||
{
|
||||
mutex_lock(&srcq->mutex_q);
|
||||
|
||||
/* remove from old queue */
|
||||
if (srcq->top == f)
|
||||
srcq->top = f->lnext; /* remove from queue top */
|
||||
if (srcq->bot == f)
|
||||
srcq->bot = f->lprev; /* remove from queue bot */
|
||||
if (f->lprev)
|
||||
f->lprev->lnext = f->lnext; /* remove from flow prev */
|
||||
if (f->lnext)
|
||||
f->lnext->lprev = f->lprev; /* remove from flow next */
|
||||
|
||||
srcq->len--; /* adjust len */
|
||||
|
||||
f->lnext = NULL;
|
||||
f->lprev = NULL;
|
||||
|
||||
/* don't unlock if src and dst are the same */
|
||||
if (srcq != dstq) mutex_unlock(&srcq->mutex_q);
|
||||
}
|
||||
|
||||
/* now put it in dst */
|
||||
if (srcq != dstq) mutex_lock(&dstq->mutex_q);
|
||||
|
||||
/* add to new queue (append) */
|
||||
f->lprev = dstq->bot;
|
||||
if (f->lprev)
|
||||
f->lprev->lnext = f;
|
||||
f->lnext = NULL;
|
||||
dstq->bot = f;
|
||||
if (dstq->top == NULL)
|
||||
dstq->top = f;
|
||||
|
||||
dstq->len++;
|
||||
#ifdef DBG_PERF
|
||||
if (dstq->len > dstq->dbg_maxlen)
|
||||
dstq->dbg_maxlen = dstq->len;
|
||||
#endif /* DBG_PERF */
|
||||
|
||||
mutex_unlock(&dstq->mutex_q);
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#ifndef __FLOW_QUEUE_H__
|
||||
#define __FLOW_QUEUE_H__
|
||||
|
||||
#include "flow.h"
|
||||
|
||||
/* Define a queue for storing unused flows */
|
||||
typedef struct _FlowQueue
|
||||
{
|
||||
Flow *top;
|
||||
Flow *bot;
|
||||
u_int32_t len;
|
||||
pthread_mutex_t mutex_q;
|
||||
pthread_cond_t cond_q;
|
||||
#ifdef DBG_PERF
|
||||
u_int32_t dbg_maxlen;
|
||||
#endif /* DBG_PERF */
|
||||
} FlowQueue;
|
||||
|
||||
/* prototypes */
|
||||
void FlowEnqueue (FlowQueue *, Flow *);
|
||||
Flow *FlowDequeue (FlowQueue *);
|
||||
void FlowRequeue(Flow *, FlowQueue *, FlowQueue *);
|
||||
|
||||
#endif /* __FLOW_QUEUE_H__ */
|
||||
|
@ -0,0 +1,77 @@
|
||||
/* Copyright (c) 2008 Victor Julien <victor@inliniac.net> */
|
||||
|
||||
#include "threads.h"
|
||||
|
||||
#include "flow.h"
|
||||
#include "flow-private.h"
|
||||
#include "flow-util.h"
|
||||
#include "flow-var.h"
|
||||
|
||||
/* Allocate a flow */
|
||||
Flow *FlowAlloc(void)
|
||||
{
|
||||
Flow *f;
|
||||
|
||||
mutex_lock(&flow_memuse_mutex);
|
||||
if (flow_memuse + sizeof(Flow) > flow_config.memcap) {
|
||||
mutex_unlock(&flow_memuse_mutex);
|
||||
return NULL;
|
||||
}
|
||||
f = malloc(sizeof(Flow));
|
||||
if (f == NULL) {
|
||||
mutex_unlock(&flow_memuse_mutex);
|
||||
return NULL;
|
||||
}
|
||||
flow_memuse += sizeof(Flow);
|
||||
mutex_unlock(&flow_memuse_mutex);
|
||||
|
||||
pthread_mutex_init(&f->m, NULL);
|
||||
f->lnext = NULL;
|
||||
f->lprev = NULL;
|
||||
f->hnext = NULL;
|
||||
f->hprev = NULL;
|
||||
|
||||
/* we need this here so even unitialized are freed
|
||||
* properly */
|
||||
f->flowvar = NULL;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void FlowFree(Flow *f)
|
||||
{
|
||||
mutex_lock(&flow_memuse_mutex);
|
||||
flow_memuse -= sizeof(Flow);
|
||||
mutex_unlock(&flow_memuse_mutex);
|
||||
|
||||
FlowVarFree(f->flowvar);
|
||||
|
||||
free(f);
|
||||
}
|
||||
|
||||
void FlowInit(Flow *f, Packet *p)
|
||||
{
|
||||
CLEAR_FLOW(f);
|
||||
|
||||
if (p->ip4h != NULL) { /* XXX MACRO */
|
||||
SET_IPV4_SRC_ADDR(p,&f->src);
|
||||
SET_IPV4_DST_ADDR(p,&f->dst);
|
||||
} else if (p->ip6h != NULL) { /* XXX MACRO */
|
||||
SET_IPV6_SRC_ADDR(p,&f->src);
|
||||
SET_IPV6_DST_ADDR(p,&f->dst);
|
||||
} /* XXX handle default */
|
||||
else {
|
||||
printf("FIXME: %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
if (p->tcph != NULL) { /* XXX MACRO */
|
||||
SET_TCP_SRC_PORT(p,&f->sp);
|
||||
SET_TCP_DST_PORT(p,&f->dp);
|
||||
} /* XXX handle default */
|
||||
else {
|
||||
printf("FIXME: %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
COPY_TIMESTAMP(&p->ts, &f->startts);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue