Initial add of the files.

remotes/origin/master-1.0.x
Victor Julien 17 years ago
parent 1cfa8dd2e5
commit bab4b62376

@ -0,0 +1 @@
Victor Julien <victor@inliniac.net>

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 of the License, 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
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

@ -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:

7532
aclocal.m4 vendored

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);
}

1500
config.guess vendored

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

1616
config.sub vendored

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
}

7008
libtool

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -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(&ethh, 0, sizeof(EthernetHdr));
ethh.eth_type = htons(ETHERNET_TYPE_IP);
memcpy(buf+buflen,&ethh,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…
Cancel
Save